Compare commits

..

883 Commits

Author SHA1 Message Date
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
sk
c3d9147705 fix wrong time/username reference when replying 2023-08-27 14:46:33 +02:00
Eugen Rochko
d8036779f8 New translations strings.xml (Japanese) 2023-08-27 14:46:15 +02:00
sk
2fafdcc4f8 fix unifiedpush settings item
closes sk22#770
2023-08-27 14:33:57 +02:00
sk
ef3f96ba74 fix timestamp being hidden for long usernames
closes sk22#772
2023-08-27 14:12:23 +02:00
sk
91bf1b277f fix null-pointer exception in filter result
closes sk22#774
2023-08-27 13:52:31 +02:00
sk
c6acd35ceb fix "blocked" button style
closes sk22#775
2023-08-27 13:45:44 +02:00
sk
a85a0b7d78 don't show blocked_by status
restoring fix for sk22#526
2023-08-27 13:38:33 +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
sk
ad96031aeb rounded corners for inset images! 2023-08-25 23:26:27 +02:00
sk
aa9e66e6a2 tweak account card design
closes sk22#731
2023-08-25 17:20:54 +02:00
sk
86081654fb remove unused import 2023-08-25 17:19:42 +02:00
sk
cac030ffed fix inconsistent avatar border radius 2023-08-25 17:19:29 +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
sk
71f4f089b6 scroll to added emoji; improve loading animation 2023-08-24 13:26:42 +02:00
sk
0f72809342 scroll to existing reaction when adding 2023-08-24 13:15:53 +02:00
sk
40a033d692 no emoji reactions for akkoma announcements 2023-08-24 13:03:24 +02:00
sk
d44df2c23c change behavior when adding reactions
closes sk22#769
2023-08-24 13:00:16 +02:00
sk
47fde1e08b undo spacing "fix" 2023-08-24 12:41:17 +02:00
sk
0688521ae8 make emoji reactions not click-through-able 2023-08-24 12:17:15 +02:00
sk
bdf0f21647 fix spacing between text and footer 2023-08-24 12:13:20 +02:00
sk
bb03342ff2 boop versinom 2023-08-24 12:12:55 +02:00
sk
937304f27b improve profile metadata editor styles 2023-08-24 00:05:36 +02:00
sk
6b4ce0ea69 hide roles when in edit mode 2023-08-23 23:48:42 +02:00
sk
7f0c4860f8 clean up code 2023-08-23 23:47:06 +02:00
sk
9b4c70a5ed fix jumping profile layout
closes sk22#656
2023-08-23 23:46:23 +02:00
sk
49137273ae clean up code 2023-08-23 23:38:45 +02:00
sk
647e3e5e85 progress indicator for emoji reactions 2023-08-23 23:38:12 +02:00
sk
4920bf63e3 oops. accidentally removed a setting 2023-08-23 23:12:11 +02:00
sk
0afcdb2cdf emoji reactions for announcements! 2023-08-23 22:56:11 +02:00
sk
d96c3c3c8a fix paddings around dummys, text and spoilers
closes sk22#638
2023-08-23 22:12:14 +02:00
Eugen Rochko
3d987b8e1d New translations strings.xml (Thai) 2023-08-23 21:39:07 +02:00
sk
f5e5408d70 Merge remote-tracking branch 'upstream/master' 2023-08-23 20:02:06 +02:00
sk
d62899c990 fix reaction data and binding inconsistencies 2023-08-23 19:49: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
Grishka
e5bdeba1d7 Fix strings 2023-08-23 00:44:40 +03:00
Grishka
8d7db7774f Merge branch 'l10n_master' 2023-08-23 00:40:45 +03:00
Grishka
78d22c670c Fix reporting 2023-08-23 00:40:38 +03:00
Eugen Rochko
0a679109f5 New translations strings.xml (Arabic) 2023-08-22 17:14:41 +02:00
Eugen Rochko
e843142b7e New translations strings.xml (Arabic) 2023-08-22 13:15:25 +02:00
Eugen Rochko
72e728f655 New translations strings.xml (French) 2023-08-22 13:15:23 +02:00
Eugen Rochko
ef56792f56 New translations strings.xml (Arabic) 2023-08-22 11:39:27 +02:00
Eugen Rochko
504a6959e8 New translations strings.xml (French) 2023-08-22 11:39:25 +02:00
sk
6054a3d65c Merge remote-tracking branch 'weblate/main' 2023-08-21 22:43:23 +02:00
sk
f50eac02d8 move adding reactions to reactions item 2023-08-21 22:40:19 +02:00
snerk
9634db9061 Translated using Weblate (Norwegian Nynorsk)
Currently translated at 20.8% (75 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nn/
2023-08-21 22:40:19 +02:00
snerk
97e3e283dd Translated using Weblate (Norwegian Nynorsk)
Currently translated at 18.8% (68 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nn/
2023-08-21 22:40:19 +02:00
snerk
f1e233569b Added translation using Weblate (Norwegian Nynorsk) 2023-08-21 22:40:19 +02:00
alextecplayz
04dd637fa9 Translated using Weblate (Romanian)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-08-21 22:40:19 +02:00
gallegonovato
c48a4105a9 Translated using Weblate (Spanish)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-08-21 22:40:19 +02:00
EndermanCo
aac53d949b Translated using Weblate (Persian)
Currently translated at 38.8% (7 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fa/
2023-08-21 22:40:19 +02:00
EndermanCo
9bb4e5b467 Translated using Weblate (Persian)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-21 22:40:19 +02:00
0eoc
fb0391d5cd Translated using Weblate (Russian)
Currently translated at 61.1% (11 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2023-08-21 22:40:19 +02:00
ihor_ck
e4d898c903 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-08-21 22:40:19 +02:00
Linerly
da222f75bb Translated using Weblate (Indonesian)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-08-21 22:40:19 +02:00
Choukajohn
25fbd91eb3 Translated using Weblate (French)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-08-21 22:40:19 +02:00
0eoc
d458cca7bf Translated using Weblate (Russian)
Currently translated at 96.1% (323 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-08-21 22:40:19 +02:00
gallegonovato
3933a61b5a Translated using Weblate (Spanish)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-08-21 22:40:19 +02:00
Codeberg Translate
29092bbf36 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/
2023-08-21 22:40:19 +02:00
edxkl
a33d2578c9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 94.4% (17 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2023-08-21 22:40:19 +02:00
edxkl
9afe4b5ac6 Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.3% (327 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-08-21 22:40:19 +02:00
EndermanCo
6782006b05 Translated using Weblate (Persian)
Currently translated at 27.7% (5 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fa/
2023-08-21 22:40:19 +02:00
0eoc
90bdbefd48 Translated using Weblate (Russian)
Currently translated at 61.1% (11 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2023-08-21 22:40:19 +02:00
gicorada
b7bcf1082e Translated using Weblate (Italian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-08-21 22:40:19 +02:00
EndermanCo
ba9bbc5b6e Translated using Weblate (Persian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-21 22:40:19 +02:00
0eoc
0fecfbd50c Translated using Weblate (Russian)
Currently translated at 81.2% (273 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-08-21 22:40:19 +02:00
gallegonovato
0031dc6119 Translated using Weblate (Spanish)
Currently translated at 99.1% (333 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-08-21 22:40:19 +02:00
EndermanCo
79e606698e Translated using Weblate (Persian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-21 22:40:19 +02:00
EndermanCo
3c9fc43780 Translated using Weblate (Persian)
Currently translated at 98.5% (331 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-21 22:40:19 +02:00
ihor_ck
adb9b7394a Translated using Weblate (Ukrainian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-08-21 22:40:19 +02:00
Eryk Michalak
6191fdfaef Translated using Weblate (Polish)
Currently translated at 91.3% (307 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-08-21 22:40:19 +02:00
Linerly
446754e8a6 Translated using Weblate (Indonesian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-08-21 22:40:19 +02:00
Choukajohn
30c67b0b39 Translated using Weblate (French)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-08-21 22:40:19 +02:00
Hudobni Volk
1043ea7b11 Translated using Weblate (Slovenian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-08-21 22:40:19 +02:00
alextecplayz
b449bcd006 Translated using Weblate (Romanian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-08-21 22:40:19 +02:00
EndermanCo
a9d513b564 Translated using Weblate (Persian)
Currently translated at 98.5% (330 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-21 22:40:19 +02:00
Hudobni Volk
5cef527810 Translated using Weblate (Slovenian)
Currently translated at 61.1% (11 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/sl/
2023-08-21 22:40:19 +02:00
ganjibaiemade
8bb907747d Translated using Weblate (Chinese (Traditional))
Currently translated at 18.2% (61 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hant/
2023-08-21 22:40:19 +02:00
Hudobni Volk
9c889f8df3 Translated using Weblate (Slovenian)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-08-21 22:40:19 +02:00
Linerly
cbc164d844 Translated using Weblate (Indonesian)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-08-21 22:40:19 +02:00
Eugen Rochko
b8e3060887 New translations strings.xml (Arabic) 2023-08-21 21:00:00 +02:00
Eugen Rochko
1aa1ede421 New translations strings.xml (Arabic) 2023-08-21 20:03:05 +02:00
Eugen Rochko
480dba7629 New translations strings.xml (Arabic) 2023-08-21 19:05:39 +02:00
Eugen Rochko
9b9c66a149 New translations strings.xml (Arabic) 2023-08-21 17:43:00 +02:00
Eugen Rochko
0f5eb923ee New translations strings.xml (Arabic) 2023-08-21 16:13:06 +02:00
snerk
7f521b3129 Translated using Weblate (Norwegian Nynorsk)
Currently translated at 100.0% (369 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nn/
2023-08-21 09:41:52 +00:00
EndermanCo
9ce217d1f2 Translated using Weblate (Persian)
Currently translated at 100.0% (369 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-21 09:41:51 +00:00
ihor_ck
7b1bd3ccad Translated using Weblate (Ukrainian)
Currently translated at 100.0% (369 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-08-21 09:41:51 +00:00
Oliebol
13b1cbde6b Translated using Weblate (Dutch)
Currently translated at 82.9% (306 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-08-21 09:41:51 +00:00
Linerly
8d898a1a78 Translated using Weblate (Indonesian)
Currently translated at 100.0% (369 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-08-21 09:41:51 +00:00
Choukajohn
51c2890ede Translated using Weblate (French)
Currently translated at 100.0% (369 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-08-21 09:41:51 +00:00
gallegonovato
03642faa9c Translated using Weblate (Spanish)
Currently translated at 100.0% (369 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-08-21 09:41:51 +00:00
sk22
084c6e1e59 Translated using Weblate (German)
Currently translated at 94.5% (349 of 369 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-08-21 09:41:51 +00:00
Eugen Rochko
90ed28e7a0 New translations strings.xml (French) 2023-08-20 17:34:05 +01:00
Eugen Rochko
d2b45c1c84 New translations strings.xml (Swedish) 2023-08-20 12:43:05 +01:00
Eugen Rochko
a119ba5f80 New translations strings.xml (Danish) 2023-08-19 17:08:25 +01:00
Eugen Rochko
8c1191a08f New translations strings.xml (Danish) 2023-08-19 16:09:27 +01:00
Eugen Rochko
4275d596e6 New translations strings.xml (Thai) 2023-08-19 12:46:09 +01:00
snerk
2709d5226d Translated using Weblate (Norwegian Nynorsk)
Currently translated at 21.6% (78 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nn/
2023-08-18 16:18:22 +00:00
snerk
8f613e3255 Translated using Weblate (Norwegian Nynorsk)
Currently translated at 20.8% (75 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nn/
2023-08-18 16:18:22 +00:00
snerk
6831e846cf Translated using Weblate (Norwegian Nynorsk)
Currently translated at 18.8% (68 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nn/
2023-08-18 16:18:22 +00:00
snerk
034eb9427d Added translation using Weblate (Norwegian Nynorsk) 2023-08-18 16:18:22 +00:00
alextecplayz
f73c325db3 Translated using Weblate (Romanian)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-08-18 16:18:22 +00:00
gallegonovato
5e2b11c504 Translated using Weblate (Spanish)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-08-18 16:18:22 +00:00
EndermanCo
ec13133431 Translated using Weblate (Persian)
Currently translated at 38.8% (7 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fa/
2023-08-18 16:18:22 +00:00
EndermanCo
a8a56a3ed8 Translated using Weblate (Persian)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-18 16:18:22 +00:00
0eoc
4e9c7c4de2 Translated using Weblate (Russian)
Currently translated at 61.1% (11 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2023-08-18 16:18:22 +00:00
ihor_ck
ffb7894098 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-08-18 16:18:22 +00:00
Linerly
0d9520ac45 Translated using Weblate (Indonesian)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-08-18 16:18:22 +00:00
Choukajohn
be852e57df Translated using Weblate (French)
Currently translated at 100.0% (360 of 360 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-08-18 16:18:22 +00:00
0eoc
157b38b8ae Translated using Weblate (Russian)
Currently translated at 96.1% (323 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-08-18 16:18:22 +00:00
gallegonovato
83196a1a0d Translated using Weblate (Spanish)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-08-18 16:18:22 +00:00
Codeberg Translate
306225b054 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/
2023-08-18 16:18:22 +00:00
edxkl
6efc71d8d2 Translated using Weblate (Portuguese (Brazil))
Currently translated at 94.4% (17 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2023-08-18 16:18:21 +00:00
edxkl
cc4cd4d3f8 Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.3% (327 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-08-18 16:18:21 +00:00
EndermanCo
00e3292205 Translated using Weblate (Persian)
Currently translated at 27.7% (5 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fa/
2023-08-18 16:18:21 +00:00
0eoc
316952423c Translated using Weblate (Russian)
Currently translated at 61.1% (11 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2023-08-18 16:18:21 +00:00
gicorada
61c2abd014 Translated using Weblate (Italian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-08-18 16:18:21 +00:00
EndermanCo
ee5f299b90 Translated using Weblate (Persian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-18 16:18:21 +00:00
0eoc
f153846381 Translated using Weblate (Russian)
Currently translated at 81.2% (273 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-08-18 16:18:21 +00:00
gallegonovato
0656db0858 Translated using Weblate (Spanish)
Currently translated at 99.1% (333 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-08-18 16:18:21 +00:00
EndermanCo
7f250cb8df Translated using Weblate (Persian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-18 16:18:21 +00:00
EndermanCo
a1e73eca89 Translated using Weblate (Persian)
Currently translated at 98.5% (331 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-18 16:18:21 +00:00
ihor_ck
1dc6936da6 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-08-18 16:18:21 +00:00
Eryk Michalak
0431d80a8d Translated using Weblate (Polish)
Currently translated at 91.3% (307 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-08-18 16:18:21 +00:00
Linerly
eaa78093f7 Translated using Weblate (Indonesian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-08-18 16:18:21 +00:00
Choukajohn
25b7151fde Translated using Weblate (French)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-08-18 16:18:21 +00:00
Hudobni Volk
0438b579b6 Translated using Weblate (Slovenian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-08-18 16:18:21 +00:00
alextecplayz
afa50a4e8c Translated using Weblate (Romanian)
Currently translated at 100.0% (336 of 336 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-08-18 16:18:21 +00:00
EndermanCo
85bdb0067b Translated using Weblate (Persian)
Currently translated at 98.5% (330 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-08-18 16:18:21 +00:00
Hudobni Volk
760cbc7f9a Translated using Weblate (Slovenian)
Currently translated at 61.1% (11 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/sl/
2023-08-18 16:18:21 +00:00
ganjibaiemade
d0e34fcd90 Translated using Weblate (Chinese (Traditional))
Currently translated at 18.2% (61 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hant/
2023-08-18 16:18:21 +00:00
Hudobni Volk
da434b9a9b Translated using Weblate (Slovenian)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-08-18 16:18:21 +00:00
Linerly
48863dd510 Translated using Weblate (Indonesian)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-08-18 16:18:21 +00:00
FineFindus
2ca34278f9 build: add F-Droid flavor (#760)
* build: add fdroid flavor

* feat: disable fcm registration in f-droid flavor
2023-08-18 18:15:57 +02:00
Jacoco
a79779f813 Emoji Reactions Support (#645)
* Display Pleroma emoji reactions

* Interact with existing Pleroma emoji reactions

* Setting for emoji reaction support

* Setting for displaying reactions in timelines

* More horizontal padding on reactions display item

* List accounts who reacted

* Arbitrary emoji reaction from status footer

* Hide custom emoji keyboard when emoji is selected

* Clear preferences before applying
All preferences get written anyways so nothing will be lost

* Reset react visibility state on bind

* Fix custom emoji turning black when reacting

* Load reactions when a new one is added

* Emoji reactions grid

* Load custom emoji in reactions list fragment

* New reaction toast messages and Unicode emoji regex

* Make custom emoji picker for reactions scrollable

* Scroll down to show custom emoji picker when reacting

* Divider after reaction custom emoji picker

* Animate react button opacity back in

* fix plural strings

* re-implement reactions using horizontal recycler view

* update reactions with event

* tweak emoji font size

* tweak button styles (a tiny bit)

* change footer react button behavior

* fix emoji reaction status item padding

* move emoji reactions below content items

* add content description and tooltip

* use custom emoji keyboard to enter unicode emoji

* fix reactions clearing on status counter updates

* fix space next to emoji reactions not clickable

* make compatible with glitch-soc

* Remove now unused EmojiReactionsView class

* improve handling of reaction padding

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-08-18 18:14:33 +02:00
Eugen Rochko
cc83f2baf3 New translations strings.xml (Danish) 2023-08-18 01:51:02 +01:00
Eugen Rochko
728496b831 New translations strings.xml (Danish) 2023-08-18 00:06:12 +01:00
Eugen Rochko
bbc99162c6 New translations strings.xml (Danish) 2023-08-17 16:47:55 +01:00
Eugen Rochko
eed3af9e3e New translations strings.xml (Arabic) 2023-08-16 22:54:50 +02:00
Eugen Rochko
50187ff376 New translations strings.xml (Arabic) 2023-08-16 21:48:52 +02:00
Eugen Rochko
5f30919fb4 New translations strings.xml (Arabic) 2023-08-16 18:38:58 +02:00
Eugen Rochko
14c3cfac85 New translations strings.xml (French) 2023-08-16 15:50:45 +02:00
Eugen Rochko
e978f02765 New translations strings.xml (French) 2023-08-16 14:09:02 +02:00
Eugen Rochko
8d877c480f New translations strings.xml (French) 2023-08-16 12:20:32 +02:00
Eugen Rochko
c53efee9a1 New translations strings.xml (Thai) 2023-08-15 22:47:32 +02:00
Eugen Rochko
148c461e86 New translations strings.xml (Danish) 2023-08-15 16:40:55 +02:00
Eugen Rochko
fcadb9883d New translations strings.xml (Danish) 2023-08-15 14:59:58 +02:00
Eugen Rochko
bb6491e10a New translations full_description.txt (Danish) 2023-08-15 14:59:57 +02:00
Eugen Rochko
6248ccf376 New translations full_description.txt (Danish) 2023-08-15 13:53:21 +02:00
Eugen Rochko
c9e08f36fa New translations full_description.txt (Danish) 2023-08-15 03:19:07 +02:00
Eugen Rochko
10b95d753b New translations full_description.txt (Danish) 2023-08-15 02:15:33 +02:00
Eugen Rochko
c3989083cf New translations strings.xml (Portuguese) 2023-08-14 15:33:01 +02:00
Eugen Rochko
01db585094 New translations strings.xml (Basque) 2023-08-14 01:42:56 +02:00
Eugen Rochko
cc67cb330c New translations full_description.txt (Basque) 2023-08-14 00:10:18 +02:00
Eugen Rochko
52ed3c5a04 New translations strings.xml (Basque) 2023-08-14 00:10:17 +02:00
Eugen Rochko
5976f6230a New translations strings.xml (Chinese Simplified) 2023-08-13 18:58:06 +02:00
Eugen Rochko
3553f03a95 New translations strings.xml (Slovenian) 2023-08-13 11:06:06 +02:00
Eugen Rochko
d6e2d889c3 New translations strings.xml (Slovenian) 2023-08-12 16:02:40 +02:00
Eugen Rochko
a777b3b450 New translations strings.xml (Slovenian) 2023-08-12 14:07:49 +02:00
Eugen Rochko
9957efbea0 New translations strings.xml (Norwegian) 2023-08-12 01:06:29 +02:00
Eugen Rochko
22e7b9730f New translations strings.xml (Vietnamese) 2023-08-11 17:50:37 +02:00
Eugen Rochko
91470b8509 New translations strings.xml (Vietnamese) 2023-08-11 16:21:15 +02:00
Eugen Rochko
c9d5327328 New translations strings.xml (Russian) 2023-08-11 12:41:37 +02:00
Eugen Rochko
1aa61b72e5 New translations strings.xml (Russian) 2023-08-11 10:45:11 +02:00
Eugen Rochko
3ca5edc3fc New translations strings.xml (Russian) 2023-08-11 09:19:15 +02:00
Eugen Rochko
a092ebaeb3 New translations strings.xml (Russian) 2023-08-11 08:03:02 +02:00
Eugen Rochko
5b9e84c255 New translations strings.xml (Russian) 2023-08-11 07:07:00 +02:00
Eugen Rochko
9c058b926f New translations strings.xml (Russian) 2023-08-10 12:30:16 +02:00
Eugen Rochko
4f2d2ae6e8 New translations strings.xml (Russian) 2023-08-10 11:10:22 +02:00
Eugen Rochko
75aa26a018 New translations strings.xml (Russian) 2023-08-09 14:50:26 +02:00
Eugen Rochko
0f795254e5 New translations strings.xml (Russian) 2023-08-09 13:28:03 +02:00
Eugen Rochko
33592f0a83 New translations strings.xml (Swedish) 2023-08-07 12:43:38 +02:00
Eugen Rochko
d6fd01eaca New translations strings.xml (Swedish) 2023-08-07 10:56:51 +02:00
Mark Hansen
1cdc58378a Sort Hashtags you follow menu (#695)
* Sort Hashtags you follow menu

* change sorting method

---------

Co-authored-by: Mark Hansen <mhansen@accusoft.com>
Co-authored-by: sk <sk22@mailbox.org>
2023-08-05 20:43:23 +02:00
FineFindus
584b11fce3 feat: allow playing multiple media (#755)
* feat: allow playing multiple media

* replace audio overlay icon

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-08-05 20:35:57 +02:00
FineFindus
fe2039062b fix(remote): send remoteAccount (#754)
closes sk22#664

* fix(remote): send remoteAccount

* fix(server-about): set adming account as remote

* fix(remote): show remote local accounts as remote
2023-08-05 20:30:41 +02:00
FineFindus
0269756b52 feat: change mute duration (#751)
* feat: add mute timer

* fix: missing ressources

* refactor(add-mute-timer): change of the mute timer popup layout

* tweak mute dialog

---------

Co-authored-by: LucasGGamerM <lucassggabriel@gmail.com>
Co-authored-by: sk <sk22@mailbox.org>
2023-08-05 20:17:40 +02:00
FineFindus
df1a6cf764 feat(openURL): open about in app (#750) 2023-08-05 19:44:18 +02:00
FineFindus
6d2385b6b3 feat: support UnifiedPush notifications (#749)
* build: add unified push dependency

* feat(notification): allow arbitrary push notification endpoint

* feat(notification/unified-push): show notification

* refactor(unifiedPush): use more consise null check

* feat(settings/notification): add UnifiedPush toggle

* feat(settings/notification): show no distributor message

* feat(settings/notification): disable unifiedpush when no distributor is available

* change icon name

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-08-05 19:42:10 +02:00
FineFindus
44eaa36cef fix: copy link invisible on EMUI (#753) 2023-08-05 19:33:36 +02:00
sk
50b40c4a07 Merge remote-tracking branch 'upstream/master' 2023-08-05 19:32:28 +02:00
Eugen Rochko
ee6e0ff26c New translations strings.xml (Russian) 2023-08-04 19:26:18 +02:00
Eugen Rochko
4d9574bf38 New translations strings.xml (Russian) 2023-08-04 17:51:30 +02:00
Eugen Rochko
813be9a2be New translations strings.xml (Russian) 2023-08-04 16:30:43 +02:00
Eugen Rochko
cc76ebfafb New translations strings.xml (Russian) 2023-08-04 14:58:02 +02:00
Eugen Rochko
7989ee0243 New translations strings.xml (Russian) 2023-08-04 13:58:08 +02:00
Eugen Rochko
3aa1997cfd New translations strings.xml (Russian) 2023-08-04 12:51:54 +02:00
Grishka
c3da15552e Merge branch 'l10n_master' 2023-08-03 17:22:04 +03:00
Grishka
a014fe9443 Fix media layout with unknown sizes 2023-08-03 17:21:40 +03:00
Eugen Rochko
92551d4ca3 New translations strings.xml (Portuguese, Brazilian) 2023-08-03 03:27:17 +02:00
Eugen Rochko
8010858e85 New translations strings.xml (Portuguese, Brazilian) 2023-08-03 02:26:22 +02:00
Eugen Rochko
4efb4875b0 New translations strings.xml (Swedish) 2023-08-02 09:16:24 +02:00
Eugen Rochko
c5d041e46d New translations strings.xml (Portuguese, Brazilian) 2023-08-01 23:11:09 +02:00
Eugen Rochko
53c2223aae New translations strings.xml (Portuguese, Brazilian) 2023-08-01 21:25:07 +02:00
Eugen Rochko
25034ac0ae New translations strings.xml (Portuguese, Brazilian) 2023-08-01 01:41:52 +02:00
Eugen Rochko
ac9de72b75 New translations strings.xml (Portuguese, Brazilian) 2023-08-01 00:42:41 +02:00
Eugen Rochko
1f48ad93f2 New translations strings.xml (Portuguese, Brazilian) 2023-07-31 23:46:36 +02:00
Eugen Rochko
38f7f7aa00 New translations strings.xml (Czech) 2023-07-31 14:32:20 +02:00
Eugen Rochko
fe8175c63a New translations strings.xml (French) 2023-07-30 19:39:54 +02:00
Eugen Rochko
2d9e01bbc1 New translations strings.xml (French) 2023-07-30 18:44:39 +02:00
Eugen Rochko
022a227b08 New translations strings.xml (Turkish) 2023-07-28 00:29:16 +02:00
Eugen Rochko
a2228259f1 New translations full_description.txt (Turkish) 2023-07-27 23:33:53 +02:00
Eugen Rochko
a61af7c56f New translations strings.xml (Turkish) 2023-07-27 23:33:52 +02:00
Eugen Rochko
5d6a646976 New translations strings.xml (French) 2023-07-27 23:33:51 +02:00
Eugen Rochko
628d0d7492 New translations strings.xml (French) 2023-07-27 22:05:11 +02:00
Eugen Rochko
b76c8745ec New translations strings.xml (Norwegian) 2023-07-25 22:57:26 +02:00
Eugen Rochko
51e67bc441 New translations strings.xml (Norwegian) 2023-07-25 21:52:29 +02:00
Gregory K
8887f75b70 Merge pull request #655 from nilathedragon/patch-1
Do not assume languages array will contain entries
2023-07-25 19:12:56 +03:00
Nila
9436a838c0 Do not assume languages array will contain entries 2023-07-25 17:28:41 +02:00
Eugen Rochko
ef120fa36f New translations strings.xml (Swedish) 2023-07-25 00:55:54 +02:00
Eugen Rochko
8c6385e2c5 New translations strings.xml (Swedish) 2023-07-24 23:57:42 +02:00
Eugen Rochko
0bd85d9905 New translations strings.xml (Persian) 2023-07-24 13:40:53 +02:00
Eugen Rochko
ce0dab7b28 New translations strings.xml (Czech) 2023-07-24 09:55:45 +02:00
sk
bdcebf1576 boop verisom 2023-07-23 22:03:25 +02:00
Eugen Rochko
ddcc5670ce New translations strings.xml (Bengali) 2023-07-22 17:48:06 +02:00
Eugen Rochko
86afa184e2 New translations strings.xml (Bengali) 2023-07-22 16:26:35 +02:00
Eugen Rochko
77f341f139 New translations strings.xml (German) 2023-07-22 12:27:40 +02:00
Eugen Rochko
918b5d99c2 New translations strings.xml (Swedish) 2023-07-21 22:09:32 +02:00
Eugen Rochko
7a098d6eff New translations strings.xml (Swedish) 2023-07-21 21:06:04 +02:00
sk
239b6f8202 fix pill-less navigation bar with labels 2023-07-21 11:41:34 +02:00
Jacoco
8404c79148 Re-implement some Akkoma specific things + hide filter settings (#729)
* Replace missing blurhash with accent color

* Correct Akkoma max account fields

* Skip discover on Akkoma

* Akkoma poll limits

* Hide filter settings on Akkoma

* clear search fragment on back

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-07-21 02:29:38 +02:00
sk
5b2d04e09d add navigation bar tab labels - with option to hide them 2023-07-21 01:45:08 +02:00
sk
6bd13f99d2 add a readme link to the sauna repo 2023-07-21 01:15:35 +02:00
sk
2e8e12c1c8 add font tracking to label_medium 2023-07-21 01:08:07 +02:00
sk
17929a6b2d upstream was right about the weird padding
see "Navigation bar target size and margins" in
https://m3.material.io/components/navigation-bar/specs
2023-07-21 00:37:05 +02:00
sk
9455eaf820 parse html in pronouns 2023-07-21 00:30:30 +02:00
sk
cc054487ba configurable pronoun display 2023-07-21 00:22:52 +02:00
sk
e2df320d00 fix edit history header lines 2023-07-21 00:03:11 +02:00
sk
d74313f996 remove code for below-header reply lines 2023-07-20 23:58:18 +02:00
sk
b3cab67049 fix null pointer when accessing draft content type
closes sk22#734
2023-07-20 23:43:46 +02:00
sk
996f0b22b9 use theme color for alt badge text 2023-07-20 23:39:11 +02:00
sk
67952ea98e fix bugged alt text badge state 2023-07-20 23:39:00 +02:00
sk
7a02ca435f make alt badge more transparent
closes sk22#735
2023-07-20 23:19:47 +02:00
Eugen Rochko
71f81283f5 New translations strings.xml (Polish) 2023-07-20 13:51:45 +02:00
Eugen Rochko
058c7c3c33 New translations strings.xml (Danish) 2023-07-20 10:31:41 +02:00
Eugen Rochko
870e33879b New translations strings.xml (Indonesian) 2023-07-19 07:48:32 +02:00
Eugen Rochko
3ca82bdfc5 New translations strings.xml (Japanese) 2023-07-19 05:08:28 +02:00
Eugen Rochko
4721bad286 New translations short_description.txt (Armenian) 2023-07-18 16:30:06 +02:00
Eugen Rochko
f040cf2f07 New translations full_description.txt (Armenian) 2023-07-18 16:30:05 +02:00
Eugen Rochko
8d50717c90 New translations strings.xml (Armenian) 2023-07-18 16:30:04 +02:00
Eugen Rochko
2512ad3c95 New translations strings.xml (Armenian) 2023-07-18 14:49:00 +02:00
sk
8d55f62da9 round inset notifications
closes sk22#665
2023-07-18 12:54:04 +02:00
Eugen Rochko
bc7e007634 New translations strings.xml (Swedish) 2023-07-18 12:03:42 +02:00
Eugen Rochko
1f3c87e0c7 New translations strings.xml (Swedish) 2023-07-18 10:31:42 +02:00
sk
ee0048a406 fix wrong margins for media posts with cw / without text 2023-07-18 09:59:47 +02:00
sk
14dcc769f2 fix monochrome icon
closes sk22#719
2023-07-18 09:01:13 +02:00
sk
f2e6255eb3 remove flagship instance reference 2023-07-18 08:52:40 +02:00
sk
7d392e20fb fix trending hashtags not loading
closes sk22#724
2023-07-18 08:40:54 +02:00
sk
3f2e6d2be6 remove log.d call 2023-07-17 22:53:16 +02:00
sk
a74c285f77 fix alt text editor theme
closes sk22#700
2023-07-17 22:51:45 +02:00
sk
8aec4a2717 fix inconsistent spoiler state, apparently?
closes sk22#711
2023-07-17 22:23:45 +02:00
sk
a106193039 use fediverse string 2023-07-17 21:59:39 +02:00
sk
5736605771 Merge remote-tracking branch 'weblate/main' 2023-07-17 21:56:19 +02:00
sk
9f0a710e40 update string 2023-07-17 21:55:33 +02:00
sk
f6f8cfb8e8 fix m3 filled disabled button opacity 2023-07-17 21:49:05 +02:00
sk
4e28f011dd Merge remote-tracking branch 'upstream/master' 2023-07-17 21:35:24 +02:00
Grishka
4bb255e0bb Fix #619 2023-07-17 20:25:08 +03:00
sk22
a48d545989 Translated using Weblate (French)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-07-17 04:03:22 +00:00
EndermanCo
e58cf54a5a Translated using Weblate (Persian)
Currently translated at 98.2% (329 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-07-17 04:03:22 +00:00
gicorada
2a45776f01 Translated using Weblate (Italian)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/it/
2023-07-17 04:03:21 +00:00
michaelmathy
332aa906b5 Translated using Weblate (French)
Currently translated at 88.8% (16 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2023-07-17 04:03:21 +00:00
ihor_ck
ef624dfe30 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-07-17 04:03:21 +00:00
Hudobni Volk
1b0b9bedea Translated using Weblate (Slovenian)
Currently translated at 91.9% (308 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/sl/
2023-07-17 04:03:21 +00:00
alextecplayz
e2672bea6e Translated using Weblate (Romanian)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-07-17 04:03:21 +00:00
Oliebol
5916001462 Translated using Weblate (Dutch)
Currently translated at 80.5% (270 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-07-17 04:03:21 +00:00
gicorada
cacd403b89 Translated using Weblate (Italian)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-07-17 04:03:21 +00:00
Espasant3
2732f710da Translated using Weblate (Galician)
Currently translated at 96.1% (322 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-07-17 04:03:21 +00:00
michaelmathy
070268eafd Translated using Weblate (French)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-07-17 04:03:21 +00:00
sk22
7149971351 Translated using Weblate (German)
Currently translated at 100.0% (335 of 335 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-07-17 04:03:21 +00:00
sk
f46668c023 Merge remote-tracking branch 'upstream/master' into fix-divergent-branches 2023-07-16 18:24:59 +02:00
sk
74d0937078 Merge remote-tracking branch 'weblate/main' 2023-07-16 18:05:55 +02:00
EndermanCo
b236e88ef2 Translated using Weblate (Persian)
Currently translated at 95.1% (312 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-07-16 16:02:44 +00:00
Gaemy
12acf6761b Translated using Weblate (Spanish)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2023-07-16 16:02:44 +00:00
Gaemy
8522f1fd29 Translated using Weblate (Spanish)
Currently translated at 100.0% (328 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-07-16 16:02:44 +00:00
sk22
7677ad39ca Merge upstream redesign (#714)
* merge toolbar fragment

* Fix store screenshot generator

* Fix alert color

* Fix #609

* Fix crash

* bigger hitbox for chips

* support mastodon languages

* merge ui utils

* merge stuff

* fix icon

* ensure 48dp touch target

* init local prefs, add helper function for enum values

* update compose action layout

* merge compose-adj files

* update extended footer

* fix poll wrong option checked

closes sk22#641

* no border when disabled

closes sk22#640

* Fix #610

* Minor fixes

* Fix alert color

* Fix #609

* Fix crash

* Fix #610

* Minor fixes

* add resources

* more compatible mastodon language

* fix html parser

* mark as read on refresh

* update tab bar

* tweak m3 buttons

* update compose-adj files

* tweak and update styles

* m3 expand button

* flag icon should be 18dp, actually

* More minor fixes

closes #612

* More minor fixes

closes #612

* Bump version

* fix no create status event when redrafting

* add material 3 assets

* New translations strings.xml (Greek)

* New translations strings.xml (Greek)

* New translations strings.xml (Italian)

* New translations strings.xml (Greek)

* New translations strings.xml (Italian)

* New translations strings.xml (Thai)

* New translations strings.xml (Thai)

* New translations strings.xml (Italian)

* New translations strings.xml (Thai)

* use new buttons for profile fragment

* merge compose fragment

* merge all the styles! oh dear

* New translations full_description.txt (Indonesian)

* New translations full_description.txt (Chinese Simplified)

* New translations strings.xml (Chinese Simplified)

* New translations full_description.txt (Chinese Simplified)

* Fix #615

* Minor fixes

* Fix #611

* A bunch of crash fixes

* New translations strings.xml (Greek)

* Make the default server configurable

* Pass the system timezone to server when signing up

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Japanese)

* Fix #615

* Minor fixes

* Fix #611

* A bunch of crash fixes

* Make the default server configurable

* Pass the system timezone to server when signing up

* oops. accidentally pasted the commit message in the code

* Remove unused code that caused a crash for some users ¯\_(ツ)_/¯

* New translations strings.xml (Japanese)

* New translations strings.xml (Japanese)

* Remove unused code that caused a crash for some users ¯\_(ツ)_/¯

* New translations strings.xml (Polish)

* New translations strings.xml (Polish)

* New translations strings.xml (Turkish)

* New translations strings.xml (Belarusian)

* prepare merging profile fragment

* merge profile fragment

* New translations strings.xml (Belarusian)

* New translations strings.xml (Greek)

* fix icon padding

* apply post header changes

* minor margin tweaks

* fix footer buttons

* fix header announcement buttons

* New translations strings.xml (Japanese)

* New translations strings.xml (Japanese)

* New translations strings.xml (Japanese)

* New translations strings.xml (Japanese)

* New translations strings.xml (Japanese)

* New translations strings.xml (Japanese)

* New translations full_description.txt (Japanese)

* New translations strings.xml (Icelandic)

* New translations strings.xml (Icelandic)

* New translations strings.xml (Icelandic)

* fix replying

* New translations strings.xml (Icelandic)

* fix translate button

* fix more button visibility

* fix counts label styling

* fix disabled boost button opacity

* fix tab layouts

* fix notification icon color crash

* New translations strings.xml (Greek)

* implement elevation listener in home tab

* fix elevation and listener in home tab

* add elevation scroll listener to notifications

* New translations strings.xml (Scottish Gaelic)

* Add editorconfig

So that PRs like #625 don't happen again

* Crash fix

* 🤔

* New translations strings.xml (Greek)

* New translations strings.xml (Japanese)

* New translations strings.xml (French)

* New translations strings.xml (French)

* New translations strings.xml (French)

* fix notification elevation and integrate divider

* 🤔

* Crash fix

* Add editorconfig

So that PRs like #625 don't happen again

* New translations strings.xml (Turkish)

* save interactions in cache

* New translations strings.xml (Turkish)

* merge new discover/search

* New translations strings.xml (Bengali)

* New translations strings.xml (Scottish Gaelic)

* New translations strings.xml (Bengali)

* merge new settings fragments

* fix no auth callback always being executed

* allow opening server info from profile

closes sk22#593

* fix hide boosts icon color

closes sk22#676

* New translations strings.xml (Turkish)

* New translations strings.xml (Turkish)

* New translations strings.xml (Turkish)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (Turkish)

* New translations strings.xml (Chinese Simplified)

* New translations strings.xml (German)

* New translations strings.xml (German)

* New translations strings.xml (Turkish)

* update fedinuke list

from source; doesn't contain any modifications regarding a recent issue

* New translations strings.xml (Turkish)

* remove unused class

* fix crash

* darken m3 outline color a bit

* use m3 outline again

* fix misalignment

closes sk22#682

* New translations strings.xml (Turkish)

* New translations full_description.txt (Turkish)

* New translations short_description.txt (Turkish)

* fix crash

* fix metadata sorting

* show pronouns in header/account lists

* fix broken divider line

closes sk22#679

* trim pronouns

* improve pronoun display

* New translations strings.xml (French)

* New translations strings.xml (Japanese)

* fix broken federated timeline

closes sk22#685

* fix broken -1 fallback behavior

closes sk22#681

* don't display nothing if server about request fails

closes sk22#678

* New translations strings.xml (Ukrainian)

* migrate global prefs to local prefs

* do confirm unfollow by default

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations full_description.txt (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Russian)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Vietnamese)

* New translations full_description.txt (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Vietnamese)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* make sure list in prefs are always mutable and nut null

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Russian)

* fix pronouns edge case

* add back fix for stretched images

closes sk22#636

* fix null pointer on missing default posting language

* fix default posting language not being applied

* bigger username hitbox

closes sk22#688

* fix rtl header username alignment

closes sk22#689

* New translations strings.xml (Ukrainian)

* New translations strings.xml (Ukrainian)

* hopefully fix crashes

closes sk22#692

* New translations strings.xml (Ukrainian)

* New translations full_description.txt (Ukrainian)

* fix pronoun crash

* New translations strings.xml (Persian)

* New translations strings.xml (Ukrainian)

* re-add true black mode

* asterisk can be a pronoun

* New translations strings.xml (Persian)

* true black mode fixes and clean-ups

* material 3 button background for switcher

* darker tab bar selected background

* better align follow/following button widths

* restore rainbow refresh colors

* fix search transition

* fix min width issue with switcher button

* fix no elevation when true black is enabled in light theme

* use statusForContent to determine spoilerRevealed

closes sk22#694

* New translations strings.xml (Persian)

* New translations strings.xml (Persian)

* New translations strings.xml (Persian)

* New translations strings.xml (Persian)

* New translations strings.xml (Persian)

* New translations strings.xml (Persian)

* fix profile tab bar in true black theme

* fix m3 default button style

closes sk22#697

* prettier role badges

closes sk22#663

* fix translate button spacing

closes sk22#655

* use m3 switches in dialogs

closes sk22#653

* implement color palette switcher

* fix color palettes being overwritten

* add display and notification settings

* clean up code

* per-account single notification setting

* add missing items to notification types

* add prefix replies setting

* add show replies/boosts and reply visibility

* add load/see new posts settings

* fix spectator mode missing spoiler padding

* add a bunch of display settings

* update fedinuke

* add content type settings

* add settings for local-onlu

* add missing settings items

* fix visibility button icon tint

* hopefully fix some crashes

* normalize padding above edit text

* apparently, some people don't like pills

closes sk22#706

* fix play button color

closes sk22#705
2023-07-16 18:01:42 +02:00
Eugen Rochko
73e08faee9 New translations strings.xml (Persian) 2023-07-13 20:45:58 +02:00
Eugen Rochko
02dc7711e4 New translations strings.xml (Persian) 2023-07-13 19:38:29 +02:00
Eugen Rochko
67b4d80e5b New translations strings.xml (Spanish) 2023-07-13 16:08:11 +02:00
Eugen Rochko
5168d2bb39 New translations strings.xml (Spanish) 2023-07-13 14:59:49 +02:00
Eugen Rochko
57190a75bf New translations strings.xml (Indonesian) 2023-07-13 11:54:32 +02:00
Eugen Rochko
f10e865895 New translations strings.xml (Indonesian) 2023-07-13 10:48:50 +02:00
Grishka
91b4dc412b Merge branch 'l10n_master' 2023-07-13 05:59:52 +03:00
nemobis
3cfea0e660 Fix typo in README.md (#701) 2023-07-12 00:22:17 +02:00
Eugen Rochko
c896fd8df8 New translations strings.xml (Persian) 2023-07-10 20:31:28 +02:00
Eugen Rochko
72cd987284 New translations strings.xml (Persian) 2023-07-10 19:33:53 +02:00
Eugen Rochko
d868d05080 New translations strings.xml (Persian) 2023-07-10 18:35:13 +02:00
Eugen Rochko
9dfb039a69 New translations strings.xml (Persian) 2023-07-10 17:14:05 +02:00
Eugen Rochko
f2920e877b New translations strings.xml (Persian) 2023-07-10 14:23:55 +02:00
Eugen Rochko
ecb0b3f9d7 New translations strings.xml (Persian) 2023-07-10 13:27:29 +02:00
EndermanCo
13ff54663c Translated using Weblate (Persian)
Currently translated at 94.5% (310 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-07-10 08:38:05 +00:00
AiOO
604d9b008a Translated using Weblate (Korean)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2023-07-10 08:38:04 +00:00
AiOO
7044a69a71 Translated using Weblate (Korean)
Currently translated at 100.0% (328 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-07-10 08:38:04 +00:00
Eugen Rochko
67c128be69 New translations strings.xml (Persian) 2023-07-09 20:48:43 +02:00
Eugen Rochko
1ecbbc2d4b New translations strings.xml (Ukrainian) 2023-07-09 19:53:27 +02:00
Eugen Rochko
82c481b014 New translations strings.xml (Persian) 2023-07-09 19:53:26 +02:00
Eugen Rochko
e7da6d7897 New translations full_description.txt (Ukrainian) 2023-07-09 18:55:26 +02:00
Eugen Rochko
e9f1e3038b New translations strings.xml (Ukrainian) 2023-07-09 18:55:25 +02:00
Eugen Rochko
a591096819 New translations strings.xml (Ukrainian) 2023-07-09 17:59:09 +02:00
Eugen Rochko
f1ef60475f New translations strings.xml (Ukrainian) 2023-07-09 14:35:38 +02:00
Eugen Rochko
ce75bb3984 New translations strings.xml (Russian) 2023-07-08 15:46:20 +02:00
Eugen Rochko
d59235e04c New translations strings.xml (Ukrainian) 2023-07-08 13:47:53 +02:00
Eugen Rochko
42f8f7e58f New translations strings.xml (Ukrainian) 2023-07-08 12:50:49 +02:00
Eugen Rochko
f9cbc9ae27 New translations strings.xml (Ukrainian) 2023-07-08 11:54:51 +02:00
Eugen Rochko
a50d6599bf New translations strings.xml (Ukrainian) 2023-07-08 10:56:13 +02:00
Eugen Rochko
cc578b496e New translations strings.xml (Vietnamese) 2023-07-08 09:39:17 +02:00
Eugen Rochko
662944d246 New translations strings.xml (Ukrainian) 2023-07-08 09:39:16 +02:00
Eugen Rochko
42810df4a5 New translations full_description.txt (Ukrainian) 2023-07-08 08:40:55 +02:00
Eugen Rochko
c3a058d2e1 New translations strings.xml (Vietnamese) 2023-07-08 08:40:54 +02:00
Eugen Rochko
ce5d835ae5 New translations strings.xml (Ukrainian) 2023-07-08 08:40:53 +02:00
Eugen Rochko
60dd561729 New translations strings.xml (Vietnamese) 2023-07-08 07:25:45 +02:00
Eugen Rochko
08c9f9ad7d New translations strings.xml (Russian) 2023-07-08 03:34:48 +02:00
Eugen Rochko
d47907906d New translations strings.xml (Ukrainian) 2023-07-07 23:24:33 +02:00
Eugen Rochko
935f0f6e05 New translations strings.xml (Ukrainian) 2023-07-07 22:27:12 +02:00
Eugen Rochko
ac0b21d574 New translations strings.xml (Ukrainian) 2023-07-07 21:27:12 +02:00
Eugen Rochko
9b5d05369f New translations strings.xml (Ukrainian) 2023-07-07 20:30:29 +02:00
Eugen Rochko
489f9f5e59 New translations strings.xml (Ukrainian) 2023-07-07 19:30:49 +02:00
Espasant3
e401dc8d6e Translated using Weblate (Galician)
Currently translated at 98.7% (324 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-07-07 16:38:05 +00:00
FineFindus
3e89087aba Translated using Weblate (German)
Currently translated at 100.0% (328 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-07-07 16:38:04 +00:00
Eugen Rochko
e62f7c23c9 New translations full_description.txt (Ukrainian) 2023-07-07 18:29:20 +02:00
Eugen Rochko
91ed7d49b5 New translations strings.xml (Ukrainian) 2023-07-07 18:29:19 +02:00
Eugen Rochko
c9e9abd811 New translations strings.xml (Ukrainian) 2023-07-07 17:11:15 +02:00
Eugen Rochko
b1e5023f62 New translations strings.xml (Ukrainian) 2023-07-07 16:10:53 +02:00
Eugen Rochko
604690b3f5 New translations strings.xml (Japanese) 2023-07-07 11:50:09 +02:00
Eugen Rochko
13ada6ecc6 New translations strings.xml (French) 2023-07-07 10:47:28 +02:00
Eugen Rochko
b897eb913e New translations short_description.txt (Turkish) 2023-07-06 22:08:52 +02:00
Eugen Rochko
c25602a650 New translations full_description.txt (Turkish) 2023-07-06 22:08:51 +02:00
Eugen Rochko
2defc9af3f New translations strings.xml (Turkish) 2023-07-06 22:08:50 +02:00
Eugen Rochko
446525389b New translations strings.xml (Turkish) 2023-07-06 21:11:01 +02:00
Eugen Rochko
756b30d04f New translations strings.xml (Turkish) 2023-07-06 20:15:49 +02:00
Eugen Rochko
51ec842815 New translations strings.xml (German) 2023-07-06 20:15:48 +02:00
Eugen Rochko
c38822849e New translations strings.xml (German) 2023-07-06 19:01:48 +02:00
Eugen Rochko
3c69201f67 New translations strings.xml (Chinese Simplified) 2023-07-06 19:01:46 +02:00
Eugen Rochko
ed9d701406 New translations strings.xml (Turkish) 2023-07-06 17:29:14 +02:00
Eugen Rochko
e70c5aa2e9 New translations strings.xml (Chinese Simplified) 2023-07-06 17:29:13 +02:00
Eugen Rochko
0c4589b257 New translations strings.xml (Turkish) 2023-07-06 15:04:45 +02:00
Eugen Rochko
84d08392fb New translations strings.xml (Turkish) 2023-07-06 14:03:25 +02:00
Eugen Rochko
8ff117308d New translations strings.xml (Turkish) 2023-07-06 13:06:03 +02:00
Eugen Rochko
b6c703adbc New translations strings.xml (Bengali) 2023-07-05 18:26:29 +02:00
Eugen Rochko
22e6934de5 New translations strings.xml (Scottish Gaelic) 2023-07-05 17:21:45 +02:00
Eugen Rochko
1b8a1d69ac New translations strings.xml (Bengali) 2023-07-05 17:21:43 +02:00
Eugen Rochko
b6ae83937b New translations strings.xml (Turkish) 2023-07-05 16:09:20 +02:00
Eugen Rochko
7115556663 New translations strings.xml (Turkish) 2023-07-05 15:08:07 +02:00
Eugen Rochko
cb3296661e New translations strings.xml (French) 2023-07-05 09:09:16 +02:00
Eugen Rochko
6dd20a6df9 New translations strings.xml (French) 2023-07-05 07:58:16 +02:00
Eugen Rochko
71c1d0e59a New translations strings.xml (French) 2023-07-04 21:49:47 +02:00
Eugen Rochko
2b275e1ff7 New translations strings.xml (Japanese) 2023-07-04 15:23:25 +02:00
EndermanCo
8520ee42cb Translated using Weblate (Persian)
Currently translated at 85.9% (282 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-07-04 09:38:04 +00:00
Eugen Rochko
a7fcae1033 New translations strings.xml (Greek) 2023-07-04 11:27:42 +02:00
Grishka
19bd189b33 🤔 2023-07-04 02:53:48 +03:00
Grishka
2d5089c047 Crash fix 2023-07-04 02:51:50 +03:00
Grishka
be7469bd54 Merge branch 'l10n_master' 2023-07-04 01:36:27 +03:00
Grishka
146d8daa6e Add editorconfig
So that PRs like #625 don't happen again
2023-07-04 01:05:55 +03:00
Eugen Rochko
f3928d9e09 New translations strings.xml (Scottish Gaelic) 2023-07-03 19:38:09 +02:00
Eugen Rochko
d4090d459d New translations strings.xml (Greek) 2023-07-03 17:49:55 +02:00
Eugen Rochko
7dd7554c08 New translations strings.xml (Icelandic) 2023-07-03 15:01:45 +02:00
Eugen Rochko
9de9a1d97d New translations strings.xml (Icelandic) 2023-07-03 13:53:20 +02:00
Eugen Rochko
04ee366fbe New translations strings.xml (Icelandic) 2023-07-03 12:41:02 +02:00
Eugen Rochko
c8784150fc New translations strings.xml (Icelandic) 2023-07-03 11:41:40 +02:00
Eugen Rochko
7b7bccb37a New translations full_description.txt (Japanese) 2023-07-03 10:26:59 +02:00
Eugen Rochko
84e2636bca New translations strings.xml (Japanese) 2023-07-03 10:26:58 +02:00
Eugen Rochko
dc73613b56 New translations strings.xml (Japanese) 2023-07-03 09:22:45 +02:00
Eugen Rochko
fd8868ef4d New translations strings.xml (Japanese) 2023-07-03 08:20:20 +02:00
alextecplayz
f443d659a3 Translated using Weblate (Romanian)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ro/
2023-07-03 05:59:10 +00:00
EndermanCo
24eb82a79d Translated using Weblate (Persian)
Currently translated at 80.4% (264 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-07-03 05:59:10 +00:00
alextecplayz
43d806fb01 Translated using Weblate (Romanian)
Currently translated at 100.0% (328 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-07-03 05:59:10 +00:00
Eugen Rochko
127df0b8e0 New translations strings.xml (Japanese) 2023-07-03 07:24:53 +02:00
Eugen Rochko
c2989df902 New translations strings.xml (Japanese) 2023-07-03 06:27:42 +02:00
Eugen Rochko
3f9ee99b69 New translations strings.xml (Japanese) 2023-07-03 05:11:26 +02:00
FineFindus
d47c4e63d7 fix(hashtag-timeline): add additional tags as separated parameter (#647) 2023-07-03 01:32:56 +02:00
Eugen Rochko
7204c4e804 New translations strings.xml (Greek) 2023-07-02 23:45:59 +02:00
Eugen Rochko
f1131cf8e7 New translations strings.xml (Belarusian) 2023-07-02 23:45:58 +02:00
Eugen Rochko
5b9a8beb07 New translations strings.xml (Belarusian) 2023-07-02 22:43:38 +02:00
Eugen Rochko
9e18e35c66 New translations strings.xml (Turkish) 2023-07-02 21:45:11 +02:00
Eugen Rochko
9db3dfa955 New translations strings.xml (Polish) 2023-07-02 21:45:11 +02:00
Eugen Rochko
4a3e56d300 New translations strings.xml (Polish) 2023-07-02 20:27:01 +02:00
Eugen Rochko
3bb4125c50 New translations strings.xml (Japanese) 2023-07-02 19:31:37 +02:00
Eugen Rochko
ce58883618 New translations strings.xml (Japanese) 2023-07-02 18:03:47 +02:00
Grishka
e7d3c60bac Remove unused code that caused a crash for some users ¯\_(ツ)_/¯ 2023-07-02 18:52:46 +03:00
Eugen Rochko
08e90139ad New translations strings.xml (Japanese) 2023-07-02 16:35:17 +02:00
Eugen Rochko
0d4dc34453 New translations strings.xml (Chinese Simplified) 2023-07-02 16:35:16 +02:00
Grishka
fe142c4626 Pass the system timezone to server when signing up 2023-07-02 16:35:19 +03:00
Grishka
d8dfa6017d Make the default server configurable 2023-07-02 16:22:32 +03:00
Eugen Rochko
b7a5d4296b New translations strings.xml (Greek) 2023-07-02 11:19:25 +02:00
Grishka
85d4c1fc24 A bunch of crash fixes 2023-07-02 12:03:21 +03:00
Grishka
66489d79be Fix #611 2023-07-02 11:04:20 +03:00
Grishka
30a66a26c6 Minor fixes 2023-07-02 10:50:01 +03:00
Grishka
fbc3081e68 Fix #615 2023-07-02 09:54:53 +03:00
EndermanCo
4ac7615cfb Translated using Weblate (Persian)
Currently translated at 77.7% (255 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-07-02 05:38:04 +00:00
Andrewblasco
a96b0d06a4 Translated using Weblate (Spanish)
Currently translated at 100.0% (328 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-07-02 05:38:04 +00:00
Eugen Rochko
7a66c94907 New translations full_description.txt (Chinese Simplified) 2023-07-02 06:12:35 +02:00
Eugen Rochko
4e38bc5769 New translations strings.xml (Chinese Simplified) 2023-07-02 06:12:34 +02:00
Eugen Rochko
0dc428dbd6 New translations full_description.txt (Chinese Simplified) 2023-07-02 04:57:11 +02:00
Eugen Rochko
6ac7fc94ea New translations full_description.txt (Indonesian) 2023-07-02 01:46:05 +02:00
Eugen Rochko
af28ed1783 New translations strings.xml (Thai) 2023-07-01 15:02:48 +02:00
Eugen Rochko
00daf084f2 New translations strings.xml (Italian) 2023-07-01 15:02:47 +02:00
Eugen Rochko
5518848e28 New translations strings.xml (Thai) 2023-07-01 13:40:15 +02:00
Eugen Rochko
6ded856b2f New translations strings.xml (Thai) 2023-07-01 12:30:46 +02:00
Eugen Rochko
d302f5132e New translations strings.xml (Italian) 2023-07-01 12:30:44 +02:00
Eugen Rochko
012e29ee3a New translations strings.xml (Greek) 2023-07-01 12:30:43 +02:00
Eugen Rochko
dbe9579d7f New translations strings.xml (Italian) 2023-07-01 11:28:20 +02:00
Eugen Rochko
c8d0221d9b New translations strings.xml (Greek) 2023-07-01 11:28:19 +02:00
Eugen Rochko
885c663d93 New translations strings.xml (Greek) 2023-07-01 10:06:44 +02:00
Grishka
3b399d5815 Merge branch 'l10n_master'
# Conflicts:
#	mastodon/src/main/res/values-ar-rSA/strings.xml
#	mastodon/src/main/res/values-be-rBY/strings.xml
#	mastodon/src/main/res/values-bn-rBD/strings.xml
#	mastodon/src/main/res/values-bs-rBA/strings.xml
#	mastodon/src/main/res/values-ca-rES/strings.xml
#	mastodon/src/main/res/values-cs-rCZ/strings.xml
#	mastodon/src/main/res/values-da-rDK/strings.xml
#	mastodon/src/main/res/values-de-rDE/strings.xml
#	mastodon/src/main/res/values-el-rGR/strings.xml
#	mastodon/src/main/res/values-es-rES/strings.xml
#	mastodon/src/main/res/values-eu-rES/strings.xml
#	mastodon/src/main/res/values-fa-rIR/strings.xml
#	mastodon/src/main/res/values-fil-rPH/strings.xml
#	mastodon/src/main/res/values-fr-rFR/strings.xml
#	mastodon/src/main/res/values-gd-rGB/strings.xml
#	mastodon/src/main/res/values-gl-rES/strings.xml
#	mastodon/src/main/res/values-hr-rHR/strings.xml
#	mastodon/src/main/res/values-hu-rHU/strings.xml
#	mastodon/src/main/res/values-hy-rAM/strings.xml
#	mastodon/src/main/res/values-in-rID/strings.xml
#	mastodon/src/main/res/values-is-rIS/strings.xml
#	mastodon/src/main/res/values-it-rIT/strings.xml
#	mastodon/src/main/res/values-iw-rIL/strings.xml
#	mastodon/src/main/res/values-ja-rJP/strings.xml
#	mastodon/src/main/res/values-kab/strings.xml
#	mastodon/src/main/res/values-ko-rKR/strings.xml
#	mastodon/src/main/res/values-my-rMM/strings.xml
#	mastodon/src/main/res/values-nl-rNL/strings.xml
#	mastodon/src/main/res/values-no-rNO/strings.xml
#	mastodon/src/main/res/values-oc-rFR/strings.xml
#	mastodon/src/main/res/values-pl-rPL/strings.xml
#	mastodon/src/main/res/values-pt-rBR/strings.xml
#	mastodon/src/main/res/values-pt-rPT/strings.xml
#	mastodon/src/main/res/values-ro-rRO/strings.xml
#	mastodon/src/main/res/values-ru-rRU/strings.xml
#	mastodon/src/main/res/values-si-rLK/strings.xml
#	mastodon/src/main/res/values-sl-rSI/strings.xml
#	mastodon/src/main/res/values-sv-rSE/strings.xml
#	mastodon/src/main/res/values-th-rTH/strings.xml
#	mastodon/src/main/res/values-tr-rTR/strings.xml
#	mastodon/src/main/res/values-uk-rUA/strings.xml
#	mastodon/src/main/res/values-vi-rVN/strings.xml
#	mastodon/src/main/res/values-zh-rCN/strings.xml
#	mastodon/src/main/res/values-zh-rTW/strings.xml
2023-06-30 20:37:37 +03:00
Grishka
9f18d1bc8b Bump version 2023-06-30 20:35:42 +03:00
Grishka
9a8cf61e38 More minor fixes
closes #612
2023-06-30 20:28:52 +03:00
Grishka
eb822282c0 Minor fixes 2023-06-30 09:18:48 +03:00
Grishka
273823a65f Fix #610 2023-06-30 08:25:05 +03:00
Grishka
f2aa1400c5 Fix crash 2023-06-29 22:31:15 +03:00
Grishka
cf8a9e1823 Fix #609 2023-06-29 22:29:51 +03:00
Grishka
b3320d534b Fix alert color 2023-06-29 22:24:35 +03:00
Grishka
f58b4c2989 Fix store screenshot generator 2023-06-29 22:17:59 +03:00
Eugen Rochko
47b3b1e307 New translations strings.xml (Hungarian) 2023-06-29 14:26:58 +02:00
Eugen Rochko
e5649c4a42 New translations strings.xml (Czech) 2023-06-29 14:26:57 +02:00
Eugen Rochko
cea77eca02 New translations strings.xml (Czech) 2023-06-29 13:11:45 +02:00
Eugen Rochko
4fbbcfba59 New translations strings.xml (Czech) 2023-06-29 12:06:31 +02:00
Eugen Rochko
6a24f70537 New translations strings.xml (Hungarian) 2023-06-29 11:09:23 +02:00
Eugen Rochko
4681160924 New translations strings.xml (Czech) 2023-06-29 11:09:22 +02:00
Eugen Rochko
6f8c2f4a44 New translations strings.xml (Hungarian) 2023-06-29 10:05:05 +02:00
Eugen Rochko
69de9dce38 New translations strings.xml (Italian) 2023-06-28 23:16:22 +02:00
Eugen Rochko
721ae9c68d New translations strings.xml (Thai) 2023-06-28 21:11:38 +02:00
Eugen Rochko
6a6ed89d29 New translations strings.xml (Thai) 2023-06-28 20:08:17 +02:00
Eugen Rochko
3e4377a366 New translations strings.xml (Italian) 2023-06-28 20:08:16 +02:00
Gregory K
287de66e0c Merge pull request #608 from sk22/fix/polls-update-content-status
Fix poll not updating content status when boosted
2023-06-28 18:29:12 +03:00
sk
df2ae9d964 fix poll not updating status when boosted
closes sk22#403
2023-06-28 17:24:46 +02:00
sk
277282d7f5 fix first notifications loaded multiple times
closes sk22#616
2023-06-28 01:37:21 +02:00
gallegonovato
4f983829b7 Translated using Weblate (Spanish)
Currently translated at 99.3% (326 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-06-27 20:02:28 +00:00
Eugen Rochko
ef55f1f49b New translations strings.xml (Thai) 2023-06-27 21:03:47 +02:00
Eugen Rochko
aebf7e9f1f New translations strings.xml (Thai) 2023-06-27 19:57:32 +02:00
Eugen Rochko
a014ce6eb5 New translations strings.xml (Thai) 2023-06-27 19:00:48 +02:00
Eugen Rochko
aed1efceb9 New translations strings.xml (Thai) 2023-06-27 17:58:06 +02:00
Eugen Rochko
124c375b14 New translations strings.xml (Thai) 2023-06-27 16:58:01 +02:00
Eugen Rochko
1d46e22a7f New translations strings.xml (Dutch) 2023-06-27 16:58:00 +02:00
Eugen Rochko
28c334429d New translations strings.xml (Czech) 2023-06-27 16:57:59 +02:00
Eugen Rochko
4726f98d4f New translations strings.xml (Thai) 2023-06-27 15:47:31 +02:00
Eugen Rochko
985f382436 New translations strings.xml (Thai) 2023-06-27 14:36:42 +02:00
Eugen Rochko
f822c788b0 New translations strings.xml (Armenian) 2023-06-27 13:38:29 +02:00
sk
664851cac5 update build.gradle 2023-06-27 09:40:59 +02:00
Eugen Rochko
46f8982aa6 New translations strings.xml (Vietnamese) 2023-06-27 05:57:29 +02:00
Eugen Rochko
7b3cec9289 New translations strings.xml (Vietnamese) 2023-06-27 04:48:02 +02:00
Eugen Rochko
a3f227cb8d New translations strings.xml (Thai) 2023-06-26 22:51:56 +02:00
Eugen Rochko
d71feb2cfc New translations strings.xml (Thai) 2023-06-26 21:47:41 +02:00
Grishka
b69565e9e6 Fix polls 2023-06-26 16:09:02 +03:00
Grishka
bf996feccf Add fading edge for alt text
closes #595
2023-06-26 16:04:24 +03:00
Eugen Rochko
b1143b0eec New translations strings.xml (Slovenian) 2023-06-26 08:30:13 +02:00
Codeberg Translate
4c6914c271 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/
2023-06-26 06:02:28 +00:00
tuongdai252
e03a62064e Translated using Weblate (Vietnamese)
Currently translated at 73.4% (241 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/vi/
2023-06-26 06:02:28 +00:00
Eugen Rochko
ce977163c2 New translations strings.xml (Slovenian) 2023-06-26 07:28:02 +02:00
Eugen Rochko
ded74bda83 New translations strings.xml (Chinese Traditional) 2023-06-26 04:01:11 +02:00
Eugen Rochko
7180113397 New translations strings.xml (Chinese Traditional) 2023-06-26 02:37:02 +02:00
Grishka
81ac8a3bc9 More minor fixes 2023-06-25 14:24:13 +03:00
Grishka
4b74da5d38 Fix another color 2023-06-25 09:50:44 +03:00
Eugen Rochko
0375cfa260 New translations short_description.txt (Vietnamese) 2023-06-25 05:27:54 +02:00
Eugen Rochko
52108a675a New translations full_description.txt (Arabic) 2023-06-25 05:26:57 +02:00
Grishka
406e95d3f7 Fix #606 2023-06-25 06:19:36 +03:00
Grishka
a9f355dea9 Fix text colors 2023-06-25 03:12:17 +03:00
Eugen Rochko
1a63c12327 New translations strings.xml (Urdu (India)) 2023-06-25 02:07:40 +02:00
Eugen Rochko
7bc2f8b352 New translations strings.xml (Kabyle) 2023-06-25 02:07:39 +02:00
Eugen Rochko
d56ef227a7 New translations strings.xml (Igbo) 2023-06-25 02:07:38 +02:00
Eugen Rochko
fcc371ab5a New translations strings.xml (Occitan) 2023-06-25 02:07:37 +02:00
Eugen Rochko
9f43a99772 New translations strings.xml (Scottish Gaelic) 2023-06-25 02:07:36 +02:00
Eugen Rochko
9fc5a4e390 New translations strings.xml (Sinhala) 2023-06-25 02:07:35 +02:00
Eugen Rochko
a2b3f873f6 New translations strings.xml (Bosnian) 2023-06-25 02:07:34 +02:00
Eugen Rochko
f6c1509e48 New translations strings.xml (Filipino) 2023-06-25 02:07:33 +02:00
Eugen Rochko
d9bbb32a28 New translations strings.xml (Burmese) 2023-06-25 02:07:32 +02:00
Eugen Rochko
d2ef6e77af New translations strings.xml (Hindi) 2023-06-25 02:07:31 +02:00
Eugen Rochko
6133e9bac3 New translations strings.xml (Croatian) 2023-06-25 02:07:30 +02:00
Eugen Rochko
6ca48f35f1 New translations strings.xml (Thai) 2023-06-25 02:07:29 +02:00
Eugen Rochko
cb016b4383 New translations strings.xml (Bengali) 2023-06-25 02:07:28 +02:00
Eugen Rochko
d0b21df28b New translations strings.xml (Portuguese, Brazilian) 2023-06-25 02:07:28 +02:00
Eugen Rochko
ce48ee888a New translations strings.xml (Icelandic) 2023-06-25 02:07:27 +02:00
Eugen Rochko
5cd8bc5a46 New translations strings.xml (Galician) 2023-06-25 02:07:26 +02:00
Eugen Rochko
4109cd75d3 New translations strings.xml (Vietnamese) 2023-06-25 02:07:25 +02:00
Eugen Rochko
97a889e019 New translations strings.xml (Chinese Traditional) 2023-06-25 02:07:24 +02:00
Eugen Rochko
b9a1b3591d New translations strings.xml (Ukrainian) 2023-06-25 02:07:22 +02:00
Eugen Rochko
fde84e3cfb New translations strings.xml (Turkish) 2023-06-25 02:07:21 +02:00
Eugen Rochko
0985eb4fac New translations strings.xml (Swedish) 2023-06-25 02:07:21 +02:00
Eugen Rochko
5957c1a221 New translations strings.xml (Slovenian) 2023-06-25 02:07:20 +02:00
Eugen Rochko
e7e34aa2c8 New translations strings.xml (Russian) 2023-06-25 02:07:19 +02:00
Eugen Rochko
b8742591b8 New translations strings.xml (Portuguese) 2023-06-25 02:07:17 +02:00
Eugen Rochko
50e73ac12e New translations strings.xml (Polish) 2023-06-25 02:07:16 +02:00
Eugen Rochko
9ed277a9b2 New translations strings.xml (Norwegian) 2023-06-25 02:07:15 +02:00
Eugen Rochko
c9e2984d68 New translations strings.xml (Dutch) 2023-06-25 02:07:14 +02:00
Eugen Rochko
00aaff10a7 New translations strings.xml (Korean) 2023-06-25 02:07:13 +02:00
Eugen Rochko
6da4256adf New translations strings.xml (Japanese) 2023-06-25 02:07:12 +02:00
Eugen Rochko
da9c826791 New translations strings.xml (Italian) 2023-06-25 02:07:11 +02:00
Eugen Rochko
bed02e248e New translations strings.xml (Armenian) 2023-06-25 02:07:11 +02:00
Eugen Rochko
f53531889f New translations strings.xml (Hungarian) 2023-06-25 02:07:10 +02:00
Eugen Rochko
ef3246ae2a New translations strings.xml (Hebrew) 2023-06-25 02:07:09 +02:00
Eugen Rochko
5504b534f7 New translations strings.xml (Irish) 2023-06-25 02:07:08 +02:00
Eugen Rochko
0e553d7868 New translations strings.xml (Finnish) 2023-06-25 02:07:07 +02:00
Eugen Rochko
38be51367e New translations strings.xml (Basque) 2023-06-25 02:07:06 +02:00
Eugen Rochko
0d4af0970c New translations strings.xml (Greek) 2023-06-25 02:07:05 +02:00
Eugen Rochko
b51335ffd6 New translations strings.xml (German) 2023-06-25 02:07:04 +02:00
Eugen Rochko
444fa07984 New translations strings.xml (Danish) 2023-06-25 02:07:03 +02:00
Eugen Rochko
feb0f304fb New translations strings.xml (Catalan) 2023-06-25 02:07:02 +02:00
Eugen Rochko
ccd4a1aa9f New translations strings.xml (Belarusian) 2023-06-25 02:07:01 +02:00
Eugen Rochko
b3723c2977 New translations strings.xml (Arabic) 2023-06-25 02:07:00 +02:00
Eugen Rochko
c5b70a9ada New translations strings.xml (Spanish) 2023-06-25 02:06:59 +02:00
Eugen Rochko
82789179e7 New translations strings.xml (French) 2023-06-25 02:06:58 +02:00
Eugen Rochko
b0a309a817 New translations strings.xml (Romanian) 2023-06-25 02:06:57 +02:00
Eugen Rochko
32a27b6e59 New translations strings.xml (Chinese Simplified) 2023-06-25 02:06:56 +02:00
Eugen Rochko
f73a318dad New translations strings.xml (Czech) 2023-06-25 02:06:55 +02:00
Eugen Rochko
4fff2c5f5c New translations strings.xml (Persian) 2023-06-25 02:06:54 +02:00
Eugen Rochko
81abac657f New translations strings.xml (Indonesian) 2023-06-25 02:06:53 +02:00
Grishka
74decd3ec7 Merge branch 'm3_redesign' 2023-06-25 02:55:26 +03:00
Grishka
11d17d1f3f Fix ripple color again 2023-06-25 02:52:54 +03:00
Grishka
ca2384ba8c Remove unused resources and fix ripple colors 2023-06-25 02:41:45 +03:00
Grishka
ded23342db Fix layout in post edit history 2023-06-25 01:46:17 +03:00
Grishka
a35c14865f Refresh the notifications list when it's opened 2023-06-25 01:28:08 +03:00
Grishka
0952d97557 Unified account row 2023-06-25 01:18:38 +03:00
Grishka
e1db5f15ca M3 redesign: search/discover 2023-06-24 22:56:55 +03:00
Espasant3
a99741c732 Translated using Weblate (Galician)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/gl/
2023-06-24 17:02:27 +00:00
ihor_ck
d6c8e8afc1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (328 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-06-24 17:02:26 +00:00
Linerly
879981e335 Translated using Weblate (Indonesian)
Currently translated at 100.0% (328 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-06-24 17:02:26 +00:00
Choukajohn
87840dd731 Translated using Weblate (French)
Currently translated at 100.0% (328 of 328 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-06-24 17:02:26 +00:00
Grishka
c9e467ac2f And again 2023-06-24 10:43:28 +03:00
Grishka
74a5e970d9 Fix #604 again 2023-06-23 23:07:28 +03:00
Eugen Rochko
935de7d02e New translations strings.xml (Chinese Simplified) 2023-06-23 13:54:49 +02:00
Codeberg Translate
cb8fddd156 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/
2023-06-22 23:12:23 +00:00
Andrewblasco
40ca834880 Translated using Weblate (Spanish)
Currently translated at 100.0% (309 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-06-22 23:12:23 +00:00
ling0412
c10206ef6f Translated using Weblate (Chinese (Simplified))
Currently translated at 95.4% (295 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-06-22 23:12:23 +00:00
sk22
e752d10e31 Translated using Weblate (German)
Currently translated at 100.0% (309 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-06-22 23:12:23 +00:00
EndermanCo
119bbc2b5c Translated using Weblate (Persian)
Currently translated at 82.2% (254 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-06-22 23:12:23 +00:00
Oliebol
6136260adc Translated using Weblate (Dutch)
Currently translated at 87.3% (270 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-06-22 23:12:23 +00:00
Andrewblasco
979ee9fdff Translated using Weblate (Spanish)
Currently translated at 100.0% (309 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-06-22 23:12:23 +00:00
EndermanCo
ab71e06ef1 Translated using Weblate (Persian)
Currently translated at 80.9% (250 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-06-22 23:12:23 +00:00
Linerly
6d487f011f Translated using Weblate (Indonesian)
Currently translated at 100.0% (309 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-06-22 23:12:23 +00:00
gallegonovato
50403cf674 Translated using Weblate (Spanish)
Currently translated at 100.0% (309 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-06-22 23:12:23 +00:00
EndermanCo
276df264cf Translated using Weblate (Persian)
Currently translated at 57.6% (178 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-06-22 23:12:23 +00:00
ihor_ck
55e18cf9af 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-06-22 23:12:23 +00:00
ihor_ck
e5392d3265 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (309 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-06-22 23:12:23 +00:00
LucasGGamerM
2de7c1d3b9 Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.6% (308 of 309 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-06-22 23:12:23 +00:00
LucasGGamerM
c21885139c Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (305 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-06-22 23:12:23 +00:00
EndermanCo
275cbaa924 Translated using Weblate (Persian)
Currently translated at 54.7% (167 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-06-22 23:12:23 +00:00
abidin24
4b6c35c9c0 Translated using Weblate (Arabic)
Currently translated at 10.4% (32 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-06-22 23:12:23 +00:00
ihor_ck
d339fa1e12 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-06-22 23:12:23 +00:00
Alfika07
31a5fc9153 Translated using Weblate (Hungarian)
Currently translated at 40.3% (123 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/hu/
2023-06-22 23:12:23 +00:00
ihor_ck
966f758d9f Translated using Weblate (Ukrainian)
Currently translated at 100.0% (305 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-06-22 23:12:23 +00:00
LucasGGamerM
6979c5097d Translated using Weblate (Portuguese (Brazil))
Currently translated at 85.2% (260 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2023-06-22 23:12:23 +00:00
a_mento
68005c762f Translated using Weblate (Basque)
Currently translated at 94.0% (287 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2023-06-22 23:12:23 +00:00
FineFindus
06543d5fc2 fix(edit-timelines/hashtags): set tags as list (#596)
* fix(edit-timelines/hashtags): set tags as list

Fixes https://github.com/sk22/megalodon/issues/595, by setting the tags a tags and not as a list.

* refactor(edit-timelines/hashtags): set all tag terminator at once

* feat(edit-timelines/hashtags): add comment
2023-06-21 22:34:22 +02:00
sk
a70d39065c add some new icons 2023-06-21 10:44:54 +02:00
sk
dc75882cee slightly adjust margin
closes sk22#585
2023-06-21 10:32:41 +02:00
sk
e47f253c0e unset name if hashtag is applied from name
closes sk22#588
2023-06-21 10:27:57 +02:00
sk
d05f3932b2 fix empty hashtag when editing 2023-06-21 10:24:50 +02:00
FineFindus
be425282a6 Hashtag timelines with multiple tags (#584)
* feat(api/hashtag): add any, all, and none parameter

* feat(timeline/hashtag): load with any, all and none parameter

* feat(timeline/hashtag): save any, all and none in timeline definition

* feat: set hastag parameter in UI

* feat: move strings to string res

* feat: show hint for tags

* refactor: use method for setting up tags text

* improve edit dialog, allow creating hashtag timelines

* add chips for hashtags

* add option for displaying only local posts in hashtag

* improve layout and wording

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-06-21 01:38:51 +02:00
Grishka
a04522ff72 Fix #605 2023-06-20 22:56:37 +03:00
Grishka
90a93ffba6 Fix #604 2023-06-20 22:54:09 +03:00
Eugen Rochko
069c55d4b9 New translations strings.xml (Persian) 2023-06-17 20:19:46 +01:00
Eugen Rochko
1efaf4b605 New translations strings.xml (Persian) 2023-06-17 19:21:04 +01:00
Eugen Rochko
ff74516ce2 New translations strings.xml (Persian) 2023-06-17 17:57:39 +01:00
Eugen Rochko
aee4b7aaab New translations full_description.txt (Persian) 2023-06-17 16:23:41 +01:00
Eugen Rochko
1d94479bde New translations strings.xml (Persian) 2023-06-17 16:23:40 +01:00
Eugen Rochko
85c95d899e New translations full_description.txt (Persian) 2023-06-17 15:24:06 +01:00
Eugen Rochko
18d4210e7d New translations strings.xml (Persian) 2023-06-17 15:24:05 +01:00
Eugen Rochko
ac25bc6d42 New translations strings.xml (Persian) 2023-06-17 14:17:46 +01:00
Eugen Rochko
ec05ef3b4c New translations full_description.txt (Persian) 2023-06-16 21:57:49 +01:00
Eugen Rochko
9827d97374 New translations strings.xml (Persian) 2023-06-16 21:57:48 +01:00
Eugen Rochko
4fab92d516 New translations strings.xml (Persian) 2023-06-16 20:43:12 +01:00
Eugen Rochko
44bc9c4e40 New translations strings.xml (Persian) 2023-06-16 19:47:01 +01:00
Eugen Rochko
1030773ef6 New translations strings.xml (Persian) 2023-06-16 18:50:21 +01:00
Eugen Rochko
1a0cb4b8c8 New translations strings.xml (Persian) 2023-06-16 17:47:36 +01:00
Eugen Rochko
4295a3672c New translations strings.xml (Persian) 2023-06-16 16:32:57 +01:00
Eugen Rochko
fd2a8fe230 New translations strings.xml (Persian) 2023-06-16 15:14:44 +01:00
Eugen Rochko
e2d1eccfb9 New translations strings.xml (Persian) 2023-06-16 14:17:09 +01:00
sk
bb4a52f03a fix threads opened from notification 2023-06-15 22:44:46 +02:00
sk
50360059ce fix margins 2023-06-15 20:38:47 +02:00
LucasGGamerM
63bcef990b feat: use correct coloring for new exclusive list explanation
cc: @sk22
2023-06-15 20:34:51 +02:00
sk
94eb6b5775 one less thing for parceler to complain about 2023-06-15 19:21:44 +02:00
sk
6595a088fb support exclusive lists
closes sk22#576
2023-06-15 19:21:26 +02:00
sk
b463ef65ce fix parceler complaining about private class member 2023-06-15 18:13:59 +02:00
sk
b22a25e7af workaround for proguard errors
re: sk22#572
2023-06-15 18:12:29 +02:00
Eugen Rochko
05d1d3e725 New translations full_description.txt (Persian) 2023-06-15 10:57:44 +01:00
Eugen Rochko
37261928c2 New translations full_description.txt (Persian) 2023-06-15 09:56:31 +01:00
Eugen Rochko
63132110d9 New translations full_description.txt (Persian) 2023-06-15 08:46:22 +01:00
Eugen Rochko
ffd7e415a2 New translations full_description.txt (Persian) 2023-06-15 07:42:12 +01:00
Eugen Rochko
d43664d018 New translations full_description.txt (Persian) 2023-06-15 06:36:15 +01:00
Eugen Rochko
8e06362ff8 New translations full_description.txt (Persian) 2023-06-14 20:11:35 +01:00
Eugen Rochko
625ccfd31f New translations strings.xml (Persian) 2023-06-14 20:11:34 +01:00
Eugen Rochko
d7b5d242ff New translations strings.xml (Persian) 2023-06-14 19:12:25 +01:00
Eugen Rochko
7973c87b9a New translations strings.xml (Persian) 2023-06-14 18:16:52 +01:00
Eugen Rochko
3085b1507b New translations strings.xml (Persian) 2023-06-14 16:46:46 +01:00
Eugen Rochko
f17ef17492 New translations strings.xml (Persian) 2023-06-14 15:49:02 +01:00
Eugen Rochko
8d0a31d0f9 New translations strings.xml (Persian) 2023-06-14 15:47:38 +02:00
Eugen Rochko
6c6d3fed05 New translations strings.xml (Persian) 2023-06-14 14:49:35 +02:00
Eugen Rochko
b616e2e11b New translations strings.xml (Persian) 2023-06-14 13:42:47 +02:00
Eugen Rochko
b18771bb79 New translations full_description.txt (Persian) 2023-06-14 12:38:20 +02:00
Eugen Rochko
40ef4c179a New translations strings.xml (Persian) 2023-06-13 18:31:58 +02:00
Eugen Rochko
62212dc6c9 New translations strings.xml (Persian) 2023-06-13 17:23:01 +02:00
Eugen Rochko
3ed2b67037 New translations strings.xml (Czech) 2023-06-13 15:55:50 +02:00
Eugen Rochko
d240750606 New translations strings.xml (Persian) 2023-06-13 14:44:08 +02:00
Eugen Rochko
ed009d3e2e New translations strings.xml (Persian) 2023-06-13 13:15:59 +02:00
sk
3af7518cf4 disable proguard for now :/ 2023-06-13 12:20:03 +02:00
sk
91b9fdf5ce add gson proguard rules 2023-06-13 12:13:55 +02:00
Eugen Rochko
be2fa0f217 New translations strings.xml (Persian) 2023-06-13 12:09:09 +02:00
sk
22f5667549 fix javadoc 2023-06-13 11:50:57 +02:00
sk
8115578e94 boop version 2023-06-13 10:19:13 +02:00
sk
08dc122b6b tweak min/max heights 2023-06-13 10:07:30 +02:00
sk
e3199c009e hopefully fix typetoken crashes 2023-06-13 09:47:48 +02:00
Eugen Rochko
a8d9b4538b New translations strings.xml (Persian) 2023-06-12 22:41:37 +02:00
Eugen Rochko
2b7b3de043 New translations strings.xml (Persian) 2023-06-12 21:44:04 +02:00
sk
2e09010151 boop version 2023-06-12 20:44:25 +02:00
sk
3d79e87ec8 Merge remote-tracking branch 'upstream/l10n_master' 2023-06-12 20:43:22 +02:00
sk
09ed3c647a reduce max height for photos 2023-06-12 20:25:12 +02:00
EndermanCo
172515ba0a Translated using Weblate (Persian)
Currently translated at 23.2% (71 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-06-12 17:43:48 +00:00
Andrewblasco
a2f0fc8c87 Translated using Weblate (Spanish)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2023-06-12 17:43:48 +00:00
Andrewblasco
888cee4556 Translated using Weblate (Spanish)
Currently translated at 100.0% (305 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-06-12 17:43:48 +00:00
sk
c005e9bf18 apply upstream alt overlay changes 2023-06-12 19:43:13 +02:00
Eugen Rochko
64362968fc New translations strings.xml (Persian) 2023-06-12 19:10:22 +02:00
sk
320027ca9b merge upstream photo layout changes 2023-06-12 18:42:07 +02:00
sk
ad2678da7c Merge remote-tracking branch 'upstream/l10n_master' 2023-06-12 18:22:38 +02:00
sk22
c56c7448d0 Translated using Weblate (German)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/de/
2023-06-12 16:22:10 +00:00
sk
731e67725c fix errors in strings 2023-06-12 18:22:02 +02:00
sk
8178f81c85 update changelog 2023-06-12 18:08:40 +02:00
sk
6fbf00a132 add newline 2023-06-12 18:07:28 +02:00
sk
968cde9e4c clean up empty regional locales 2023-06-12 18:03:22 +02:00
Grishka
aa9caefed1 Fix unread notifications 2023-06-12 18:54:46 +03:00
Grishka
14bbe1ffef Update the update icon 2023-06-12 18:50:06 +03:00
sk
f2ab2acef7 Merge remote-tracking branch 'weblate/main' 2023-06-12 17:47:22 +02:00
sk
81d1ecc5f8 update readme, changelog 2023-06-12 17:47:10 +02:00
EndermanCo
513e6439ff Translated using Weblate (Persian)
Currently translated at 22.2% (68 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fa/
2023-06-12 15:35:16 +00:00
Oliebol
1f0108b14e Translated using Weblate (Dutch)
Currently translated at 84.5% (258 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-06-12 15:35:15 +00:00
Choukajohn
1433d0717e Translated using Weblate (French)
Currently translated at 100.0% (305 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-06-12 15:35:15 +00:00
sk
be91775f4b fix pinned posts showing post multiple times 2023-06-12 17:29:00 +02:00
sk
7b2f8d2be3 update readme 2023-06-12 16:40:52 +02:00
sk
54c386ccec update readme 2023-06-12 16:32:28 +02:00
sk
9d9e98959f change glitch url 2023-06-12 16:18:45 +02:00
sk
a3cd7224bd update readme 2023-06-12 16:17:08 +02:00
sk
6cf214f127 fix header disappearing in some cases
closes sk22#570
2023-06-12 15:39:38 +02:00
Eugen Rochko
b6976fb519 New translations strings.xml (Persian) 2023-06-12 15:36:23 +02:00
sk
871ada23ab don't display context until fragment transition finished 2023-06-12 14:33:09 +02:00
Eugen Rochko
040237de2b New translations strings.xml (Persian) 2023-06-12 14:30:32 +02:00
sk
29b2a25840 no error when opening url that looks like fedi url 2023-06-12 13:33:30 +02:00
sk
bd2f05be67 hide followers/following count if count is -1 2023-06-12 12:13:44 +02:00
sk22
ed075b276f Translated using Weblate (German)
Currently translated at 100.0% (305 of 305 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-06-11 23:48:58 +00:00
sk
dd25f3380a add setting to configure default value for "forward report"
closes sk22#565
2023-06-12 01:38:44 +02:00
sk22
1a2d1efa29 Added translation using Weblate (Persian) 2023-06-11 23:10:35 +00:00
sk
f3e1fa4b2b fix announcements loading infinitely
closes sk22#569
2023-06-12 01:01:45 +02:00
Eugen Rochko
fc307ff43f New translations strings.xml (Persian) 2023-06-11 21:52:27 +02:00
Eugen Rochko
04304b3397 New translations strings.xml (Persian) 2023-06-11 20:49:08 +02:00
sk
23f4b63195 Merge remote-tracking branch 'upstream/l10n_master' 2023-06-11 20:04:33 +02:00
sk22
edeae13dda Translated using Weblate (German)
Currently translated at 100.0% (304 of 304 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-06-11 18:04:03 +00:00
Oliebol
44558534e9 Translated using Weblate (Dutch)
Currently translated at 85.0% (256 of 301 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/nl/
2023-06-11 17:49:51 +00:00
Linerly
2b760bb215 Translated using Weblate (Indonesian)
Currently translated at 100.0% (301 of 301 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-06-11 17:49:51 +00:00
sk
44154a987d setting for "re:" reply CW prefix always or only to others
re: sk22#567
2023-06-11 19:46:18 +02:00
Eugen Rochko
7260db6668 New translations full_description.txt (Persian) 2023-06-11 19:41:48 +02:00
Eugen Rochko
1dadc51ddf New translations strings.xml (Persian) 2023-06-11 19:41:48 +02:00
Eugen Rochko
fe85351869 New translations strings.xml (Persian) 2023-06-11 18:34:16 +02:00
Eugen Rochko
74a83c6ac4 New translations strings.xml (Persian) 2023-06-11 17:37:10 +02:00
sk
acb1369e88 fix "show replies/boosts" filter not applied
closes sk22#566
2023-06-11 17:23:54 +02:00
sk
8e0d74f9c2 use appkit V.sp 2023-06-11 17:12:56 +02:00
Eugen Rochko
df77ba61ad New translations strings.xml (Persian) 2023-06-11 15:12:30 +02:00
Eugen Rochko
ed40f74d59 New translations strings.xml (Persian) 2023-06-11 13:57:15 +02:00
Eugen Rochko
42e26bef68 New translations strings.xml (Persian) 2023-06-11 12:54:18 +02:00
Eugen Rochko
af60adb55f New translations strings.xml (Indonesian) 2023-06-11 05:16:01 +02:00
sk
b94741feae boop version 2023-06-10 22:10:24 +02:00
sk
e43d6c35d8 update languages 2023-06-10 22:10:13 +02:00
sk
4a6f9e80b1 Merge remote-tracking branch 'weblate/main' 2023-06-10 22:03:41 +02:00
gallegonovato
ec02680507 Translated using Weblate (Spanish)
Currently translated at 99.6% (300 of 301 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-06-10 20:03:34 +00:00
sk22
5fc569a45a Translated using Weblate (German)
Currently translated at 100.0% (301 of 301 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-06-10 20:03:34 +00:00
sk
4bc9c5691d Merge remote-tracking branch 'upstream/l10n_master' 2023-06-10 22:03:19 +02:00
sk
19b68855ac move permission definition to status privacy 2023-06-10 21:54:47 +02:00
sk
70fdfb612e fix issue on re-bind 2023-06-10 21:54:18 +02:00
sk
0a32c217d8 Merge branch 'main' into pr/FineFindus/557 2023-06-10 21:47:26 +02:00
Eugen Rochko
5dfa9237ad New translations short_description.txt (Persian) 2023-06-10 21:44:47 +02:00
sk
573ff75498 update ancestor when deleting post 2023-06-10 21:32:41 +02:00
sk
87c37df370 insert replied directly below status
closes sk22#558
2023-06-10 20:57:01 +02:00
sk22
7fb0944e66 Translated using Weblate (German)
Currently translated at 100.0% (301 of 301 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-06-10 16:59:16 +00:00
sk
35c8a3d121 change strings 2023-06-10 18:59:05 +02:00
sk
9e58413d1a Merge remote-tracking branch 'weblate/main' 2023-06-10 18:54:32 +02:00
sk
90e60aef84 change auto-reveal cw wording
closes sk22#562
2023-06-10 18:53:38 +02:00
sk
8547ce05ed change auto-reveal cw wording
closes sk22#562
2023-06-10 18:52:01 +02:00
gicorada
0825faee5c Translated using Weblate (Italian)
Currently translated at 100.0% (297 of 297 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-06-10 16:42:23 +00:00
Linerly
d43a697df7 Translated using Weblate (Indonesian)
Currently translated at 100.0% (297 of 297 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-06-10 16:42:23 +00:00
Choukajohn
3b742c4391 Translated using Weblate (French)
Currently translated at 100.0% (297 of 297 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-06-10 16:42:23 +00:00
ihor_ck
a43a396043 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (297 of 297 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-06-10 16:42:23 +00:00
Choukajohn
bcb4fac553 Translated using Weblate (French)
Currently translated at 100.0% (297 of 297 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-06-10 16:42:23 +00:00
Eugen Rochko
c890195567 New translations strings.xml (Swedish) 2023-06-08 22:57:52 +02:00
Eugen Rochko
b50a327b17 New translations strings.xml (Swedish) 2023-06-08 17:47:06 +02:00
FineFindus
dbe7eb25ff Merge branch 'main' into feat/hide-non-boostable-boosts 2023-06-08 10:35:12 +02:00
FineFindus
45ecec09f5 feat: hide boost count on non-boostable statuses 2023-06-08 10:33:27 +02:00
FineFindus
9b4556d293 refactor: move boostable check to status 2023-06-08 10:33:27 +02:00
Grishka
17957b69d1 Filtered posts in timelines (AND-8) 2023-06-07 04:47:54 +03:00
Grishka
a24b4363d7 Bring toolbar appearance more in line with design 2023-06-05 04:46:21 +03:00
Grishka
02ddad22e7 Update profile menu (AND-34) 2023-06-05 04:32:18 +03:00
Grishka
a705512dc5 Update post options menu (AND-33) 2023-06-05 04:25:11 +03:00
Grishka
cfd6954755 Update launcher icon (AND-84) 2023-06-05 02:34:58 +03:00
Grishka
702ac43f86 Fix shortcut icon (AND-85) 2023-06-05 01:45:23 +03:00
Grishka
6ede2d22bb Fix #591 2023-06-04 23:02:48 +03:00
Grishka
315d26ad52 Settings tweaks 2023-06-04 05:32:27 +03:00
Grishka
a78b0687f7 Fix it again 2023-06-04 04:50:40 +03:00
Grishka
148b8e9369 Fix #583 2023-06-04 02:40:59 +03:00
Grishka
ae6ce0f9b0 Fix #548 2023-06-04 02:11:40 +03:00
Grishka
31c8665653 Settings M3 redesign wip 2023-06-04 02:04:55 +03:00
Grishka
7c6ec2e3d7 Fix #587 2023-05-30 21:32:08 +03:00
Grishka
31c7116a15 Merge branch 'master' into m3_redesign
# Conflicts:
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HashtagStatusDisplayItem.java
2023-05-28 20:58:27 +03:00
Grishka
5c480b37b3 Notifications M3 redesign (+ read marker support) 2023-05-27 13:31:01 +03:00
Grishka
92335d8678 Merge branch 'master' into m3_redesign 2023-05-25 21:02:17 +03:00
Grishka
1dcb5717ea Fix #553 2023-05-23 12:56:49 +03:00
Grishka
36f1a557d7 Fix default tab in profile 2023-05-23 12:17:26 +03:00
Grishka
bd7157c172 Reporting M3 redesign 2023-05-22 17:08:04 +03:00
Grishka
34a2af8429 Compose M3 redesign: custom emoji keyboard 2023-05-13 04:27:12 +03:00
Grishka
15883f2138 Compose: language selection 2023-05-12 22:21:21 +03:00
Grishka
89501271ce Compose autocomplete improvements 2023-05-12 03:39:46 +03:00
Grishka
968a6ea9b3 Merge branch 'master' into m3_redesign
# Conflicts:
#	mastodon/build.gradle
2023-05-11 05:49:34 +03:00
Grishka
e253d8f4f3 Pull user row into a separate view holder & update its design 2023-05-11 03:45:23 +03:00
Grishka
cfabe47e10 Select "timeline" tab in profiles by default 2023-05-10 02:10:19 +03:00
Grishka
d3fe7857b7 Move media & poll stuff out of ComposeFragment to separate classes 2023-05-09 23:59:56 +03:00
Grishka
642e96a439 Compose M3 redesign wip 2023-05-09 21:34:42 +03:00
Grishka
2b8451e045 Merge branch 'master' into m3_redesign 2023-05-01 21:38:31 +03:00
Grishka
62074e554a Account switcher M3 redesign 2023-05-01 13:43:00 +03:00
Grishka
0434cda2da Thread view M3 redesign 2023-04-30 23:04:45 +03:00
Grishka
4b4c88d44d Support opening mastodon.online and mastodon.social links 2023-04-17 06:47:49 +03:00
Grishka
9e116bec97 Merge branch 'master' into m3_redesign
# Conflicts:
#	mastodon/build.gradle
2023-04-12 19:41:39 +03:00
Grishka
dc25e16c00 fix 2023-04-09 01:48:54 +03:00
Grishka
42a7c324fa Merge branch 'master' into m3_redesign 2023-04-07 23:16:53 +03:00
Grishka
849888d128 Welcome fragment redesign again 2023-04-07 22:40:00 +03:00
Grishka
8a7e910e7c Reblog -> boost 2023-03-30 19:14:12 +03:00
Grishka
72d72d443e Limit aspect ratio to 9:20 2023-03-30 18:53:59 +03:00
Grishka
7b0a3f0f96 More media layout optimizations 2023-03-27 04:04:16 +03:00
Grishka
cf4604e0d8 More media layout optimizations 2023-03-24 01:33:33 +03:00
Grishka
e873dd7d0a New sensitive media design 2023-03-24 00:33:02 +03:00
Grishka
4492e940e5 Media attachments minor fixes 2023-03-23 22:36:52 +03:00
Grishka
c833c03dc3 New play button & alt text support for gifs & videos 2023-03-23 03:15:15 +03:00
Grishka
30b0d226b5 Tab bar M3 design 2023-03-23 01:49:39 +03:00
Grishka
8afad21113 Add "error" M3 button style 2023-03-23 01:09:03 +03:00
Grishka
6b5e5b0f25 More minor tweaks 2023-03-23 00:58:38 +03:00
Grishka
3c0ab6822f Add elevation effect stuff to a base class for all fragments that need it 2023-03-23 00:31:17 +03:00
Grishka
f7215d00ca Profile about tab redesign 2023-03-22 17:22:22 +03:00
Grishka
43bbe9be0f Fix LinkedTextView breaking XML layout editor 2023-03-22 17:01:13 +03:00
Grishka
477a691c9e Fix z-order and remove V.dp from more custom views 2023-03-22 16:55:09 +03:00
Grishka
e5d60050a2 Add filters to AccontTimelineFragment 2023-03-22 03:22:04 +03:00
Grishka
9a698fda18 Merge branch 'master' into m3_redesign 2023-03-22 02:47:13 +03:00
Grishka
d5701c1073 Merge branch 'master' into m3_redesign 2023-03-22 02:41:26 +03:00
Grishka
955b9a4b2b Featured tab in profiles 2023-03-22 02:30:42 +03:00
Grishka
09ffda2605 Merge branch 'master' into m3_redesign 2023-03-17 22:07:51 +03:00
Grishka
039fb0c505 Profile redesign: header 2023-03-17 22:07:28 +03:00
Grishka
20799ef1a8 Posts redesign wip 2023-03-14 19:17:37 +03:00
1534 changed files with 39663 additions and 22810 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!
> 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

@@ -3,7 +3,12 @@ buildscript {
repositories {
google()
mavenCentral()
mavenLocal()
maven {
url "https://www.jitpack.io"
content {
includeModule 'com.github.UnifiedPush', 'android-connector'
}
}
}
dependencies {
classpath 'com.android.tools.build:gradle:8.0.0'

View File

@@ -0,0 +1,9 @@
<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<style>
path { fill: black; }
@media (prefers-color-scheme: dark) {
path { fill: white; }
}
</style>
<path d="M15.4925 3.50673C14.652 3.58251 13.9933 4.28929 13.9933 5.15V10C13.9933 10.4142 13.6577 10.75 13.2437 10.75C11.8002 10.75 10.7863 11.3378 10.0365 12.238C9.26389 13.1656 8.7607 14.444 8.44554 15.7954C8.13254 17.1376 8.01871 18.4912 7.98453 19.5172C7.97182 19.8987 7.9702 20.2324 7.97313 20.5H14.9928V19.75C14.9928 18.5074 13.986 17.5 12.744 17.5H11.4947C11.0807 17.5 10.7451 17.1642 10.7451 16.75C10.7451 16.3358 11.0807 16 11.4947 16H12.744C14.8139 16 16.4919 17.6789 16.4919 19.75V20.5H17.2415C17.6555 20.5 17.9911 20.1642 17.9911 19.75V9.75C17.9911 9.33579 18.3267 9 18.7407 9H19.2472C20.2264 9 20.8249 7.92404 20.309 7.09132L19.6893 6.09132C19.4615 5.72367 19.0599 5.5 18.6275 5.5H16.2421C15.8281 5.5 15.4925 5.16421 15.4925 4.75V3.50673ZM6.47388 20.5C6.47098 20.2156 6.47293 19.8655 6.4862 19.4672C6.52229 18.3838 6.64271 16.9249 6.98559 15.4546C7.32631 13.9935 7.90065 12.4594 8.88484 11.2777C9.75681 10.2307 10.9399 9.47669 12.4942 9.29318V5.15C12.4942 3.4103 13.9037 2 15.6424 2C16.3876 2 16.9916 2.60442 16.9916 3.35V4H18.6275C19.5787 4 20.4622 4.49207 20.9634 5.30092L21.5831 6.30092C22.6749 8.06291 21.4985 10.32 19.4903 10.4898V19.75C19.4903 20.9926 18.4835 22 17.2415 22H7.24708L7.24537 22H5.79625C3.69964 22 2 20.2994 2 18.2016C2 17.2395 2.36489 16.3133 3.02098 15.6099L4.15612 14.393C4.92005 13.5741 5.17521 12.4027 4.82117 11.3399C4.67114 10.8896 4.41837 10.4804 4.08288 10.1447L2.96914 9.03042C2.67641 8.73753 2.67639 8.26266 2.96912 7.96976C3.26184 7.67686 3.73645 7.67685 4.02919 7.96974L5.14293 9.08405C5.643 9.58438 6.01977 10.1943 6.2434 10.8656C6.77114 12.4497 6.3908 14.1958 5.25209 15.4165L4.11695 16.6334C3.71996 17.059 3.49916 17.6195 3.49916 18.2016C3.49916 19.471 4.52761 20.5 5.79625 20.5H6.47388Z" fill="#212121"/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

1
img/saunarepo-badge.svg Normal file
View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="124.25" height="28" role="img" aria-label="SAUNAREPO"><title>SAUNAREPO</title><g shape-rendering="crispEdges"><rect width="124.25" height="28" fill="#fb8441"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="100"><image x="9" y="7" width="14" height="14" xlink:href="data:image/svg+xml;base64,PHN2ZyBmaWxsPSJ3aGl0ZSIgcm9sZT0iaW1nIiB2aWV3Qm94PSIwIDAgMjQgMjQiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHRpdGxlPkFuZHJvaWQ8L3RpdGxlPjxwYXRoIGQ9Ik0xNy41MjMgMTUuMzQxNGMtLjU1MTEgMC0uOTk5My0uNDQ4Ni0uOTk5My0uOTk5N3MuNDQ4My0uOTk5My45OTkzLS45OTkzYy41NTExIDAgLjk5OTMuNDQ4My45OTkzLjk5OTMuMDAwMS41NTExLS40NDgyLjk5OTctLjk5OTMuOTk5N20tMTEuMDQ2IDBjLS41NTExIDAtLjk5OTMtLjQ0ODYtLjk5OTMtLjk5OTdzLjQ0ODItLjk5OTMuOTk5My0uOTk5M2MuNTUxMSAwIC45OTkzLjQ0ODMuOTk5My45OTkzIDAgLjU1MTEtLjQ0ODMuOTk5Ny0uOTk5My45OTk3bTExLjQwNDUtNi4wMmwxLjk5NzMtMy40NTkyYS40MTYuNDE2IDAgMDAtLjE1MjEtLjU2NzYuNDE2LjQxNiAwIDAwLS41Njc2LjE1MjFsLTIuMDIyMyAzLjUwM0MxNS41OTAyIDguMjQzOSAxMy44NTMzIDcuODUwOCAxMiA3Ljg1MDhzLTMuNTkwMi4zOTMxLTUuMTM2NyAxLjA5ODlMNC44NDEgNS40NDY3YS40MTYxLjQxNjEgMCAwMC0uNTY3Ny0uMTUyMS40MTU3LjQxNTcgMCAwMC0uMTUyMS41Njc2bDEuOTk3MyAzLjQ1OTJDMi42ODg5IDExLjE4NjcuMzQzMiAxNC42NTg5IDAgMTguNzYxaDI0Yy0uMzQzNS00LjEwMjEtMi42ODkyLTcuNTc0My02LjExODUtOS40Mzk2Ii8+PC9zdmc+"/><text transform="scale(.1)" x="721.25" y="175" textLength="802.5" fill="#fff" font-weight="bold">SAUNAREPO</text></g></svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

279
mastodon/.editorconfig Normal file
View File

@@ -0,0 +1,279 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
indent_style = tab
insert_final_newline = false
max_line_length = 300
tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_smart_tabs = false
ij_visual_guides = none
ij_wrap_on_typing = false
[*.java]
ij_java_align_consecutive_assignments = false
ij_java_align_consecutive_variable_declarations = false
ij_java_align_group_field_declarations = false
ij_java_align_multiline_annotation_parameters = false
ij_java_align_multiline_array_initializer_expression = false
ij_java_align_multiline_assignment = false
ij_java_align_multiline_binary_operation = false
ij_java_align_multiline_chained_methods = false
ij_java_align_multiline_extends_list = false
ij_java_align_multiline_for = true
ij_java_align_multiline_method_parentheses = false
ij_java_align_multiline_parameters = true
ij_java_align_multiline_parameters_in_calls = false
ij_java_align_multiline_parenthesized_expression = false
ij_java_align_multiline_records = true
ij_java_align_multiline_resources = true
ij_java_align_multiline_ternary_operation = false
ij_java_align_multiline_text_blocks = false
ij_java_align_multiline_throws_list = false
ij_java_align_subsequent_simple_methods = false
ij_java_align_throws_keyword = false
ij_java_align_types_in_multi_catch = true
ij_java_annotation_parameter_wrap = off
ij_java_array_initializer_new_line_after_left_brace = false
ij_java_array_initializer_right_brace_on_new_line = false
ij_java_array_initializer_wrap = off
ij_java_assert_statement_colon_on_next_line = false
ij_java_assert_statement_wrap = off
ij_java_assignment_wrap = off
ij_java_binary_operation_sign_on_next_line = false
ij_java_binary_operation_wrap = off
ij_java_blank_lines_after_anonymous_class_header = 0
ij_java_blank_lines_after_class_header = 0
ij_java_blank_lines_after_imports = 1
ij_java_blank_lines_after_package = 1
ij_java_blank_lines_around_class = 1
ij_java_blank_lines_around_field = 0
ij_java_blank_lines_around_field_in_interface = 0
ij_java_blank_lines_around_initializer = 1
ij_java_blank_lines_around_method = 1
ij_java_blank_lines_around_method_in_interface = 1
ij_java_blank_lines_before_class_end = 0
ij_java_blank_lines_before_imports = 1
ij_java_blank_lines_before_method_body = 0
ij_java_blank_lines_before_package = 0
ij_java_block_brace_style = end_of_line
ij_java_block_comment_add_space = false
ij_java_block_comment_at_first_column = true
ij_java_builder_methods = none
ij_java_call_parameters_new_line_after_left_paren = false
ij_java_call_parameters_right_paren_on_new_line = false
ij_java_call_parameters_wrap = off
ij_java_case_statement_on_separate_line = true
ij_java_catch_on_new_line = false
ij_java_class_annotation_wrap = split_into_lines
ij_java_class_brace_style = end_of_line
ij_java_class_count_to_use_import_on_demand = 99
ij_java_class_names_in_javadoc = 1
ij_java_do_not_indent_top_level_class_members = false
ij_java_do_not_wrap_after_single_annotation = false
ij_java_do_not_wrap_after_single_annotation_in_parameter = false
ij_java_do_while_brace_force = never
ij_java_doc_add_blank_line_after_description = true
ij_java_doc_add_blank_line_after_param_comments = false
ij_java_doc_add_blank_line_after_return = false
ij_java_doc_add_p_tag_on_empty_lines = true
ij_java_doc_align_exception_comments = true
ij_java_doc_align_param_comments = true
ij_java_doc_do_not_wrap_if_one_line = false
ij_java_doc_enable_formatting = true
ij_java_doc_enable_leading_asterisks = true
ij_java_doc_indent_on_continuation = false
ij_java_doc_keep_empty_lines = true
ij_java_doc_keep_empty_parameter_tag = true
ij_java_doc_keep_empty_return_tag = true
ij_java_doc_keep_empty_throws_tag = true
ij_java_doc_keep_invalid_tags = true
ij_java_doc_param_description_on_new_line = false
ij_java_doc_preserve_line_breaks = false
ij_java_doc_use_throws_not_exception_tag = true
ij_java_else_on_new_line = false
ij_java_enum_constants_wrap = off
ij_java_extends_keyword_wrap = off
ij_java_extends_list_wrap = off
ij_java_field_annotation_wrap = split_into_lines
ij_java_finally_on_new_line = false
ij_java_for_brace_force = never
ij_java_for_statement_new_line_after_left_paren = false
ij_java_for_statement_right_paren_on_new_line = false
ij_java_for_statement_wrap = off
ij_java_generate_final_locals = false
ij_java_generate_final_parameters = false
ij_java_if_brace_force = never
ij_java_imports_layout = android.**,|,com.**,|,junit.**,|,net.**,|,org.**,|,java.**,|,javax.**,|,*,|,$*,|
ij_java_indent_case_from_switch = true
ij_java_insert_inner_class_imports = false
ij_java_insert_override_annotation = true
ij_java_keep_blank_lines_before_right_brace = 2
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
ij_java_keep_blank_lines_in_code = 2
ij_java_keep_blank_lines_in_declarations = 2
ij_java_keep_builder_methods_indents = false
ij_java_keep_control_statement_in_one_line = true
ij_java_keep_first_column_comment = true
ij_java_keep_indents_on_empty_lines = false
ij_java_keep_line_breaks = true
ij_java_keep_multiple_expressions_in_one_line = false
ij_java_keep_simple_blocks_in_one_line = false
ij_java_keep_simple_classes_in_one_line = false
ij_java_keep_simple_lambdas_in_one_line = false
ij_java_keep_simple_methods_in_one_line = false
ij_java_label_indent_absolute = false
ij_java_label_indent_size = 0
ij_java_lambda_brace_style = end_of_line
ij_java_layout_static_imports_separately = true
ij_java_line_comment_add_space = false
ij_java_line_comment_add_space_on_reformat = false
ij_java_line_comment_at_first_column = true
ij_java_method_annotation_wrap = split_into_lines
ij_java_method_brace_style = end_of_line
ij_java_method_call_chain_wrap = off
ij_java_method_parameters_new_line_after_left_paren = false
ij_java_method_parameters_right_paren_on_new_line = false
ij_java_method_parameters_wrap = off
ij_java_modifier_list_wrap = false
ij_java_multi_catch_types_wrap = normal
ij_java_names_count_to_use_import_on_demand = 99
ij_java_new_line_after_lparen_in_annotation = false
ij_java_new_line_after_lparen_in_record_header = false
ij_java_parameter_annotation_wrap = off
ij_java_parentheses_expression_new_line_after_left_paren = false
ij_java_parentheses_expression_right_paren_on_new_line = false
ij_java_place_assignment_sign_on_next_line = false
ij_java_prefer_longer_names = true
ij_java_prefer_parameters_wrap = false
ij_java_record_components_wrap = normal
ij_java_repeat_synchronized = true
ij_java_replace_instanceof_and_cast = false
ij_java_replace_null_check = true
ij_java_replace_sum_lambda_with_method_ref = true
ij_java_resource_list_new_line_after_left_paren = false
ij_java_resource_list_right_paren_on_new_line = false
ij_java_resource_list_wrap = off
ij_java_rparen_on_new_line_in_annotation = false
ij_java_rparen_on_new_line_in_record_header = false
ij_java_space_after_closing_angle_bracket_in_type_argument = false
ij_java_space_after_colon = true
ij_java_space_after_comma = true
ij_java_space_after_comma_in_type_arguments = true
ij_java_space_after_for_semicolon = true
ij_java_space_after_quest = true
ij_java_space_after_type_cast = true
ij_java_space_before_annotation_array_initializer_left_brace = false
ij_java_space_before_annotation_parameter_list = false
ij_java_space_before_array_initializer_left_brace = false
ij_java_space_before_catch_keyword = false
ij_java_space_before_catch_left_brace = false
ij_java_space_before_catch_parentheses = false
ij_java_space_before_class_left_brace = false
ij_java_space_before_colon = true
ij_java_space_before_colon_in_foreach = true
ij_java_space_before_comma = false
ij_java_space_before_do_left_brace = false
ij_java_space_before_else_keyword = false
ij_java_space_before_else_left_brace = false
ij_java_space_before_finally_keyword = false
ij_java_space_before_finally_left_brace = false
ij_java_space_before_for_left_brace = false
ij_java_space_before_for_parentheses = false
ij_java_space_before_for_semicolon = false
ij_java_space_before_if_left_brace = false
ij_java_space_before_if_parentheses = false
ij_java_space_before_method_call_parentheses = false
ij_java_space_before_method_left_brace = false
ij_java_space_before_method_parentheses = false
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
ij_java_space_before_quest = true
ij_java_space_before_switch_left_brace = false
ij_java_space_before_switch_parentheses = false
ij_java_space_before_synchronized_left_brace = false
ij_java_space_before_synchronized_parentheses = false
ij_java_space_before_try_left_brace = false
ij_java_space_before_try_parentheses = false
ij_java_space_before_type_parameter_list = false
ij_java_space_before_while_keyword = false
ij_java_space_before_while_left_brace = false
ij_java_space_before_while_parentheses = false
ij_java_space_inside_one_line_enum_braces = false
ij_java_space_within_empty_array_initializer_braces = false
ij_java_space_within_empty_method_call_parentheses = false
ij_java_space_within_empty_method_parentheses = false
ij_java_spaces_around_additive_operators = false
ij_java_spaces_around_annotation_eq = true
ij_java_spaces_around_assignment_operators = false
ij_java_spaces_around_bitwise_operators = false
ij_java_spaces_around_equality_operators = false
ij_java_spaces_around_lambda_arrow = false
ij_java_spaces_around_logical_operators = true
ij_java_spaces_around_method_ref_dbl_colon = false
ij_java_spaces_around_multiplicative_operators = false
ij_java_spaces_around_relational_operators = false
ij_java_spaces_around_shift_operators = false
ij_java_spaces_around_type_bounds_in_type_parameters = true
ij_java_spaces_around_unary_operator = false
ij_java_spaces_within_angle_brackets = false
ij_java_spaces_within_annotation_parentheses = false
ij_java_spaces_within_array_initializer_braces = false
ij_java_spaces_within_braces = false
ij_java_spaces_within_brackets = false
ij_java_spaces_within_cast_parentheses = false
ij_java_spaces_within_catch_parentheses = false
ij_java_spaces_within_for_parentheses = false
ij_java_spaces_within_if_parentheses = false
ij_java_spaces_within_method_call_parentheses = false
ij_java_spaces_within_method_parentheses = false
ij_java_spaces_within_parentheses = false
ij_java_spaces_within_record_header = false
ij_java_spaces_within_switch_parentheses = false
ij_java_spaces_within_synchronized_parentheses = false
ij_java_spaces_within_try_parentheses = false
ij_java_spaces_within_while_parentheses = false
ij_java_special_else_if_treatment = true
ij_java_subclass_name_suffix = Impl
ij_java_ternary_operation_signs_on_next_line = false
ij_java_ternary_operation_wrap = off
ij_java_test_name_suffix = Test
ij_java_throws_keyword_wrap = off
ij_java_throws_list_wrap = off
ij_java_use_external_annotations = false
ij_java_use_fq_class_names = false
ij_java_use_relative_indents = false
ij_java_use_single_class_imports = true
ij_java_variable_annotation_wrap = off
ij_java_visibility = public
ij_java_while_brace_force = never
ij_java_while_on_new_line = false
ij_java_wrap_comments = false
ij_java_wrap_first_method_in_call_chain = false
ij_java_wrap_long_lines = false
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.rng,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
ij_continuation_indent_size = 4
ij_xml_align_attributes = false
ij_xml_align_text = false
ij_xml_attribute_wrap = normal
ij_xml_block_comment_add_space = false
ij_xml_block_comment_at_first_column = true
ij_xml_keep_blank_lines = 2
ij_xml_keep_indents_on_empty_lines = false
ij_xml_keep_line_breaks = false
ij_xml_keep_line_breaks_in_text = true
ij_xml_keep_whitespaces = false
ij_xml_keep_whitespaces_around_cdata = preserve
ij_xml_keep_whitespaces_inside_cdata = false
ij_xml_line_comment_at_first_column = true
ij_xml_space_after_tag_name = false
ij_xml_space_around_equals_in_attribute = false
ij_xml_space_inside_empty_tag = true
ij_xml_text_wrap = normal
ij_xml_use_custom_settings = true

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 100
versionName "1.3.0+fork.100.moshinda"
versionCode 99
versionName "2.0.3+fork.99"
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,30 +31,10 @@ 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 }
fdroidRelease { initWith release }
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_17
@@ -91,7 +46,7 @@ android {
setRoot "src/github"
}
debug {
setRoot "src/debug"
setRoot "src/github"
}
}
namespace 'org.joinmastodon.android'
@@ -114,7 +69,8 @@ dependencies {
implementation 'me.grishka.litex:dynamicanimation:1.1.0-alpha03'
implementation 'me.grishka.litex:viewpager:1.0.0'
implementation 'me.grishka.litex:viewpager2:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.8'
implementation 'me.grishka.litex:palette:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.9'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8'
@@ -122,10 +78,11 @@ dependencies {
implementation 'org.parceler:parceler-api:1.1.12'
implementation 'com.github.bottom-software-foundation:bottom-java:2.1.0'
annotationProcessor 'org.parceler:parceler:1.1.12'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.3'
implementation 'com.github.UnifiedPush:android-connector:2.1.1'
androidTestImplementation 'androidx.test:core:1.4.1-alpha05'
androidTestImplementation 'androidx.test.ext:junit:1.1.4-alpha05'
androidTestImplementation 'androidx.test:runner:1.5.0-alpha02'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0-alpha05'
androidTestImplementation 'androidx.test:core:1.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

View File

@@ -30,6 +30,9 @@
*;
}
# i don't know how proguard works
-keep class org.joinmastodon.android.** { *; }
# Keep all enums for debugging purposes
-keepnames public enum * {
*;
@@ -42,14 +45,43 @@
-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 * { *; }
-keep class **$$Parcelable { *; }
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
##---------------End: proguard configuration for Gson ----------
-dontobfuscate

View File

@@ -65,6 +65,7 @@ import static androidx.test.espresso.matcher.ViewMatchers.*;
@LargeTest
public class StoreScreenshotsGenerator{
private static final String PHOTO_FILE="IMG_1010.jpg";
private static final long LOAD_WAIT_TIMEOUT=20_000;
@Rule
public ActivityScenarioRule<MainActivity> activityScenarioRule=new ActivityScenarioRule<>(MainActivity.class);
@@ -84,14 +85,14 @@ public class StoreScreenshotsGenerator{
AccountSession session=AccountSessionManager.getInstance().getAccount(AccountSessionManager.getInstance().getLastActiveAccountID());
MastodonApp.context.deleteDatabase(session.getID()+".db");
onView(isRoot()).perform(waitId(R.id.more, 5000));
onView(isRoot()).perform(waitId(R.id.more, LOAD_WAIT_TIMEOUT));
Thread.sleep(500);
takeScreenshot("HomeTimeline");
GlobalUserPreferences.theme=GlobalUserPreferences.ThemePreference.DARK;
activityScenarioRule.getScenario().recreate();
onView(isRoot()).perform(waitId(R.id.more, 5000));
onView(isRoot()).perform(waitId(R.id.more, LOAD_WAIT_TIMEOUT));
Thread.sleep(500);
takeScreenshot("HomeTimeline_Dark");
@@ -100,8 +101,8 @@ public class StoreScreenshotsGenerator{
activityScenarioRule.getScenario().onActivity(activity->UiUtils.openProfileByID(activity, session.getID(), args.getString("profileAccountID")));
Thread.sleep(500);
onView(isRoot()).perform(waitId(R.id.avatar_border, 5000)); // wait for profile to load
onView(isRoot()).perform(waitId(R.id.more, 5000)); // wait for timeline to load
onView(isRoot()).perform(waitId(R.id.avatar_border, LOAD_WAIT_TIMEOUT)); // wait for profile to load
onView(isRoot()).perform(waitId(R.id.more, LOAD_WAIT_TIMEOUT)); // wait for timeline to load
Thread.sleep(500);
takeScreenshot("Profile");

View File

@@ -2,15 +2,22 @@ package org.joinmastodon.android.ui.utils;
import static org.junit.Assert.*;
import android.content.Context;
import android.content.res.Resources;
import android.util.Pair;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AccountField;
import org.joinmastodon.android.model.Instance;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
public class UiUtilsTest {
@@ -103,4 +110,152 @@ public class UiUtilsTest {
"somewhere.else"
));
}
private final String[] args = new String[] { "Megalodon", "" };
private String gen(String format, CharSequence... args) {
return UiUtils.generateFormattedString(format, args).toString();
}
@Test
public void generateFormattedString() {
assertEquals(
"ordered substitution",
"Megalodon reacted with ♡",
gen("%s reacted with %s", args)
);
assertEquals(
"1 2 3 4 5",
gen("%s %s %s %s %s", "1", "2", "3", "4", "5")
);
assertEquals(
"indexed substitution",
"with ♡ was reacted by Megalodon",
gen("with %2$s was reacted by %1$s", args)
);
assertEquals(
"indexed substitution, in order",
"Megalodon reacted with ♡",
gen("%1$s reacted with %2$s", args)
);
assertEquals(
"indexed substitution, 0-based",
"Megalodon reacted with ♡",
gen("%0$s reacted with %1$s", args)
);
assertEquals(
"indexed substitution, 5 items",
"5 4 3 2 1",
gen("%5$s %4$s %3$s %2$s %1$s", "1", "2", "3", "4", "5")
);
assertEquals(
"one argument missing",
"Megalodon reacted with ♡",
gen("reacted with %s", args)
);
assertEquals(
"multiple arguments missing",
"Megalodon reacted with ♡",
gen("reacted with", args)
);
assertEquals(
"multiple arguments missing, numbers in expeced positions",
"1 2 x 3 4 5",
gen("%s x %s", "1", "2", "3", "4", "5")
);
assertEquals(
"one leading and trailing space",
"Megalodon reacted with ♡",
gen(" reacted with ", args)
);
assertEquals(
"multiple leading and trailing spaces",
"Megalodon reacted with ♡",
gen(" reacted with ", args)
);
assertEquals(
"invalid format produces expected invalid result",
"Megalodon reacted with % s ♡",
gen("reacted with % s", args)
);
assertEquals(
"plain string as format, all arguments get added",
"a x b c",
gen("x", new String[] { "a", "b", "c" })
);
assertEquals("empty input produces empty output", "", gen(""));
// not supported:
// assertEquals("a b a", gen("%1$s %2$s %2$s %1$s", new String[] { "a", "b", "c" }));
// assertEquals("x", gen("%s %1$s %2$s %1$s %s", new String[] { "a", "b", "c" }));
}
private AccountField makeField(String name, String value) {
AccountField f = new AccountField();
f.name = name;
f.value = value;
return f;
}
private Account fakeAccount(AccountField... fields) {
Account a = new Account();
a.fields = Arrays.asList(fields);
return a;
}
@Test
public void extractPronouns() {
assertEquals("they", UiUtils.extractPronouns(MastodonApp.context, fakeAccount(
makeField("name and pronouns", "https://pronouns.site"),
makeField("pronouns", "they"),
makeField("pronouns something", "bla bla")
)).orElseThrow());
assertTrue(UiUtils.extractPronouns(MastodonApp.context, fakeAccount()).isEmpty());
assertEquals("it/its", UiUtils.extractPronouns(MastodonApp.context, fakeAccount(
makeField("pronouns pronouns pronouns", "hi hi hi"),
makeField("pronouns", "it/its"),
makeField("the pro's nouns", "professional")
)).orElseThrow());
assertEquals("she/he", UiUtils.extractPronouns(MastodonApp.context, fakeAccount(
makeField("my name is", "jeanette shork, apparently"),
makeField("my pronouns are", "she/he")
)).orElseThrow());
assertEquals("they/them", UiUtils.extractPronouns(MastodonApp.context, fakeAccount(
makeField("pronouns", "https://pronouns.cc/pronouns/they/them")
)).orElseThrow());
Context german = UiUtils.getLocalizedContext(MastodonApp.context, Locale.GERMAN);
assertEquals("sie/ihr", UiUtils.extractPronouns(german, fakeAccount(
makeField("pronomen lauten", "sie/ihr"),
makeField("pronouns are", "she/her"),
makeField("die pronomen", "stehen oben")
)).orElseThrow());
assertEquals("er/ihm", UiUtils.extractPronouns(german, fakeAccount(
makeField("die pronomen", "stehen unten"),
makeField("pronomen sind", "er/ihm"),
makeField("pronouns are", "he/him")
)).orElseThrow());
assertEquals("* (asterisk)", UiUtils.extractPronouns(MastodonApp.context, fakeAccount(
makeField("pronouns", "-- * (asterisk) --")
)).orElseThrow());
}
}

View File

@@ -1,10 +1,10 @@
package org.joinmastodon.android.utils;
import static org.joinmastodon.android.model.Filter.FilterAction.*;
import static org.joinmastodon.android.model.Filter.FilterContext.*;
import static org.joinmastodon.android.model.FilterAction.*;
import static org.joinmastodon.android.model.FilterContext.*;
import static org.junit.Assert.*;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.LegacyFilter;
import org.joinmastodon.android.model.Status;
import org.junit.Test;
@@ -14,8 +14,8 @@ import java.util.List;
public class StatusFilterPredicateTest {
private static final Filter hideMeFilter = new Filter(), warnMeFilter = new Filter();
private static final List<Filter> allFilters = List.of(hideMeFilter, warnMeFilter);
private static final LegacyFilter hideMeFilter = new LegacyFilter(), warnMeFilter = new LegacyFilter();
private static final List<LegacyFilter> allFilters = List.of(hideMeFilter, warnMeFilter);
private static final Status
hideInHomePublic = Status.ofFake(null, "hide me, please", Instant.now()),

View File

@@ -1,369 +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();
}
}
/*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

@@ -100,8 +100,8 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
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){
long timeSinceLastCheck=System.currentTimeMillis()-getPrefs().getLong("lastCheck", 0);
if(timeSinceLastCheck>CHECK_PERIOD || forceUpdate){
setState(UpdateState.CHECKING);
MastodonAPIController.runInBackground(this::actuallyCheckForUpdates);
}
@@ -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()){
@@ -148,12 +148,13 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
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){
if(newVersion>curVersion || newForkNumber>curForkNumber || forceUpdate){
forceUpdate=false;
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())){
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();
@@ -323,6 +324,15 @@ public class GithubSelfUpdaterImpl extends GithubSelfUpdater{
}
}
@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

View File

@@ -1,11 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.joinmastodon.android">
<manifest xmlns:tools="http://schemas.android.com/tools"
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"/>
@@ -26,13 +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:roundIcon="@mipmap/ic_launcher_round"
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">
@@ -49,7 +46,6 @@
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="info.guardianproject.panic.action.TRIGGER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@@ -62,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"
@@ -92,6 +88,15 @@
<category android:name="me.grishka.fcmtest"/>
</intent-filter>
</receiver>
<receiver android:exported="true" android:enabled="true" android:name=".UnifiedPushNotificationReceiver"
tools:ignore="ExportedReceiver">
<intent-filter>
<action android:name="org.unifiedpush.android.connector.MESSAGE"/>
<action android:name="org.unifiedpush.android.connector.UNREGISTERED"/>
<action android:name="org.unifiedpush.android.connector.NEW_ENDPOINT"/>
<action android:name="org.unifiedpush.android.connector.REGISTRATION_FAILED"/>
</intent-filter>
</receiver>
</application>

View File

@@ -1,6 +1,7 @@
13bells.com
1611.social
4aem.com
aethy.com
adachi.party
anime.website
annihilation.social
anon-kenkai.com
@@ -9,14 +10,17 @@ bae.st
bajax.us
banepo.st
baraag.net
bassam.social
beefyboys.win
beepboop.ga
berserker.town
bikeshed.party
boks.moe
boymoder.biz
brainsoap.net
breastmilk.club
brighteon.social
bungle.online
cawfee.club
clew.lol
clubcyberia.co
@@ -25,8 +29,8 @@ comfyboy.club
contrapointsfan.club
cum.camp
cum.salon
cybercriminal.eu
darknight-coffee.org
decayable.ink
dembased.xyz
desupost.soy
detroitriotcity.com
@@ -40,7 +44,6 @@ fluf.club
foxfam.club
freak.university
freeatlantis.com
freecumextremist.com
freedomstrike.org
freesoftwareextremist.com
freespeech.group
@@ -59,7 +62,6 @@ goyim.app
goyslop.cafe
haeder.net
handholding.io
hidamari.apartments
hitchhiker.social
hunk.city
iddqd.social
@@ -75,14 +77,13 @@ leftychan.net
lewdieheaven.com
liberdon.com
ligma.pro
lizards.live
lolicon.rocks
lolison.top
lovingexpressions.net
lucasvl.nl
mahodou.moe
makemysarcophagus.com
maladaptive.art
marsey.moe
masochi.st
mastinator.com
merovingian.club
@@ -105,7 +106,6 @@ nobodyhasthe.biz
nukem.biz
obo.sh
onionfarms.org
outpoa.st
pawlicker.com
pawoo.net
pedo.school
@@ -121,6 +121,7 @@ poast.tv
poster.place
prospeech.space
quodverum.com
r18.social
rakket.app
rapemeat.solutions
rdrama.cc
@@ -132,7 +133,6 @@ schwartzwelt.xyz
seal.cafe
shigusegubu.club
shitpost.cloud
shitposter.club
shota.house
silliness.observer
skinheads.eu
@@ -149,7 +149,6 @@ sonichu.com
spinster.xyz
springbo.cc
starnix.network
stereophonic.space
strelizia.net
syspxl.xyz
tastingtraffic.net

View File

@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<style>
*{
box-sizing: border-box;
overflow-wrap: break-word;
}
body{
background: {{colorSurface}};
padding: 16px 16px 0 16px;
margin: 0;
color: {{colorOnSurface}};
font-family: Roboto, sans-serif;
font-size: 14px;
line-height: 20px;
-webkit-tap-highlight-color: {{colorPrimaryTransparent}};
}
a{
text-decoration: none;
color: {{colorPrimary}};
}
p, h1, h2, h3, h4, h5, h6, ul, ol{
margin-bottom: 8px;
margin-top: 0;
}
h1, h2{
font-size: 16px;
line-height: 24px;
font-weight: 500;
}
h3, h4, h5, h6{
font-size: 14px;
line-height: 20px;
font-weight: 500;
}
b, strong{
font-weight: 500;
}
ul, ol{
padding-inline-start: 16px;
}
ul>li, ol>li{
padding-inline-start: 4px;
}
</style>
</head>
<body>
{{content}}
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 358 KiB

View File

@@ -0,0 +1,78 @@
package com.hootsuite.nachos;
import android.content.res.ColorStateList;
public class ChipConfiguration {
private final int mChipHorizontalSpacing;
private final ColorStateList mChipBackground;
private final int mChipCornerRadius;
private final int mChipTextColor;
private final int mChipTextSize;
private final int mChipHeight;
private final int mChipVerticalSpacing;
private final int mMaxAvailableWidth;
/**
* Creates a new ChipConfiguration. You can pass in {@code -1} or {@code null} for any of the parameters to indicate that parameter should be
* ignored.
*
* @param chipHorizontalSpacing the amount of horizontal space (in pixels) to put between consecutive chips
* @param chipBackground the {@link ColorStateList} to set as the background of the chips
* @param chipCornerRadius the corner radius of the chip background, in pixels
* @param chipTextColor the color to set as the text color of the chips
* @param chipTextSize the font size (in pixels) to use for the text of the chips
* @param chipHeight the height (in pixels) of each chip
* @param chipVerticalSpacing the amount of vertical space (in pixels) to put between chips on consecutive lines
* @param maxAvailableWidth the maximum available with for a chip (the width of a full line of text in the text view)
*/
ChipConfiguration(int chipHorizontalSpacing,
ColorStateList chipBackground,
int chipCornerRadius,
int chipTextColor,
int chipTextSize,
int chipHeight,
int chipVerticalSpacing,
int maxAvailableWidth) {
mChipHorizontalSpacing = chipHorizontalSpacing;
mChipBackground = chipBackground;
mChipCornerRadius = chipCornerRadius;
mChipTextColor = chipTextColor;
mChipTextSize = chipTextSize;
mChipHeight = chipHeight;
mChipVerticalSpacing = chipVerticalSpacing;
mMaxAvailableWidth = maxAvailableWidth;
}
public int getChipHorizontalSpacing() {
return mChipHorizontalSpacing;
}
public ColorStateList getChipBackground() {
return mChipBackground;
}
public int getChipCornerRadius() {
return mChipCornerRadius;
}
public int getChipTextColor() {
return mChipTextColor;
}
public int getChipTextSize() {
return mChipTextSize;
}
public int getChipHeight() {
return mChipHeight;
}
public int getChipVerticalSpacing() {
return mChipVerticalSpacing;
}
public int getMaxAvailableWidth() {
return mMaxAvailableWidth;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
package com.hootsuite.nachos.chip;
import androidx.annotation.Nullable;
public interface Chip {
/**
* @return the text represented by this Chip
*/
CharSequence getText();
/**
* @return the data associated with this Chip or null if no data is associated with it
*/
@Nullable
Object getData();
/**
* @return the width of the Chip or -1 if the Chip hasn't been given the chance to calculate its width
*/
int getWidth();
/**
* Sets the UI state.
*
* @param stateSet one of the state constants in {@link android.view.View}
*/
void setState(int[] stateSet);
}

View File

@@ -0,0 +1,44 @@
package com.hootsuite.nachos.chip;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hootsuite.nachos.ChipConfiguration;
/**
* Interface to allow the creation and configuration of chips
*
* @param <C> The type of {@link Chip} that the implementation will create/configure
*/
public interface ChipCreator<C extends Chip> {
/**
* Creates a chip from the given context and text. Use this method when creating a brand new chip from a piece of text.
*
* @param context the {@link Context} to use to initialize the chip
* @param text the text the Chip should represent
* @param data the data to associate with the Chip, or null to associate no data
* @return the created chip
*/
C createChip(@NonNull Context context, @NonNull CharSequence text, @Nullable Object data);
/**
* Creates a chip from the given context and existing chip. Use this method when recreating a chip from an existing one.
*
* @param context the {@link Context} to use to initialize the chip
* @param existingChip the chip that the created chip should be based on
* @return the created chip
*/
C createChip(@NonNull Context context, @NonNull C existingChip);
/**
* Applies the given {@link ChipConfiguration} to the given {@link Chip}. Use this method to customize the appearance/behavior of a chip before
* adding it to the text.
*
* @param chip the chip to configure
* @param chipConfiguration the configuration to apply to the chip
*/
void configureChip(@NonNull C chip, @NonNull ChipConfiguration chipConfiguration);
}

View File

@@ -0,0 +1,20 @@
package com.hootsuite.nachos.chip;
public class ChipInfo {
private final CharSequence mText;
private final Object mData;
public ChipInfo(CharSequence text, Object data) {
this.mText = text;
this.mData = data;
}
public CharSequence getText() {
return mText;
}
public Object getData() {
return mData;
}
}

View File

@@ -0,0 +1,510 @@
package com.hootsuite.nachos.chip;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.text.style.ImageSpan;
import androidx.annotation.Dimension;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.joinmastodon.android.R;
/**
* A Span that displays text and an optional icon inside of a material design chip. The chip's dimensions, colors etc. can be extensively customized
* through the various setter methods available in this class.
* The basic structure of the chip is the following:
* For chips with the icon on right:
* <pre>
*
* (chip vertical spacing / 2)
* ----------------------------------------------------------
* | |
* (left margin) | (padding edge) text (padding between image) icon | (right margin)
* | |
* ----------------------------------------------------------
* (chip vertical spacing / 2)
*
* </pre>
* For chips with the icon on the left (see {@link #setShowIconOnLeft(boolean)}):
* <pre>
*
* (chip vertical spacing / 2)
* ----------------------------------------------------------
* | |
* (left margin) | icon (padding between image) text (padding edge) | (right margin)
* | |
* ----------------------------------------------------------
* (chip vertical spacing / 2)
* </pre>
*/
public class ChipSpan extends ImageSpan implements Chip {
private static final float SCALE_PERCENT_OF_CHIP_HEIGHT = 0.70f;
private static final boolean ICON_ON_LEFT_DEFAULT = true;
private int[] mStateSet = new int[]{};
private String mEllipsis;
private ColorStateList mDefaultBackgroundColor;
private ColorStateList mBackgroundColor;
private int mTextColor;
private int mCornerRadius = -1;
private int mIconBackgroundColor;
private int mTextSize = -1;
private int mPaddingEdgePx;
private int mPaddingBetweenImagePx;
private int mLeftMarginPx;
private int mRightMarginPx;
private int mMaxAvailableWidth = -1;
private CharSequence mText;
private String mTextToDraw;
private Drawable mIcon;
private boolean mShowIconOnLeft = ICON_ON_LEFT_DEFAULT;
private int mChipVerticalSpacing = 0;
private int mChipHeight = -1;
private int mChipWidth = -1;
private int mIconWidth;
private int mCachedSize = -1;
private Object mData;
/**
* Constructs a new ChipSpan.
*
* @param context a {@link Context} that will be used to retrieve default configurations from resource files
* @param text the text for the ChipSpan to display
* @param icon an optional icon (can be {@code null}) for the ChipSpan to display
*/
public ChipSpan(@NonNull Context context, @NonNull CharSequence text, @Nullable Drawable icon, Object data) {
super(icon);
mIcon = icon;
mText = text;
mTextToDraw = mText.toString();
mEllipsis = context.getString(R.string.chip_ellipsis);
mDefaultBackgroundColor = context.getColorStateList(R.color.chip_material_background);
mBackgroundColor = mDefaultBackgroundColor;
mTextColor = context.getColor(R.color.chip_default_text_color);
mIconBackgroundColor = context.getColor(R.color.chip_default_icon_background_color);
Resources resources = context.getResources();
mPaddingEdgePx = resources.getDimensionPixelSize(R.dimen.chip_default_padding_edge);
mPaddingBetweenImagePx = resources.getDimensionPixelSize(R.dimen.chip_default_padding_between_image);
mLeftMarginPx = resources.getDimensionPixelSize(R.dimen.chip_default_left_margin);
mRightMarginPx = resources.getDimensionPixelSize(R.dimen.chip_default_right_margin);
mData = data;
}
/**
* Copy constructor to recreate a ChipSpan from an existing one
*
* @param context a {@link Context} that will be used to retrieve default configurations from resource files
* @param chipSpan the ChipSpan to copy
*/
public ChipSpan(@NonNull Context context, @NonNull ChipSpan chipSpan) {
this(context, chipSpan.getText(), chipSpan.getDrawable(), chipSpan.getData());
mDefaultBackgroundColor = chipSpan.mDefaultBackgroundColor;
mTextColor = chipSpan.mTextColor;
mIconBackgroundColor = chipSpan.mIconBackgroundColor;
mCornerRadius = chipSpan.mCornerRadius;
mTextSize = chipSpan.mTextSize;
mPaddingEdgePx = chipSpan.mPaddingEdgePx;
mPaddingBetweenImagePx = chipSpan.mPaddingBetweenImagePx;
mLeftMarginPx = chipSpan.mLeftMarginPx;
mRightMarginPx = chipSpan.mRightMarginPx;
mMaxAvailableWidth = chipSpan.mMaxAvailableWidth;
mShowIconOnLeft = chipSpan.mShowIconOnLeft;
mChipVerticalSpacing = chipSpan.mChipVerticalSpacing;
mChipHeight = chipSpan.mChipHeight;
mStateSet = chipSpan.mStateSet;
}
@Override
public Object getData() {
return mData;
}
/**
* Sets the height of the chip. This height should not include any extra spacing (for extra vertical spacing call {@link #setChipVerticalSpacing(int)}).
* The background of the chip will fill the full height provided here. If this method is never called, the chip will have the height of one full line
* of text by default. If {@code -1} is passed here, the chip will revert to this default behavior.
*
* @param chipHeight the height to set in pixels
*/
public void setChipHeight(int chipHeight) {
mChipHeight = chipHeight;
}
/**
* Sets the vertical spacing to include in between chips. Half of the value set here will be placed as empty space above the chip and half the value
* will be placed as empty space below the chip. Therefore chips on consecutive lines will have the full value as vertical space in between them.
* This spacing is achieved by adjusting the font metrics used by the text view containing these chips; however it does not come into effect until
* at least one chip is created. Note that vertical spacing is dependent on having a fixed chip height (set in {@link #setChipHeight(int)}). If a
* height is not specified in that method, the value set here will be ignored.
*
* @param chipVerticalSpacing the vertical spacing to set in pixels
*/
public void setChipVerticalSpacing(int chipVerticalSpacing) {
mChipVerticalSpacing = chipVerticalSpacing;
}
/**
* Sets the font size for the chip's text. If this method is never called, the chip text will have the same font size as the text in the TextView
* containing this chip by default. If {@code -1} is passed here, the chip will revert to this default behavior.
*
* @param size the font size to set in pixels
*/
public void setTextSize(int size) {
mTextSize = size;
invalidateCachedSize();
}
/**
* Sets the color for the chip's text.
*
* @param color the color to set (as a hexadecimal number in the form 0xAARRGGBB)
*/
public void setTextColor(int color) {
mTextColor = color;
}
/**
* Sets where the icon (if an icon was provided in the constructor) will appear.
*
* @param showIconOnLeft if true, the icon will appear on the left, otherwise the icon will appear on the right
*/
public void setShowIconOnLeft(boolean showIconOnLeft) {
this.mShowIconOnLeft = showIconOnLeft;
invalidateCachedSize();
}
/**
* Sets the left margin. This margin will appear as empty space (it will not share the chip's background color) to the left of the chip.
*
* @param leftMarginPx the left margin to set in pixels
*/
public void setLeftMargin(int leftMarginPx) {
mLeftMarginPx = leftMarginPx;
invalidateCachedSize();
}
/**
* Sets the right margin. This margin will appear as empty space (it will not share the chip's background color) to the right of the chip.
*
* @param rightMarginPx the right margin to set in pixels
*/
public void setRightMargin(int rightMarginPx) {
this.mRightMarginPx = rightMarginPx;
invalidateCachedSize();
}
/**
* Sets the background color. To configure which color in the {@link ColorStateList} is shown you can call {@link #setState(int[])}.
* Passing {@code null} here will cause the chip to revert to it's default background.
*
* @param backgroundColor a {@link ColorStateList} containing backgrounds for different states.
* @see #setState(int[])
*/
public void setBackgroundColor(@Nullable ColorStateList backgroundColor) {
mBackgroundColor = backgroundColor != null ? backgroundColor : mDefaultBackgroundColor;
}
/**
* Sets the chip background corner radius.
*
* @param cornerRadius The corner radius value, in pixels.
*/
public void setCornerRadius(@Dimension int cornerRadius) {
mCornerRadius = cornerRadius;
}
/**
* Sets the icon background color. This is the color of the circle that gets drawn behind the icon passed to the
* {@link #ChipSpan(Context, CharSequence, Drawable, Object)} constructor}
*
* @param iconBackgroundColor the icon background color to set (as a hexadecimal number in the form 0xAARRGGBB)
*/
public void setIconBackgroundColor(int iconBackgroundColor) {
mIconBackgroundColor = iconBackgroundColor;
}
public void setMaxAvailableWidth(int maxAvailableWidth) {
mMaxAvailableWidth = maxAvailableWidth;
invalidateCachedSize();
}
/**
* Sets the UI state. This state will be reflected in the background color drawn for the chip.
*
* @param stateSet one of the state constants in {@link android.view.View}
* @see #setBackgroundColor(ColorStateList)
*/
@Override
public void setState(int[] stateSet) {
this.mStateSet = stateSet != null ? stateSet : new int[]{};
}
@Override
public CharSequence getText() {
return mText;
}
@Override
public int getWidth() {
// If we haven't actually calculated a chip width yet just return -1, otherwise return the chip width + margins
return mChipWidth != -1 ? (mLeftMarginPx + mChipWidth + mRightMarginPx) : -1;
}
@Override
public int getSize(Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) {
boolean usingFontMetrics = (fm != null);
// Adjust the font metrics regardless of whether or not there is a cached size so that the text view can maintain its height
if (usingFontMetrics) {
adjustFontMetrics(paint, fm);
}
if (mCachedSize == -1 && usingFontMetrics) {
mIconWidth = (mIcon != null) ? calculateChipHeight(fm.top, fm.bottom) : 0;
int actualWidth = calculateActualWidth(paint);
mCachedSize = actualWidth;
if (mMaxAvailableWidth != -1) {
int maxAvailableWidthMinusMargins = mMaxAvailableWidth - mLeftMarginPx - mRightMarginPx;
if (actualWidth > maxAvailableWidthMinusMargins) {
mTextToDraw = mText + mEllipsis;
while ((calculateActualWidth(paint) > maxAvailableWidthMinusMargins) && mTextToDraw.length() > 0) {
int lastCharacterIndex = mTextToDraw.length() - mEllipsis.length() - 1;
if (lastCharacterIndex < 0) {
break;
}
mTextToDraw = mTextToDraw.substring(0, lastCharacterIndex) + mEllipsis;
}
// Avoid a negative width
mChipWidth = Math.max(0, maxAvailableWidthMinusMargins);
mCachedSize = mMaxAvailableWidth;
}
}
}
return mCachedSize;
}
private int calculateActualWidth(Paint paint) {
// Only change the text size if a text size was set
if (mTextSize != -1) {
paint.setTextSize(mTextSize);
}
int totalPadding = mPaddingEdgePx;
// Find text width
Rect bounds = new Rect();
paint.getTextBounds(mTextToDraw, 0, mTextToDraw.length(), bounds);
int textWidth = bounds.width();
if (mIcon != null) {
totalPadding += mPaddingBetweenImagePx;
} else {
totalPadding += mPaddingEdgePx;
}
mChipWidth = totalPadding + textWidth + mIconWidth;
return getWidth();
}
public void invalidateCachedSize() {
mCachedSize = -1;
}
/**
* Adjusts the provided font metrics to make it seem like the font takes up {@code mChipHeight + mChipVerticalSpacing} pixels in height.
* This effectively ensures that the TextView will have a height equal to {@code mChipHeight + mChipVerticalSpacing} + whatever padding it has set.
* In {@link #draw(Canvas, CharSequence, int, int, float, int, int, int, Paint)} the chip itself is drawn to that it is vertically centered with
* {@code mChipVerticalSpacing / 2} pixels of space above and below it
*
* @param paint the paint whose font metrics should be adjusted
* @param fm the font metrics object to populate through {@link Paint#getFontMetricsInt(Paint.FontMetricsInt)}
*/
private void adjustFontMetrics(Paint paint, Paint.FontMetricsInt fm) {
// Only actually adjust font metrics if we have a chip height set
if (mChipHeight != -1) {
paint.getFontMetricsInt(fm);
int textHeight = fm.descent - fm.ascent;
// Break up the vertical spacing in half because half will go above the chip, half will go below the chip
int halfSpacing = mChipVerticalSpacing / 2;
// Given that the text is centered vertically within the chip, the amount of space above or below the text (inbetween the text and chip)
// is half their difference in height:
int spaceBetweenChipAndText = (mChipHeight - textHeight) / 2;
int textTop = fm.top;
int chipTop = fm.top - spaceBetweenChipAndText;
int textBottom = fm.bottom;
int chipBottom = fm.bottom + spaceBetweenChipAndText;
// The text may have been taller to begin with so we take the most negative coordinate (highest up) to be the top of the content
int topOfContent = Math.min(textTop, chipTop);
// Same as above but we want the largest positive coordinate (lowest down) to be the bottom of the content
int bottomOfContent = Math.max(textBottom, chipBottom);
// Shift the top up by halfSpacing and the bottom down by halfSpacing
int topOfContentWithSpacing = topOfContent - halfSpacing;
int bottomOfContentWithSpacing = bottomOfContent + halfSpacing;
// Change the font metrics so that the TextView thinks the font takes up the vertical space of a chip + spacing
fm.ascent = topOfContentWithSpacing;
fm.descent = bottomOfContentWithSpacing;
fm.top = topOfContentWithSpacing;
fm.bottom = bottomOfContentWithSpacing;
}
}
private int calculateChipHeight(int top, int bottom) {
// If a chip height was set we can return that, otherwise calculate it from top and bottom
return mChipHeight != -1 ? mChipHeight : bottom - top;
}
@Override
public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, Paint paint) {
// Shift everything mLeftMarginPx to the left to create an empty space on the left (creating the margin)
x += mLeftMarginPx;
if (mChipHeight != -1) {
// If we set a chip height, adjust to vertically center chip in the line
// Adding (bottom - top) / 2 shifts the chip down so the top of it will be centered vertically
// Subtracting (mChipHeight / 2) shifts the chip back up so that the center of it will be centered vertically (as desired)
top += ((bottom - top) / 2) - (mChipHeight / 2);
bottom = top + mChipHeight;
}
// Perform actual drawing
drawBackground(canvas, x, top, bottom, paint);
drawText(canvas, x, top, bottom, paint, mTextToDraw);
if (mIcon != null) {
drawIcon(canvas, x, top, bottom, paint);
}
}
private void drawBackground(Canvas canvas, float x, int top, int bottom, Paint paint) {
int backgroundColor = mBackgroundColor.getColorForState(mStateSet, mBackgroundColor.getDefaultColor());
paint.setColor(backgroundColor);
int height = calculateChipHeight(top, bottom);
RectF rect = new RectF(x, top, x + mChipWidth, bottom);
int cornerRadius = (mCornerRadius != -1) ? mCornerRadius : height / 2;
canvas.drawRoundRect(rect, cornerRadius, cornerRadius, paint);
paint.setColor(mTextColor);
}
private void drawText(Canvas canvas, float x, int top, int bottom, Paint paint, CharSequence text) {
if (mTextSize != -1) {
paint.setTextSize(mTextSize);
}
int height = calculateChipHeight(top, bottom);
Paint.FontMetrics fm = paint.getFontMetrics();
// The top value provided here is the y coordinate for the very top of the chip
// The y coordinate we are calculating is where the baseline of the text will be drawn
// Our objective is to have the midpoint between the top and baseline of the text be in line with the vertical center of the chip
// First we add height / 2 which will put the baseline at the vertical center of the chip
// Then we add half the height of the text which will lower baseline so that the midpoint is at the vertical center of the chip as desired
float adjustedY = top + ((height / 2) + ((-fm.top - fm.bottom) / 2));
// The x coordinate provided here is the left-most edge of the chip
// If there is no icon or the icon is on the right, then the text will start at the left-most edge, but indented with the edge padding, so we
// add mPaddingEdgePx
// If there is an icon and it's on the left, the text will start at the left-most edge, but indented by the combined width of the icon and
// the padding between the icon and text, so we add (mIconWidth + mPaddingBetweenImagePx)
float adjustedX = x + ((mIcon == null || !mShowIconOnLeft) ? mPaddingEdgePx : (mIconWidth + mPaddingBetweenImagePx));
canvas.drawText(text, 0, text.length(), adjustedX, adjustedY, paint);
}
private void drawIcon(Canvas canvas, float x, int top, int bottom, Paint paint) {
drawIconBackground(canvas, x, top, bottom, paint);
drawIconBitmap(canvas, x, top, bottom, paint);
}
private void drawIconBackground(Canvas canvas, float x, int top, int bottom, Paint paint) {
int height = calculateChipHeight(top, bottom);
paint.setColor(mIconBackgroundColor);
// Since it's a circle the diameter is equal to the height, so the radius == diameter / 2 == height / 2
int radius = height / 2;
// The coordinates that get passed to drawCircle are for the center of the circle
// x is the left edge of the chip, (x + mChipWidth) is the right edge of the chip
// So the center of the circle is one radius distance from either the left or right edge (depending on which side the icon is being drawn on)
float circleX = mShowIconOnLeft ? (x + radius) : (x + mChipWidth - radius);
// The y coordinate is always just one radius distance from the top
canvas.drawCircle(circleX, top + radius, radius, paint);
paint.setColor(mTextColor);
}
private void drawIconBitmap(Canvas canvas, float x, int top, int bottom, Paint paint) {
int height = calculateChipHeight(top, bottom);
// Create a scaled down version of the bitmap to fit within the circle (whose diameter == height)
Bitmap iconBitmap = Bitmap.createBitmap(mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Bitmap scaledIconBitMap = scaleDown(iconBitmap, (float) height * SCALE_PERCENT_OF_CHIP_HEIGHT, true);
iconBitmap.recycle();
Canvas bitmapCanvas = new Canvas(scaledIconBitMap);
mIcon.setBounds(0, 0, bitmapCanvas.getWidth(), bitmapCanvas.getHeight());
mIcon.draw(bitmapCanvas);
// We are drawing a square icon inside of a circle
// The coordinates we pass to canvas.drawBitmap have to be for the top-left corner of the bitmap
// The bitmap should be inset by half of (circle width - bitmap width)
// Since it's a circle, the circle's width is equal to it's height which is equal to the chip height
float xInsetWithinCircle = (height - bitmapCanvas.getWidth()) / 2;
// The icon x coordinate is going to be insetWithinCircle pixels away from the left edge of the circle
// If the icon is on the left, the left edge of the circle is just x
// If the icon is on the right, the left edge of the circle is x + mChipWidth - height
float iconX = mShowIconOnLeft ? (x + xInsetWithinCircle) : (x + mChipWidth - height + xInsetWithinCircle);
// The y coordinate works the same way (only it's always from the top edge)
float yInsetWithinCircle = (height - bitmapCanvas.getHeight()) / 2;
float iconY = top + yInsetWithinCircle;
canvas.drawBitmap(scaledIconBitMap, iconX, iconY, paint);
}
private Bitmap scaleDown(Bitmap realImage, float maxImageSize, boolean filter) {
float ratio = Math.min(maxImageSize / realImage.getWidth(), maxImageSize / realImage.getHeight());
int width = Math.round(ratio * realImage.getWidth());
int height = Math.round(ratio * realImage.getHeight());
return Bitmap.createScaledBitmap(realImage, width, height, filter);
}
@Override
public String toString() {
return mText.toString();
}
}

View File

@@ -0,0 +1,60 @@
package com.hootsuite.nachos.chip;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Color;
import androidx.annotation.NonNull;
import com.hootsuite.nachos.ChipConfiguration;
public class ChipSpanChipCreator implements ChipCreator<ChipSpan> {
@Override
public ChipSpan createChip(@NonNull Context context, @NonNull CharSequence text, Object data) {
return new ChipSpan(context, text, null, data);
}
@Override
public ChipSpan createChip(@NonNull Context context, @NonNull ChipSpan existingChip) {
return new ChipSpan(context, existingChip);
}
@Override
public void configureChip(@NonNull ChipSpan chip, @NonNull ChipConfiguration chipConfiguration) {
int chipHorizontalSpacing = chipConfiguration.getChipHorizontalSpacing();
ColorStateList chipBackground = chipConfiguration.getChipBackground();
int chipCornerRadius = chipConfiguration.getChipCornerRadius();
int chipTextColor = chipConfiguration.getChipTextColor();
int chipTextSize = chipConfiguration.getChipTextSize();
int chipHeight = chipConfiguration.getChipHeight();
int chipVerticalSpacing = chipConfiguration.getChipVerticalSpacing();
int maxAvailableWidth = chipConfiguration.getMaxAvailableWidth();
if (chipHorizontalSpacing != -1) {
chip.setLeftMargin(chipHorizontalSpacing / 2);
chip.setRightMargin(chipHorizontalSpacing / 2);
}
if (chipBackground != null) {
chip.setBackgroundColor(chipBackground);
}
if (chipCornerRadius != -1) {
chip.setCornerRadius(chipCornerRadius);
}
if (chipTextColor != Color.TRANSPARENT) {
chip.setTextColor(chipTextColor);
}
if (chipTextSize != -1) {
chip.setTextSize(chipTextSize);
}
if (chipHeight != -1) {
chip.setChipHeight(chipHeight);
}
if (chipVerticalSpacing != -1) {
chip.setChipVerticalSpacing(chipVerticalSpacing);
}
if (maxAvailableWidth != -1) {
chip.setMaxAvailableWidth(maxAvailableWidth);
}
}
}

View File

@@ -0,0 +1,95 @@
package com.hootsuite.nachos.terminator;
import android.text.Editable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
import java.util.Map;
/**
* This interface is used to handle the management of characters that should trigger the creation of chips in a text view.
*
* @see ChipTokenizer
*/
public interface ChipTerminatorHandler {
/**
* When a chip terminator character is encountered in newly inserted text, all tokens in the whole text view will be chipified
*/
int BEHAVIOR_CHIPIFY_ALL = 0;
/**
* When a chip terminator character is encountered in newly inserted text, only the current token (that in which the chip terminator character
* was found) will be chipified. This token may extend beyond where the chip terminator character was located.
*/
int BEHAVIOR_CHIPIFY_CURRENT_TOKEN = 1;
/**
* When a chip terminator character is encountered in newly inserted text, only the text from the previous chip up until the chip terminator
* character will be chipified. This may not be an entire token.
*/
int BEHAVIOR_CHIPIFY_TO_TERMINATOR = 2;
/**
* Constant for use with {@link #setPasteBehavior(int)}. Use this if a paste should behave the same as a standard text input (the chip temrinators
* will all behave according to their pre-determined behavior set through {@link #addChipTerminator(char, int)} or {@link #setChipTerminators(Map)}).
*/
int PASTE_BEHAVIOR_USE_DEFAULT = -1;
/**
* Sets all the characters that will be marked as chip terminators. This will replace any previously set chip terminators.
*
* @param chipTerminators a map of characters to be marked as chip terminators to behaviors that describe how to respond to the characters, or null
* to remove all chip terminators
*/
void setChipTerminators(@Nullable Map<Character, Integer> chipTerminators);
/**
* Adds a character as a chip terminator. When the provided character is encountered in entered text, the nearby text will be chipified according
* to the behavior provided here.
* {@code behavior} Must be one of:
* <ul>
* <li>{@link #BEHAVIOR_CHIPIFY_ALL}</li>
* <li>{@link #BEHAVIOR_CHIPIFY_CURRENT_TOKEN}</li>
* <li>{@link #BEHAVIOR_CHIPIFY_TO_TERMINATOR}</li>
* </ul>
*
* @param character the character to mark as a chip terminator
* @param behavior the behavior describing how to respond to the chip terminator
*/
void addChipTerminator(char character, int behavior);
/**
* Customizes the way paste events are handled.
* If one of:
* <ul>
* <li>{@link #BEHAVIOR_CHIPIFY_ALL}</li>
* <li>{@link #BEHAVIOR_CHIPIFY_CURRENT_TOKEN}</li>
* <li>{@link #BEHAVIOR_CHIPIFY_TO_TERMINATOR}</li>
* </ul>
* is passed, all chip terminators will be handled with that behavior when a paste event occurs.
* If {@link #PASTE_BEHAVIOR_USE_DEFAULT} is passed, whatever behavior is configured for a particular chip terminator
* (through {@link #setChipTerminators(Map)} or {@link #addChipTerminator(char, int)} will be used for that chip terminator
*
* @param pasteBehavior the behavior to use on a paste event
*/
void setPasteBehavior(int pasteBehavior);
/**
* Parses the provided text looking for characters marked as chip terminators through {@link #addChipTerminator(char, int)} and {@link #setChipTerminators(Map)}.
* The provided {@link Editable} will be modified if chip terminators are encountered.
*
* @param tokenizer the {@link ChipTokenizer} to use to identify and chipify tokens in the text
* @param text the text in which to search for chip terminators tokens to be chipped
* @param start the index at which to begin looking for chip terminators (inclusive)
* @param end the index at which to end looking for chip terminators (exclusive)
* @param isPasteEvent true if this handling is for a paste event in which case the behavior set in {@link #setPasteBehavior(int)} will be used,
* otherwise false
* @return an non-negative integer indicating the index where the cursor (selection) should be placed once the handling is complete,
* or a negative integer indicating that the cursor should not be moved.
*/
int findAndHandleChipTerminators(@NonNull ChipTokenizer tokenizer, @NonNull Editable text, int start, int end, boolean isPasteEvent);
}

View File

@@ -0,0 +1,115 @@
package com.hootsuite.nachos.terminator;
import android.text.Editable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
import java.util.HashMap;
import java.util.Map;
public class DefaultChipTerminatorHandler implements ChipTerminatorHandler {
@Nullable
private Map<Character, Integer> mChipTerminators;
private int mPasteBehavior = BEHAVIOR_CHIPIFY_TO_TERMINATOR;
@Override
public void setChipTerminators(@Nullable Map<Character, Integer> chipTerminators) {
mChipTerminators = chipTerminators;
}
@Override
public void addChipTerminator(char character, int behavior) {
if (mChipTerminators == null) {
mChipTerminators = new HashMap<>();
}
mChipTerminators.put(character, behavior);
}
@Override
public void setPasteBehavior(int pasteBehavior) {
mPasteBehavior = pasteBehavior;
}
@Override
public int findAndHandleChipTerminators(@NonNull ChipTokenizer tokenizer, @NonNull Editable text, int start, int end, boolean isPasteEvent) {
// If we don't have a tokenizer or any chip terminators, there's nothing to look for
if (mChipTerminators == null) {
return -1;
}
TextIterator textIterator = new TextIterator(text, start, end);
int selectionIndex = -1;
characterLoop:
while (textIterator.hasNextCharacter()) {
char theChar = textIterator.nextCharacter();
if (isChipTerminator(theChar)) {
int behavior = (isPasteEvent && mPasteBehavior != PASTE_BEHAVIOR_USE_DEFAULT) ? mPasteBehavior : mChipTerminators.get(theChar);
int newSelection = -1;
switch (behavior) {
case BEHAVIOR_CHIPIFY_ALL:
selectionIndex = handleChipifyAll(textIterator, tokenizer);
break characterLoop;
case BEHAVIOR_CHIPIFY_CURRENT_TOKEN:
newSelection = handleChipifyCurrentToken(textIterator, tokenizer);
break;
case BEHAVIOR_CHIPIFY_TO_TERMINATOR:
newSelection = handleChipifyToTerminator(textIterator, tokenizer);
break;
}
if (newSelection != -1) {
selectionIndex = newSelection;
}
}
}
return selectionIndex;
}
private int handleChipifyAll(TextIterator textIterator, ChipTokenizer tokenizer) {
textIterator.deleteCharacter(true);
tokenizer.terminateAllTokens(textIterator.getText());
return textIterator.totalLength();
}
private int handleChipifyCurrentToken(TextIterator textIterator, ChipTokenizer tokenizer) {
textIterator.deleteCharacter(true);
Editable text = textIterator.getText();
int index = textIterator.getIndex();
int tokenStart = tokenizer.findTokenStart(text, index);
int tokenEnd = tokenizer.findTokenEnd(text, index);
if (tokenStart < tokenEnd) {
CharSequence chippedText = tokenizer.terminateToken(text.subSequence(tokenStart, tokenEnd), null);
textIterator.replace(tokenStart, tokenEnd, chippedText);
return tokenStart + chippedText.length();
}
return -1;
}
private int handleChipifyToTerminator(TextIterator textIterator, ChipTokenizer tokenizer) {
Editable text = textIterator.getText();
int index = textIterator.getIndex();
if (index > 0) {
int tokenStart = tokenizer.findTokenStart(text, index);
if (tokenStart < index) {
CharSequence chippedText = tokenizer.terminateToken(text.subSequence(tokenStart, index), null);
textIterator.replace(tokenStart, index + 1, chippedText);
} else {
textIterator.deleteCharacter(false);
}
} else {
textIterator.deleteCharacter(false);
}
return -1;
}
private boolean isChipTerminator(char character) {
return mChipTerminators != null && mChipTerminators.keySet().contains(character);
}
}

View File

@@ -0,0 +1,63 @@
package com.hootsuite.nachos.terminator;
import android.text.Editable;
public class TextIterator {
private Editable mText;
private int mStart;
private int mEnd;
private int mIndex;
public TextIterator(Editable text, int start, int end) {
mText = text;
mStart = start;
mEnd = end;
mIndex = mStart - 1; // Subtract 1 so that the first call to nextCharacter() will return the first character
}
public int totalLength() {
return mText.length();
}
public int windowLength() {
return mEnd - mStart;
}
public Editable getText() {
return mText;
}
public int getIndex() {
return mIndex;
}
public boolean hasNextCharacter() {
return (mIndex + 1) < mEnd;
}
public char nextCharacter() {
mIndex++;
return mText.charAt(mIndex);
}
public void deleteCharacter(boolean maintainIndex) {
mText.replace(mIndex, mIndex + 1, "");
if (!maintainIndex) {
mIndex--;
}
mEnd--;
}
public void replace(int replaceStart, int replaceEnd, CharSequence chippedText) {
mText.replace(replaceStart, replaceEnd, chippedText);
// Update indexes
int newLength = chippedText.length();
int oldLength = replaceEnd - replaceStart;
mIndex = replaceStart + newLength - 1;
mEnd += newLength - oldLength;
}
}

View File

@@ -0,0 +1,89 @@
package com.hootsuite.nachos.tokenizer;
import android.text.Editable;
import android.text.Spanned;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hootsuite.nachos.ChipConfiguration;
import com.hootsuite.nachos.chip.Chip;
import java.util.ArrayList;
import java.util.List;
/**
* Base implementation of the {@link ChipTokenizer} interface that performs no actions and returns default values.
* This class allows for the easy creation of a ChipTokenizer that only implements some of the methods of the interface.
*/
public abstract class BaseChipTokenizer implements ChipTokenizer {
@Override
public void applyConfiguration(Editable text, ChipConfiguration chipConfiguration) {
// Do nothing
}
@Override
public int findTokenStart(CharSequence charSequence, int i) {
// Do nothing
return 0;
}
@Override
public int findTokenEnd(CharSequence charSequence, int i) {
// Do nothing
return 0;
}
@NonNull
@Override
public List<Pair<Integer, Integer>> findAllTokens(CharSequence text) {
// Do nothing
return new ArrayList<>();
}
@Override
public CharSequence terminateToken(CharSequence charSequence, @Nullable Object data) {
// Do nothing
return charSequence;
}
@Override
public void terminateAllTokens(Editable text) {
// Do nothing
}
@Override
public int findChipStart(Chip chip, Spanned text) {
// Do nothing
return 0;
}
@Override
public int findChipEnd(Chip chip, Spanned text) {
// Do nothing
return 0;
}
@NonNull
@Override
public Chip[] findAllChips(int start, int end, Spanned text) {
return new Chip[]{};
}
@Override
public void revertChipToToken(Chip chip, Editable text) {
// Do nothing
}
@Override
public void deleteChip(Chip chip, Editable text) {
// Do nothing
}
@Override
public void deleteChipAndPadding(Chip chip, Editable text) {
// Do nothing
}
}

View File

@@ -0,0 +1,134 @@
package com.hootsuite.nachos.tokenizer;
import android.text.Editable;
import android.text.Spanned;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hootsuite.nachos.ChipConfiguration;
import com.hootsuite.nachos.chip.Chip;
import java.util.List;
/**
* An extension of {@link android.widget.MultiAutoCompleteTextView.Tokenizer Tokenizer} that provides extra support
* for chipification.
* <p>
* In the context of this interface, a token is considered to be plain (non-chipped) text. Once a token is terminated it becomes or contains a chip.
* </p>
* <p>
* The CharSequences passed to the ChipTokenizer methods may contain both chipped text
* and plain text so the tokenizer must have some method of distinguishing between the two (e.g. using a delimeter character.
* The {@link #terminateToken(CharSequence, Object)} method is where a chip can be formed and returned to replace the plain text.
* Whatever class the implementation deems to represent a chip, must implement the {@link Chip} interface.
* </p>
*
* @see SpanChipTokenizer
*/
public interface ChipTokenizer {
/**
* Configures this ChipTokenizer to produce chips with the provided attributes. For each of these attributes, {@code -1} or {@code null} may be
* passed to indicate that the attribute may be ignored.
* <p>
* This will also apply the provided {@link ChipConfiguration} to any existing chips in the provided text.
* </p>
*
* @param text the text in which to search for existing chips to apply the configuration to
* @param chipConfiguration a {@link ChipConfiguration} containing customizations for the chips produced by this class
*/
void applyConfiguration(Editable text, ChipConfiguration chipConfiguration);
/**
* Returns the start of the token that ends at offset
* <code>cursor</code> within <code>text</code>.
*/
int findTokenStart(CharSequence text, int cursor);
/**
* Returns the end of the token (minus trailing punctuation)
* that begins at offset <code>cursor</code> within <code>text</code>.
*/
int findTokenEnd(CharSequence text, int cursor);
/**
* Searches through {@code text} for any tokens.
*
* @param text the text in which to search for un-terminated tokens
* @return a list of {@link Pair}s of the form (startIndex, endIndex) containing the locations of all
* unterminated tokens
*/
@NonNull
List<Pair<Integer, Integer>> findAllTokens(CharSequence text);
/**
* Returns <code>text</code>, modified, if necessary, to ensure that
* it ends with a token terminator (for example a space or comma).
*/
CharSequence terminateToken(CharSequence text, @Nullable Object data);
/**
* Terminates (converts from token into chip) all unterminated tokens in the provided text.
* This method CAN alter the provided text.
*
* @param text the text in which to terminate all tokens
*/
void terminateAllTokens(Editable text);
/**
* Finds the index of the first character in {@code text} that is a part of {@code chip}
*
* @param chip the chip whose start should be found
* @param text the text in which to search for the start of {@code chip}
* @return the start index of the chip
*/
int findChipStart(Chip chip, Spanned text);
/**
* Finds the index of the character after the last character in {@code text} that is a part of {@code chip}
*
* @param chip the chip whose end should be found
* @param text the text in which to search for the end of {@code chip}
* @return the end index of the chip
*/
int findChipEnd(Chip chip, Spanned text);
/**
* Searches through {@code text} for any chips
*
* @param start index to start looking for terminated tokens (inclusive)
* @param end index to end looking for terminated tokens (exclusive)
* @param text the text in which to search for terminated tokens
* @return a list of objects implementing the {@link Chip} interface to represent the terminated tokens
*/
@NonNull
Chip[] findAllChips(int start, int end, Spanned text);
/**
* Effectively does the opposite of {@link #terminateToken(CharSequence, Object)} by reverting the provided chip back into a token.
* This method CAN alter the provided text.
*
* @param chip the chip to revert into a token
* @param text the text in which the chip resides
*/
void revertChipToToken(Chip chip, Editable text);
/**
* Removes a chip and any text it encompasses from {@code text}. This method CAN alter the provided text.
*
* @param chip the chip to remove
* @param text the text to remove the chip from
*/
void deleteChip(Chip chip, Editable text);
/**
* Removes a chip, any text it encompasses AND any padding text (such as spaces) that may have been inserted when the chip was created in
* {@link #terminateToken(CharSequence, Object)} or after. This method CAN alter the provided text.
*
* @param chip the chip to remove
* @param text the text to remove the chip and padding from
*/
void deleteChipAndPadding(Chip chip, Editable text);
}

View File

@@ -0,0 +1,246 @@
package com.hootsuite.nachos.tokenizer;
import android.content.Context;
import android.text.Editable;
import android.text.SpannableString;
import android.text.Spanned;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.hootsuite.nachos.ChipConfiguration;
import com.hootsuite.nachos.chip.Chip;
import com.hootsuite.nachos.chip.ChipCreator;
import com.hootsuite.nachos.chip.ChipSpan;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* A default implementation of {@link ChipTokenizer}.
* This implementation does the following:
* <ul>
* <li>Surrounds each token with a space and the Unit Separator ASCII control character (31) - See the diagram below
* <ul>
* <li>The spaces are included so that android keyboards can distinguish the chips as different words and provide accurate
* autocorrect suggestions</li>
* </ul>
* </li>
* <li>Replaces each token with a {@link ChipSpan} containing the same text, once the token terminates</li>
* <li>Uses the values passed to {@link #applyConfiguration(Editable, ChipConfiguration)} to configure any ChipSpans that get created</li>
* </ul>
* Each terminated token will therefore look like the following (this is what will be returned from {@link #terminateToken(CharSequence, Object)}):
* <pre>
* -----------------------------------------------------------
* | SpannableString |
* | ---------------------------------------------------- |
* | | ChipSpan | |
* | | | |
* | | space separator text separator space | |
* | | | |
* | ---------------------------------------------------- |
* -----------------------------------------------------------
* </pre>
*
* @see ChipSpan
*/
public class SpanChipTokenizer<C extends Chip> implements ChipTokenizer {
/**
* The character used to separate chips internally is the US (Unit Separator) ASCII control character.
* This character is used because it's untypable so we have complete control over when chips are created.
*/
public static final char CHIP_SPAN_SEPARATOR = 31;
public static final char AUTOCORRECT_SEPARATOR = ' ';
private Context mContext;
@Nullable
private ChipConfiguration mChipConfiguration;
@NonNull
private ChipCreator<C> mChipCreator;
@NonNull
private Class<C> mChipClass;
private Comparator<Pair<Integer, Integer>> mReverseTokenIndexesSorter = new Comparator<Pair<Integer, Integer>>() {
@Override
public int compare(Pair<Integer, Integer> lhs, Pair<Integer, Integer> rhs) {
return rhs.first - lhs.first;
}
};
public SpanChipTokenizer(Context context, @NonNull ChipCreator<C> chipCreator, @NonNull Class<C> chipClass) {
mContext = context;
mChipCreator = chipCreator;
mChipClass = chipClass;
}
@Override
public void applyConfiguration(Editable text, ChipConfiguration chipConfiguration) {
mChipConfiguration = chipConfiguration;
for (C chip : findAllChips(0, text.length(), text)) {
// Recreate the chips with the new configuration
int chipStart = findChipStart(chip, text);
deleteChip(chip, text);
text.insert(chipStart, terminateToken(mChipCreator.createChip(mContext, chip)));
}
}
@Override
public int findTokenStart(CharSequence text, int cursor) {
int i = cursor;
// Work backwards until we find a CHIP_SPAN_SEPARATOR
while (i > 0 && text.charAt(i - 1) != CHIP_SPAN_SEPARATOR) {
i--;
}
// Work forwards to skip over any extra whitespace at the beginning of the token
while (i > 0 && i < text.length() && Character.isWhitespace(text.charAt(i))) {
i++;
}
return i;
}
@Override
public int findTokenEnd(CharSequence text, int cursor) {
int i = cursor;
int len = text.length();
// Work forwards till we find a CHIP_SPAN_SEPARATOR
while (i < len) {
if (text.charAt(i) == CHIP_SPAN_SEPARATOR) {
return (i - 1); // subtract one because the CHIP_SPAN_SEPARATOR will be preceded by a space
} else {
i++;
}
}
return len;
}
@NonNull
@Override
public List<Pair<Integer, Integer>> findAllTokens(CharSequence text) {
List<Pair<Integer, Integer>> unterminatedTokens = new ArrayList<>();
boolean insideChip = false;
// Iterate backwards through the text (to avoid messing up indexes)
for (int index = text.length() - 1; index >= 0; index--) {
char theCharacter = text.charAt(index);
// Every time we hit a CHIP_SPAN_SEPARATOR character we switch from being inside to outside
// or outside to inside a chip
// This check must happen before the whitespace check because CHIP_SPAN_SEPARATOR is considered a whitespace character
if (theCharacter == CHIP_SPAN_SEPARATOR) {
insideChip = !insideChip;
continue;
}
// Completely skip over whitespace
if (Character.isWhitespace(theCharacter)) {
continue;
}
// If we're ever outside a chip, see if the text we're in is a viable token for chipification
if (!insideChip) {
int tokenStart = findTokenStart(text, index);
int tokenEnd = findTokenEnd(text, index);
// Can only actually be chipified if there's at least one character between them
if (tokenEnd - tokenStart >= 1) {
unterminatedTokens.add(new Pair<>(tokenStart, tokenEnd));
index = tokenStart;
}
}
}
return unterminatedTokens;
}
@Override
public CharSequence terminateToken(CharSequence text, @Nullable Object data) {
// Remove leading/trailing whitespace
CharSequence trimmedText = text.toString().trim();
return terminateToken(mChipCreator.createChip(mContext, trimmedText, data));
}
private CharSequence terminateToken(C chip) {
// Surround the text with CHIP_SPAN_SEPARATOR and spaces
// The spaces allow autocorrect to correctly identify words
String chipSeparator = Character.toString(CHIP_SPAN_SEPARATOR);
String autoCorrectSeparator = Character.toString(AUTOCORRECT_SEPARATOR);
CharSequence textWithSeparator = autoCorrectSeparator + chipSeparator + chip.getText() + chipSeparator + autoCorrectSeparator;
// Build the container object to house the ChipSpan and space
SpannableString spannableString = new SpannableString(textWithSeparator);
// Attach the ChipSpan
if (mChipConfiguration != null) {
mChipCreator.configureChip(chip, mChipConfiguration);
}
spannableString.setSpan(chip, 0, textWithSeparator.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return spannableString;
}
@Override
public void terminateAllTokens(Editable text) {
List<Pair<Integer, Integer>> unterminatedTokens = findAllTokens(text);
// Sort in reverse order (so index changes don't affect anything)
Collections.sort(unterminatedTokens, mReverseTokenIndexesSorter);
for (Pair<Integer, Integer> indexes : unterminatedTokens) {
int start = indexes.first;
int end = indexes.second;
CharSequence textToChip = text.subSequence(start, end);
CharSequence chippedText = terminateToken(textToChip, null);
text.replace(start, end, chippedText);
}
}
@Override
public int findChipStart(Chip chip, Spanned text) {
return text.getSpanStart(chip);
}
@Override
public int findChipEnd(Chip chip, Spanned text) {
return text.getSpanEnd(chip);
}
@SuppressWarnings("unchecked")
@NonNull
@Override
public C[] findAllChips(int start, int end, Spanned text) {
C[] spansArray = text.getSpans(start, end, mChipClass);
return (spansArray != null) ? spansArray : (C[]) Array.newInstance(mChipClass, 0);
}
@Override
public void revertChipToToken(Chip chip, Editable text) {
int chipStart = findChipStart(chip, text);
int chipEnd = findChipEnd(chip, text);
text.removeSpan(chip);
text.replace(chipStart, chipEnd, chip.getText());
}
@Override
public void deleteChip(Chip chip, Editable text) {
int chipStart = findChipStart(chip, text);
int chipEnd = findChipEnd(chip, text);
text.removeSpan(chip);
// On the emulator for some reason the text automatically gets deleted and chipStart and chipEnd end up both being -1, so in that case we
// don't need to call text.delete(...)
if (chipStart != chipEnd) {
text.delete(chipStart, chipEnd);
}
}
@Override
public void deleteChipAndPadding(Chip chip, Editable text) {
// This implementation does not add any extra padding outside of the span so we can just delete the chip normally
deleteChip(chip, text);
}
}

View File

@@ -0,0 +1,32 @@
package com.hootsuite.nachos.validator;
import android.text.SpannableStringBuilder;
import android.util.Pair;
import androidx.annotation.NonNull;
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
import java.util.List;
/**
* A {@link NachoValidator} that deems text to be invalid if it contains
* unterminated tokens and fixes the text by chipifying all the unterminated tokens.
*/
public class ChipifyingNachoValidator implements NachoValidator {
@Override
public boolean isValid(@NonNull ChipTokenizer chipTokenizer, CharSequence text) {
// The text is considered valid if there are no unterminated tokens (everything is a chip)
List<Pair<Integer, Integer>> unterminatedTokens = chipTokenizer.findAllTokens(text);
return unterminatedTokens.isEmpty();
}
@Override
public CharSequence fixText(@NonNull ChipTokenizer chipTokenizer, CharSequence invalidText) {
SpannableStringBuilder newText = new SpannableStringBuilder(invalidText);
chipTokenizer.terminateAllTokens(newText);
return newText;
}
}

View File

@@ -0,0 +1,5 @@
package com.hootsuite.nachos.validator;
public interface IllegalCharacterIdentifier {
boolean isCharacterIllegal(Character c);
}

View File

@@ -0,0 +1,29 @@
package com.hootsuite.nachos.validator;
import androidx.annotation.NonNull;
import com.hootsuite.nachos.tokenizer.ChipTokenizer;
/**
* Interface used to ensure that a given CharSequence complies to a particular format.
*/
public interface NachoValidator {
/**
* Validates the specified text.
*
* @return true If the text currently in the text editor is valid.
* @see #fixText(ChipTokenizer, CharSequence)
*/
boolean isValid(@NonNull ChipTokenizer chipTokenizer, CharSequence text);
/**
* Corrects the specified text to make it valid.
*
* @param invalidText A string that doesn't pass validation: isValid(invalidText)
* returns false
* @return A string based on invalidText such as invoking isValid() on it returns true.
* @see #isValid(ChipTokenizer, CharSequence)
*/
CharSequence fixText(@NonNull ChipTokenizer chipTokenizer, CharSequence invalidText);
}

View File

@@ -31,7 +31,6 @@ import org.joinmastodon.android.ui.text.HtmlParser;
import org.parceler.Parcels;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import androidx.annotation.Nullable;
@@ -57,6 +56,7 @@ public class AudioPlayerService extends Service{
private static HashSet<Callback> callbacks=new HashSet<>();
private AudioManager.OnAudioFocusChangeListener audioFocusChangeListener=this::onAudioFocusChanged;
private boolean resumeAfterAudioFocusGain;
private boolean isBuffering=true;
private BroadcastReceiver receiver=new BroadcastReceiver(){
@Override
@@ -169,13 +169,15 @@ public class AudioPlayerService extends Service{
}
updateNotification(false, false);
getSystemService(AudioManager.class).requestAudioFocus(audioFocusChangeListener, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
int audiofocus = GlobalUserPreferences.overlayMedia ? AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK : AudioManager.AUDIOFOCUS_GAIN;
getSystemService(AudioManager.class).requestAudioFocus(audioFocusChangeListener, AudioManager.STREAM_MUSIC, audiofocus);
player=new MediaPlayer();
player.setOnPreparedListener(this::onPlayerPrepared);
player.setOnErrorListener(this::onPlayerError);
player.setOnCompletionListener(this::onPlayerCompletion);
player.setOnSeekCompleteListener(this::onPlayerSeekCompleted);
player.setOnInfoListener(this::onPlayerInfo);
try{
player.setDataSource(this, Uri.parse(attachment.url));
player.prepareAsync();
@@ -187,7 +189,9 @@ public class AudioPlayerService extends Service{
}
private void onPlayerPrepared(MediaPlayer mp){
Log.i(TAG, "onPlayerPrepared");
playerReady=true;
isBuffering=false;
player.start();
updateSessionState(false);
}
@@ -205,6 +209,21 @@ public class AudioPlayerService extends Service{
stopSelf();
}
private boolean onPlayerInfo(MediaPlayer mp, int what, int extra){
switch(what){
case MediaPlayer.MEDIA_INFO_BUFFERING_START -> {
isBuffering=true;
updateSessionState(false);
}
case MediaPlayer.MEDIA_INFO_BUFFERING_END -> {
isBuffering=false;
updateSessionState(false);
}
default -> Log.i(TAG, "onPlayerInfo() called with: mp = ["+mp+"], what = ["+what+"], extra = ["+extra+"]");
}
return true;
}
private void onAudioFocusChanged(int change){
switch(change){
case AudioManager.AUDIOFOCUS_LOSS -> {
@@ -212,7 +231,7 @@ public class AudioPlayerService extends Service{
pause(false);
}
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT -> {
resumeAfterAudioFocusGain=true;
resumeAfterAudioFocusGain=isPlaying();
pause(false);
}
case AudioManager.AUDIOFOCUS_GAIN -> {
@@ -232,12 +251,16 @@ public class AudioPlayerService extends Service{
private void updateSessionState(boolean removeNotification){
session.setPlaybackState(new PlaybackState.Builder()
.setState(player.isPlaying() ? PlaybackState.STATE_PLAYING : PlaybackState.STATE_PAUSED, player.getCurrentPosition(), 1f)
.setState(switch(getPlayState()){
case PLAYING -> PlaybackState.STATE_PLAYING;
case PAUSED -> PlaybackState.STATE_PAUSED;
case BUFFERING -> PlaybackState.STATE_BUFFERING;
}, player.getCurrentPosition(), 1f)
.setActions(PlaybackState.ACTION_STOP | PlaybackState.ACTION_PLAY_PAUSE | PlaybackState.ACTION_SEEK_TO)
.build());
updateNotification(!player.isPlaying(), removeNotification);
for(Callback cb:callbacks)
cb.onPlayStateChanged(attachment.id, player.isPlaying(), player.getCurrentPosition());
cb.onPlayStateChanged(attachment.id, getPlayState(), player.getCurrentPosition());
}
private void updateNotification(boolean dismissable, boolean removeNotification){
@@ -310,6 +333,12 @@ public class AudioPlayerService extends Service{
return attachment.id;
}
public PlayState getPlayState(){
if(isBuffering)
return PlayState.BUFFERING;
return player.isPlaying() ? PlayState.PLAYING : PlayState.PAUSED;
}
public static void registerCallback(Callback cb){
callbacks.add(cb);
}
@@ -333,7 +362,13 @@ public class AudioPlayerService extends Service{
}
public interface Callback{
void onPlayStateChanged(String attachmentID, boolean playing, int position);
void onPlayStateChanged(String attachmentID, PlayState state, int position);
void onPlaybackStopped(String attachmentID);
}
public enum PlayState{
PLAYING,
PAUSED,
BUFFERING
}
}

View File

@@ -1,83 +0,0 @@
package org.joinmastodon.android;
import android.app.Activity;
import android.app.NotificationManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.os.Build;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.browser.customtabs.CustomTabsIntent;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.PushSubscriptionManager;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
import org.joinmastodon.android.api.requests.accounts.GetPreferences;
import org.joinmastodon.android.api.requests.accounts.GetWordFilters;
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
import org.joinmastodon.android.api.requests.instance.GetInstance;
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
import org.joinmastodon.android.api.session.AccountActivationInfo;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiUpdatedEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Application;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.EmojiCategory;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.Token;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
public class DomainManager {
private static final String TAG="DomainManager";
private static final DomainManager instance=new DomainManager();
private String currentDomain = "";
public static DomainManager getInstance(){
return instance;
}
private DomainManager(){
}
public String getCurrentDomain() {
return currentDomain;
}
public void setCurrentDomain(String domain) {
this.currentDomain = domain;
}
}

View File

@@ -35,7 +35,7 @@ public class ExternalShareActivity extends FragmentStackActivity{
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();
@@ -69,7 +69,7 @@ public class ExternalShareActivity extends FragmentStackActivity{
.ifPresent(req ->
req.wrapProgress(this, R.string.loading, true, d -> {
UiUtils.transformDialogForLookup(this, accountId, isFediUrl ? text.get() : null, d);
d.setOnDismissListener((ev) -> finish());
d.setOnDismissListener((x) -> finish());
}));
} else {
openComposeFragment(accountId);

View File

@@ -4,221 +4,237 @@ import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Build;
import android.util.Log;
import androidx.annotation.StringRes;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
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.model.ContentType;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.TimelineDefinition;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import androidx.annotation.StringRes;
public class GlobalUserPreferences{
private static final String TAG="GlobalUserPreferences";
public static boolean playGifs;
public static boolean useCustomTabs;
public static boolean altTextReminders, confirmUnfollow, confirmBoost, confirmDeletePost;
public static ThemePreference theme;
// MEGALODON
public static boolean trueBlackTheme;
public static boolean showReplies;
public static boolean showBoosts;
public static boolean loadNewPosts;
public static boolean showNewPostsButton;
public static boolean showInteractionCounts;
public static boolean alwaysExpandContentWarnings;
public static boolean disableMarquee;
public static boolean toolbarMarquee;
public static boolean disableSwipe;
public static boolean showDividers;
public static boolean voteButtonForSingleChoice;
public static boolean enableDeleteNotifications;
public static boolean translateButtonOpenedOnly;
public static boolean uniformNotificationIcon;
public static boolean relocatePublishButton;
public static boolean reduceMotion;
public static boolean keepOnlyLatestNotification;
public static boolean disableAltTextReminder;
public static boolean showAltIndicator;
public static boolean showNoAltIndicator;
public static boolean enablePreReleases;
public static boolean prefixRepliesWithRe;
public static boolean bottomEncoding;
public static PrefixRepliesMode prefixReplies;
public static boolean collapseLongPosts;
public static boolean spectatorMode;
public static boolean autoHideFab;
public static boolean defaultToUnlistedReplies;
public static boolean doubleTapToSwipe;
public static boolean compactReblogReplyLine;
public static boolean confirmBeforeReblog;
public static boolean replyLineAboveHeader;
public static boolean swapBookmarkWithBoostAction;
public static boolean loadRemoteAccountFollowers;
public static boolean mentionRebloggerAutomatically;
public static boolean allowRemoteLoading;
public static boolean forwardReportDefault;
public static AutoRevealMode autoRevealEqualSpoilers;
public static String publishButtonText;
public static ThemePreference theme;
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;
private final static Type recentLanguagesType = new TypeToken<Map<String, List<String>>>() {}.getType();
private final static Type pinnedTimelinesType = new TypeToken<Map<String, List<TimelineDefinition>>>() {}.getType();
private final static Type accountsDefaultContentTypesType = new TypeToken<Map<String, ContentType>>() {}.getType();
public static Map<String, List<String>> recentLanguages;
public static Map<String, List<TimelineDefinition>> pinnedTimelines;
public static Set<String> accountsWithLocalOnlySupport;
public static Set<String> accountsInGlitchMode;
public static Set<String> accountsWithContentTypesEnabled;
public static Map<String, ContentType> accountsDefaultContentTypes;
private final static Type recentEmojisType = new TypeToken<Map<String, Integer>>() {}.getType();
public static Map<String, Integer> recentEmojis;
/**
* Pleroma
*/
public static String replyVisibility;
public static SharedPreferences getPrefs(){
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
}
private static <T> T fromJson(String json, Type type, T orElse) {
if (json == null) return orElse;
try { return gson.fromJson(json, type); }
catch (JsonSyntaxException ignored) { return orElse; }
public static <T> T fromJson(String json, Type type, T orElse){
if(json==null) return orElse;
try{
T value=gson.fromJson(json, type);
return value==null ? orElse : value;
}catch(JsonSyntaxException ignored){
return orElse;
}
}
public static void removeAccount(String accountId) {
recentLanguages.remove(accountId);
pinnedTimelines.remove(accountId);
accountsInGlitchMode.remove(accountId);
accountsWithLocalOnlySupport.remove(accountId);
accountsWithContentTypesEnabled.remove(accountId);
accountsDefaultContentTypes.remove(accountId);
save();
public static <T extends Enum<T>> T enumValue(Class<T> enumType, String name) {
try { return Enum.valueOf(enumType, name); }
catch (NullPointerException npe) { return null; }
}
public static void load(){
SharedPreferences prefs=getPrefs();
playGifs=prefs.getBoolean("playGifs", true);
useCustomTabs=prefs.getBoolean("useCustomTabs", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
altTextReminders=prefs.getBoolean("altTextReminders", true);
confirmUnfollow=prefs.getBoolean("confirmUnfollow", true);
confirmBoost=prefs.getBoolean("confirmBoost", false);
confirmDeletePost=prefs.getBoolean("confirmDeletePost", true);
// MEGALODON
trueBlackTheme=prefs.getBoolean("trueBlackTheme", false);
showReplies=prefs.getBoolean("showReplies", true);
showBoosts=prefs.getBoolean("showBoosts", true);
loadNewPosts=prefs.getBoolean("loadNewPosts", true);
showNewPostsButton=prefs.getBoolean("showNewPostsButton", true);
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", false);
showInteractionCounts=prefs.getBoolean("showInteractionCounts", false);
alwaysExpandContentWarnings=prefs.getBoolean("alwaysExpandContentWarnings", false);
disableMarquee=prefs.getBoolean("disableMarquee", false);
toolbarMarquee=prefs.getBoolean("toolbarMarquee", true);
disableSwipe=prefs.getBoolean("disableSwipe", false);
showDividers =prefs.getBoolean("showDividers", false);
relocatePublishButton=prefs.getBoolean("relocatePublishButton", true);
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
enableDeleteNotifications=prefs.getBoolean("enableDeleteNotifications", false);
translateButtonOpenedOnly=prefs.getBoolean("translateButtonOpenedOnly", false);
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", false);
reduceMotion=prefs.getBoolean("reduceMotion", false);
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
disableAltTextReminder=prefs.getBoolean("disableAltTextReminder", false);
showAltIndicator=prefs.getBoolean("showAltIndicator", true);
showNoAltIndicator=prefs.getBoolean("showNoAltIndicator", true);
enablePreReleases=prefs.getBoolean("enablePreReleases", false);
prefixRepliesWithRe=prefs.getBoolean("prefixRepliesWithRe", false);
bottomEncoding=prefs.getBoolean("bottomEncoding", false);
prefixReplies=PrefixRepliesMode.valueOf(prefs.getString("prefixReplies", PrefixRepliesMode.NEVER.name()));
collapseLongPosts=prefs.getBoolean("collapseLongPosts", true);
spectatorMode=prefs.getBoolean("spectatorMode", false);
autoHideFab=prefs.getBoolean("autoHideFab", true);
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
defaultToUnlistedReplies=prefs.getBoolean("defaultToUnlistedReplies", false);
doubleTapToSwipe =prefs.getBoolean("doubleTapToSwipe", true);
replyLineAboveHeader=prefs.getBoolean("replyLineAboveHeader", true);
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
confirmBeforeReblog=prefs.getBoolean("confirmBeforeReblog", false);
swapBookmarkWithBoostAction=prefs.getBoolean("swapBookmarkWithBoostAction", false);
loadRemoteAccountFollowers=prefs.getBoolean("loadRemoteAccountFollowers", true);
mentionRebloggerAutomatically=prefs.getBoolean("mentionRebloggerAutomatically", false);
publishButtonText=prefs.getString("publishButtonText", "");
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>());
recentEmojis=fromJson(prefs.getString("recentEmojis", "{}"), recentEmojisType, new HashMap<>());
publishButtonText=prefs.getString("publishButtonText", "");
pinnedTimelines=fromJson(prefs.getString("pinnedTimelines", null), pinnedTimelinesType, new HashMap<>());
accountsWithLocalOnlySupport=prefs.getStringSet("accountsWithLocalOnlySupport", new HashSet<>());
accountsInGlitchMode=prefs.getStringSet("accountsInGlitchMode", new HashSet<>());
replyVisibility=prefs.getString("replyVisibility", null);
accountsWithContentTypesEnabled=prefs.getStringSet("accountsWithContentTypesEnabled", new HashSet<>());
accountsDefaultContentTypes=fromJson(prefs.getString("accountsDefaultContentTypes", null), accountsDefaultContentTypesType, new HashMap<>());
allowRemoteLoading=prefs.getBoolean("allowRemoteLoading", true);
autoRevealEqualSpoilers=AutoRevealMode.valueOf(prefs.getString("autoRevealEqualSpoilers", AutoRevealMode.THREADS.name()));
forwardReportDefault=prefs.getBoolean("forwardReportDefault", true);
disableM3PillActiveIndicator=prefs.getBoolean("disableM3PillActiveIndicator", false);
showNavigationLabels=prefs.getBoolean("showNavigationLabels", true);
displayPronounsInTimelines=prefs.getBoolean("displayPronounsInTimelines", true);
displayPronounsInThreads=prefs.getBoolean("displayPronounsInThreads", true);
displayPronounsInUserListings=prefs.getBoolean("displayPronounsInUserListings", true);
overlayMedia=prefs.getBoolean("overlayMedia", false);
showSuicideHelp=prefs.getBoolean("showSuicideHelp", true);
if (prefs.contains("prefixRepliesWithRe")) {
prefixReplies = prefs.getBoolean("prefixRepliesWithRe", false)
? PrefixRepliesMode.TO_OTHERS : PrefixRepliesMode.NEVER;
prefs.edit()
.putString("prefixReplies", prefixReplies.name())
.remove("prefixRepliesWithRe")
.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()));
}
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.PINK.name()));
} catch (IllegalArgumentException|ClassCastException ignored) {
// invalid color name or color was previously saved as integer
color=ColorPreference.PURPLE;
color=ColorPreference.PINK;
}
if(prefs.getInt("migrationLevel", 0) < 61) migrateToUpstreamVersion61();
}
public static void save(){
getPrefs().edit()
.putBoolean("playGifs", playGifs)
.putBoolean("useCustomTabs", useCustomTabs)
.putBoolean("showReplies", showReplies)
.putBoolean("showBoosts", showBoosts)
.putInt("theme", theme.ordinal())
.putBoolean("altTextReminders", altTextReminders)
.putBoolean("confirmUnfollow", confirmUnfollow)
.putBoolean("confirmBoost", confirmBoost)
.putBoolean("confirmDeletePost", confirmDeletePost)
// MEGALODON
.putBoolean("loadNewPosts", loadNewPosts)
.putBoolean("showNewPostsButton", showNewPostsButton)
.putBoolean("trueBlackTheme", trueBlackTheme)
.putBoolean("showInteractionCounts", showInteractionCounts)
.putBoolean("alwaysExpandContentWarnings", alwaysExpandContentWarnings)
.putBoolean("disableMarquee", disableMarquee)
.putBoolean("toolbarMarquee", toolbarMarquee)
.putBoolean("disableSwipe", disableSwipe)
.putBoolean("showDividers", showDividers)
.putBoolean("relocatePublishButton", relocatePublishButton)
.putBoolean("uniformNotificationIcon", uniformNotificationIcon)
.putBoolean("enableDeleteNotifications", enableDeleteNotifications)
.putBoolean("translateButtonOpenedOnly", translateButtonOpenedOnly)
.putBoolean("uniformNotificationIcon", uniformNotificationIcon)
.putBoolean("reduceMotion", reduceMotion)
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
.putBoolean("disableAltTextReminder", disableAltTextReminder)
.putBoolean("showAltIndicator", showAltIndicator)
.putBoolean("showNoAltIndicator", showNoAltIndicator)
.putBoolean("enablePreReleases", enablePreReleases)
.putBoolean("prefixRepliesWithRe", prefixRepliesWithRe)
.putString("prefixReplies", prefixReplies.name())
.putBoolean("collapseLongPosts", collapseLongPosts)
.putBoolean("spectatorMode", spectatorMode)
.putBoolean("autoHideFab", autoHideFab)
.putBoolean("compactReblogReplyLine", compactReblogReplyLine)
.putString("publishButtonText", publishButtonText)
.putBoolean("bottomEncoding", bottomEncoding)
.putBoolean("defaultToUnlistedReplies", defaultToUnlistedReplies)
.putBoolean("doubleTapToSwipe", doubleTapToSwipe)
.putBoolean("compactReblogReplyLine", compactReblogReplyLine)
.putBoolean("replyLineAboveHeader", replyLineAboveHeader)
.putBoolean("confirmBeforeReblog", confirmBeforeReblog)
.putBoolean("swapBookmarkWithBoostAction", swapBookmarkWithBoostAction)
.putBoolean("loadRemoteAccountFollowers", loadRemoteAccountFollowers)
.putBoolean("mentionRebloggerAutomatically", mentionRebloggerAutomatically)
.putInt("theme", theme.ordinal())
.putString("color", color.name())
.putString("recentLanguages", gson.toJson(recentLanguages))
.putString("pinnedTimelines", gson.toJson(pinnedTimelines))
.putString("recentEmojis", gson.toJson(recentEmojis))
.putStringSet("accountsWithLocalOnlySupport", accountsWithLocalOnlySupport)
.putStringSet("accountsInGlitchMode", accountsInGlitchMode)
.putString("replyVisibility", replyVisibility)
.putStringSet("accountsWithContentTypesEnabled", accountsWithContentTypesEnabled)
.putString("accountsDefaultContentTypes", gson.toJson(accountsDefaultContentTypes))
.putBoolean("allowRemoteLoading", allowRemoteLoading)
.putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name())
.putBoolean("forwardReportDefault", forwardReportDefault)
.putBoolean("disableM3PillActiveIndicator", disableM3PillActiveIndicator)
.putBoolean("showNavigationLabels", showNavigationLabels)
.putBoolean("displayPronounsInTimelines", displayPronounsInTimelines)
.putBoolean("displayPronounsInThreads", displayPronounsInThreads)
.putBoolean("displayPronounsInUserListings", displayPronounsInUserListings)
.putBoolean("overlayMedia", overlayMedia)
.putBoolean("showSuicideHelp", showSuicideHelp)
.apply();
}
private static void migrateToUpstreamVersion61(){
Log.d(TAG, "Migrating preferences to upstream version 61!!");
Type accountsDefaultContentTypesType = new TypeToken<Map<String, ContentType>>() {}.getType();
Type pinnedTimelinesType = new TypeToken<Map<String, ArrayList<TimelineDefinition>>>() {}.getType();
Type recentLanguagesType = new TypeToken<Map<String, ArrayList<String>>>() {}.getType();
// migrate global preferences
SharedPreferences prefs=getPrefs();
altTextReminders=!prefs.getBoolean("disableAltTextReminder", false);
confirmBoost=prefs.getBoolean("confirmBeforeReblog", false);
toolbarMarquee=!prefs.getBoolean("disableMarquee", false);
save();
// migrate local preferences
AccountSessionManager asm=AccountSessionManager.getInstance();
// reset: Set<String> accountsWithContentTypesEnabled=prefs.getStringSet("accountsWithContentTypesEnabled", new HashSet<>());
Map<String, ContentType> accountsDefaultContentTypes=fromJson(prefs.getString("accountsDefaultContentTypes", null), accountsDefaultContentTypesType, new HashMap<>());
Map<String, ArrayList<TimelineDefinition>> pinnedTimelines=fromJson(prefs.getString("pinnedTimelines", null), pinnedTimelinesType, new HashMap<>());
Set<String> accountsWithLocalOnlySupport=prefs.getStringSet("accountsWithLocalOnlySupport", new HashSet<>());
Set<String> accountsInGlitchMode=prefs.getStringSet("accountsInGlitchMode", new HashSet<>());
Map<String, ArrayList<String>> recentLanguages=fromJson(prefs.getString("recentLanguages", null), recentLanguagesType, new HashMap<>());
for(AccountSession session : asm.getLoggedInAccounts()){
String accountID=session.getID();
AccountLocalPreferences localPrefs=session.getLocalPreferences();
localPrefs.revealCWs=prefs.getBoolean("alwaysExpandContentWarnings", false);
localPrefs.recentLanguages=recentLanguages.get(accountID);
// reset: localPrefs.contentTypesEnabled=accountsWithContentTypesEnabled.contains(accountID);
localPrefs.defaultContentType=accountsDefaultContentTypes.getOrDefault(accountID, ContentType.PLAIN);
localPrefs.showInteractionCounts=prefs.getBoolean("showInteractionCounts", false);
localPrefs.timelines=pinnedTimelines.getOrDefault(accountID, TimelineDefinition.getDefaultTimelines(accountID));
localPrefs.localOnlySupported=accountsWithLocalOnlySupport.contains(accountID);
localPrefs.glitchInstance=accountsInGlitchMode.contains(accountID);
localPrefs.publishButtonText=prefs.getString("publishButtonText", null);
localPrefs.keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
localPrefs.showReplies=prefs.getBoolean("showReplies", true);
localPrefs.showBoosts=prefs.getBoolean("showBoosts", true);
if(session.getInstance().map(Instance::isAkkoma).orElse(false)){
localPrefs.timelineReplyVisibility=prefs.getString("replyVisibility", null);
}
localPrefs.save();
}
prefs.edit().putInt("migrationLevel", 61).apply();
}
public enum ColorPreference{
MATERIAL3,
PINK,
@@ -227,8 +243,20 @@ public class GlobalUserPreferences{
BLUE,
BROWN,
RED,
YELLOW,
NORD
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 ThemePreference{
@@ -242,4 +270,10 @@ public class GlobalUserPreferences{
THREADS,
DISCUSSIONS
}
public enum PrefixRepliesMode {
NEVER,
ALWAYS,
TO_OTHERS
}
}

View File

@@ -1,28 +1,22 @@
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.os.Build;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.Toast;
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.PictureTakenEvent;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
@@ -30,6 +24,7 @@ import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.SearchResults;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
import org.joinmastodon.android.utils.ProvidesAssistContent;
@@ -37,6 +32,9 @@ import org.parceler.Parcels;
import androidx.annotation.Nullable;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
public class MainActivity extends FragmentStackActivity implements ProvidesAssistContent {
@Override
@@ -82,6 +80,8 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
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();
@@ -120,11 +120,55 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
}
}else if(intent.getBooleanExtra("compose", false)){
showCompose();
}else if(Intent.ACTION_VIEW.equals(intent.getAction())){
handleURL(intent.getData(), null);
}/*else if(intent.hasExtra(PackageInstaller.EXTRA_STATUS) && GithubSelfUpdater.needSelfUpdating()){
GithubSelfUpdater.getInstance().handleIntentFromInstaller(intent, this);
}*/
}
public void handleURL(Uri uri, String accountID){
if(uri==null)
return;
if(!"https".equals(uri.getScheme()) && !"http".equals(uri.getScheme()))
return;
AccountSession session;
if(accountID==null)
session=AccountSessionManager.getInstance().getLastActiveAccount();
else
session=AccountSessionManager.get(accountID);
if(session==null || !session.activated)
return;
openSearchQuery(uri.toString(), session.getID(), R.string.opening_link, false);
}
public void openSearchQuery(String q, String accountID, int progressText, boolean fromSearch){
new GetSearchResults(q, null, true)
.setCallback(new Callback<>(){
@Override
public void onSuccess(SearchResults result){
Bundle args=new Bundle();
args.putString("account", accountID);
if(result.statuses!=null && !result.statuses.isEmpty()){
args.putParcelable("status", Parcels.wrap(result.statuses.get(0)));
Nav.go(MainActivity.this, ThreadFragment.class, args);
}else if(result.accounts!=null && !result.accounts.isEmpty()){
args.putParcelable("profileAccount", Parcels.wrap(result.accounts.get(0)));
Nav.go(MainActivity.this, ProfileFragment.class, args);
}else{
Toast.makeText(MainActivity.this, fromSearch ? R.string.no_search_results : R.string.link_not_supported, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onError(ErrorResponse error){
error.showToast(MainActivity.this);
}
})
.wrapProgress(this, progressText, true)
.exec(accountID);
}
private void showFragmentForNotification(Notification notification, String accountID){
try{
notification.postprocess();
@@ -132,7 +176,9 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
Log.w("MainActivity", x);
return;
}
UiUtils.showFragmentForNotification(this, notification, accountID, null);
Bundle args = new Bundle();
args.putBoolean("noTransition", true);
UiUtils.showFragmentForNotification(this, notification, accountID, args);
}
private void showFragmentForExternalShare(Bundle args) {
@@ -197,27 +243,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){
Bitmap image = (Bitmap) data.getExtras().get("data");
String path = MediaStore.Images.Media.insertImage(this.getContentResolver(), image, null, null);
E.post(new PictureTakenEvent(Uri.parse(path)));
}
}
@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(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);

View File

@@ -3,6 +3,7 @@ package org.joinmastodon.android;
import android.annotation.SuppressLint;
import android.app.Application;
import android.content.Context;
import android.webkit.WebView;
import org.joinmastodon.android.api.PushSubscriptionManager;
@@ -28,5 +29,8 @@ public class MastodonApp extends Application{
PushSubscriptionManager.tryRegisterFCM();
GlobalUserPreferences.load();
if(BuildConfig.DEBUG){
WebView.setWebContentsDebuggingEnabled(true);
}
}
}

View File

@@ -1,6 +1,6 @@
package org.joinmastodon.android;
import static org.joinmastodon.android.GlobalUserPreferences.getPrefs;
import static org.joinmastodon.android.GlobalUserPreferences.PrefixRepliesMode.*;
import android.app.Notification;
import android.app.NotificationChannel;
@@ -12,14 +12,13 @@ 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;
@@ -27,7 +26,6 @@ import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.NotificationReceivedEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Mention;
import org.joinmastodon.android.model.NotificationAction;
@@ -35,13 +33,15 @@ 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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.UUID;
import java.util.stream.Collectors;
@@ -60,6 +60,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
private static final int SUMMARY_ID = 791;
private static int notificationId = 0;
private static final Map<String, Integer> notificationIdsForAccounts = new HashMap<>();
@Override
public void onReceive(Context context, Intent intent){
@@ -91,9 +92,12 @@ public class PushNotificationReceiver extends BroadcastReceiver{
Log.w(TAG, "onReceive: account for id '"+pushAccountID+"' not found");
return;
}
if(account.getLocalPreferences().getNotificationsPauseEndTime()>System.currentTimeMillis()){
Log.i(TAG, "onReceive: dropping notification because user has paused notifications for this account");
return;
}
String accountID=account.getID();
PushNotification pn=AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().decryptNotification(k, p, s);
E.post(new NotificationReceivedEvent(accountID, pn.notificationId+""));
new GetNotificationByID(pn.notificationId+"")
.setCallback(new Callback<>(){
@Override
@@ -126,26 +130,17 @@ public class PushNotificationReceiver extends BroadcastReceiver{
if(intent.hasExtra("notification")){
org.joinmastodon.android.model.Notification notification=Parcels.unwrap(intent.getParcelableExtra("notification"));
String statusID = null;
String targetAccountID = null;
if(notification.status != null){
statusID = notification.status.id;
}
if(notification.account != null){
targetAccountID = notification.account.id;
}
if (statusID != null || targetAccountID != null) {
String statusID=notification.status.id;
if (statusID != null) {
AccountSessionManager accountSessionManager = AccountSessionManager.getInstance();
Preferences preferences = accountSessionManager.getAccount(accountID).preferences;
switch (NotificationAction.values()[intent.getIntExtra("notificationAction", 0)]) {
case FAVORITE -> new SetStatusFavorited(statusID, true).exec(accountID);
case BOOKMARK -> new SetStatusBookmarked(statusID, true).exec(accountID);
case BOOST -> new SetStatusReblogged(notification.status.id, true, preferences.postingDefaultVisibility).exec(accountID);
case UNBOOST -> new SetStatusReblogged(notification.status.id, false, preferences.postingDefaultVisibility).exec(accountID);
case 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");
}
}
@@ -155,10 +150,15 @@ public class PushNotificationReceiver extends BroadcastReceiver{
}
}
public void notifyUnifiedPush(Context context, String accountID, org.joinmastodon.android.model.Notification notification) {
// push notifications are only created from the official push notification, so we create a fake from by transforming the notification
PushNotificationReceiver.this.notify(context, PushNotification.fromNotification(context, notification), accountID, notification);
}
private void notify(Context context, PushNotification pn, String accountID, org.joinmastodon.android.model.Notification notification){
NotificationManager nm=context.getSystemService(NotificationManager.class);
notificationId=getPrefs().getInt("latestNotificationId", 0);
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
AccountSession session=AccountSessionManager.get(accountID);
Account self=session.self;
String accountName="@"+self.username+"@"+AccountSessionManager.getInstance().getAccount(accountID).domain;
Notification.Builder builder;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
@@ -205,7 +205,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
.setShowWhen(true)
.setCategory(Notification.CATEGORY_SOCIAL)
.setAutoCancel(true)
.setColor(context.getColor(R.color.shortcut_icon_background));
.setColor(UiUtils.getThemeColor(context, android.R.attr.colorAccent));
if (!GlobalUserPreferences.uniformNotificationIcon) {
builder.setSmallIcon(switch (pn.notificationType) {
@@ -228,8 +228,21 @@ public class PushNotificationReceiver extends BroadcastReceiver{
builder.setSubText(accountName);
}
int id = GlobalUserPreferences.keepOnlyLatestNotification ? NOTIFICATION_ID : notificationId++;
getPrefs().edit().putInt("latestNotificationId", notificationId).apply();
int id;
if(session.getLocalPreferences().keepOnlyLatestNotification){
if(notificationIdsForAccounts.containsKey(accountID)){
// we overwrite the existing notification
id=notificationIdsForAccounts.get(accountID);
}else{
// there's no existing notification, so we increment
id=notificationId++;
// and store the notification id for this account
notificationIdsForAccounts.put(accountID, id);
}
}else{
// we don't want to overwrite anything, therefore incrementing
id=notificationId++;
}
if (notification != null){
switch (pn.notificationType){
@@ -238,23 +251,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));
}
}
}
@@ -320,7 +324,11 @@ public class PushNotificationReceiver extends BroadcastReceiver{
req.language = preferences.postingDefaultLanguage;
req.visibility = preferences.postingDefaultVisibility;
req.inReplyToId = notification.status.id;
if(!notification.status.spoilerText.isEmpty() && GlobalUserPreferences.prefixRepliesWithRe && !notification.status.spoilerText.startsWith("re: ")){
if (notification.status.hasSpoiler() &&
(GlobalUserPreferences.prefixReplies == ALWAYS
|| (GlobalUserPreferences.prefixReplies == TO_OTHERS && !ownID.equals(notification.status.account.id)))
&& !notification.status.spoilerText.startsWith("re: ")) {
req.spoilerText = "re: " + notification.status.spoilerText;
}

View File

@@ -0,0 +1,84 @@
package org.joinmastodon.android;
import android.content.Context;
import android.util.Log;
import org.jetbrains.annotations.NotNull;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse;
import org.unifiedpush.android.connector.MessagingReceiver;
import java.util.List;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
public class UnifiedPushNotificationReceiver extends MessagingReceiver{
private static final String TAG="UnifiedPushNotificationReceiver";
public UnifiedPushNotificationReceiver() {
super();
}
@Override
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().tryGetAccount(instance);
if (account != null)
account.getPushSubscriptionManager().registerAccountForPush(null, endpoint);
}
@Override
public void onRegistrationFailed(@NotNull Context context, @NotNull String instance) {
// called when the registration is not possible, eg. no network
Log.d(TAG, "onRegistrationFailed: " + instance);
//re-register for gcm
AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance);
if (account != null)
account.getPushSubscriptionManager().registerAccountForPush(null);
}
@Override
public void onUnregistered(@NotNull Context context, @NotNull String instance) {
// called when this application is unregistered from receiving push messages
Log.d(TAG, "onUnregistered: " + instance);
//re-register for gcm
AccountSession account = AccountSessionManager.getInstance().tryGetAccount(instance);
if (account != null)
account.getPushSubscriptionManager().registerAccountForPush(null);
}
@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().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,
// thus it is not possible to decrypt them. SO we need to re-request them from the server and transform them later on
// The official uses fcm and moves the headers to extra data, see
// https://github.com/mastodon/webpush-fcm-relay/blob/cac95b28d5364b0204f629283141ac3fb749e0c5/webpush-fcm-relay.go#L116
// https://github.com/tuskyapp/Tusky/pull/2303#issue-1112080540
account.getCacheController().getNotifications(null, 1, false, false, true, new Callback<>(){
@Override
public void onSuccess(PaginatedResponse<List<Notification>> result){
result.items
.stream()
.findFirst()
.ifPresent(value->MastodonAPIController.runInBackground(()->new PushNotificationReceiver().notifyUnifiedPush(context, instance, value)));
}
@Override
public void onError(ErrorResponse error){
//professional error handling
}
});
}
}

View File

@@ -13,22 +13,20 @@ import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.SearchResult;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
@@ -43,6 +41,8 @@ public class CacheController{
private final String accountID;
private DatabaseHelper db;
private final Runnable databaseCloseRunnable=this::closeDatabase;
private boolean loadingNotifications;
private final ArrayList<Callback<PaginatedResponse<List<Notification>>>> pendingNotificationsCallbacks=new ArrayList<>();
private static final int POST_FLAG_GAP_AFTER=1;
@@ -58,7 +58,6 @@ public class CacheController{
cancelDelayedClose();
databaseThread.postRunnable(()->{
try{
List<Filter> filters=AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream().filter(f->f.context.contains(Filter.FilterContext.HOME)).collect(Collectors.toList());
if(!forceReload){
SQLiteDatabase db=getOrOpenDatabase();
try(Cursor cursor=db.query("home_timeline", new String[]{"json", "flags"}, maxID==null ? null : "`id`<?", maxID==null ? null : new String[]{maxID}, null, null, "`time` DESC", count+"")){
@@ -66,18 +65,16 @@ public class CacheController{
ArrayList<Status> result=new ArrayList<>();
cursor.moveToFirst();
String newMaxID;
outer:
do{
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);
newMaxID=status.id;
if (!new StatusFilterPredicate(filters, Filter.FilterContext.HOME).test(status))
continue outer;
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;
}
@@ -85,11 +82,13 @@ public class CacheController{
Log.w(TAG, "getHomeTimeline: corrupted status object in database", x);
}
}
new GetHomeTimeline(maxID, null, count, null)
new GetHomeTimeline(maxID, null, count, null, AccountSessionManager.get(accountID).getLocalPreferences().timelineReplyVisibility)
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Status> result){
callback.onSuccess(new CacheablePaginatedResponse<>(result.stream().filter(new StatusFilterPredicate(filters, Filter.FilterContext.HOME)).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id, false));
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));
putHomeTimeline(result, maxID==null);
}
@@ -126,12 +125,39 @@ public class CacheController{
});
}
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean onlyPosts, boolean forceReload, Callback<CacheablePaginatedResponse<List<Notification>>> callback){
public void updateStatus(Status status) {
runOnDbThread((db)->{
ContentValues statusUpdate=new ContentValues(1);
statusUpdate.put("json", MastodonAPIController.gson.toJson(status));
db.update("home_timeline", statusUpdate, "id = ?", new String[] { status.id });
});
}
public void updateNotification(Notification notification) {
runOnDbThread((db)->{
ContentValues notificationUpdate=new ContentValues(1);
notificationUpdate.put("json", MastodonAPIController.gson.toJson(notification));
String[] notificationArgs = new String[] { notification.id };
db.update("notifications_all", notificationUpdate, "id = ?", notificationArgs);
db.update("notifications_mentions", notificationUpdate, "id = ?", notificationArgs);
db.update("notifications_posts", notificationUpdate, "id = ?", notificationArgs);
ContentValues statusUpdate=new ContentValues(1);
statusUpdate.put("json", MastodonAPIController.gson.toJson(notification.status));
db.update("home_timeline", statusUpdate, "id = ?", new String[] { notification.status.id });
});
}
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean onlyPosts, boolean forceReload, Callback<PaginatedResponse<List<Notification>>> callback){
cancelDelayedClose();
databaseThread.postRunnable(()->{
try{
AccountSession accountSession=AccountSessionManager.getInstance().getAccount(accountID);
List<Filter> filters=accountSession.wordFilters.stream().filter(f->f.context.contains(Filter.FilterContext.NOTIFICATIONS)).collect(Collectors.toList());
if(!onlyMentions && !onlyPosts && loadingNotifications){
synchronized(pendingNotificationsCallbacks){
pendingNotificationsCallbacks.add(callback);
}
return;
}
if(!forceReload){
SQLiteDatabase db=getOrOpenDatabase();
String table=onlyPosts ? "notifications_posts" : onlyMentions ? "notifications_mentions" : "notifications_all";
@@ -140,42 +166,56 @@ public class CacheController{
ArrayList<Notification> result=new ArrayList<>();
cursor.moveToFirst();
String newMaxID;
outer:
do{
Notification ntf=MastodonAPIController.gson.fromJson(cursor.getString(0), Notification.class);
ntf.postprocess();
newMaxID=ntf.id;
if(ntf.status!=null){
if (!new StatusFilterPredicate(filters, Filter.FilterContext.NOTIFICATIONS).test(ntf.status))
continue outer;
}
result.add(ntf);
}while(cursor.moveToNext());
String _newMaxID=newMaxID;
uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
AccountSessionManager.get(accountID).filterStatusContainingObjects(result, n->n.status, FilterContext.NOTIFICATIONS);
uiHandler.post(()->callback.onSuccess(new PaginatedResponse<>(result, _newMaxID)));
return;
}
}catch(IOException x){
Log.w(TAG, "getNotifications: corrupted notification object in database", x);
}
}
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(accountSession.domain);
new GetNotifications(maxID, count, onlyPosts ? EnumSet.of(Notification.Type.STATUS) : onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class), instance.isAkkoma())
if(!onlyMentions && !onlyPosts)
loadingNotifications=true;
boolean isAkkoma = AccountSessionManager.get(accountID).getInstance().map(Instance::isAkkoma).orElse(false);
new GetNotifications(maxID, count, onlyPosts ? EnumSet.of(Notification.Type.STATUS) : onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class), isAkkoma)
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Notification> result){
callback.onSuccess(new CacheablePaginatedResponse<>(result.stream().filter(ntf->{
if(ntf.status!=null){
return new StatusFilterPredicate(filters, Filter.FilterContext.NOTIFICATIONS).test(ntf.status);
}
return true;
}).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id, false));
ArrayList<Notification> filtered=new ArrayList<>(result);
AccountSessionManager.get(accountID).filterStatusContainingObjects(filtered, n->n.status, FilterContext.NOTIFICATIONS);
PaginatedResponse<List<Notification>> res=new PaginatedResponse<>(filtered, result.isEmpty() ? null : result.get(result.size()-1).id);
callback.onSuccess(res);
putNotifications(result, onlyMentions, onlyPosts, maxID==null);
if(!onlyMentions){
loadingNotifications=false;
synchronized(pendingNotificationsCallbacks){
for(Callback<PaginatedResponse<List<Notification>>> cb:pendingNotificationsCallbacks){
cb.onSuccess(res);
}
pendingNotificationsCallbacks.clear();
}
}
}
@Override
public void onError(ErrorResponse error){
callback.onError(error);
if(!onlyMentions){
loadingNotifications=false;
synchronized(pendingNotificationsCallbacks){
for(Callback<PaginatedResponse<List<Notification>>> cb:pendingNotificationsCallbacks){
cb.onError(error);
}
pendingNotificationsCallbacks.clear();
}
}
}
})
.exec(accountID);
@@ -327,7 +367,7 @@ public class CacheController{
createRecentSearchesTable(db);
}
if(oldVersion<3){
// MEGALODON-SPECIFIC
// MEGALODON
createPostsNotificationsTable(db);
}
if(oldVersion<4){

View File

@@ -89,13 +89,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)
@@ -117,6 +117,9 @@ public class MastodonAPIController{
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);
@@ -153,13 +156,17 @@ public class MastodonAPIController{
Log.d(TAG, "["+(session==null ? "no-auth" : session.getID())+"] response body: "+respJson);
if(req.respTypeToken!=null)
respObj=gson.fromJson(respJson, req.respTypeToken.getType());
else
else if(req.respClass!=null)
respObj=gson.fromJson(respJson, req.respClass);
else
respObj=null;
}else{
if(req.respTypeToken!=null)
respObj=gson.fromJson(reader, req.respTypeToken.getType());
else
else if(req.respClass!=null)
respObj=gson.fromJson(reader, req.respClass);
else
respObj=null;
}
}catch(JsonIOException|JsonSyntaxException x){
if (req.context != null && response.body().contentType().subtype().equals("html")) {

View File

@@ -49,6 +49,7 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
Token token;
boolean canceled, isRemote;
Map<String, String> headers;
long timeout;
private ProgressDialog progressDialog;
protected boolean removeUnsupportedItems;
@Nullable Context context;
@@ -117,16 +118,16 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
.findAny())
.map(AccountSession::getID)
.map(this::exec)
.orElse(this.execNoAuth(domain));
.orElseGet(() -> this.execNoAuth(domain));
}
public MastodonAPIRequest<T> wrapProgress(Activity activity, @StringRes int message, boolean cancelable){
return wrapProgress(activity, message, cancelable, null);
public MastodonAPIRequest<T> wrapProgress(Context context, @StringRes int message, boolean cancelable){
return wrapProgress(context, message, cancelable, null);
}
public MastodonAPIRequest<T> wrapProgress(Activity activity, @StringRes int message, boolean cancelable, Consumer<ProgressDialog> transform){
progressDialog=new ProgressDialog(activity);
progressDialog.setMessage(activity.getString(message));
public MastodonAPIRequest<T> wrapProgress(Context context, @StringRes int message, boolean cancelable, Consumer<ProgressDialog> transform){
progressDialog=new ProgressDialog(context);
progressDialog.setMessage(context.getString(message));
progressDialog.setCancelable(cancelable);
if (transform != null) transform.accept(progressDialog);
if(cancelable){
@@ -152,6 +153,10 @@ public abstract class MastodonAPIRequest<T> extends APIRequest<T>{
headers.put(key, value);
}
protected void setTimeout(long timeout){
this.timeout=timeout;
}
protected String getPathPrefix(){
return "/api/v1";
}

View File

@@ -87,7 +87,6 @@ public class PushSubscriptionManager{
private String accountID;
private PrivateKey privateKey;
private PublicKey publicKey;
private PublicKey serverKey;
private byte[] authKey;
public PushSubscriptionManager(String accountID){
@@ -98,7 +97,7 @@ public class PushSubscriptionManager{
deviceToken=getPrefs().getString("deviceToken", null);
int tokenVersion=getPrefs().getInt("version", 0);
if(!TextUtils.isEmpty(deviceToken) && tokenVersion==BuildConfig.VERSION_CODE){
registerAllAccountsForPush(false);
registerAllAccountsForPush(true); // TODO: revert this before release
return;
}
Log.i(TAG, "tryRegisterFCM: no token found or app was updated. Trying to get push token...");
@@ -121,9 +120,21 @@ public class PushSubscriptionManager{
return !TextUtils.isEmpty(deviceToken);
}
public void registerAccountForPush(PushSubscription subscription){
if(TextUtils.isEmpty(deviceToken))
throw new IllegalStateException("No device push token available");
// 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") || TextUtils.isEmpty(deviceToken)){
Log.d(TAG, "Skipping registering for FCM push notifications");
return;
}
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;
@@ -152,20 +163,21 @@ public class PushSubscriptionManager{
Log.e(TAG, "registerAccountForPush: error generating encryption key", e);
return;
}
new RegisterForPushNotifications(deviceToken,
//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,
subscription==null ? PushSubscription.Policy.ALL : subscription.policy,
pushAccountID)
subscription==null ? PushSubscription.Policy.ALL : subscription.policy)
.setCallback(new Callback<>(){
@Override
public void onSuccess(PushSubscription result){
MastodonAPIController.runInBackground(()->{
result.serverKey=result.serverKey.replace('/','_');
result.serverKey=result.serverKey.replace('+','-');
serverKey=deserializeRawPublicKey(Base64.decode(result.serverKey, Base64.URL_SAFE));
AccountSession session=AccountSessionManager.getInstance().tryGetAccount(accountID);
if(session==null)
return;

View File

@@ -0,0 +1,9 @@
package org.joinmastodon.android.api;
import com.google.gson.reflect.TypeToken;
public abstract class ResultlessMastodonAPIRequest extends MastodonAPIRequest<Void>{
public ResultlessMastodonAPIRequest(HttpMethod method, String path){
super(method, path, (Class<Void>)null);
}
}

View File

@@ -0,0 +1,14 @@
package org.joinmastodon.android.api.requests.accounts;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Hashtag;
import java.util.List;
public class GetAccountFeaturedHashtags extends MastodonAPIRequest<List<Hashtag>>{
public GetAccountFeaturedHashtags(String id){
super(HttpMethod.GET, "/accounts/"+id+"/featured_tags", new TypeToken<>(){});
}
}

View File

@@ -21,22 +21,22 @@ public class GetAccountStatuses extends MastodonAPIRequest<List<Status>>{
switch(filter){
case DEFAULT -> addQueryParameter("exclude_replies", "true");
case INCLUDE_REPLIES -> {}
case PINNED -> addQueryParameter("pinned", "true");
case MEDIA -> addQueryParameter("only_media", "true");
case NO_REBLOGS -> {
addQueryParameter("exclude_replies", "true");
addQueryParameter("exclude_reblogs", "true");
}
case OWN_POSTS_AND_REPLIES -> addQueryParameter("exclude_reblogs", "true");
case PINNED -> addQueryParameter("pinned", "true");
}
}
public enum Filter{
DEFAULT,
INCLUDE_REPLIES,
PINNED,
MEDIA,
NO_REBLOGS,
OWN_POSTS_AND_REPLIES
OWN_POSTS_AND_REPLIES,
PINNED
}
}

View File

@@ -4,21 +4,22 @@ import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Token;
public class RegisterAccount extends MastodonAPIRequest<Token>{
public RegisterAccount(String username, String email, String password, String locale, String reason){
public RegisterAccount(String username, String email, String password, String locale, String reason, String timezone){
super(HttpMethod.POST, "/accounts", Token.class);
setRequestBody(new Body(username, email, password, locale, reason));
setRequestBody(new Body(username, email, password, locale, reason, timezone));
}
private static class Body{
public String username, email, password, locale, reason;
public String username, email, password, locale, reason, timeZone;
public boolean agreement=true;
public Body(String username, String email, String password, String locale, String reason){
public Body(String username, String email, String password, String locale, String reason, String timeZone){
this.username=username;
this.email=email;
this.password=password;
this.locale=locale;
this.reason=reason;
this.timeZone=timeZone;
}
}
}

View File

@@ -6,7 +6,7 @@ import org.joinmastodon.android.model.Relationship;
public class SetAccountMuted extends MastodonAPIRequest<Relationship>{
public SetAccountMuted(String id, boolean muted, long duration){
super(HttpMethod.POST, "/accounts/"+id+"/"+(muted ? "mute" : "unmute"), Relationship.class);
setRequestBody(muted ? new Request(duration): new Object());
setRequestBody(new Request(duration));
}
private static class Request{

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

@@ -0,0 +1,34 @@
package org.joinmastodon.android.api.requests.accounts;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Account;
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){
super(HttpMethod.PATCH, "/accounts/update_credentials", Account.class);
setRequestBody(new Request(locked, discoverable, new RequestSource(preferences.postingDefaultVisibility, preferences.postingDefaultLanguage)));
}
private static class Request{
public Boolean locked, discoverable;
public RequestSource source;
public Request(Boolean locked, Boolean discoverable, RequestSource source){
this.locked=locked;
this.discoverable=discoverable;
this.source=source;
}
}
private static class RequestSource{
public StatusPrivacy privacy;
public String language;
public RequestSource(StatusPrivacy privacy, String language){
this.privacy=privacy;
this.language=language;
}
}
}

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.announcements;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
public class AddAnnouncementReaction extends MastodonAPIRequest<Object> {
public AddAnnouncementReaction(String id, String emoji) {
super(HttpMethod.PUT, "/announcements/" + id + "/reactions/" + emoji, Object.class);
setRequestBody(new Object());
}
}

View File

@@ -0,0 +1,9 @@
package org.joinmastodon.android.api.requests.announcements;
import org.joinmastodon.android.api.MastodonAPIRequest;
public class DeleteAnnouncementReaction extends MastodonAPIRequest<Object> {
public DeleteAnnouncementReaction(String id, String emoji) {
super(HttpMethod.DELETE, "/announcements/" + id + "/reactions/" + emoji, Object.class);
}
}

View File

@@ -0,0 +1,22 @@
package org.joinmastodon.android.api.requests.catalog;
import android.net.Uri;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.catalog.CatalogDefaultInstance;
import java.util.List;
public class GetCatalogDefaultInstances extends MastodonAPIRequest<List<CatalogDefaultInstance>>{
public GetCatalogDefaultInstances(){
super(HttpMethod.GET, null, new TypeToken<>(){});
setTimeout(500);
}
@Override
public Uri getURL(){
return Uri.parse("https://api.joinmastodon.org/default-servers");
}
}

View File

@@ -0,0 +1,23 @@
package org.joinmastodon.android.api.requests.filters;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.FilterAction;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.FilterKeyword;
import java.util.EnumSet;
import java.util.List;
import java.util.stream.Collectors;
public class CreateFilter extends MastodonAPIRequest<Filter>{
public CreateFilter(String title, EnumSet<FilterContext> context, FilterAction action, int expiresIn, List<FilterKeyword> words){
super(HttpMethod.POST, "/filters", Filter.class);
setRequestBody(new FilterRequest(title, context, action, expiresIn==0 ? null : expiresIn, words.stream().map(w->new KeywordAttribute(null, null, w.keyword, w.wholeWord)).collect(Collectors.toList())));
}
@Override
protected String getPathPrefix(){
return "/api/v2";
}
}

View File

@@ -0,0 +1,14 @@
package org.joinmastodon.android.api.requests.filters;
import org.joinmastodon.android.api.ResultlessMastodonAPIRequest;
public class DeleteFilter extends ResultlessMastodonAPIRequest{
public DeleteFilter(String id){
super(HttpMethod.DELETE, "/filters/"+id);
}
@Override
protected String getPathPrefix(){
return "/api/v2";
}
}

View File

@@ -0,0 +1,23 @@
package org.joinmastodon.android.api.requests.filters;
import org.joinmastodon.android.model.FilterAction;
import org.joinmastodon.android.model.FilterContext;
import java.util.EnumSet;
import java.util.List;
class FilterRequest{
public String title;
public EnumSet<FilterContext> context;
public FilterAction filterAction;
public Integer expiresIn;
public List<KeywordAttribute> keywordsAttributes;
public FilterRequest(String title, EnumSet<FilterContext> context, FilterAction filterAction, Integer expiresIn, List<KeywordAttribute> keywordsAttributes){
this.title=title;
this.context=context;
this.filterAction=filterAction;
this.expiresIn=expiresIn;
this.keywordsAttributes=keywordsAttributes;
}
}

View File

@@ -1,4 +1,4 @@
package org.joinmastodon.android.api.requests.accounts;
package org.joinmastodon.android.api.requests.filters;
import com.google.gson.reflect.TypeToken;
@@ -7,8 +7,13 @@ import org.joinmastodon.android.model.Filter;
import java.util.List;
public class GetWordFilters extends MastodonAPIRequest<List<Filter>>{
public GetWordFilters(){
public class GetFilters extends MastodonAPIRequest<List<Filter>>{
public GetFilters(){
super(HttpMethod.GET, "/filters", new TypeToken<>(){});
}
@Override
protected String getPathPrefix(){
return "/api/v2";
}
}

View File

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

View File

@@ -0,0 +1,18 @@
package org.joinmastodon.android.api.requests.filters;
import com.google.gson.annotations.SerializedName;
class KeywordAttribute{
public String id;
@SerializedName("_destroy")
public Boolean delete;
public String keyword;
public Boolean wholeWord;
public KeywordAttribute(String id, Boolean delete, String keyword, Boolean wholeWord){
this.id=id;
this.delete=delete;
this.keyword=keyword;
this.wholeWord=wholeWord;
}
}

View File

@@ -0,0 +1,30 @@
package org.joinmastodon.android.api.requests.filters;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.FilterAction;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.FilterKeyword;
import java.util.EnumSet;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class UpdateFilter extends MastodonAPIRequest<Filter>{
public UpdateFilter(String id, String title, EnumSet<FilterContext> context, FilterAction action, int expiresIn, List<FilterKeyword> words, List<String> deletedWords){
super(HttpMethod.PUT, "/filters/"+id, Filter.class);
List<KeywordAttribute> attrs=Stream.of(
words.stream().map(w->new KeywordAttribute(w.id, null, w.keyword, w.wholeWord)),
deletedWords.stream().map(wid->new KeywordAttribute(wid, true, null, null))
).flatMap(Function.identity()).collect(Collectors.toList());
setRequestBody(new FilterRequest(title, context, action, expiresIn==0 ? null : expiresIn, attrs));
}
@Override
protected String getPathPrefix(){
return "/api/v2";
}
}

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

@@ -0,0 +1,16 @@
package org.joinmastodon.android.api.requests.instance;
import org.joinmastodon.android.api.MastodonAPIRequest;
import java.time.Instant;
public class GetInstanceExtendedDescription extends MastodonAPIRequest<GetInstanceExtendedDescription.Response>{
public GetInstanceExtendedDescription(){
super(HttpMethod.GET, "/instance/extended_description", Response.class);
}
public static class Response{
public Instant updatedAt;
public String content;
}
}

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

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