Compare commits

..

662 Commits

Author SHA1 Message Date
LucasGGamerM
03cb0b3c47 fix: fix missing app icon for stable builds 2023-09-29 17:14:39 -03:00
LucasGGamerM
53c454a59b build: fix oopsie where I forgot to increase the version code as well 2023-09-29 16:57:43 -03:00
LucasGGamerM
d21ae9d94e build: bump version 2023-09-29 16:35:23 -03:00
LucasGGamerM
453f082822 Merge remote-tracking branch 'megalodon_weblate/main'
# Conflicts:
#	mastodon/src/main/res/values-pt-rBR/strings_sk.xml
#	metadata/ar/short_description.txt
#	metadata/id/changelogs/67.txt
2023-09-29 16:29:16 -03:00
LucasGGamerM
23843e9002 fix: use built-in appkit empty view styles entry and remove hack to apply colors to the empty view texts 2023-09-29 16:23:33 -03:00
LucasGGamerM
232d2e7e6d build: upgrade to appkit 1.2.14 2023-09-29 16:23:33 -03:00
LucasGGamerM
e9d73cbe32 build(CI): use LucasGGamerM's appkit repo 2023-09-29 16:17:14 -03:00
LucasGGamerM
4bb0597edf Merge remote-tracking branch 'mastodon/master'
# Conflicts:
#	mastodon/build.gradle
2023-09-29 07:56:14 -03:00
Grishka
a00afd5d7f Same crash fix in 2 more places ugh 2023-09-29 03:20:58 +03:00
LucasGGamerM
796bdf2893 Merge pull request #264 from Xen4n/master
Posts divider brightness fix (now looks like in settings and profile)
2023-09-28 19:25:11 -03:00
Xen4n
5b7868b44e Posts divider brightness fix (now looks like in settings and profile) 2023-09-28 23:52:35 +02:00
LucasGGamerM
66e67231c8 build: revert appkit to 1.2.9 and gson to 2.9.0 for app stability's sake 2023-09-28 15:31:31 -03:00
LucasGGamerM
58be2214a4 Merge remote-tracking branch 'mastodon/master'
# Conflicts:
#	mastodon/build.gradle
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java
2023-09-28 15:19:32 -03:00
LucasGGamerM
72a370aa84 fix(nord-theme): fix nord theme pill color 2023-09-28 14:20:14 -03:00
Grishka
9a41a2d6fb Merge branch 'l10n_master' 2023-09-28 20:14:21 +03:00
LucasGGamerM
2629e0039c chore: remove untested privacy settings category 2023-09-28 14:11:43 -03:00
Grishka
2cd98a6620 More crash fixes 2023-09-28 20:11:43 +03:00
LucasGGamerM
24048a677f fix: make app compile again (again) 2023-09-28 14:07:31 -03:00
Grishka
283b56be5b Finally fix the mysterious RecyclerView crash 2023-09-28 19:56:25 +03:00
LucasGGamerM
debf8c52a1 Merge remote-tracking branch 'mastodon/master'
# Conflicts:
#	fastlane/metadata/android/fi-FI/full_description.txt
#	fastlane/metadata/android/th-TH/full_description.txt
#	mastodon/build.gradle
#	mastodon/src/main/java/org/joinmastodon/android/PushNotificationReceiver.java
#	mastodon/src/main/java/org/joinmastodon/android/api/requests/statuses/TranslateStatus.java
#	mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java
#	mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSessionManager.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/BaseStatusListFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/FeaturedHashtagsListFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/HashtagTimelineFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFeaturedFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/discover/SearchFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/discover/SearchQueryFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsMainFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/model/Status.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HeaderStatusDisplayItem.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/TextStatusDisplayItem.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/text/HtmlParser.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/text/LinkSpan.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/viewcontrollers/ComposePollViewController.java
#	mastodon/src/main/res/layout/display_item_text.xml
#	mastodon/src/main/res/menu/post.xml
#	mastodon/src/main/res/values/styles.xml
2023-09-28 13:52:48 -03:00
LucasGGamerM
7fdea9710f fix: make app compile again 2023-09-28 13:52:04 -03:00
Grishka
d2de62ee55 Probably fix #703 2023-09-28 13:33:59 -03:00
Grishka
d706768112 Fix #682 2023-09-28 13:29:16 -03:00
Grishka
1614213aae Fix #683 2023-09-28 13:27:20 -03:00
Grishka
3045fe0357 Probably need to set this too 2023-09-28 13:27:20 -03:00
Grishka
5a35be0ebd Specify LED color for notifications
closes #695
2023-09-28 13:27:20 -03:00
Grishka
22b1cd0d0b Crash fixes 2023-09-28 13:26:06 -03:00
Eugen Rochko
49f10bacb3 New translations strings.xml (Turkish) 2023-09-28 13:24:59 -03:00
Eugen Rochko
2926e5096e New translations strings.xml (Chinese Traditional) 2023-09-28 13:24:59 -03:00
Eugen Rochko
361f27d5df New translations strings.xml (Filipino) 2023-09-28 13:24:59 -03:00
Grishka
d068093c5a Add a tool to detect invalid formatting in localized strings 2023-09-28 13:24:27 -03:00
Eugen Rochko
3bea1b7f3e New translations strings.xml (Filipino) 2023-09-28 13:24:26 -03:00
Eugen Rochko
5a34d9ffce New translations strings.xml (Greek) 2023-09-28 13:23:35 -03:00
Eugen Rochko
240754b70a New translations strings.xml (Turkish) 2023-09-28 13:23:34 -03:00
Eugen Rochko
7973ad7042 New translations strings.xml (Chinese Simplified) 2023-09-28 13:23:34 -03:00
Eugen Rochko
8446dbe05d New translations strings.xml (Japanese) 2023-09-28 13:23:34 -03:00
Eugen Rochko
7b0313cc69 New translations strings.xml (Japanese) 2023-09-28 13:23:23 -03:00
Grishka
994ae0242c Fix indexable setting 2023-09-28 13:23:22 -03:00
Eugen Rochko
fd34be3c66 New translations strings.xml (Russian) 2023-09-28 13:23:22 -03:00
Grishka
20785d53fe Fix custom emojis in names setting 2023-09-28 13:23:05 -03:00
Eugen Rochko
3cc1748231 New translations strings.xml (Slovenian) 2023-09-28 13:22:54 -03:00
Eugen Rochko
079112b905 New translations strings.xml (Japanese) 2023-09-28 13:22:54 -03:00
Eugen Rochko
38aa55b371 New translations strings.xml (Japanese) 2023-09-28 13:22:53 -03:00
Eugen Rochko
e07c01018b New translations strings.xml (Russian) 2023-09-28 13:22:53 -03:00
Eugen Rochko
08de4525eb New translations strings.xml (Italian) 2023-09-28 13:22:53 -03:00
Eugen Rochko
062dca6a77 New translations strings.xml (Thai) 2023-09-28 13:22:53 -03:00
Eugen Rochko
d9abb8dfa1 New translations strings.xml (Icelandic) 2023-09-28 13:22:53 -03:00
Eugen Rochko
5bcbe19435 New translations strings.xml (Persian) 2023-09-28 13:22:52 -03:00
Eugen Rochko
955b985d1a New translations strings.xml (Swedish) 2023-09-28 13:22:31 -03:00
Grishka
6d6ab789a3 Privacy settings 2023-09-28 13:22:30 -03:00
Grishka
ad8be2f7a3 Scroll profile tab views to top when tab is reselected 2023-09-28 13:13:33 -03:00
Eugen Rochko
64be55e406 New translations strings.xml (French) 2023-09-28 13:09:44 -03:00
Eugen Rochko
6230f32135 New translations strings.xml (Persian) 2023-09-28 13:09:43 -03:00
Eugen Rochko
30db82fc98 New translations strings.xml (Persian) 2023-09-28 13:09:43 -03:00
Eugen Rochko
921589b9bb New translations strings.xml (Vietnamese) 2023-09-28 13:09:43 -03:00
Eugen Rochko
0b0de7a4e3 New translations strings.xml (Italian) 2023-09-28 13:09:42 -03:00
Eugen Rochko
c790eaf9c0 New translations strings.xml (Finnish) 2023-09-28 13:09:42 -03:00
Grishka
2c7cef488b Paginate search results 2023-09-28 13:09:41 -03:00
Grishka
c26603e0ca Crash fixes 2023-09-28 13:08:40 -03:00
Grishka
e1e5c9b0bd Crash fix 2023-09-28 13:08:40 -03:00
Grishka
96f0817c20 Fix #690 2023-09-28 13:07:01 -03:00
Eugen Rochko
e0165a25f4 New translations strings.xml (Arabic) 2023-09-28 13:02:35 -03:00
Eugen Rochko
e465fb944a New translations strings.xml (Arabic) 2023-09-28 13:02:35 -03:00
Eugen Rochko
fb159b5a52 New translations strings.xml (Vietnamese) 2023-09-28 13:02:35 -03:00
Eugen Rochko
1a349f0bb8 New translations strings.xml (Chinese Traditional) 2023-09-28 13:02:31 -03:00
Eugen Rochko
034dfe551c New translations strings.xml (Chinese Traditional) 2023-09-28 13:02:30 -03:00
Eugen Rochko
1f713dc50e New translations strings.xml (Finnish) 2023-09-28 13:02:21 -03:00
Eugen Rochko
258df9546b New translations strings.xml (Thai) 2023-09-28 13:02:21 -03:00
Eugen Rochko
2daabd6a7e New translations strings.xml (Finnish) 2023-09-28 13:02:21 -03:00
Eugen Rochko
1e96b76b33 New translations strings.xml (Dutch) 2023-09-28 13:02:21 -03:00
Eugen Rochko
6dd944341e New translations strings.xml (Dutch) 2023-09-28 13:02:20 -03:00
Eugen Rochko
5dca70c657 New translations strings.xml (Urdu (India)) 2023-09-28 13:02:20 -03:00
Eugen Rochko
c6f2e8151f New translations strings.xml (Kabyle) 2023-09-28 13:02:20 -03:00
Eugen Rochko
99135ebdd6 New translations strings.xml (Igbo) 2023-09-28 13:02:20 -03:00
Eugen Rochko
53348be732 New translations strings.xml (Occitan) 2023-09-28 13:02:20 -03:00
Eugen Rochko
023c1d1598 New translations strings.xml (Scottish Gaelic) 2023-09-28 13:02:20 -03:00
Eugen Rochko
1d0c591cdb New translations strings.xml (Sinhala) 2023-09-28 13:02:20 -03:00
Eugen Rochko
a03482fa53 New translations strings.xml (Bosnian) 2023-09-28 13:02:19 -03:00
Eugen Rochko
bc5fd2530a New translations strings.xml (Filipino) 2023-09-28 13:02:19 -03:00
Eugen Rochko
0ca57c3d72 New translations strings.xml (Burmese) 2023-09-28 13:02:19 -03:00
Eugen Rochko
5d20697e07 New translations strings.xml (Hindi) 2023-09-28 13:02:19 -03:00
Eugen Rochko
2847a1fae0 New translations strings.xml (Croatian) 2023-09-28 13:02:19 -03:00
Eugen Rochko
4bd78f31f2 New translations strings.xml (Thai) 2023-09-28 13:02:19 -03:00
Eugen Rochko
e6281f9bb5 New translations strings.xml (Bengali) 2023-09-28 13:02:18 -03:00
Eugen Rochko
2c83b5aa02 New translations strings.xml (Persian) 2023-09-28 13:02:18 -03:00
Eugen Rochko
586d48c80e New translations strings.xml (Indonesian) 2023-09-28 13:02:18 -03:00
Eugen Rochko
fff2c5a3f5 New translations strings.xml (Portuguese, Brazilian) 2023-09-28 13:02:18 -03:00
Eugen Rochko
3411cf4e56 New translations strings.xml (Icelandic) 2023-09-28 13:02:17 -03:00
Eugen Rochko
e126858e7a New translations strings.xml (Galician) 2023-09-28 13:02:17 -03:00
Eugen Rochko
9e0b40d409 New translations strings.xml (Vietnamese) 2023-09-28 13:02:17 -03:00
Eugen Rochko
e362efb453 New translations strings.xml (Chinese Traditional) 2023-09-28 13:02:17 -03:00
Eugen Rochko
8095d3004a New translations strings.xml (Chinese Simplified) 2023-09-28 13:02:16 -03:00
Eugen Rochko
27f023863b New translations strings.xml (Ukrainian) 2023-09-28 13:02:16 -03:00
Eugen Rochko
af6fae4d86 New translations strings.xml (Turkish) 2023-09-28 13:02:15 -03:00
Eugen Rochko
8119049df1 New translations strings.xml (Swedish) 2023-09-28 13:02:13 -03:00
Eugen Rochko
b5c09a4398 New translations strings.xml (Slovenian) 2023-09-28 13:02:13 -03:00
Eugen Rochko
14df6c4e05 New translations strings.xml (Russian) 2023-09-28 13:02:11 -03:00
Eugen Rochko
5c34d38783 New translations strings.xml (Portuguese) 2023-09-28 13:02:11 -03:00
Eugen Rochko
cfce3595f6 New translations strings.xml (Polish) 2023-09-28 13:02:07 -03:00
Eugen Rochko
411b561a3a New translations strings.xml (Norwegian) 2023-09-28 13:02:04 -03:00
Eugen Rochko
ff9c211f3c New translations strings.xml (Dutch) 2023-09-28 13:02:03 -03:00
Eugen Rochko
c8a650acd4 New translations strings.xml (Korean) 2023-09-28 13:02:01 -03:00
Eugen Rochko
a8cca76392 New translations strings.xml (Japanese) 2023-09-28 13:02:00 -03:00
Eugen Rochko
5e2f653d30 New translations strings.xml (Italian) 2023-09-28 13:01:54 -03:00
Eugen Rochko
418f87999c New translations strings.xml (Armenian) 2023-09-28 13:01:52 -03:00
Eugen Rochko
c330428c07 New translations strings.xml (Hungarian) 2023-09-28 13:01:50 -03:00
Eugen Rochko
119537f45f New translations strings.xml (Hebrew) 2023-09-28 13:01:48 -03:00
Eugen Rochko
9f09b437ab New translations strings.xml (Irish) 2023-09-28 13:01:46 -03:00
Eugen Rochko
1141dd5875 New translations strings.xml (Finnish) 2023-09-28 13:01:45 -03:00
Eugen Rochko
a008a0ac9a New translations strings.xml (Basque) 2023-09-28 13:01:44 -03:00
Eugen Rochko
5cf5267e49 New translations strings.xml (Greek) 2023-09-28 13:01:42 -03:00
Eugen Rochko
df2246b71a New translations strings.xml (German) 2023-09-28 13:01:42 -03:00
Eugen Rochko
7862fefe94 New translations strings.xml (Danish) 2023-09-28 13:01:40 -03:00
Eugen Rochko
b59957bd90 New translations strings.xml (Czech) 2023-09-28 13:01:39 -03:00
Eugen Rochko
e307f1cca2 New translations strings.xml (Catalan) 2023-09-28 13:01:37 -03:00
Eugen Rochko
de185e5a27 New translations strings.xml (Belarusian) 2023-09-28 13:01:36 -03:00
Eugen Rochko
e1fbe2c96e New translations strings.xml (Arabic) 2023-09-28 13:01:36 -03:00
Eugen Rochko
d7babf1e4d New translations strings.xml (Spanish) 2023-09-28 13:01:36 -03:00
Eugen Rochko
1203de0015 New translations strings.xml (French) 2023-09-28 13:01:35 -03:00
Eugen Rochko
e7148acefb New translations strings.xml (Romanian) 2023-09-28 13:01:35 -03:00
Eugen Rochko
88741b0db4 New translations strings.xml (Portuguese, Brazilian) 2023-09-28 13:00:55 -03:00
Eugen Rochko
12f9a11f03 New translations strings.xml (Finnish) 2023-09-28 13:00:55 -03:00
Eugen Rochko
234972352d New translations strings.xml (Finnish) 2023-09-28 13:00:55 -03:00
Eugen Rochko
67448f9de5 New translations strings.xml (Indonesian) 2023-09-28 13:00:54 -03:00
Eugen Rochko
9681256a06 New translations strings.xml (Finnish) 2023-09-28 13:00:53 -03:00
Eugen Rochko
7f44c2ca49 New translations strings.xml (Finnish) 2023-09-28 13:00:53 -03:00
Eugen Rochko
f355919660 New translations strings.xml (Ukrainian) 2023-09-28 13:00:52 -03:00
Eugen Rochko
928f24b460 New translations strings.xml (Finnish) 2023-09-28 13:00:52 -03:00
Eugen Rochko
40e54b165b New translations strings.xml (Finnish) 2023-09-28 13:00:51 -03:00
Eugen Rochko
57d6b33b58 New translations strings.xml (Finnish) 2023-09-28 13:00:51 -03:00
Grishka
6b02a2df68 Fix #658, fix #620 2023-09-28 13:00:51 -03:00
Eugen Rochko
6d56771aba New translations strings.xml (Galician) 2023-09-28 16:51:59 +02:00
LucasGGamerM
56a83e66cd feat(notifications): readd account card for follow notifications 2023-09-28 08:31:21 -03:00
LucasGGamerM
9f17f1600a feat(profile): update unmute icon
This is to be consistent with the mute hashtag icon thingy
2023-09-28 07:43:22 -03:00
Grishka
1724d8a532 Probably fix #703 2023-09-27 19:50:59 +03:00
LucasGGamerM
7b4be83781 refactor(notification-headers): make only avatar and icon be clickable. Also fixes the ripple not being drawn correctly 2023-09-27 12:16:39 -03:00
butterflyoffire
52030b3b2d Translated using Weblate (Arabic)
Currently translated at 76.1% (294 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-09-27 07:53:09 +00:00
CDN18
3b36434dff Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (34 of 34 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/zh_Hans/
2023-09-26 17:16:44 +00:00
CDN18
f73be653ce Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (97 of 97 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/zh_Hans/
2023-09-26 17:16:44 +00:00
Oliebol
808c922637 Translated using Weblate (Dutch)
Currently translated at 86.5% (84 of 97 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/nl/
2023-09-26 17:16:44 +00:00
Andrewblasco
ceef155e03 Translated using Weblate (Spanish)
Currently translated at 100.0% (97 of 97 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/es/
2023-09-26 17:16:43 +00:00
dontobi
eb5a38d514 Translated using Weblate (German)
Currently translated at 100.0% (97 of 97 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/de/
2023-09-26 17:16:43 +00:00
LucasGGamerM
33d4e05e96 refactor(translations): remove blocks/mutes strings in favor of blocked accounts/muted accounts strings 2023-09-26 11:08:54 -03:00
LucasGGamerM
968668e38c Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (99 of 99 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-09-26 14:02:01 +00:00
butterflyoffire
097a18fa92 Translated using Weblate (Arabic (Algeria))
Currently translated at 90.5% (86 of 95 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/ar_DZ/
2023-09-26 13:56:53 +00:00
butterflyoffire
5a85420866 Translated using Weblate (Arabic (Algeria))
Currently translated at 63.7% (58 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/ar_DZ/
2023-09-26 13:56:53 +00:00
Parsa Ranjbar
50cee02191 Translated using Weblate (Persian)
Currently translated at 93.4% (85 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/fa/
2023-09-26 13:56:53 +00:00
butterflyoffire
e7dbb9fdf7 Translated using Weblate (French)
Currently translated at 93.4% (85 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/fr/
2023-09-26 13:56:52 +00:00
Parsa Ranjbar
e2b2361ad2 Translated using Weblate (Persian)
Currently translated at 92.3% (84 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/fa/
2023-09-26 13:56:52 +00:00
Andrewblasco
89fe1dc783 Translated using Weblate (Spanish)
Currently translated at 100.0% (91 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/es/
2023-09-26 13:56:52 +00:00
LucasGGamerM
eaadd80eeb refactor(translations): move blocks/mutes strings to strings_mo.xml while we wait for megalodon to merge sk22#821 2023-09-26 10:53:22 -03:00
LucasGGamerM
c8063e961e fix(mute-hashtag): clear the filter optional when successfully deleting the hashtag filter on the server 2023-09-26 07:56:20 -03:00
LucasGGamerM
3057546c55 fix(mute-hashtag): make the mute button follow the mute state of the hashtag 2023-09-26 07:54:18 -03:00
LucasGGamerM
f90e799caa Revert "fix(hashtag-timeline): (un)show mute button as action"
This reverts commit 72ca3d0204.
2023-09-26 07:37:35 -03:00
Eugen Rochko
b4cdf35d36 New translations strings.xml (Russian) 2023-09-25 23:39:42 +02:00
Eugen Rochko
cad0ad7a59 New translations strings.xml (Ukrainian) 2023-09-25 22:25:17 +02:00
Grishka
ca60003c39 Fix #682 2023-09-25 23:11:10 +03:00
Grishka
0f030e0bac Fix #683 2023-09-25 23:07:34 +03:00
Grishka
6d4f212a18 Probably need to set this too 2023-09-25 23:00:15 +03:00
Grishka
183b39bc24 Specify LED color for notifications
closes #695
2023-09-25 22:58:08 +03:00
Grishka
27ad0c6fcf Crash fixes 2023-09-25 22:52:51 +03:00
LucasGGamerM
9944185424 Merge pull request #263 from FineFindus/feat/mute-hashtag
fix(hashtag/mute): update state on unmute
2023-09-25 16:39:33 -03:00
LucasGGamerM
72ca3d0204 fix(hashtag-timeline): (un)show mute button as action
Lets wait until I have enough life force to actually update the icon of this thing
2023-09-25 16:26:03 -03:00
FineFindus
53204a9998 fix(hashtag/mute): update state on unmute 2023-09-25 21:15:45 +02:00
LucasGGamerM
c3624eddb3 feat(hashtag-timeline): show mute button as action 2023-09-25 16:09:37 -03:00
LucasGGamerM
e144d0ac6f Merge pull request #261 from FineFindus/feat/mute-hashtag
feat: add option to mute hashtag
2023-09-25 15:43:22 -03:00
FineFindus
ac8562aaa2 fix(hashtag/mute): mute hashtag with prefixed #-symbol 2023-09-25 20:31:29 +02:00
FineFindus
4f8c4c67d2 feat(hashtag): allow unmuting hashtag 2023-09-25 20:22:06 +02:00
Grishka
b5f661f1af I forgot to increment the version code 2023-09-25 19:25:59 +03:00
Grishka
0015f3f0bf Merge branch 'l10n_master' 2023-09-25 19:22:38 +03:00
Eugen Rochko
c5d0fdd645 New translations strings.xml (Turkish) 2023-09-25 18:20:56 +02:00
Grishka
2d09ad44fb Merge branch 'l10n_master' 2023-09-25 19:18:24 +03:00
Eugen Rochko
667fffd124 New translations strings.xml (Chinese Traditional) 2023-09-25 18:18:22 +02:00
Eugen Rochko
699233d8c7 New translations strings.xml (Filipino) 2023-09-25 18:18:05 +02:00
Grishka
56aabdc4a6 Fix empty view text style
closes #701
2023-09-25 19:12:04 +03:00
Grishka
443e2c7a6f Add a tool to detect invalid formatting in localized strings 2023-09-25 18:51:49 +03:00
Eugen Rochko
985b0f6e63 New translations strings.xml (Filipino) 2023-09-25 17:49:57 +02:00
Grishka
cc86edf276 Fix #700 2023-09-25 17:18:42 +03:00
Grishka
4071b9342d Update appkit 2023-09-25 17:13:59 +03:00
LucasGGamerM
c92ab11dcd fix(recycler-empty-view): make the textViews in the empty views follow the color themes 2023-09-25 11:10:37 -03:00
LucasGGamerM
f3a1e7cf58 fix(poll-options): fix poll options layout when screen is too small and there are multiple lines in a poll option
cc: @FineFindus
2023-09-25 08:41:14 -03:00
LucasGGamerM
ebcafbf90d Merge branch 'fix/long-poll-options' 2023-09-25 08:21:11 -03:00
LucasGGamerM
b5f7135e38 Merge branch 'fix/chipify' 2023-09-25 08:13:03 -03:00
LucasGGamerM
8a3df3657b fix(ProfileFragment): max out number of profile roles to 4 2023-09-25 07:18:46 -03:00
Eugen Rochko
f71d1bc5d3 New translations strings.xml (Greek) 2023-09-24 23:27:13 +02:00
FineFindus
f293619189 feat: add mute hashtag option
Fixes https://github.com/LucasGGamerM/moshidon/issues/260, by opening the create filter page
2023-09-24 12:33:17 +02:00
FineFindus
68ec3499ea fix: show individual chips 2023-09-24 12:18:55 +02:00
FineFindus
4b79d35854 feat(settings/filter): allow passing words 2023-09-24 11:47:42 +02:00
FineFindus
54ec1d781a fix: show multiline poll options 2023-09-24 10:57:23 +02:00
Andrewblasco
2b926ffa46 Translated using Weblate (Spanish)
Currently translated at 100.0% (386 of 386 strings)

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

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-09-22 12:53:08 +00:00
Eugen Rochko
d02a72e079 New translations strings.xml (Japanese) 2023-09-22 13:01:51 +02:00
Eugen Rochko
3be57d1b0b New translations strings.xml (Japanese) 2023-09-22 11:08:13 +02:00
Eugen Rochko
bed550e97c New translations strings.xml (Russian) 2023-09-22 09:19:11 +02:00
Eugen Rochko
7e2619ea75 New translations strings.xml (Italian) 2023-09-22 01:48:10 +02:00
Eugen Rochko
4b22f1d3a7 New translations strings.xml (Thai) 2023-09-21 21:39:59 +02:00
LucasGGamerM
885b3e3c60 refactor(ScheduledStatusListFragment): refactor the apply window insets method
This allows for a smoother experience in my views
2023-09-21 11:45:27 -03:00
Eugen Rochko
9dcc7e293f New translations strings.xml (Icelandic) 2023-09-21 15:39:27 +02:00
Eugen Rochko
6a68cf5e41 New translations strings.xml (Persian) 2023-09-21 13:13:31 +02:00
LucasGGamerM
1edcf847b5 fix(mute-conversation): don't show mute conversation toggle on scheduled posts 2023-09-21 07:48:24 -03:00
LucasGGamerM
f5aff4d262 fix(drafts): fix crash when editing a draft with a poll
Fixes #243
2023-09-21 07:32:24 -03:00
Grishka
29297be4a3 Merge branch 'l10n_master' 2023-09-20 22:43:16 +03:00
Eugen Rochko
90b87529e0 New translations strings.xml (Swedish) 2023-09-20 21:16:11 +02:00
Grishka
39af05524d Privacy settings 2023-09-20 21:44:28 +03:00
LucasGGamerM
2c8246341a fix(search): stop empty search queries from happening 2023-09-20 14:21:52 -03:00
LucasGGamerM
77e19b4d6f fix(compose): make 'This post will be saved as a draft' view work better on smaller screens
cc: @sk22
2023-09-20 10:31:59 -03:00
LucasGGamerM
18857e6233 refactor(compose): remove unnecessary drawables 2023-09-20 10:26:08 -03:00
LucasGGamerM
4aee67382b refactor(compose): move publish button icon coloring to compose_button.xml 2023-09-20 10:12:37 -03:00
LucasGGamerM
3656402277 fix(compose): fix bottom bar icons tint
This uses the action_bar_icons.xml color scheme to dictate the colors of the compose bottom bar items
2023-09-20 10:06:03 -03:00
Grishka
e3fb2cd03c Scroll profile tab views to top when tab is reselected 2023-09-20 14:47:25 +03:00
LucasGGamerM
56e752c0b3 feat(mute-conversations): also show mute conversation when your acct matches the mention acct
We all gotta love some edge cases
2023-09-20 08:42:52 -03:00
LucasGGamerM
de7bc49f85 feat(mute-conversations): also show mute conversation when your fully qualified name matches the username of the mention 2023-09-20 08:31:50 -03:00
LucasGGamerM
beeffdff91 fix(mute-conversations): fix NPE when the mention id is null
This fixes an issue causing the app to crash when there is a mention on a post from a remote timeline and you tap on the three dot menu on the post header
2023-09-20 08:20:54 -03:00
Gregory K
90f84d628a Merge pull request #694 from LucasGGamerM/mastodon-android
fix(compose): fix photoPicker not popping up when there is less than 2 spaces available for media
2023-09-20 14:10:26 +03:00
LucasGGamerM
b89e0b5c5a fix(compose): fix photoPicker not popping up when there is less than 2 spaces available for media 2023-09-20 07:55:23 -03:00
LucasGGamerM
2dd983c803 fix(compose): fix photoPicker not popping up when there is less than 2 spaces available for media 2023-09-20 07:46:39 -03:00
LucasGGamerM
bb895c88b2 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (91 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-09-20 10:21:48 +00:00
LucasGGamerM
e33d0e692c Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (91 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-09-20 10:20:58 +00:00
Andrewblasco
133c941dc8 Translated using Weblate (Spanish)
Currently translated at 100.0% (91 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/es/
2023-09-20 10:20:58 +00:00
LucasGGamerM
62222cd1d9 feat(mute-conversations-toggle): Update mute/unmute confirmation dialog strings (again) 2023-09-20 07:20:41 -03:00
LucasGGamerM
5d358d79ff feat(mute-conversations-toggle): Update mute/unmute confirmation dialog strings 2023-09-20 07:12:17 -03:00
Espasant3
f724644d84 Translated using Weblate (Galician)
Currently translated at 89.6% (346 of 386 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-09-19 21:53:09 +00:00
LucasGGamerM
f71c4b1374 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (91 of 91 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-09-19 18:05:28 +00:00
Parsa Ranjbar
a921a925b0 Translated using Weblate (Persian)
Currently translated at 72.2% (60 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/fa/
2023-09-19 18:00:04 +00:00
butterflyoffire
0f08af8c03 Translated using Weblate (Arabic (Algeria))
Currently translated at 62.6% (52 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/ar_DZ/
2023-09-19 18:00:04 +00:00
butterflyoffire
d54a59dbee Translated using Weblate (French)
Currently translated at 98.7% (82 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/fr/
2023-09-19 18:00:04 +00:00
dontobi
c6cd3995b0 Translated using Weblate (German)
Currently translated at 100.0% (83 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/de/
2023-09-19 18:00:04 +00:00
edxkl
54d06b7a23 Translated using Weblate (Portuguese (Brazil))
Currently translated at 26.4% (9 of 34 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/pt_BR/
2023-09-19 18:00:04 +00:00
Andrewblasco
1ec0505d52 Translated using Weblate (Spanish)
Currently translated at 100.0% (83 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/es/
2023-09-19 18:00:04 +00:00
LucasGGamerM
be225f8bb4 feat(mute-conversations-toggle): add success confirmation toast 2023-09-19 14:56:16 -03:00
LucasGGamerM
f5732fd2ae fix(mute-conversations-toggle): fix oversight where only the answers would get muted/unmuted on the conversion. This make the whole thread either muted or unmuted 2023-09-19 14:35:40 -03:00
LucasGGamerM
17fc14de97 refactor(mute-conversations-toggle): implement event for StatusMuteChanged 2023-09-19 14:26:46 -03:00
LucasGGamerM
7c9d11fab0 fix(thread-fragment): fixes crash when status.inReplyTo is null on getDirectDescendants 2023-09-19 14:25:03 -03:00
LucasGGamerM
24abf9d317 refactor(mute-conversations-toggle): remove unused method 2023-09-19 13:20:38 -03:00
LucasGGamerM
22bf8840d5 fix(mute-conversations-toggle): make unmute option work 2023-09-19 12:21:12 -03:00
LucasGGamerM
a1fbb733ce refactor(mute-conversations-toggle): move mute and unmute options to own menu group 2023-09-19 12:19:56 -03:00
LucasGGamerM
851fa70563 feat: add mute conversations menu item 2023-09-19 12:13:03 -03:00
LucasGGamerM
6cab15b4c6 fix(file-display-tem): fix title text padding 2023-09-19 11:44:08 -03:00
Eugen Rochko
aac89c354c New translations full_description.txt (Thai) 2023-09-18 20:35:41 +02:00
Eugen Rochko
a032f9af10 New translations strings.xml (French) 2023-09-18 20:34:32 +02:00
LucasGGamerM
ec3670d562 fix(reply-icon): fix reply icon side text coloring 2023-09-18 11:35:16 -03:00
LucasGGamerM
96c3bd890a fix(boost-icon): fixes coloring on boost icon (again)
why
2023-09-18 11:32:12 -03:00
LucasGGamerM
8a0852d1a4 fix(video-player): fixes coloring on video player items 2023-09-18 11:18:42 -03:00
LucasGGamerM
77e2c6c09f fix(video-player): fixes looping video Seekbar and timestamp going on indefinitely as video restarts 2023-09-18 10:36:32 -03:00
LucasGGamerM
af60c8ba4a fix(insets): fix window insets on video player 2023-09-18 07:37:47 -03:00
LucasGGamerM
70a2f1fc0b fix(themes): fix pink dark theme bottom bar pill color 2023-09-17 13:30:50 -03:00
LucasGGamerM
b7d06a47db fix(compose): fixes compose language button being too thin when
You can see its too thin by tapping on it and seeing the button shadow, which indicates its too thin
2023-09-17 13:03:18 -03:00
LucasGGamerM
f0a5799eea fix: fix warning status display item background being too bright 2023-09-17 12:50:10 -03:00
LucasGGamerM
f0b2a25dce fix(themes): fix purple light theme bottom bar pills being slightly off 2023-09-17 12:38:40 -03:00
LucasGGamerM
de1a3fb939 fix(strings): use correct "sk_settings_see_new_posts_button" instead of "sk_settings_show_new_posts_button" 2023-09-17 10:11:33 -03:00
LucasGGamerM
823344dfc0 Merge branch 'feat/mutes-list'
# Conflicts:
#	mastodon/src/main/res/menu/profile_own.xml
#	mastodon/src/main/res/values/strings_sk.xml
2023-09-17 10:09:02 -03:00
LucasGGamerM
a6e6143157 Merge branch 'fix/akkoma_media_issue_fix' 2023-09-17 10:02:14 -03:00
LucasGGamerM
b5feab89b4 Merge branch 'fix/gap-singular' 2023-09-17 09:59:15 -03:00
LucasGGamerM
c2c31de433 fix(notifications): make reply language equal to language of the status being replied to 2023-09-17 09:45:11 -03:00
LucasGGamerM
775f799968 fix(notifications): fix reply visibility being PUBLIC no matter the status being replied to 2023-09-17 09:41:58 -03:00
LucasGGamerM
5cda112129 refactor(PreviewlessMedia): move margin value to layout file 2023-09-17 09:26:33 -03:00
Eugen Rochko
642aaec6da New translations strings.xml (Persian) 2023-09-17 14:08:04 +02:00
LucasGGamerM
f69ae5e816 refactor(PreviewlessMediaItems): make FileStatusDisplayItem be used only for files 2023-09-17 08:41:32 -03:00
LucasGGamerM
91c7fc64bd refactor(PreviewlessMediaItems): remove unused class 2023-09-17 08:37:07 -03:00
LucasGGamerM
91211b7720 refactor: do some final adjustments to PreviewlessMediaGridStatusDisplayItem layout 2023-09-17 08:34:29 -03:00
Eugen Rochko
ff667d6aed New translations strings.xml (Persian) 2023-09-17 12:27:57 +02:00
Eugen Rochko
5e98496ea6 New translations strings.xml (Vietnamese) 2023-09-17 10:39:46 +02:00
Eugen Rochko
972fe1d15b New translations strings.xml (Italian) 2023-09-17 10:39:45 +02:00
Eugen Rochko
26eaa36faa New translations strings.xml (Finnish) 2023-09-17 10:39:44 +02:00
Grishka
c517f41595 Paginate search results 2023-09-17 11:20:12 +03:00
Grishka
56a6d7243f Crash fixes 2023-09-17 10:49:13 +03:00
Grishka
18e43dfc22 Crash fix 2023-09-17 10:32:59 +03:00
Grishka
816f6370ef Fix #690 2023-09-17 10:26:27 +03:00
LucasGGamerM
51ef732d50 fix: fix crashes on PreviewlessMediaGridStatusDisplayItem 2023-09-16 16:22:00 -03:00
LucasGGamerM
31a7aa9d40 refactor: start of refactor of previewless media status display item
Its crashing a lot, and has a lot to be done
2023-09-16 16:14:48 -03:00
butterflyoffire
30866a5292 Translated using Weblate (Arabic)
Currently translated at 71.5% (276 of 386 strings)

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

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

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

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

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

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-09-14 17:53:07 +00:00
Jacocococo
fd99879ffc Revert "Fix media layout with unknown sizes"
This reverts commit a014fe9443.
2023-09-14 17:16:03 +02:00
Eugen Rochko
a78be8bc1d New translations strings.xml (Chinese Traditional) 2023-09-14 12:55:27 +02:00
Eugen Rochko
abfb497577 New translations strings.xml (Chinese Traditional) 2023-09-14 11:17:24 +02:00
Eugen Rochko
a10b184508 New translations full_description.txt (Finnish) 2023-09-13 21:32:19 +02:00
Eugen Rochko
f0ea6660e6 New translations strings.xml (Finnish) 2023-09-13 21:32:18 +02:00
Eugen Rochko
a829f25d56 New translations strings.xml (Thai) 2023-09-13 20:36:48 +02:00
Eugen Rochko
deff3dd8e0 New translations strings.xml (Finnish) 2023-09-13 20:36:47 +02:00
LucasGGamerM
ed6aa0725e Revert "fix: use better colors for true black mode"
This reverts commit 69272e891e.
2023-09-13 08:26:02 -03:00
LucasGGamerM
6fd9047a8e fix: use consistent coloring on boost icon 2023-09-13 07:57:19 -03:00
LucasGGamerM
48d7635a56 fix: unscrew the brown theme 2023-09-13 07:54:34 -03:00
LucasGGamerM
9515edea4b feat: make images scrollable in hidden preview mode 2023-09-13 07:43:00 -03:00
EndermanCo
dab596f527 Translated using Weblate (Persian)
Currently translated at 55.5% (10 of 18 strings)

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

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

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-09-12 02:43:45 +00:00
Grishka
645af12c3f Merge branch 'l10n_master' 2023-09-12 02:32:38 +03:00
Grishka
fadc42d72b New version 2023-09-12 02:32:23 +03:00
Eugen Rochko
fc831e7d42 New translations strings.xml (Portuguese, Brazilian) 2023-09-11 22:36:20 +02:00
LucasGGamerM
1ba30a4d28 Merge remote-tracking branch 'megalodon_main/main'
# Conflicts:
#	mastodon/build.gradle
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/FooterStatusDisplayItem.java
#	mastodon/src/main/res/values-ar/strings_sk.xml
#	mastodon/src/main/res/values-fr-rFR/strings_sk.xml
#	mastodon/src/main/res/values-ja-rJP/strings_sk.xml
#	metadata/ar/short_description.txt
2023-09-11 16:47:24 -03:00
Eugen Rochko
2998ee9145 New translations strings.xml (Finnish) 2023-09-11 20:09:41 +02:00
Eugen Rochko
971c4e5879 New translations strings.xml (Finnish) 2023-09-11 19:00:28 +02:00
Linerly
48c53ee88b Translated using Weblate (Indonesian)
Currently translated at 100.0% (18 of 18 strings)

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

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

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-09-11 14:53:07 +00:00
FineFindus
e274cf89c0 refactor: add query params 2023-09-10 21:31:06 +02:00
FineFindus
8929482466 feat: add blocks fragment 2023-09-10 21:29:40 +02:00
FineFindus
b570c8d946 feat: add mutes fragment 2023-09-10 21:19:50 +02:00
Eugen Rochko
b396ee7987 New translations strings.xml (Indonesian) 2023-09-10 15:07:27 +02:00
butterflyoffire
90856a414a Translated using Weblate (Arabic)
Currently translated at 16.6% (3 of 18 strings)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-09-07 19:23:08 +00:00
sk
9dd694ce2e Merge branch 'merge/load-more-direction' 2023-09-07 18:32:21 +02:00
FineFindus
f51f2a1197 fix: use random account id in notification endpoint (#806)
Closes https://github.com/sk22/megalodon/issues/803. This was due to registering with the actual accounId, whilst saving a random one. Once receiving a notification, the id could not be found.
2023-09-07 18:28:32 +02:00
LucasGGamerM
3020cab243 fix: fixes crashes when currentQuery is null and suicide prevention dialog is enabled (#807)
cc: @FineFindus
2023-09-07 10:03:22 +02:00
Eugen Rochko
be73c9e81c New translations strings.xml (Basque) 2023-09-07 02:28:42 +02:00
Eugen Rochko
1c2183bf1a New translations strings.xml (Slovenian) 2023-09-06 22:29:03 +02:00
LucasGGamerM
da54c93af1 Merge branch 'fix/notification-endpoint' 2023-09-06 14:34:27 -03:00
LucasGGamerM
777891ebe9 fix: fixes crashes when currentQuery is null and suicide prevention dialog is enabled
cc: @FineFindus
2023-09-06 11:24:50 -03:00
Andrewblasco
9836538562 Translated using Weblate (Spanish)
Currently translated at 100.0% (83 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/es/
2023-09-06 12:12:24 +00:00
GunChleoc
4a443d4826 Translated using Weblate (Gaelic)
Currently translated at 100.0% (83 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/gd/
2023-09-06 12:07:38 +00:00
butterflyoffire
1c93d1fa67 Translated using Weblate (French)
Currently translated at 90.3% (75 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/fr/
2023-09-06 12:07:38 +00:00
LucasGGamerM
0246059556 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (83 of 83 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-09-06 12:07:38 +00:00
butterflyoffire
46382bd8b0 Translated using Weblate (Arabic (Algeria))
Currently translated at 62.1% (51 of 82 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/ar_DZ/
2023-09-06 12:07:38 +00:00
LucasGGamerM
090d2658dd feat: also hide link card image previews according to showMediaPreview setting 2023-09-06 09:06:14 -03:00
LucasGGamerM
e47fa4f8db Merge pull request #255
fix: update timeline when showMediaPreview changes
2023-09-06 09:00:16 -03:00
FineFindus
8338fff4e5 fix: use random account id in notification endpoint
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-06 09:44:03 +02:00
FineFindus
b2d09c2ab6 fix: update timeline when showMediaPreview changes 2023-09-06 09:05:51 +02:00
LucasGGamerM
0aa4493e5c Merge remote-tracking branch 'mastodon/master' 2023-09-05 20:51:12 -03:00
LucasGGamerM
6e2a5437e8 fix: apply correct showMediaPreview setting on threads and notifications 2023-09-05 20:46:56 -03:00
LucasGGamerM
ae61007d22 fix: use correct polarization in FLAG_NO_MEDIA_PREVIEW in StatusListFragment
Wtf is wrong with this
2023-09-05 20:29:57 -03:00
LucasGGamerM
20f3c7c9db fix: use correct polarization in FLAG_NO_MEDIA_PREVIEW 2023-09-05 19:52:59 -03: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
LucasGGamerM
bbdd1c4aa9 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:00:16 -03:00
LucasGGamerM
81d13537e3 fix: fixes incorrect icon coloring on compose fragment relocated publish button 2023-09-05 15:19:46 -03:00
LucasGGamerM
b6c951c026 feat: add indicatives/hints of what type of media is on an media item without preview 2023-09-05 14:51:32 -03:00
LucasGGamerM
860cdb05e2 feat: add no alt text and sensitive media warning to images without preview 2023-09-05 14:25:20 -03:00
LucasGGamerM
e239600af6 feat: full implementation of not showing media preview in timelines 2023-09-05 11:56:56 -03:00
LucasGGamerM
d7bef67550 feat: initial steps for only show media preview setting
It contains settings, flags and settings. But no implementation just yet
2023-09-05 11:24:35 -03:00
LucasGGamerM
ad86a00fa7 fix: make changing showPostDividers setting restart the activity 2023-09-05 10:37:17 -03:00
LucasGGamerM
da13926269 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (82 of 82 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-09-05 12:21:52 +00:00
LucasGGamerM
9da0173215 Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.9% (77 of 82 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/pt_BR/
2023-09-05 12:16:25 +00:00
LucasGGamerM
cfeda06bf9 fix: make repo and donate links non-translatable 2023-09-05 09:16:07 -03:00
butterflyoffire
ca60ac6722 Translated using Weblate (Arabic (Algeria))
Currently translated at 2.9% (1 of 34 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/ar_DZ/
2023-09-05 12:09:40 +00:00
butterflyoffire
80f70bd530 Translated using Weblate (Arabic (Algeria))
Currently translated at 44.0% (164 of 372 strings)

Translation: Moshidon/values_sk
Translate-URL: https://translate.codeberg.org/projects/moshidon/values_sk/ar_DZ/
2023-09-05 12:09:40 +00:00
butterflyoffire
3982fa4835 Translated using Weblate (Arabic)
Currently translated at 0.0% (0 of 34 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/ar/
2023-09-05 12:09:40 +00:00
butterflyoffire
31e720690c Translated using Weblate (French)
Currently translated at 100.0% (372 of 372 strings)

Translation: Moshidon/values_sk
Translate-URL: https://translate.codeberg.org/projects/moshidon/values_sk/fr/
2023-09-05 12:09:40 +00:00
butterflyoffire
560c75c669 Translated using Weblate (Arabic (Algeria))
Currently translated at 13.4% (11 of 82 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/ar_DZ/
2023-09-05 12:09:40 +00:00
butterflyoffire
fb441b21e0 Translated using Weblate (Burmese)
Currently translated at 2.9% (1 of 34 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/my/
2023-09-05 12:09:40 +00:00
butterflyoffire
e2f957f985 Translated using Weblate (Chinese (Traditional))
Currently translated at 5.8% (2 of 34 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/zh_Hant/
2023-09-05 12:09:40 +00:00
butterflyoffire
a4f97a134b Translated using Weblate (Croatian)
Currently translated at 5.8% (2 of 34 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/hr/
2023-09-05 12:09:40 +00:00
butterflyoffire
18ae9efad3 Translated using Weblate (French)
Currently translated at 2.9% (1 of 34 strings)

Translation: Moshidon/metadata
Translate-URL: https://translate.codeberg.org/projects/moshidon/metadata/fr/
2023-09-05 12:09:39 +00:00
butterflyoffire
8232047c55 Translated using Weblate (French)
Currently translated at 90.2% (74 of 82 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/fr/
2023-09-05 12:09:39 +00:00
LucasGGamerM
fb3b9513f2 fix: fix window insets on ScheduledStatusListFragment
cc: @sk22
2023-09-05 08:21:06 -03:00
LucasGGamerM
2ee4b03fe8 refactor: remove DomainDisplay.java 2023-09-05 07:23:07 -03:00
LucasGGamerM
61b20eea05 Merge remote-tracking branch 'megalodon_main/main'
# Conflicts:
#	mastodon/src/main/java/org/joinmastodon/android/GlobalUserPreferences.java
#	mastodon/src/main/java/org/joinmastodon/android/model/Account.java
2023-09-05 07:12:27 -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
LucasGGamerM
0e58b00086 fix: make use of correct coloring in filled button backgrounds (again) 2023-09-04 12:13:55 -03:00
LucasGGamerM
9f18844148 fix: make use of correct coloring in filled button backgrounds 2023-09-04 11:18:36 -03:00
LucasGGamerM
d854da54fe fix: make purple be on top of pink
Me no likey pink >:C
2023-09-04 10:39:37 -03:00
LucasGGamerM
33f4dd4716 fix: compose fragment bottom drafts button being not centered 2023-09-04 10:31:01 -03:00
LucasGGamerM
93ca187f1c fix: use bigger bot icon on header display item 2023-09-04 07:56:17 -03:00
LucasGGamerM
6fd59a19e8 fix: remove duplicate variable assigning 2023-09-04 07:46:42 -03:00
LucasGGamerM
531ce568c0 Merge remote-tracking branch 'megalodon_main/main'
# Conflicts:
#	mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java
#	mastodon/src/main/res/drawable/ic_fluent_bot_20_filled.xml
#	mastodon/src/main/res/layout/display_item_header.xml
2023-09-04 07:42:25 -03:00
LucasGGamerM
c49b25454e refactor(HomeFragment): refactor long click action for cleaner code 2023-09-04 07:35:48 -03:00
LucasGGamerM
d39d5c2602 Merge pull request #252
feat: allow doubleTapToSwipe when doubleTapToSearch is disabled
2023-09-04 07:19:54 -03: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
a2d0738a68 fix: only call openSearch once without doubleTapToSearch 2023-09-03 21:47:45 +02: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
924d6a9dd9 Merge remote-tracking branch 'weblate/master'
# Conflicts:
#	mastodon/src/main/res/values-es-rES/strings_sk.xml
#	mastodon/src/main/res/values-fr-rFR/strings_sk.xml
2023-09-03 16:34:13 -03:00
butterflyoffire
816a307bc0 Translated using Weblate (Arabic (Algeria))
Currently translated at 18.3% (68 of 370 strings)

Translation: Moshidon/values_sk
Translate-URL: https://translate.codeberg.org/projects/moshidon/values_sk/ar_DZ/
2023-09-03 19:31:20 +00:00
butterflyoffire
a947a6ea26 Translated using Weblate (Arabic)
Currently translated at 18.9% (70 of 370 strings)

Translation: Moshidon/values_sk
Translate-URL: https://translate.codeberg.org/projects/moshidon/values_sk/ar/
2023-09-03 19:31:20 +00:00
LucasGGamerM
f14df2bb0f fix: allows for editing timeline badges again. fixes sk22#800 (#804) 2023-09-03 20:49:29 +02:00
LucasGGamerM
b5123ff865 feat: readd recent emoji support 2023-09-03 15:32:35 -03:00
FineFindus
ca4630e6e1 feat: always allow longtap to search 2023-09-03 16:00:11 +02:00
FineFindus
a8a1c7824d feat: allow doubleTapToSwipe in discoverfragment 2023-09-03 15:59:19 +02:00
FineFindus
0725c2a741 feat: add setting to disable double tap to search 2023-09-03 15:47:11 +02:00
LucasGGamerM
c3f3a9be7e feat: update edit note confirmation button design (again) 2023-09-03 09:23:33 -03:00
Eugen Rochko
228fdc8ffe New translations strings.xml (Swedish) 2023-09-03 11:26:37 +02:00
butterflyoffire
da2a69b4a1 Translated using Weblate (Arabic)
Currently translated at 48.7% (39 of 80 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/ar/
2023-09-03 09:20:46 +00:00
butterflyoffire
822a6a3653 Translated using Weblate (French)
Currently translated at 99.7% (369 of 370 strings)

Translation: Moshidon/values_sk
Translate-URL: https://translate.codeberg.org/projects/moshidon/values_sk/fr/
2023-09-03 09:20:46 +00:00
butterflyoffire
410f694863 Translated using Weblate (Arabic)
Currently translated at 18.3% (68 of 370 strings)

Translation: Moshidon/values_sk
Translate-URL: https://translate.codeberg.org/projects/moshidon/values_sk/ar/
2023-09-03 09:20:46 +00:00
butterflyoffire
57b2596d9f Translated using Weblate (French)
Currently translated at 83.7% (67 of 80 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/fr/
2023-09-03 09:20:45 +00:00
ca
caebce897b Translated using Weblate (Catalan)
Currently translated at 35.0% (28 of 80 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/ca/
2023-09-03 09:20:45 +00:00
LucasGGamerM
677fb4e4da fix: readds bot icon to timelines
This was accidentally removed during the great merge, but its back again
2023-09-02 21:02:11 -03:00
LucasGGamerM
ce51fc3c0d fix: allows for editing timeline badges again. fixes sk22#800 2023-09-02 20:40:55 -03:00
LucasGGamerM
0dcade767b Merge remote-tracking branch 'megalodon_main/main' 2023-09-02 20:26:22 -03:00
LucasGGamerM
f4f4cbe78b fix: fix incorrect m3_overlay alpha values 2023-09-02 20:06:56 -03:00
alextecplayz
ebb6897582 Translated using Weblate (Romanian)
Currently translated at 100.0% (370 of 370 strings)

Translation: Moshidon/values_sk
Translate-URL: https://translate.codeberg.org/projects/moshidon/values_sk/ro/
2023-09-01 22:53:06 +00:00
gallegonovato
9720a133ba Translated using Weblate (Spanish)
Currently translated at 100.0% (370 of 370 strings)

Translation: Moshidon/values_sk
Translate-URL: https://translate.codeberg.org/projects/moshidon/values_sk/es/
2023-09-01 22:53:06 +00:00
alextecplayz
29c36e90ab Translated using Weblate (Romanian)
Currently translated at 100.0% (80 of 80 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/ro/
2023-09-01 22:53:05 +00:00
gallegonovato
1b822676a8 Translated using Weblate (Spanish)
Currently translated at 100.0% (80 of 80 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/es/
2023-09-01 22:53:05 +00: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
LucasGGamerM
aeb0aa65a8 Merge remote-tracking branch 'megalodon_main/main'
# Conflicts:
#	mastodon/src/main/java/org/joinmastodon/android/api/session/AccountLocalPreferences.java
2023-09-01 14:11:19 -03: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
LucasGGamerM
74db111a4f Merge remote-tracking branch 'megalodon_main/main'
# Conflicts:
#	mastodon/src/main/java/org/joinmastodon/android/api/session/AccountLocalPreferences.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/StatusListFragment.java
2023-08-31 14:36:59 -03: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
LucasGGamerM
befa5a9f6d fix: fix alt texts not being able to be edited
fixes #70 cc: @sk22
2023-08-31 11:43:39 -03: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
Oliebol
87a9acd860 Translated using Weblate (Dutch)
Currently translated at 96.2% (77 of 80 strings)

Translation: Moshidon/values
Translate-URL: https://translate.codeberg.org/projects/moshidon/values/nl/
2023-08-31 03:53:05 +00: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
LucasGGamerM
d871d2cad8 fix: fix broken Ask before unfollowing option 2023-08-30 11:36:17 -03:00
LucasGGamerM
323018daa9 fix: fix crash when there is an error on status posting 2023-08-30 07:50:32 -03: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
LucasGGamerM
67d89f5799 fix: fix less prominent post dividers
cc: @sk22
2023-08-29 19:12:47 -03:00
LucasGGamerM
485d25f9f4 fix: undo wrong string rename
AAAAAAAAAAAAAAAAAAA
2023-08-29 10:44:18 -03:00
LucasGGamerM
c4b7262e89 Merge remote-tracking branch 'megalodon_main/main'
# Conflicts:
#	mastodon/src/main/java/org/joinmastodon/android/fragments/settings/SettingsAboutAppFragment.java
2023-08-29 10:41:09 -03:00
LucasGGamerM
7191e5a96a feat: use better account log off alert 2023-08-29 10:33:08 -03:00
LucasGGamerM
0edaffee59 fix: fix Warning item title being cut off 2023-08-29 09:05:33 -03:00
Weblate
c859d35c93 Added translation using Weblate (Norwegian Nynorsk) 2023-08-29 11:47:51 +00:00
LucasGGamerM
17a59b5db4 fix: fix hide with a warning posts without alt text 2023-08-29 08:20:11 -03: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
LucasGGamerM
7c3b4128de feat: use better color background for extended footer 2023-08-28 21:25:35 -03:00
LucasGGamerM
da5929c092 feat: improvements on the black and white theme 2023-08-28 21:14:20 -03:00
LucasGGamerM
77fca4d763 fix: fix bottom bar labels ellipsizing wrongly on devices with a smaller screen 2023-08-28 21:03:00 -03: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
LucasGGamerM
d93bcd9241 feat: use ellipsize for settings items
IDK why It can't just continue on the next line :(
2023-08-28 17:23:00 -03:00
LucasGGamerM
cfad3144f8 fix: fix the nord theme (again) 2023-08-28 16:13:43 -03:00
LucasGGamerM
69272e891e fix: use better colors for true black mode
cc: @sk22
2023-08-28 15:57:33 -03:00
LucasGGamerM
576030f262 fix: fixes inconsistent coloring on turned-off switches
cc: @sk22
2023-08-28 15:54:18 -03:00
sk
fb39f74ba5 fix bottom padding for above emoji reactions 2023-08-28 20:22:16 +02:00
LucasGGamerM
272afca0fb fix: fixes inconsistent coloring on bottom tabbar 2023-08-28 15:15:02 -03:00
sk
9bfc73d6ee fix wrong bottom padding
hopefully, lol
2023-08-28 20:04:52 +02:00
LucasGGamerM
d0e3da67a4 fix: fix wrong favorite selected coloring on nord theme 2023-08-28 14:04:13 -03:00
LucasGGamerM
1ecb9820c0 refactor: change bookmark_selected to colorBookmark 2023-08-28 12:18:25 -03: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
LucasGGamerM
8810ac52f6 Merge pull request #245
fix: small nord theme improvements
2023-08-28 11:38:30 -03:00
LucasGGamerM
9442de7e5a Merge pull request #246
fix: allow long version names
2023-08-28 11:32:37 -03:00
LucasGGamerM
4f40ecd112 Merge pull request #247
fix: display 'Lists with' with username
2023-08-28 11:31:03 -03:00
LucasGGamerM
5456f4fbea refactor: tidy things up with the show posts with missing alt text
IT DOESNT WORK YET GODDAMNIT
2023-08-28 11:30:08 -03:00
LucasGGamerM
b294c998ae Merge branch 'feature/hide_alttext'
# Conflicts:
#	mastodon/src/androidTest/java/org/joinmastodon/android/utils/StatusFilterPredicateTest.java
#	mastodon/src/main/java/org/joinmastodon/android/fragments/settings/TimeLineFragment.java
#	mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/WarningFilteredStatusDisplayItem.java
#	mastodon/src/main/java/org/joinmastodon/android/utils/StatusFilterPredicate.java
#	mastodon/src/main/res/values-de-rDE/strings_mo.xml
#	mastodon/src/main/res/values/strings_mo.xml
2023-08-28 10:15:18 -03:00
FineFindus
b7b7ef4faf fix: display 'Lists with' with username 2023-08-28 14:43:28 +02:00
FineFindus
6a736ef387 fix: allow long version names 2023-08-28 14:32:31 +02:00
FineFindus
2a7d7d2e45 fix: use single color for favorites 2023-08-28 14:08:38 +02:00
LucasGGamerM
bdf822d6a5 fix: fix haptic feedback setting not being saved 2023-08-28 09:04:15 -03:00
LucasGGamerM
a9cd67a64e fix: fix wrong coloring on the follow suggestions fragment bottom bar 2023-08-28 08:44:01 -03:00
LucasGGamerM
a3ee20f06e feat: increase roundness of the select instance button background
Yes, this is the 3rd time I do this
2023-08-28 08:33:52 -03:00
FineFindus
2158a1abae fix(theme/nord): use #2E3440 as background color 2023-08-28 13:29:32 +02:00
LucasGGamerM
52955b6c42 fix: fix wrong tap-to-reveal string 2023-08-28 08:27:42 -03:00
LucasGGamerM
8524e57ecd fix inconsistent coloring on alert dialog items
cc: @sk22
2023-08-27 20:57:29 -03:00
LucasGGamerM
639ecba380 feat: increase roundness of the Popup menus 2023-08-27 20:46:13 -03:00
LucasGGamerM
ed6961016e feat: increase roundness of the logon instance input field (again) 2023-08-27 20:41:41 -03:00
LucasGGamerM
5d1d6e4bd7 fix: fix crash when long clicking search from the search tab 2023-08-27 20:15:53 -03:00
LucasGGamerM
e87f47228f fix: readd only translate when opened settings (off by default) 2023-08-27 19:22:35 -03:00
LucasGGamerM
8e038b204c fix: readd showDividers setting 2023-08-27 19:16:42 -03:00
Eugen Rochko
900b204bb0 New translations strings.xml (Portuguese, Brazilian) 2023-08-27 16:51:00 +02:00
Eugen Rochko
17d679901a New translations strings.xml (Japanese) 2023-08-27 15:42:52 +02:00
Eugen Rochko
d8036779f8 New translations strings.xml (Japanese) 2023-08-27 14:46:15 +02:00
0que
3a35674ea2 Translated using Weblate (Russian)
Currently translated at 77.7% (14 of 18 strings)

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

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

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

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

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-08-25 14:53:06 +00:00
Eugen Rochko
f36aee44c6 New translations strings.xml (Scottish Gaelic) 2023-08-25 09:54:23 +02:00
Eugen Rochko
cd24526a9d New translations strings.xml (Swedish) 2023-08-24 17:48:37 +02:00
Eugen Rochko
a345ac1390 New translations strings.xml (Icelandic) 2023-08-24 17:48:36 +02:00
Eugen Rochko
3d987b8e1d New translations strings.xml (Thai) 2023-08-23 21:39:07 +02:00
Eugen Rochko
57043912e0 New translations strings.xml (Chinese Traditional) 2023-08-23 19:16:40 +02:00
Eugen Rochko
00aef5ea6b New translations full_description.txt (Arabic) 2023-08-23 13:02:31 +02:00
Eugen Rochko
369b69668c New translations strings.xml (Arabic) 2023-08-23 13:02:29 +02:00
Eugen Rochko
65245f4560 New translations strings.xml (Arabic) 2023-08-23 09:39:50 +02:00
Eugen Rochko
4d4fdc97d4 New translations strings.xml (French) 2023-08-23 09:39:49 +02:00
Eugen Rochko
c96577891c New translations strings.xml (Scottish Gaelic) 2023-08-23 07:00:18 +02:00
Eugen Rochko
f48b2fc9cb New translations strings.xml (Thai) 2023-08-23 07:00:13 +02:00
Eugen Rochko
2fca2580ed New translations strings.xml (Bengali) 2023-08-23 07:00:12 +02:00
Eugen Rochko
7adc1da361 New translations strings.xml (Persian) 2023-08-23 07:00:11 +02:00
Eugen Rochko
6dc24dde43 New translations strings.xml (Indonesian) 2023-08-23 07:00:10 +02:00
Eugen Rochko
4929e0e6ec New translations strings.xml (Portuguese, Brazilian) 2023-08-23 07:00:09 +02:00
Eugen Rochko
16a8b8ed71 New translations strings.xml (Icelandic) 2023-08-23 07:00:08 +02:00
Eugen Rochko
ad1412817e New translations strings.xml (Galician) 2023-08-23 07:00:07 +02:00
Eugen Rochko
d9e6bb3bea New translations strings.xml (Vietnamese) 2023-08-23 07:00:06 +02:00
Eugen Rochko
8970404638 New translations strings.xml (Chinese Traditional) 2023-08-23 07:00:05 +02:00
Eugen Rochko
2a2241d7f9 New translations strings.xml (Chinese Simplified) 2023-08-23 07:00:04 +02:00
Eugen Rochko
db1a47e8eb New translations strings.xml (Ukrainian) 2023-08-23 07:00:03 +02:00
Eugen Rochko
3e57061cef New translations strings.xml (Turkish) 2023-08-23 07:00:02 +02:00
Eugen Rochko
cd200f8450 New translations strings.xml (Slovenian) 2023-08-23 07:00:00 +02:00
Eugen Rochko
782013079f New translations strings.xml (Russian) 2023-08-23 06:59:59 +02:00
Eugen Rochko
e5db8acd66 New translations strings.xml (Polish) 2023-08-23 06:59:57 +02:00
Eugen Rochko
1a6a8019c8 New translations strings.xml (Norwegian) 2023-08-23 06:59:57 +02:00
Eugen Rochko
e935eef29f New translations strings.xml (Dutch) 2023-08-23 06:59:56 +02:00
Eugen Rochko
381defda51 New translations strings.xml (Japanese) 2023-08-23 06:59:54 +02:00
Eugen Rochko
02ae80c204 New translations strings.xml (Italian) 2023-08-23 06:59:53 +02:00
Eugen Rochko
82214b30e8 New translations strings.xml (Armenian) 2023-08-23 06:59:52 +02:00
Eugen Rochko
33a1f48602 New translations strings.xml (Greek) 2023-08-23 06:59:48 +02:00
Eugen Rochko
aee845e5cc New translations strings.xml (German) 2023-08-23 06:59:47 +02:00
Eugen Rochko
cd780f6006 New translations strings.xml (Danish) 2023-08-23 06:59:46 +02:00
Eugen Rochko
d4741fefa0 New translations strings.xml (Czech) 2023-08-23 06:59:46 +02:00
Eugen Rochko
7e1e8a2616 New translations strings.xml (Belarusian) 2023-08-23 06:59:44 +02:00
Eugen Rochko
d73c05cdfc New translations strings.xml (Arabic) 2023-08-23 06:59:43 +02:00
Eugen Rochko
78323023cb New translations strings.xml (Spanish) 2023-08-23 06:59:42 +02:00
Eugen Rochko
2cf084c98f New translations strings.xml (French) 2023-08-23 06:59:41 +02:00
Botiplz
009dc226d5 Update mastodon/src/main/res/values-de-rDE/strings_mo.xml
Co-authored-by: FineFindus <63370021+FineFindus@users.noreply.github.com>
2023-07-22 22:16:17 +02:00
Botiplz
94ab5835d8 Formatting strings_mo.xml 2023-07-22 19:51:54 +02:00
Botiplz
ae5d2a7ed3 Formatting 2023-07-22 19:50:58 +02:00
Botiplz
6ed7d24513 PR comments:
- StatusFilterPredicate sets clientFilters bases on settings
- Reverted changes on SettingsFragment
- Resources in strings_mo.xml
- removed duplicate comments
- conditional in onBind method
2023-07-22 19:41:01 +02:00
Botiplz
605ba441d3 Option "Show media posts with missing alt text" 2023-07-22 16:58:15 +02:00
285 changed files with 6861 additions and 1320 deletions

View File

@@ -13,7 +13,7 @@ jobs:
- name: Checkout Appkit Repo
uses: actions/checkout@v3
with:
repository: grishka/appkit
repository: LucasGGamerM/appkit
- name: set up JDK 17
uses: actions/setup-java@v3

0
fix-metadata-markdown-lists.sh Executable file → Normal file
View File

0
gradlew vendored Executable file → Normal file
View File

View File

@@ -16,8 +16,8 @@ android {
applicationId "org.joinmastodon.android.moshinda"
minSdk 23
targetSdk 33
versionCode 101
versionName "1.2.3+fork.101.moshinda"
versionCode 102
versionName "2.1.4+fork.102.moshinda"
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']
}
@@ -118,7 +118,7 @@ dependencies {
implementation 'me.grishka.litex:viewpager:1.0.0'
implementation 'me.grishka.litex:viewpager2:1.0.0'
implementation 'me.grishka.litex:palette:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.9'
implementation 'me.grishka.appkit:appkit:1.2.14'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8'

View File

@@ -19,7 +19,9 @@ public class StatusFilterPredicateTest {
private static final Status
hideInHomePublic = Status.ofFake(null, "hide me, please", Instant.now()),
warnInHomePublic = Status.ofFake(null, "display me with a warning", Instant.now());
warnInHomePublic = Status.ofFake(null, "display me with a warning", Instant.now()),
noAltText = Status.ofFake(null, "display me with a warning", Instant.now()),
withAltText = Status.ofFake(null, "display me with a warning", Instant.now());
static {
hideMeFilter.phrase = "hide me";
@@ -29,6 +31,12 @@ public class StatusFilterPredicateTest {
warnMeFilter.phrase = "warning";
warnMeFilter.filterAction = WARN;
warnMeFilter.context = EnumSet.of(PUBLIC, HOME);
noAltText.mediaAttachments = Attachment.createFakeAttachments("fakeurl", new ColorDrawable());
withAltText.mediaAttachments = Attachment.createFakeAttachments("fakeurl", new ColorDrawable());
for (Attachment mediaAttachment : withAltText.mediaAttachments) {
mediaAttachment.description = "Alt Text";
}
}
@Test
@@ -78,4 +86,16 @@ public class StatusFilterPredicateTest {
assertTrue("should pass because matching filter is for hiding",
new StatusFilterPredicate(allFilters, HOME, WARN).test(hideInHomePublic));
}
@Test
public void testAltTextFilterNoPass() {
assertFalse("should not pass because of no alt text",
new StatusFilterPredicate(allFilters, HOME).test(noAltText));
}
@Test
public void testAltTextFilterPass() {
assertTrue("should pass because of alt text",
new StatusFilterPredicate(allFilters, HOME).test(withAltText));
}
}

View File

@@ -18,7 +18,6 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.utils.ColorPalette;
import java.lang.reflect.Type;
import java.util.ArrayList;
@@ -27,6 +26,8 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import androidx.annotation.StringRes;
public class GlobalUserPreferences{
private static final String TAG="GlobalUserPreferences";
@@ -62,11 +63,13 @@ public class GlobalUserPreferences{
public static boolean showNavigationLabels;
public static boolean displayPronounsInTimelines, displayPronounsInThreads, displayPronounsInUserListings;
public static boolean overlayMedia;
public static boolean showSuicideHelp;
// MOSHIDON
public static boolean showDividers;
public static boolean relocatePublishButton;
public static boolean defaultToUnlistedReplies;
public static boolean doubleTapToSearch;
public static boolean doubleTapToSwipe;
public static boolean confirmBeforeReblog;
public static boolean hapticFeedback;
@@ -74,6 +77,8 @@ public class GlobalUserPreferences{
public static boolean swapBookmarkWithBoostAction;
public static boolean loadRemoteAccountFollowers;
public static boolean mentionRebloggerAutomatically;
public static boolean showPostsWithoutAlt;
public static boolean showMediaPreview;
public static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
@@ -133,6 +138,7 @@ public class GlobalUserPreferences{
displayPronounsInThreads=prefs.getBoolean("displayPronounsInThreads", true);
displayPronounsInUserListings=prefs.getBoolean("displayPronounsInUserListings", true);
overlayMedia=prefs.getBoolean("overlayMedia", false);
showSuicideHelp=prefs.getBoolean("showSuicideHelp", true);
// MOSHIDON
uniformNotificationIcon=prefs.getBoolean("uniformNotificationIcon", false);
@@ -140,6 +146,7 @@ public class GlobalUserPreferences{
relocatePublishButton=prefs.getBoolean("relocatePublishButton", true);
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
defaultToUnlistedReplies=prefs.getBoolean("defaultToUnlistedReplies", false);
doubleTapToSearch =prefs.getBoolean("doubleTapToSearch", true);
doubleTapToSwipe =prefs.getBoolean("doubleTapToSwipe", true);
replyLineAboveHeader=prefs.getBoolean("replyLineAboveHeader", true);
confirmBeforeReblog=prefs.getBoolean("confirmBeforeReblog", false);
@@ -147,6 +154,9 @@ public class GlobalUserPreferences{
swapBookmarkWithBoostAction=prefs.getBoolean("swapBookmarkWithBoostAction", false);
loadRemoteAccountFollowers=prefs.getBoolean("loadRemoteAccountFollowers", true);
mentionRebloggerAutomatically=prefs.getBoolean("mentionRebloggerAutomatically", false);
showPostsWithoutAlt=prefs.getBoolean("showPostsWithoutAlt", true);
showMediaPreview=prefs.getBoolean("showMediaPreview", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
@@ -211,19 +221,25 @@ public class GlobalUserPreferences{
.putBoolean("displayPronounsInThreads", displayPronounsInThreads)
.putBoolean("displayPronounsInUserListings", displayPronounsInUserListings)
.putBoolean("overlayMedia", overlayMedia)
.putBoolean("showSuicideHelp", showSuicideHelp)
// MOSHIDON
.putBoolean("defaultToUnlistedReplies", defaultToUnlistedReplies)
.putBoolean("doubleTapToSearch", doubleTapToSearch)
.putBoolean("doubleTapToSwipe", doubleTapToSwipe)
.putBoolean("compactReblogReplyLine", compactReblogReplyLine)
.putBoolean("replyLineAboveHeader", replyLineAboveHeader)
.putBoolean("confirmBeforeReblog", confirmBeforeReblog)
.putBoolean("swapBookmarkWithBoostAction", swapBookmarkWithBoostAction)
.putBoolean("loadRemoteAccountFollowers", loadRemoteAccountFollowers)
.putBoolean("hapticFeedback", hapticFeedback)
.putBoolean("mentionRebloggerAutomatically", mentionRebloggerAutomatically)
.putBoolean("showDividers", showDividers)
.putBoolean("relocatePublishButton", relocatePublishButton)
.putBoolean("enableDeleteNotifications", enableDeleteNotifications)
.putBoolean("showPostsWithoutAlt", showPostsWithoutAlt)
.putBoolean("showMediaPreview", showMediaPreview)
.putInt("theme", theme.ordinal())
.apply();
@@ -281,8 +297,8 @@ public class GlobalUserPreferences{
public enum ColorPreference{
MATERIAL3,
PINK,
PURPLE,
PINK,
GREEN,
BLUE,
BROWN,

View File

@@ -151,7 +151,7 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
}
public void openSearchQuery(String q, String accountID, int progressText, boolean fromSearch){
new GetSearchResults(q, null, true)
new GetSearchResults(q, null, true, null, 0, 0)
.setCallback(new Callback<>(){
@Override
public void onSuccess(SearchResults result){

View File

@@ -182,6 +182,8 @@ public class PushNotificationReceiver extends BroadcastReceiver{
List<NotificationChannel> channels=Arrays.stream(PushNotification.Type.values())
.map(type->{
NotificationChannel channel=new NotificationChannel(accountID+"_"+type, context.getString(type.localizedName), NotificationManager.IMPORTANCE_DEFAULT);
channel.setLightColor(context.getColor(R.color.primary_700));
channel.enableLights(true);
channel.setGroup(accountID);
return channel;
})
@@ -211,6 +213,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
.setShowWhen(true)
.setCategory(Notification.CATEGORY_SOCIAL)
.setAutoCancel(true)
.setLights(context.getColor(R.color.primary_700), 500, 1000)
.setColor(context.getColor(R.color.shortcut_icon_background));
if (!GlobalUserPreferences.uniformNotificationIcon) {
@@ -336,11 +339,11 @@ public class PushNotificationReceiver extends BroadcastReceiver{
CreateStatus.Request req=new CreateStatus.Request();
req.status = initialText + input.toString();
req.language = preferences.postingDefaultLanguage;
req.visibility = preferences.postingDefaultVisibility;
req.language = notification.status.language;
req.visibility = (notification.status.visibility == StatusPrivacy.PUBLIC && GlobalUserPreferences.defaultToUnlistedReplies ? StatusPrivacy.UNLISTED : notification.status.visibility);
req.inReplyToId = notification.status.id;
if (!notification.status.spoilerText.isEmpty() &&
if (notification.status.hasSpoiler() &&
(GlobalUserPreferences.prefixReplies == ALWAYS
|| (GlobalUserPreferences.prefixReplies == TO_OTHERS && !ownID.equals(notification.status.account.id)))
&& !notification.status.spoilerText.startsWith("re: ")) {

View File

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

View File

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

View File

@@ -6,6 +6,7 @@ import org.joinmastodon.android.E;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.api.requests.statuses.SetStatusBookmarked;
import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
import org.joinmastodon.android.api.requests.statuses.SetStatusMuted;
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.model.Status;
@@ -23,6 +24,7 @@ public class StatusInteractionController{
private final HashMap<String, SetStatusFavorited> runningFavoriteRequests=new HashMap<>();
private final HashMap<String, SetStatusReblogged> runningReblogRequests=new HashMap<>();
private final HashMap<String, SetStatusBookmarked> runningBookmarkRequests=new HashMap<>();
private final HashMap<String, SetStatusMuted> runningMuteRequests=new HashMap<>();
public StatusInteractionController(String accountID, boolean updateCounters) {
this.accountID=accountID;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
public class SetStatusMuted extends MastodonAPIRequest<Status>{
public SetStatusMuted(String id, boolean muted){
super(HttpMethod.POST, "/statuses/"+id+"/"+(muted ? "mute" : "unmute"), Status.class);
setRequestBody(new Object());
}
}

View File

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

View File

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

View File

@@ -42,7 +42,7 @@ public class AccountLocalPreferences{
public boolean keepOnlyLatestNotification;
public boolean emojiReactionsEnabled;
public boolean showEmojiReactionsInLists;
public ShowEmojiReactions showEmojiReactions;
private final static Type recentLanguagesType = new TypeToken<ArrayList<String>>() {}.getType();
private final static Type timelinesType = new TypeToken<ArrayList<TimelineDefinition>>() {}.getType();
@@ -73,7 +73,7 @@ public class AccountLocalPreferences{
timelineReplyVisibility=prefs.getString("timelineReplyVisibility", null);
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma());
showEmojiReactionsInLists=prefs.getBoolean("showEmojiReactionsInLists", false);
showEmojiReactions=ShowEmojiReactions.valueOf(prefs.getString("showEmojiReactions", ShowEmojiReactions.HIDE_EMPTY.name()));
// MOSHIDON
recentEmojis=fromJson(prefs.getString("recentEmojis", "{}"), recentEmojisType, new HashMap<>());
@@ -109,10 +109,16 @@ public class AccountLocalPreferences{
.putString("timelineReplyVisibility", timelineReplyVisibility)
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
.putBoolean("emojiReactionsEnabled", emojiReactionsEnabled)
.putBoolean("showEmojiReactionsInLists", showEmojiReactionsInLists)
.putString("showEmojiReactions", showEmojiReactions.name())
// MOSHIDON
.putString("recentEmojis", gson.toJson(recentEmojis))
.apply();
}
public enum ShowEmojiReactions{
HIDE_EMPTY,
ONLY_OPENED,
ALWAYS
}
}

View File

@@ -146,6 +146,9 @@ public class AccountSession{
@Override
public void onError(ErrorResponse error){
Log.w(TAG, "Failed to load preferences for account "+getID()+": "+error);
if (preferences==null)
preferences=new Preferences();
preferencesFromAccountSource(self);
}
})
.exec(getID());
@@ -216,7 +219,7 @@ public class AccountSession{
public void savePreferencesIfPending(){
if(preferencesNeedSaving){
new UpdateAccountCredentialsPreferences(preferences, null, null)
new UpdateAccountCredentialsPreferences(preferences, null, self.discoverable, self.source.indexable)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Account result){
@@ -310,4 +313,14 @@ public class AccountSession{
.authority(getInstance().map(i -> i.normalizedUri).orElse(domain))
.build();
}
public String getDefaultAvatarUrl() {
return getInstance()
.map(instance->"https://"+domain+(instance.isAkkoma() ? "/images/avi.png" : "/avatars/original/missing.png"))
.orElse("");
}
public void updateAccountInfo(){
AccountSessionManager.getInstance().updateSessionLocalInfo(this);
}
}

View File

@@ -315,7 +315,7 @@ public class AccountSessionManager{
}
private void updateSessionLocalInfo(AccountSession session){
public void updateSessionLocalInfo(AccountSession session){
new GetOwnAccount()
.setCallback(new Callback<>(){
@Override

View File

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

View File

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

View File

@@ -0,0 +1,15 @@
package org.joinmastodon.android.events;
import org.joinmastodon.android.model.Status;
public class StatusMuteChangedEvent{
public String id;
public boolean muted;
public Status status;
public StatusMuteChangedEvent(Status s){
id=s.id;
muted=s.muted;
status=s;
}
}

View File

@@ -44,6 +44,7 @@ import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.PollFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.PollOptionStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.PreviewlessMediaGridStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.SpoilerStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
@@ -51,6 +52,7 @@ import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
import org.joinmastodon.android.ui.utils.PreviewlessMediaAttachmentViewController;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.utils.ProvidesAssistContent;
import org.joinmastodon.android.utils.TypedObjectPool;
@@ -90,6 +92,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
protected HashMap<String, Relationship> relationships=new HashMap<>();
protected Rect tmpRect=new Rect();
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, PreviewlessMediaAttachmentViewController> previewlessAttachmentViewsPool=new TypedObjectPool<>(this::makeNewPreviewlessMediaAttachmentView);
protected boolean currentlyScrolling;
public BaseStatusListFragment(){
@@ -280,6 +284,79 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
});
}
public void openPreviewlessMediaPhotoViewer(String parentID, Status _status, int attachmentIndex, PreviewlessMediaGridStatusDisplayItem.Holder gridHolder){
final Status status=_status.getContentStatus();
currentPhotoViewer=new PhotoViewer(getActivity(), status.mediaAttachments, attachmentIndex, new PhotoViewer.Listener(){
private PreviewlessMediaAttachmentViewController transitioningHolder;
@Override
public void setPhotoViewVisibility(int index, boolean visible){
}
@Override
public boolean startPhotoViewTransition(int index, @NonNull Rect outRect, @NonNull int[] outCornerRadius){
PreviewlessMediaAttachmentViewController holder=findPhotoViewHolder(index);
if(holder!=null && list!=null){
transitioningHolder=holder;
View view=transitioningHolder.inner;
int[] pos={0, 0};
view.getLocationOnScreen(pos);
outRect.set(pos[0], pos[1], pos[0]+view.getWidth(), pos[1]+view.getHeight());
list.setClipChildren(false);
gridHolder.setClipChildren(false);
transitioningHolder.view.setElevation(1f);
return true;
}
return false;
}
@Override
public void setTransitioningViewTransform(float translateX, float translateY, float scale){
View view=transitioningHolder.inner;
view.setTranslationX(translateX);
view.setTranslationY(translateY);
view.setScaleX(scale);
view.setScaleY(scale);
}
@Override
public void endPhotoViewTransition(){
View view=transitioningHolder.inner;
view.setTranslationX(0f);
view.setTranslationY(0f);
view.setScaleX(1f);
view.setScaleY(1f);
transitioningHolder.view.setElevation(0f);
if(list!=null)
list.setClipChildren(true);
gridHolder.setClipChildren(true);
transitioningHolder=null;
}
@Nullable
@Override
public Drawable getPhotoViewCurrentDrawable(int index){
return null;
}
@Override
public void photoViewerDismissed(){
currentPhotoViewer=null;
}
@Override
public void onRequestPermissions(String[] permissions){
requestPermissions(permissions, PhotoViewer.PERMISSION_REQUEST);
}
private PreviewlessMediaAttachmentViewController findPhotoViewHolder(int index){
return gridHolder.getViewController(index);
}
});
}
@Override
public @Nullable View getFab() {
if (getParentFragment() instanceof HasFab l) return l.getFab();
@@ -622,7 +699,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
}
}
public void onGapClick(GapStatusDisplayItem.Holder item){}
public void onGapClick(GapStatusDisplayItem.Holder item, boolean downwards){}
public void onWarningClick(WarningFilteredStatusDisplayItem.Holder warning){
int startPos = warning.getAbsoluteAdapterPosition();
@@ -768,10 +845,18 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
return new MediaAttachmentViewController(getActivity(), type);
}
private PreviewlessMediaAttachmentViewController makeNewPreviewlessMediaAttachmentView(MediaGridStatusDisplayItem.GridItemType type){
return new PreviewlessMediaAttachmentViewController(getActivity(), type);
}
public TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> getAttachmentViewsPool(){
return attachmentViewsPool;
}
public TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, PreviewlessMediaAttachmentViewController> getPreviewlessAttachmentViewsPool(){
return previewlessAttachmentViewsPool;
}
@Override
public void onProvideAssistContent(AssistContent assistContent) {
assistContent.setWebUri(getWebUri(getSession().getInstanceUri().buildUpon()));
@@ -848,7 +933,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
{
dividerPaint.setColor(UiUtils.getThemeColor(getActivity(), GlobalUserPreferences.showDividers ? R.attr.colorM3OutlineVariant : R.attr.colorM3Surface));
dividerPaint.setStyle(Paint.Style.STROKE);
dividerPaint.setStrokeWidth(V.dp(0.5f));
dividerPaint.setStrokeWidth(V.dp(1f));
}
@Override

View File

@@ -465,7 +465,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
hasSpoiler=true;
spoilerWrap.setVisibility(View.VISIBLE);
spoilerBtn.setSelected(true);
}else if(editingStatus!=null && !TextUtils.isEmpty(editingStatus.spoilerText)){
}else if(editingStatus!=null && editingStatus.hasSpoiler()){
hasSpoiler=true;
spoilerWrap.setVisibility(View.VISIBLE);
spoilerEdit.setText(getArguments().getString("sourceSpoiler", editingStatus.spoilerText));
@@ -737,7 +737,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
view.findViewById(R.id.time).setVisibility(time==null ? View.GONE : View.VISIBLE);
if(time!=null) ((TextView) view.findViewById(R.id.time)).setText(time);
if (status.spoilerText != null && !status.spoilerText.isBlank()) {
if (status.hasSpoiler()) {
TextView replyToSpoiler = view.findViewById(R.id.reply_to_spoiler);
replyToSpoiler.setVisibility(View.VISIBLE);
replyToSpoiler.setText(status.spoilerText);
@@ -1171,6 +1171,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
req.scheduledAt=scheduledAt;
if(!mediaViewController.isEmpty()){
req.mediaIds=mediaViewController.getAttachmentIDs();
if(editingStatus != null){
req.mediaAttributes=mediaViewController.getAttachmentAttributes();
}
}
// ask whether to publish now when editing an existing draft
if (!force && editingStatus != null && scheduledAt != null && scheduledAt.isAfter(DRAFTS_AFTER_INSTANT)) {
@@ -1291,7 +1294,13 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
wm.removeView(sendingOverlay);
sendingOverlay=null;
V.setVisibilityAnimated(sendProgress, View.GONE);
if(GlobalUserPreferences.relocatePublishButton) {
publishButtonRelocated.setEnabled(true);
} else {
publishButton.setEnabled(true);
}
if(error instanceof MastodonErrorResponse me){
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.post_failed)
@@ -1410,6 +1419,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
boolean usePhotoPicker=photoPicker && UiUtils.isPhotoPickerAvailable();
if(usePhotoPicker){
intent=new Intent(MediaStore.ACTION_PICK_IMAGES);
if(mediaViewController.getMaxAttachments()-mediaViewController.getMediaAttachmentsCount()>1)
intent.putExtra(MediaStore.EXTRA_PICK_IMAGES_MAX, mediaViewController.getMaxAttachments()-mediaViewController.getMediaAttachmentsCount());
}else{
intent=new Intent(Intent.ACTION_GET_CONTENT);
@@ -1589,7 +1599,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
} else {
draftsBtn.setImageDrawable(getContext().getDrawable(GlobalUserPreferences.relocatePublishButton ? R.drawable.ic_fluent_clock_24_regular : R.drawable.ic_fluent_clock_20_regular));
if(GlobalUserPreferences.relocatePublishButton){
publishButtonRelocated.setImageResource(R.drawable.ic_fluent_send_24_selector);
publishButtonRelocated.setImageResource(R.drawable.ic_fluent_send_24_regular);
}
resetPublishButtonText();
}

View File

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

View File

@@ -274,16 +274,21 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
private boolean setTagListContent(NachoTextView editText, @Nullable List<String> tags) {
if (tags == null || tags.isEmpty()) return false;
editText.setText(String.join(",", tags));
editText.setText(tags);
editText.chipifyAllUnterminatedTokens();
return true;
}
private NachoTextView prepareChipTextView(NachoTextView nacho) {
nacho.addChipTerminator(',', BEHAVIOR_CHIPIFY_ALL);
nacho.addChipTerminator('\n', BEHAVIOR_CHIPIFY_ALL);
nacho.addChipTerminator(' ', BEHAVIOR_CHIPIFY_ALL);
nacho.addChipTerminator(';', BEHAVIOR_CHIPIFY_ALL);
//Ill Be Back
nacho.setChipTerminators(
Map.of(
',', BEHAVIOR_CHIPIFY_ALL,
'\n', BEHAVIOR_CHIPIFY_ALL,
' ', BEHAVIOR_CHIPIFY_ALL,
';', BEHAVIOR_CHIPIFY_ALL
)
);
nacho.enableEditChipOnTouch(true, true);
nacho.setOnFocusChangeListener((v, hasFocus) -> nacho.chipifyAllUnterminatedTokens());
return nacho;
@@ -379,7 +384,7 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
mainHashtag = name;
name = null;
}
if (TextUtils.isEmpty(mainHashtag)) {
if (TextUtils.isEmpty(mainHashtag) && (item != null && item.getType() == TimelineDefinition.TimelineType.HASHTAG)) {
Toast.makeText(ctx, R.string.sk_add_timeline_tag_error_empty, Toast.LENGTH_SHORT).show();
onSave.accept(null);
return;

View File

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

View File

@@ -17,8 +17,10 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
import org.joinmastodon.android.api.requests.accounts.GetFollowRequests;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.text.HtmlParser;
@@ -357,8 +359,9 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
public AccountWrapper(Account account){
this.account=account;
if(!TextUtils.isEmpty(account.avatar))
avaRequest=new UrlImageLoaderRequest(account.avatar, V.dp(50), V.dp(50));
avaRequest=new UrlImageLoaderRequest(
TextUtils.isEmpty(account.avatar) ? AccountSessionManager.get(getAccountID()).getDefaultAvatarUrl() : account.avatar,
V.dp(50), V.dp(50));
if(!TextUtils.isEmpty(account.header))
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);

View File

@@ -13,18 +13,29 @@ import android.widget.Toast;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.filters.CreateFilter;
import org.joinmastodon.android.api.requests.filters.DeleteFilter;
import org.joinmastodon.android.api.requests.filters.GetFilters;
import org.joinmastodon.android.api.requests.tags.GetHashtag;
import org.joinmastodon.android.api.requests.tags.SetHashtagFollowed;
import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline;
import org.joinmastodon.android.events.HashtagUpdatedEvent;
import org.joinmastodon.android.fragments.settings.EditFilterFragment;
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 org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import org.parceler.Parcels;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import me.grishka.appkit.Nav;
@@ -41,6 +52,8 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
private boolean following;
private boolean localOnly;
private MenuItem followButton;
private MenuItem muteButton;
private Optional<Filter> filter = Optional.empty();
@Override
protected boolean wantsComposeButton() {
@@ -72,13 +85,19 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
E.post(new HashtagUpdatedEvent(hashtag, following));
}
private void updateMuteState(boolean newMute) {
muteButton.setTitle(getString(newMute ? R.string.unmute_user : R.string.mute_user, "#" + hashtag));
muteButton.setIcon(newMute ? R.drawable.ic_fluent_speaker_2_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.hashtag_timeline, menu);
super.onCreateOptionsMenu(menu, inflater);
followButton = menu.findItem(R.id.follow_hashtag);
updateFollowingState(following);
muteButton = menu.findItem(R.id.mute_hashtag);
updateMuteState(filter.isPresent());
new GetHashtag(hashtag).setCallback(new Callback<>() {
@Override
public void onSuccess(Hashtag hashtag) {
@@ -92,6 +111,20 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
error.showToast(getActivity());
}
}).exec(accountID);
new GetFilters().setCallback(new Callback<>() {
@Override
public void onSuccess(List<Filter> filters) {
if (getActivity() == null) return;
filter=filters.stream().filter(filter->filter.title.equals("#"+hashtag)).findAny();
updateMuteState(filter.isPresent());
}
@Override
public void onError(ErrorResponse error) {
error.showToast(getActivity());
}
}).exec(accountID);
}
@@ -116,10 +149,58 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
}
}).exec(accountID);
return true;
} else if (item.getItemId() == R.id.mute_hashtag) {
showMuteDialog(filter.isPresent());
return true;
}
return false;
}
private void showMuteDialog(boolean mute) {
UiUtils.showConfirmationAlert(getContext(),
mute ? R.string.mo_unmute_hashtag : R.string.mo_mute_hashtag,
mute ? R.string.mo_confirm_to_unmute_hashtag : R.string.mo_confirm_to_mute_hashtag,
mute ? R.string.do_unmute : R.string.do_mute,
mute ? R.drawable.ic_fluent_speaker_2_28_regular : R.drawable.ic_fluent_speaker_off_28_regular,
mute ? this::unmuteHashtag : this::muteHashtag
);
}
private void unmuteHashtag() {
//safe to get, this only called if filter is present
new DeleteFilter(filter.get().id).setCallback(new Callback<>(){
@Override
public void onSuccess(Void result){
filter=Optional.empty();
updateMuteState(false);
}
@Override
public void onError(ErrorResponse error){
error.showToast(getContext());
}
}).exec(accountID);
}
private void muteHashtag() {
FilterKeyword hashtagFilter=new FilterKeyword();
hashtagFilter.wholeWord=true;
hashtagFilter.keyword="#"+hashtag;
new CreateFilter("#"+hashtag, EnumSet.of(FilterContext.HOME), FilterAction.HIDE, 0 , List.of(hashtagFilter)).setCallback(new Callback<>(){
@Override
public void onSuccess(Filter result){
filter=Optional.of(result);
updateMuteState(true);
}
@Override
public void onError(ErrorResponse error){
error.showToast(getContext());
}
}).exec(accountID);
}
@Override
protected TimelineDefinition makeTimelineDefinition() {
return TimelineDefinition.ofHashtag(hashtag);

View File

@@ -189,6 +189,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
});
}
}
tabBar.selectTab(currentTab);
return content;
}
@@ -269,7 +270,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
private void onTabSelected(@IdRes int tab){
Fragment newFragment=fragmentForTab(tab);
if(tab==currentTab){
if (tab == R.id.tab_search)
if (tab == R.id.tab_search && GlobalUserPreferences.doubleTapToSearch)
discoverFragment.openSearch();
else if(newFragment instanceof ScrollableToTop scrollable)
scrollable.scrollToTop();
@@ -309,8 +310,10 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
return true;
}
if(tab==R.id.tab_search){
if(currentTab!=R.id.tab_search){
onTabSelected(R.id.tab_search);
tabBar.selectTab(R.id.tab_search);
}
discoverFragment.openSearch();
return true;
}

View File

@@ -13,25 +13,24 @@ import org.joinmastodon.android.api.requests.markers.SaveMarkers;
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.TimelineMarkers;
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.V;
public class HomeTimelineFragment extends StatusListFragment {
private HomeTabFragment parent;
@@ -176,15 +175,23 @@ public class HomeTimelineFragment extends StatusListFragment {
}
@Override
public void onGapClick(GapStatusDisplayItem.Holder item){
public void onGapClick(GapStatusDisplayItem.Holder item, boolean downwards){
if(dataLoading)
return;
item.getItem().loading=true;
V.setVisibilityAnimated(item.progress, View.VISIBLE);
V.setVisibilityAnimated(item.text, View.GONE);
GapStatusDisplayItem gap=item.getItem();
gap.loading=true;
dataLoading=true;
currentRequest=new GetHomeTimeline(item.getItemID(), null, 20, null, getLocalPrefs().timelineReplyVisibility)
String maxID = null;
String minID = null;
if (downwards) {
maxID = item.getItemID();
} else {
int gapPos=displayItems.indexOf(gap);
StatusDisplayItem nextItem=displayItems.get(gapPos + 1);
minID=nextItem.parentID;
}
currentRequest=new GetHomeTimeline(maxID, minID, 20, null, getLocalPrefs().timelineReplyVisibility)
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Status> result){
@@ -204,6 +211,7 @@ public class HomeTimelineFragment extends StatusListFragment {
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus), false);
}
}else{
if(downwards) {
Set<String> idsBelowGap=new HashSet<>();
boolean belowGap=false;
int gapPostIndex=0;
@@ -229,19 +237,16 @@ public class HomeTimelineFragment extends StatusListFragment {
}else{
result=result.subList(0, endIndex);
}
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.HOME);
List<StatusDisplayItem> targetList=displayItems.subList(gapPos, gapPos+1);
targetList.clear();
List<Status> insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1);
StatusFilterPredicate filterPredicate=new StatusFilterPredicate(accountID, getFilterContext());
for(Status s:result){
if(idsBelowGap.contains(s.id))
break;
if(typeFilterPredicate(s) && filterPredicate.test(s)){
targetList.addAll(buildDisplayItems(s));
insertedPosts.add(s);
}
}
AccountSessionManager.get(accountID).filterStatuses(insertedPosts, getFilterContext());
if(targetList.isEmpty()){
// oops. We didn't add new posts, but at least we know there are none.
adapter.notifyItemRemoved(getMainAdapterOffset()+gapPos);
@@ -250,6 +255,52 @@ public class HomeTimelineFragment extends StatusListFragment {
adapter.notifyItemRangeInserted(getMainAdapterOffset()+gapPos+1, targetList.size()-1);
}
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(insertedPosts, false);
} else {
String aboveGapID = gap.parentID;
int gapPostIndex = 0;
for (;gapPostIndex<data.size();gapPostIndex++){
if (Objects.equals(aboveGapID, data.get(gapPostIndex).id)) {
break;
}
}
// find if there's an overlap between the new data and the current data
int indexOfGapInResponse = 0;
for (;indexOfGapInResponse<result.size();indexOfGapInResponse++){
if (Objects.equals(aboveGapID, result.get(indexOfGapInResponse).id)) {
break;
}
}
// there is an overlap between new and current data
List<StatusDisplayItem> targetList=displayItems.subList(gapPos, gapPos+1);
if(indexOfGapInResponse<result.size()){
result=result.subList(indexOfGapInResponse+1,result.size());
Optional<Status> gapStatus=data.stream()
.filter(s->Objects.equals(s.id, gap.parentID))
.findFirst();
if (gapStatus.isPresent()) {
gapStatus.get().hasGapAfter=false;
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(Collections.singletonList(gapStatus.get()), false);
}
targetList.clear();
} else {
gap.loading=false;
}
List<Status> insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1);
for(Status s:result){
targetList.addAll(buildDisplayItems(s));
insertedPosts.add(s);
}
AccountSessionManager.get(accountID).filterStatuses(insertedPosts, FilterContext.HOME);
if(targetList.isEmpty()){
// oops. We didn't add new posts, but at least we know there are none.
adapter.notifyItemRemoved(getMainAdapterOffset()+gapPos);
}else{
adapter.notifyItemChanged(getMainAdapterOffset()+gapPos);
adapter.notifyItemRangeInserted(getMainAdapterOffset()+gapPos+1, targetList.size()-1);
}
list.scrollToPosition(getMainAdapterOffset()+gapPos+targetList.size());
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(insertedPosts, false);
}
}
}

View File

@@ -2,6 +2,8 @@ package org.joinmastodon.android.fragments;
import android.os.Bundle;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toolbar;
import org.joinmastodon.android.R;
@@ -38,13 +40,12 @@ public abstract class MastodonRecyclerFragment<T> extends BaseRecyclerFragment<T
@CallSuper
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
if (getParentFragment() instanceof HasElevationOnScrollListener elevator)
list.addOnScrollListener(elevator.getElevationOnScrollListener());
else if(wantsElevationOnScrollEffect())
if(wantsElevationOnScrollEffect())
list.addOnScrollListener(elevationOnScrollListener=new ElevationOnScrollListener((FragmentRootLinearLayout) view, getViewsForElevationEffect()));
if(refreshLayout!=null)
if(refreshLayout!=null){
setRefreshLayoutColors(refreshLayout);
}
}
@Override
@CallSuper

View File

@@ -15,6 +15,7 @@ import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
@@ -27,6 +28,7 @@ import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.NotificationHeaderStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
import org.joinmastodon.android.ui.utils.InsetStatusItemDecoration;
import org.joinmastodon.android.ui.utils.UiUtils;
@@ -36,6 +38,7 @@ import org.parceler.Parcels;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -43,7 +46,6 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.views.FragmentRootLinearLayout;
public class NotificationsListFragment extends BaseStatusListFragment<Notification> {
private boolean onlyMentions;
@@ -92,18 +94,18 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
}else{
titleItem=new NotificationHeaderStatusDisplayItem(n.id, this, n, accountID);
}
if (n.type == Notification.Type.FOLLOW_REQUEST) {
if (n.type == Notification.Type.FOLLOW_REQUEST || n.type == Notification.Type.FOLLOW) {
ArrayList<StatusDisplayItem> items = new ArrayList<>();
items.add(titleItem);
items.add(new AccountCardStatusDisplayItem(n.id, this, n.account, n));
items.add(new AccountCardStatusDisplayItem(n.id, this, accountID, n.account, n));
return items;
}
if(n.status!=null){
int flags=titleItem==null ? 0 : (StatusDisplayItem.FLAG_NO_FOOTER | StatusDisplayItem.FLAG_INSET | StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS); // | StatusDisplayItem.FLAG_NO_HEADER);
if (GlobalUserPreferences.spectatorMode)
flags |= StatusDisplayItem.FLAG_NO_FOOTER;
if (!getLocalPrefs().showEmojiReactionsInLists)
flags |= StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS;
if (!GlobalUserPreferences.showMediaPreview)
flags |= StatusDisplayItem.FLAG_NO_MEDIA_PREVIEW;
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, null, flags);
if(titleItem!=null)
items.add(0, titleItem);
@@ -133,6 +135,13 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
public void onSuccess(PaginatedResponse<List<Notification>> result){
if(getActivity()==null)
return;
Set<String> needRelationships=result.items.stream()
.filter(ntf->ntf.status==null && !relationships.containsKey(ntf.account.id))
.map(ntf->ntf.account.id)
.collect(Collectors.toSet());
loadRelationships(needRelationships);
maxID=result.maxID;
onDataLoaded(result.items.stream().filter(n->n.type!=null).collect(Collectors.toList()), !result.items.isEmpty());
reloadingFromCache=false;
@@ -143,6 +152,17 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
});
}
@Override
protected void onRelationshipsLoaded(){
if(getActivity()==null)
return;
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof AccountCardStatusDisplayItem.Holder accountHolder)
accountHolder.rebind();
}
}
@Override
protected void onShown(){
super.onShown();
@@ -248,8 +268,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
@Subscribe
public void onStatusCountersUpdated(StatusCountersUpdatedEvent ev){
for(Notification n:data){
if (n.status == null) continue;
if(n.status.getContentStatus().id.equals(ev.id)){
if(n.status!=null && n.status.getContentStatus().id.equals(ev.id)){
n.status.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateNotification(n);
for(int i=0;i<list.getChildCount();i++){
@@ -258,15 +277,36 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
footer.rebind();
}else if(holder instanceof ExtendedFooterStatusDisplayItem.Holder footer && footer.getItem().status==n.status.getContentStatus()){
footer.rebind();
}else if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && ev.viewHolder!=holder){
reactions.rebind();
}
}
}
}
for(Notification n:preloadedData){
if (n.status == null) continue;
if(n.status.getContentStatus().id.equals(ev.id)){
if(n.status!=null && n.status.getContentStatus().id.equals(ev.id)){
n.status.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateNotification(n);
}
}
}
@Subscribe
public void onEmojiReactionsChanged(EmojiReactionsUpdatedEvent ev){
for(Notification n : data){
if(n.status!=null && n.status.getContentStatus().id.equals(ev.id)){
n.status.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateNotification(n);
for(int i=0; i<list.getChildCount(); i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && reactions.getItem().status==n.status.getContentStatus() && ev.viewHolder!=holder){
reactions.rebind();
}else if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(n.getID())){
text.rebind();
}
}
}
}
for(Notification n : preloadedData){
if(n.status!=null && n.status.getContentStatus().id.equals(ev.id)){
n.status.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateNotification(n);
}

View File

@@ -44,7 +44,7 @@ import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareFragment{
static final int MAX_FIELDS=Integer.MAX_VALUE;
static final int MAX_FIELDS=4;
public UsableRecyclerView list;
private List<AccountField> fields=Collections.emptyList();

View File

@@ -4,10 +4,12 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Fragment;
import android.app.assist.AssistContent;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.Color;
@@ -66,8 +68,10 @@ import org.joinmastodon.android.api.requests.accounts.SetPrivateNote;
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
import org.joinmastodon.android.api.requests.instance.GetInstance;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.account_list.BlocksListFragment;
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
import org.joinmastodon.android.fragments.account_list.FollowingListFragment;
import org.joinmastodon.android.fragments.account_list.MutesListFragment;
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
import org.joinmastodon.android.fragments.settings.SettingsServerFragment;
import org.joinmastodon.android.model.Account;
@@ -135,6 +139,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private CoverImageView cover;
private View avatarBorder;
private TextView name, username, bio, followersCount, followersLabel, followingCount, followingLabel;
private ImageView lockIcon, botIcon;
private ProgressBarButton actionButton, notifyButton;
private ViewPager2 pager;
private NestedRecyclerScrollView scrollView;
@@ -150,7 +155,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private TextView followsYouView;
private ViewGroup rolesView;
private LinearLayout countersLayout;
private View nameEditWrap, bioEditWrap;
private View nameEditWrap, bioEditWrap, usernameWrap;
private View tabsDivider;
private View actionButtonWrap;
private CustomDrawingOrderLinearLayout scrollableContent;
@@ -237,6 +242,8 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
avatarBorder=content.findViewById(R.id.avatar_border);
name=content.findViewById(R.id.name);
username=content.findViewById(R.id.username);
lockIcon=content.findViewById(R.id.lock_icon);
botIcon=content.findViewById(R.id.bot_icon);
bio=content.findViewById(R.id.bio);
followersCount=content.findViewById(R.id.followers_count);
followersLabel=content.findViewById(R.id.followers_label);
@@ -254,6 +261,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
bioEdit=content.findViewById(R.id.bio_edit);
nameEditWrap=content.findViewById(R.id.name_edit_wrap);
bioEditWrap=content.findViewById(R.id.bio_edit_wrap);
usernameWrap=content.findViewById(R.id.username_wrap);
actionProgress=content.findViewById(R.id.action_progress);
notifyProgress=content.findViewById(R.id.notify_progress);
fab=content.findViewById(R.id.fab);
@@ -374,6 +382,19 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
if (position == 4) tab.view.setVisibility(View.GONE);
}
});
tabbar.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
@Override
public void onTabSelected(TabLayout.Tab tab){}
@Override
public void onTabUnselected(TabLayout.Tab tab){}
@Override
public void onTabReselected(TabLayout.Tab tab){
if(getFragmentForPage(tab.getPosition()) instanceof ScrollableToTop stt)
stt.scrollToTop();
}
});
cover.setOutlineProvider(new ViewOutlineProvider(){
@Override
@@ -409,7 +430,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
followersBtn.setOnClickListener(this::onFollowersOrFollowingClick);
followingBtn.setOnClickListener(this::onFollowersOrFollowingClick);
username.setOnClickListener(v->{
content.findViewById(R.id.username_wrap).setOnClickListener(v->{
try {
new GetInstance()
.setCallback(new Callback<>(){
@@ -430,11 +451,11 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
.execRemote(Uri.parse(account.url).getHost());
} catch (NullPointerException ignored) {
// maybe the url was malformed?
Toast.makeText(getContext(), R.string.error, Toast.LENGTH_SHORT);
Toast.makeText(getContext(), R.string.error, Toast.LENGTH_SHORT).show();
}
});
username.setOnLongClickListener(v->{
content.findViewById(R.id.username_wrap).setOnLongClickListener(v->{
String usernameString=account.acct;
if(!usernameString.contains("@")){
usernameString+="@"+domain;
@@ -678,10 +699,14 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
}
}
@SuppressLint("SetTextI18n")
private void bindHeaderView(){
setTitle(account.displayName);
setSubtitle(getResources().getQuantityString(R.plurals.x_posts, (int)(account.statusesCount%1000), account.statusesCount));
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(100), V.dp(100)));
ViewImageLoader.load(avatar, null, new UrlImageLoaderRequest(
TextUtils.isEmpty(account.avatar) ? getSession().getDefaultAvatarUrl() :
GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic,
V.dp(100), V.dp(100)));
ViewImageLoader.load(cover, null, new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.header : account.headerStatic, 1000, 1000));
SpannableStringBuilder ssb=new SpannableStringBuilder(account.displayName);
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
@@ -710,36 +735,16 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
String acct = ((isSelf || account.isRemote)
? account.getFullyQualifiedName()
: account.acct);
if(account.locked){
ssb=new SpannableStringBuilder("@");
ssb.append(acct);
ssb.append(" ");
Drawable lock=username.getResources().getDrawable(R.drawable.ic_lock, getActivity().getTheme()).mutate();
lock.setBounds(0, 0, lock.getIntrinsicWidth(), lock.getIntrinsicHeight());
lock.setTint(username.getCurrentTextColor());
ssb.append(getString(R.string.manually_approves_followers), new ImageSpan(lock, ImageSpan.ALIGN_BASELINE), 0);
username.setText(ssb);
}else if(account.bot){
ssb=new SpannableStringBuilder("@");
ssb.append(account.acct);
if(isSelf){
ssb.append('@');
ssb.append(AccountSessionManager.getInstance().getAccount(accountID).domain);
}
ssb.append(" ");
Drawable botIcon=username.getResources().getDrawable(R.drawable.ic_bot, getActivity().getTheme()).mutate();
botIcon.setBounds(0, 0, botIcon.getIntrinsicWidth(), botIcon.getIntrinsicHeight());
botIcon.setTint(username.getCurrentTextColor());
ssb.append(getString(R.string.manually_approves_followers), new ImageSpan(botIcon, ImageSpan.ALIGN_BASELINE), 0);
username.setText(ssb);
}else{
// noinspection SetTextI18n
username.setText('@'+acct);
}
CharSequence parsedBio = null;
if(account.note != null){
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
}
lockIcon.setVisibility(account.locked ? View.VISIBLE : View.GONE);
lockIcon.setImageTintList(ColorStateList.valueOf(username.getCurrentTextColor()));
botIcon.setVisibility(account.bot ? View.VISIBLE : View.GONE);
botIcon.setImageTintList(ColorStateList.valueOf(username.getCurrentTextColor()));
CharSequence parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
if(TextUtils.isEmpty(parsedBio)){
bio.setVisibility(View.GONE);
}else{
@@ -849,7 +854,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
MenuItem mute = menu.findItem(R.id.mute);
mute.setTitle(getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getShortUsername()));
mute.setIcon(relationship.muting ? R.drawable.ic_fluent_speaker_0_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
mute.setIcon(relationship.muting ? R.drawable.ic_fluent_speaker_2_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
UiUtils.insetPopupMenuIcon(getContext(), mute);
menu.findItem(R.id.block).setTitle(getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getShortUsername()));
menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getShortUsername()));
@@ -928,6 +933,16 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
args.putString("profileDisplayUsername", account.getDisplayUsername());
}
Nav.go(getActivity(), ListsFragment.class, args);
}else if(id==R.id.mutes){
final Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("targetAccount", Parcels.wrap(account));
Nav.go(getActivity(), MutesListFragment.class, args);
}else if(id==R.id.blocks){
final Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("targetAccount", Parcels.wrap(account));
Nav.go(getActivity(), BlocksListFragment.class, args);
}else if(id==R.id.followed_hashtags){
Bundle args=new Bundle();
args.putString("account", accountID);
@@ -972,11 +987,12 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
notifyProgress.setIndeterminateTintList(notifyButton.getTextColors());
followsYouView.setVisibility(relationship.followedBy ? View.VISIBLE : View.GONE);
notifyButton.setSelected(relationship.notifying);
notifyButton.setContentDescription(getString(relationship.notifying ? R.string.sk_user_post_notifications_on : R.string.sk_user_post_notifications_off, '@'+account.username));
if (!isOwnProfile) {
setNote(relationship.note);
// aboutFragment.setNote(relationship.note, accountID, profileAccountID);
}
notifyButton.setContentDescription(getString(relationship.notifying ? R.string.sk_user_post_notifications_on : R.string.sk_user_post_notifications_off, '@'+account.username));
}
public ImageButton getFab() {
@@ -1169,7 +1185,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
actionButton.setText(R.string.save_changes);
pager.setVisibility(View.GONE);
tabbar.setVisibility(View.GONE);
Drawable overlay=getResources().getDrawable(R.drawable.edit_avatar_overlay).mutate();
Drawable overlay=getResources().getDrawable(R.drawable.edit_avatar_overlay, getActivity().getTheme()).mutate();
avatar.setForeground(overlay);
updateMetadataHeight();
@@ -1189,7 +1205,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
name.setVisibility(View.GONE);
rolesView.setVisibility(View.GONE);
username.setVisibility(View.GONE);
usernameWrap.setVisibility(View.GONE);
bio.setVisibility(View.GONE);
countersLayout.setVisibility(View.GONE);
@@ -1238,7 +1254,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
bioEditWrap.setVisibility(View.GONE);
name.setVisibility(View.VISIBLE);
rolesView.setVisibility(View.VISIBLE);
username.setVisibility(View.VISIBLE);
usernameWrap.setVisibility(View.VISIBLE);
bio.setVisibility(View.VISIBLE);
countersLayout.setVisibility(View.VISIBLE);
refreshLayout.setEnabled(true);
@@ -1340,7 +1356,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
if(ava==null)
return;
int radius=V.dp(25);
currentPhotoViewer=new PhotoViewer(getActivity(), createFakeAttachments(account.avatar, ava), 0,
currentPhotoViewer=new PhotoViewer(getActivity(), createFakeAttachments(TextUtils.isEmpty(account.avatar) ? getSession().getDefaultAvatarUrl() : account.avatar, ava), 0,
new SingleImagePhotoViewerListener(avatar, avatarBorder, new int[]{radius, radius, radius, radius}, this, ()->currentPhotoViewer=null, ()->ava, null, null));
}
}
@@ -1412,9 +1428,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
@NonNull
@Override
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
FrameLayout view=tabViews[viewType];
if (view.getParent() != null) ((ViewGroup)view.getParent()).removeView(view);
view.setVisibility(View.VISIBLE);
FrameLayout view=new FrameLayout(parent.getContext());
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return new SimpleViewHolder(view);
}
@@ -1422,8 +1436,13 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
@Override
public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){
Fragment fragment=getFragmentForPage(position);
FrameLayout fragmentView=tabViews[position];
fragmentView.setVisibility(View.VISIBLE);
if(fragmentView.getParent() instanceof ViewGroup parent)
parent.removeView(fragmentView);
((FrameLayout)holder.itemView).addView(fragmentView);
if(!fragment.isAdded()){
getChildFragmentManager().beginTransaction().add(holder.itemView.getId(), fragment).commit();
getChildFragmentManager().beginTransaction().add(fragmentView.getId(), fragment).commit();
holder.itemView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){
@@ -1541,16 +1560,14 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
}
}
private class AboutViewHolder extends BaseViewHolder implements ImageLoaderViewHolder {
private class AboutViewHolder extends BaseViewHolder implements ImageLoaderViewHolder{
private final TextView title;
private final LinkedTextView value;
// private final ImageView verifiedIcon;
public AboutViewHolder(){
super(R.layout.item_profile_about);
title=findViewById(R.id.title);
value=findViewById(R.id.value);
// verifiedIcon=findViewById(R.id.verified_icon);
}
@Override
@@ -1558,7 +1575,18 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
super.onBind(item);
title.setText(item.parsedName);
value.setText(item.parsedValue);
// verifiedIcon.setVisibility(item.verifiedAt!=null ? View.VISIBLE : View.GONE);
if(item.verifiedAt!=null){
int textColor=UiUtils.isDarkTheme() ? 0xFF89bb9c : 0xFF5b8e63;
value.setTextColor(textColor);
value.setLinkTextColor(textColor);
Drawable check=getResources().getDrawable(R.drawable.ic_fluent_checkmark_starburst_20_regular, getActivity().getTheme()).mutate();
check.setTint(textColor);
value.setCompoundDrawablesRelativeWithIntrinsicBounds(null, null, check, null);
}else{
value.setTextColor(UiUtils.getThemeColor(getActivity(), android.R.attr.textColorPrimary));
value.setLinkTextColor(UiUtils.getThemeColor(getActivity(), android.R.attr.colorAccent));
value.setCompoundDrawables(null, null, null, null);
}
}
@Override

View File

@@ -2,8 +2,11 @@ package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.ImageButton;
import com.squareup.otto.Subscribe;
@@ -27,6 +30,7 @@ import java.util.List;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.V;
public class ScheduledStatusListFragment extends BaseStatusListFragment<ScheduledStatus> {
private String nextMaxID;
@@ -81,7 +85,10 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
@Override
protected List<StatusDisplayItem> buildDisplayItems(ScheduledStatus s) {
return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, false, false, false, true, null);
return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, null,
StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS |
StatusDisplayItem.FLAG_NO_FOOTER |
StatusDisplayItem.FLAG_NO_TRANSLATE);
}
@Override
@@ -184,6 +191,18 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
return null;
}
@Override
public void onApplyWindowInsets(WindowInsets insets){
if(contentView!=null){
if(Build.VERSION.SDK_INT>=29 && insets.getTappableElementInsets().bottom==0){
((ViewGroup.MarginLayoutParams) fab.getLayoutParams()).bottomMargin=V.dp(16)+insets.getSystemWindowInsetBottom();
}else{
((ViewGroup.MarginLayoutParams) fab.getLayoutParams()).bottomMargin=V.dp(16);
}
}
super.onApplyWindowInsets(insets);
}
@Override
public Uri getWebUri(Uri.Builder base) {
// TODO: adapt when frontends finally implement a scheduled posts list

View File

@@ -9,6 +9,7 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetStatusEditHistory;
import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.DummyStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.utils.InsetStatusItemDecoration;
@@ -143,7 +144,8 @@ public class StatusEditHistoryFragment extends StatusListFragment{
}
}
String sep = getString(R.string.sk_separator);
items.add(0, new ReblogOrReplyLineStatusDisplayItem(s.id, this, action+" "+sep+" "+date, Collections.emptyList(), 0, null, null));
items.add(0, new ReblogOrReplyLineStatusDisplayItem(s.id, this, action+" "+sep+" "+date, Collections.emptyList(), 0, null, null, s));
items.add(1, new DummyStatusDisplayItem(s.id, this));
}
return items;
}

View File

@@ -1,5 +1,7 @@
package org.joinmastodon.android.fragments;
import static org.joinmastodon.android.api.session.AccountLocalPreferences.ShowEmojiReactions.ONLY_OPENED;
import android.content.res.Configuration;
import android.os.Bundle;
@@ -7,8 +9,10 @@ import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.events.StatusMuteChangedEvent;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
@@ -20,7 +24,9 @@ import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.EmojiReactionsStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
@@ -38,10 +44,13 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
protected List<StatusDisplayItem> buildDisplayItems(Status s){
boolean isMainThreadStatus = this instanceof ThreadFragment t && s.id.equals(t.mainStatus.id);
int flags = 0;
AccountLocalPreferences lp=getLocalPrefs();
if (GlobalUserPreferences.spectatorMode)
flags |= StatusDisplayItem.FLAG_NO_FOOTER;
if (!getLocalPrefs().showEmojiReactionsInLists)
if (!lp.emojiReactionsEnabled || lp.showEmojiReactions==ONLY_OPENED)
flags |= StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS;
if(!GlobalUserPreferences.showMediaPreview)
flags |= StatusDisplayItem.FLAG_NO_MEDIA_PREVIEW;
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, getFilterContext(), isMainThreadStatus ? 0 : flags);
}
@@ -237,8 +246,52 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
footer.rebind();
}else if(holder instanceof ExtendedFooterStatusDisplayItem.Holder footer && footer.getItem().status==s.getContentStatus()){
footer.rebind();
}else if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && reactions.getItem().status==s.getContentStatus() && ev.viewHolder!=holder){
}
}
}
}
for(Status s:preloadedData){
if(s.getContentStatus().id.equals(ev.id)){
s.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateStatus(s);
}
}
}
@Subscribe
public void onStatusMuteChaged(StatusMuteChangedEvent ev){
for(Status s:data){
if(s.getContentStatus().id.equals(ev.id)){
s.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateStatus(s);
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof HeaderStatusDisplayItem.Holder header && header.getItem().status==s.getContentStatus()){
header.rebind();
}
}
}
}
for(Status s:preloadedData){
if(s.getContentStatus().id.equals(ev.id)){
s.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateStatus(s);
}
}
}
@Subscribe
public void onEmojiReactionsChanged(EmojiReactionsUpdatedEvent ev){
for(Status s:data){
if(s.getContentStatus().id.equals(ev.id)){
s.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateStatus(s);
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof EmojiReactionsStatusDisplayItem.Holder reactions && reactions.getItem().status==s.getContentStatus() && ev.viewHolder!=holder){
reactions.rebind();
}else if(holder instanceof TextStatusDisplayItem.Holder text && text.getItem().parentID.equals(s.getID())){
text.rebind();
}
}
}

View File

@@ -7,14 +7,17 @@ import android.view.View;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.GlobalUserPreferences.AutoRevealMode;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
import org.joinmastodon.android.api.requests.statuses.GetStatusContext;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusMuteChangedEvent;
import org.joinmastodon.android.events.StatusUpdatedEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.FilterContext;
@@ -23,6 +26,7 @@ import org.joinmastodon.android.model.StatusContext;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.displayitems.ExtendedFooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.FooterStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
@@ -66,6 +70,28 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
onAppendItems(Collections.singletonList(mainStatus));
setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.displayName), mainStatus.account.emojis));
transitionFinished = getArguments().getBoolean("noTransition", false);
E.register(this);
}
@Override
public void onDestroy(){
super.onDestroy();
E.unregister(this);
}
@Subscribe
public void onStatusMuteChaged(StatusMuteChangedEvent ev){
for(Status s:data){
s.getContentStatus().update(ev);
AccountSessionManager.get(accountID).getCacheController().updateStatus(s);
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof HeaderStatusDisplayItem.Holder header && header.getItem().status==s.getContentStatus()){
header.rebind();
}
}
}
}
@Override
@@ -321,7 +347,7 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
private static List<Status> getDirectDescendants(String id, List<Status> statuses){
return statuses.stream()
.filter(s -> s.inReplyToId.equals(id))
.filter(s -> id.equals(s.inReplyToId))
.collect(Collectors.toList());
}

View File

@@ -0,0 +1,36 @@
package org.joinmastodon.android.fragments.account_list;
import android.net.Uri;
import android.os.Bundle;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
import org.joinmastodon.android.api.requests.accounts.GetAccountBlocks;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
public class BlocksListFragment extends AccountRelatedAccountListFragment{
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setTitle(R.string.mo_blocked_accounts);
}
@Override
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
return new GetAccountBlocks(maxID, count);
}
@Override
protected void onConfigureViewHolder(AccountViewHolder holder){
super.onConfigureViewHolder(holder);
holder.setStyle(AccountViewHolder.AccessoryType.NONE, false);
}
@Override
public Uri getWebUri(Uri.Builder base) {
return super.getWebUri(base).buildUpon()
.appendPath("/blocks").build();
}
}

View File

@@ -48,7 +48,7 @@ public class ComposeAccountSearchFragment extends BaseAccountListFragment{
@Override
protected void doLoadData(int offset, int count){
refreshing=true;
currentRequest=new GetSearchResults(currentQuery, GetSearchResults.Type.ACCOUNTS, false)
currentRequest=new GetSearchResults(currentQuery, GetSearchResults.Type.ACCOUNTS, false, null, 0, 0)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(SearchResults result){

View File

@@ -0,0 +1,36 @@
package org.joinmastodon.android.fragments.account_list;
import android.net.Uri;
import android.os.Bundle;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.HeaderPaginationRequest;
import org.joinmastodon.android.api.requests.accounts.GetAccountMutes;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
public class MutesListFragment extends AccountRelatedAccountListFragment{
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setTitle(R.string.mo_muted_accounts);
}
@Override
public HeaderPaginationRequest<Account> onCreateRequest(String maxID, int count){
return new GetAccountMutes(maxID, count);
}
@Override
protected void onConfigureViewHolder(AccountViewHolder holder){
super.onConfigureViewHolder(holder);
holder.setStyle(AccountViewHolder.AccessoryType.NONE, false);
}
@Override
public Uri getWebUri(Uri.Builder base) {
return super.getWebUri(base).buildUpon()
.appendPath("/mutes").build();
}
}

View File

@@ -16,6 +16,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
import org.joinmastodon.android.api.requests.accounts.GetFollowSuggestions;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.MastodonRecyclerFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
@@ -319,8 +320,9 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
public AccountWrapper(Account account){
this.account=account;
if(!TextUtils.isEmpty(account.avatar))
avaRequest=new UrlImageLoaderRequest(account.avatar, V.dp(50), V.dp(50));
avaRequest=new UrlImageLoaderRequest(
TextUtils.isEmpty(account.avatar) ? AccountSessionManager.getInstance().getAccount(accountID).getDefaultAvatarUrl() : account.avatar,
V.dp(50), V.dp(50));
if(!TextUtils.isEmpty(account.header))
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);

View File

@@ -12,6 +12,7 @@ import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ScrollableToTop;
@@ -208,6 +209,11 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
@Override
public void scrollToTop(){
if(!searchActive){
if (((IsOnTop)getFragmentForPage(pager.getCurrentItem())).isOnTop() && GlobalUserPreferences.doubleTapToSwipe){
int nextPage=(pager.getCurrentItem()+1)%tabViews.length;
pager.setCurrentItem(nextPage, true);
return;
}
((ScrollableToTop)getFragmentForPage(pager.getCurrentItem())).scrollToTop();
}else{
searchFragment.scrollToTop();
@@ -289,15 +295,19 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
@NonNull
@Override
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
FrameLayout view=tabViews[viewType];
((ViewGroup)view.getParent()).removeView(view);
view.setVisibility(View.VISIBLE);
FrameLayout view=new FrameLayout(parent.getContext());
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return new SimpleViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){}
public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){
FrameLayout view=tabViews[position];
if(view.getParent() instanceof ViewGroup parent)
parent.removeView(view);
view.setVisibility(View.VISIBLE);
((FrameLayout)holder.itemView).addView(view, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
@Override
public int getItemCount(){

View File

@@ -11,6 +11,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.trends.GetTrendingLinks;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.model.Card;
import org.joinmastodon.android.model.viewmodel.CardViewModel;
@@ -43,7 +44,7 @@ import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class DiscoverNewsFragment extends BaseRecyclerFragment<CardViewModel> implements ScrollableToTop{
public class DiscoverNewsFragment extends BaseRecyclerFragment<CardViewModel> implements ScrollableToTop, IsOnTop{
private String accountID;
private DiscoverInfoBannerHelper bannerHelper;
private MergeRecyclerAdapter mergeAdapter;
@@ -111,6 +112,11 @@ public class DiscoverNewsFragment extends BaseRecyclerFragment<CardViewModel> im
smoothScrollRecyclerViewToTop(list);
}
@Override
public boolean isOnTop(){
return isRecyclerViewOnTop(list);
}
private class LinksAdapter extends UsableRecyclerView.Adapter<BaseLinkViewHolder> implements ImageLoaderRecyclerAdapter{
private final List<CardViewModel> data;

View File

@@ -23,7 +23,6 @@ import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.AccountStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.tabs.TabLayout;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
@@ -31,7 +30,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
import me.grishka.appkit.Nav;
@@ -70,7 +69,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
return switch(s.type){
case ACCOUNT -> Collections.singletonList(new AccountStatusDisplayItem(s.id, this, s.account));
case HASHTAG -> Collections.singletonList(new HashtagStatusDisplayItem(s.id, this, s.hashtag));
case STATUS -> StatusDisplayItem.buildItems(this, s.status, accountID, s, knownAccounts, FilterContext.PUBLIC, !getLocalPrefs().showEmojiReactionsInLists ? StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS : 0);
case STATUS -> StatusDisplayItem.buildItems(this, s.status, accountID, s, knownAccounts, FilterContext.PUBLIC, 0);
};
}
@@ -113,7 +112,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
}
@Override
protected void doLoadData(int offset, int count){
protected void doLoadData(int _offset, int count){
GetSearchResults.Type type;
if(currentFilter.size()==1){
type=switch(currentFilter.iterator().next()){
@@ -128,7 +127,21 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
dataLoaded();
return;
}
currentRequest=new GetSearchResults(currentQuery, type, true)
String maxID=null;
// TODO server-side bug
/*int offset=0;
if(_offset>0){
if(type==GetSearchResults.Type.STATUSES){
if(!preloadedData.isEmpty())
maxID=preloadedData.get(preloadedData.size()-1).status.id;
else if(!data.isEmpty())
maxID=data.get(data.size()-1).status.id;
}else{
offset=_offset;
}
}*/
int offset=_offset;
currentRequest=new GetSearchResults(currentQuery, type, type==null, maxID, offset, type==null ? 0 : count)
.setCallback(new Callback<>(){
@Override
public void onSuccess(SearchResults result){
@@ -142,12 +155,15 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult>{
results.add(new SearchResult(tag));
}
if(result.statuses!=null){
for(Status status:result.statuses)
Set<String> alreadyLoadedStatuses=data.stream().filter(r->r.type==SearchResult.Type.STATUS).map(r->r.status.id).collect(Collectors.toSet());
for(Status status:result.statuses){
if(!alreadyLoadedStatuses.contains(status.id))
results.add(new SearchResult(status));
}
}
prevDisplayItems=new ArrayList<>(displayItems);
unfilteredResults=results;
onDataLoaded(filterSearchResults(results), false);
onDataLoaded(filterSearchResults(results), type!=null && !results.isEmpty());
}
@Override

View File

@@ -10,7 +10,6 @@ import android.graphics.Outline;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.text.TextUtils;
@@ -26,7 +25,7 @@ import android.widget.TextView;
import android.widget.Toast;
import android.widget.Toolbar;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.search.GetSearchResults;
import org.joinmastodon.android.api.session.AccountSessionManager;
@@ -38,19 +37,16 @@ import org.joinmastodon.android.model.SearchResults;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.model.viewmodel.SearchResultViewModel;
import org.joinmastodon.android.ui.DividerItemDecoration;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.SearchViewHelper;
import org.joinmastodon.android.ui.adapters.GenericListItemsAdapter;
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.viewholders.AccountViewHolder;
import org.joinmastodon.android.ui.viewholders.SimpleListItemViewHolder;
import org.parceler.Parcels;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -126,7 +122,7 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
recentsHeader.setVisible(!data.isEmpty());
});
}else{
currentRequest=new GetSearchResults(currentQuery, null, false)
currentRequest=new GetSearchResults(currentQuery, null, false, null, 0, 0)
.limit(2)
.setCallback(new SimpleCallback<>(this){
@Override
@@ -381,16 +377,56 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
}
private void openHashtag(SearchResult res){
wrapSuicideDialog(()->{
UiUtils.openHashtagTimeline(getActivity(), accountID, res.hashtag.name, res.hashtag.following);
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putRecentSearch(res);
});
}
private boolean isInRecentMode(){
return TextUtils.isEmpty(currentQuery);
}
private void wrapSuicideDialog(Runnable r){
if(!GlobalUserPreferences.showSuicideHelp || currentQuery==null){
r.run();
return;
}
String[] terms=getContext().getString(R.string.sk_suicide_search_terms).toLowerCase().split(",");
String query=currentQuery.trim().toLowerCase();
boolean termMatches=false;
for(String term : terms){
if(query.contains(term)){
termMatches=true;
break;
}
}
if(!termMatches){
r.run();
return;
}
String url=getContext().getString(R.string.sk_suicide_helplines_url);
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.sk_search_suicide_title)
.setMessage(R.string.sk_search_suicide_message)
.setNegativeButton(R.string.sk_do_not_show_again, (dialog, which)->{
GlobalUserPreferences.showSuicideHelp = false;
GlobalUserPreferences.save();
r.run();
})
.setNeutralButton(R.string.sk_search_suicide_hotlines, (dialog, which)->UiUtils.launchWebBrowser(getContext(), url))
.setPositiveButton(R.string.ok, (dialog, which)->r.run())
.setOnDismissListener((dialog)->{})
.show();
}
private void onSearchViewEnter(){
deliverResult(currentQuery, null);
if(TextUtils.isEmpty(currentQuery) || currentQuery.trim().isEmpty())
return;
wrapSuicideDialog(()->deliverResult(currentQuery, null));
}
private void onOpenURLClick(){
@@ -398,10 +434,12 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
}
private void onGoToHashtagClick(){
wrapSuicideDialog(()->{
String q=searchViewHelper.getQuery();
if(q.startsWith("#"))
q=q.substring(1);
UiUtils.openHashtagTimeline(getActivity(), accountID, q, null);
});
}
private void onGoToAccountClick(){
@@ -422,11 +460,11 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
}
private void onGoToStatusSearchClick(){
deliverResult(searchViewHelper.getQuery(), SearchResult.Type.STATUS);
wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.STATUS));
}
private void onGoToAccountSearchClick(){
deliverResult(searchViewHelper.getQuery(), SearchResult.Type.ACCOUNT);
wrapSuicideDialog(()->deliverResult(searchViewHelper.getQuery(), SearchResult.Type.ACCOUNT));
}
private void onClearRecentClick(){
@@ -439,6 +477,8 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
}
private void deliverResult(String query, SearchResult.Type typeFilter){
if(query.isEmpty())
return;
Bundle res=new Bundle();
res.putString("query", query);
if(typeFilter!=null)

View File

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

View File

@@ -271,7 +271,7 @@ public class SignupFragment extends ToolbarFragment{
@Override
public void tail(Node node, int depth){
if(node instanceof Element){
ssb.setSpan(new LinkSpan("", SignupFragment.this::onGoBackLinkClick, LinkSpan.Type.CUSTOM, null), spanStart, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.setSpan(new LinkSpan("", SignupFragment.this::onGoBackLinkClick, LinkSpan.Type.CUSTOM, null, null), spanStart, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
ssb.setSpan(new TypefaceSpan("sans-serif-medium"), spanStart, ssb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}

View File

@@ -83,7 +83,7 @@ public class ReportReasonChoiceFragment extends StatusListFragment{
reportStatus=Parcels.unwrap(getArguments().getParcelable("status"));
if(reportStatus!=null){
Status hiddenStatus=reportStatus.clone();
hiddenStatus.spoilerText=getString(R.string.post_hidden);
if(hiddenStatus.spoilerText==null) hiddenStatus.spoilerText=getString(R.string.post_hidden);
onDataLoaded(Collections.singletonList(hiddenStatus));
setTitle(R.string.report_title_post);
}else{
@@ -168,17 +168,6 @@ public class ReportReasonChoiceFragment extends StatusListFragment{
((UsableRecyclerView)list).setIncludeMarginsInItemHitbox(false);
if(reportStatus!=null){
list.addItemDecoration(new RecyclerView.ItemDecoration(){
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
RecyclerView.ViewHolder holder=parent.getChildViewHolder(view);
if(holder instanceof LinkCardStatusDisplayItem.Holder || holder instanceof MediaGridStatusDisplayItem.Holder){
outRect.left=V.dp(16);
outRect.right=V.dp(16);
}
}
});
list.addItemDecoration(new RecyclerView.ItemDecoration(){
private Paint paint=new Paint(Paint.ANTI_ALIAS_FLAG);
{
@@ -222,10 +211,6 @@ public class ReportReasonChoiceFragment extends StatusListFragment{
if(holder instanceof StatusDisplayItem.Holder<?>){
outRect.left=outRect.right=V.dp(16);
}
int index=holder.getAbsoluteAdapterPosition()-mergeAdapter.getPositionForAdapter(adapter);
if(index==displayItems.size()){
outRect.top=V.dp(32);
}
}
});
}
@@ -251,18 +236,6 @@ public class ReportReasonChoiceFragment extends StatusListFragment{
return null;
}
@Override
protected void onModifyItemViewHolder(BindableViewHolder<StatusDisplayItem> holder){
if((Object)holder instanceof MediaGridStatusDisplayItem.Holder h){
View layout=h.getLayout();
layout.setOutlineProvider(OutlineProviders.roundedRect(8));
layout.setClipToOutline(true);
View overlay=h.getSensitiveOverlay();
overlay.setOutlineProvider(OutlineProviders.roundedRect(8));
overlay.setClipToOutline(true);
}
}
@Override
public void putRelationship(String id, Relationship rel){
super.putRelationship(id, rel);

View File

@@ -68,6 +68,10 @@ public class EditFilterFragment extends BaseSettingsFragment<Void> implements On
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
filter=Parcels.unwrap(getArguments().getParcelable("filter"));
ArrayList<Parcelable> words=getArguments().getParcelableArrayList("words");
if (words != null) {
words.stream().map(p->(FilterKeyword)Parcels.unwrap(p)).forEach(keywords::add);
}
setTitle(filter==null ? R.string.settings_add_filter : R.string.settings_edit_filter);
onDataLoaded(List.of(
durationItem=new ListItem<>(R.string.settings_filter_duration, 0, this::onDurationClick),

View File

@@ -12,10 +12,13 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.HasAccountID;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.imageloader.ImageCache;
@@ -23,9 +26,11 @@ import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
import me.grishka.appkit.utils.V;
public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
public class SettingsAboutAppFragment extends BaseSettingsFragment<Void> implements HasAccountID{
private ListItem<Void> mediaCacheItem;
// MOSHIDON
private ListItem<Void> clearRecentEmojisItem;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
@@ -36,6 +41,7 @@ public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
new ListItem<>(R.string.mo_settings_contribute, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), getString(R.string.mo_repo_url))),
new ListItem<>(R.string.settings_tos, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/terms")),
new ListItem<>(R.string.settings_privacy_policy, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), getString(R.string.privacy_policy_url)), 0, true),
clearRecentEmojisItem=new ListItem<>(R.string.mo_clear_recent_emoji, 0, this::onClearRecentEmojisClick),
mediaCacheItem=new ListItem<>(R.string.settings_clear_cache, 0, this::onClearMediaCacheClick)
));
@@ -51,7 +57,6 @@ public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
adapter.addAdapter(super.getAdapter());
TextView versionInfo=new TextView(getActivity());
versionInfo.setSingleLine();
versionInfo.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(32)));
versionInfo.setTextAppearance(R.style.m3_label_medium);
versionInfo.setTextColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Outline));
@@ -73,10 +78,21 @@ public class SettingsAboutAppFragment extends BaseSettingsFragment<Void>{
});
}
private void onClearRecentEmojisClick(){
getLocalPrefs().recentEmojis=new HashMap<>();
getLocalPrefs().save();
Toast.makeText(getContext(), R.string.mo_recent_emoji_cleared, Toast.LENGTH_SHORT).show();
}
private void updateMediaCacheItem(){
long size=ImageCache.getInstance(getActivity()).getDiskCache().size();
mediaCacheItem.subtitle=UiUtils.formatFileSize(getActivity(), size, false);
mediaCacheItem.isEnabled=size>0;
rebindItem(mediaCacheItem);
}
@Override
public String getAccountID(){
return accountID;
}
}

View File

@@ -1,7 +1,6 @@
package org.joinmastodon.android.fragments.settings;
import android.os.Bundle;
import android.provider.Settings;
import androidx.annotation.StringRes;
@@ -21,6 +20,7 @@ import org.joinmastodon.android.utils.MastodonLanguage;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> implements HasAccountID{
private ListItem<Void> languageItem;
@@ -34,7 +34,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
private CheckableListItem<Void> forwardReportsItem, remoteLoadingItem, showBoostsItem, showRepliesItem, loadNewPostsItem, seeNewPostsBtnItem, overlayMediaItem;
// MOSHIDON
private CheckableListItem<Void> mentionRebloggerAutomaticallyItem, hapticFeedbackItem, unlistedRepliesItem;
private CheckableListItem<Void> mentionRebloggerAutomaticallyItem, hapticFeedbackItem, unlistedRepliesItem, showPostsWithoutAltItem;
@Override
public void onCreate(Bundle savedInstanceState){
@@ -50,6 +50,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
List<ListItem<Void>> items = new ArrayList<>(List.of(
languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(getContext()) : null, R.drawable.ic_fluent_local_language_24_regular, this::onDefaultLanguageClick),
altTextItem=new CheckableListItem<>(R.string.settings_alt_text_reminders, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.altTextReminders, R.drawable.ic_fluent_image_alt_text_24_regular, ()->toggleCheckableItem(altTextItem)),
showPostsWithoutAltItem=new CheckableListItem<>(R.string.mo_settings_show_posts_without_alt, R.string.mo_settings_show_posts_without_alt_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showPostsWithoutAlt, R.drawable.ic_fluent_eye_tracking_on_24_regular, ()->toggleCheckableItem(showPostsWithoutAltItem)),
playGifsItem=new CheckableListItem<>(R.string.settings_gif, R.string.mo_setting_play_gif_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.playGifs, R.drawable.ic_fluent_gif_24_regular, ()->toggleCheckableItem(playGifsItem)),
unlistedRepliesItem=new CheckableListItem<>(R.string.mo_change_default_reply_visibility_to_unlisted, R.string.mo_setting_default_reply_privacy_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.defaultToUnlistedReplies, R.drawable.ic_fluent_lock_open_24_regular, ()->toggleCheckableItem(unlistedRepliesItem)),
overlayMediaItem=new CheckableListItem<>(R.string.sk_settings_continues_playback, R.string.sk_settings_continues_playback_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.overlayMedia, R.drawable.ic_fluent_play_circle_hint_24_regular, ()->toggleCheckableItem(overlayMediaItem)),
@@ -60,7 +61,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
prefixRepliesItem=new ListItem<>(R.string.sk_settings_prefix_reply_cw_with_re, getPrefixWithRepliesString(), R.drawable.ic_fluent_arrow_reply_24_regular, this::onPrefixRepliesClick),
forwardReportsItem=new CheckableListItem<>(R.string.sk_settings_forward_report_default, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.forwardReportDefault, R.drawable.ic_fluent_arrow_forward_24_regular, ()->toggleCheckableItem(forwardReportsItem)),
loadNewPostsItem=new CheckableListItem<>(R.string.sk_settings_load_new_posts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.loadNewPosts, R.drawable.ic_fluent_arrow_sync_24_regular, this::onLoadNewPostsClick),
seeNewPostsBtnItem=new CheckableListItem<>(R.string.sk_settings_show_new_posts_button, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNewPostsButton, R.drawable.ic_fluent_arrow_up_24_regular, ()->toggleCheckableItem(seeNewPostsBtnItem)),
seeNewPostsBtnItem=new CheckableListItem<>(R.string.sk_settings_see_new_posts_button, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNewPostsButton, R.drawable.ic_fluent_arrow_up_24_regular, ()->toggleCheckableItem(seeNewPostsBtnItem)),
remoteLoadingItem=new CheckableListItem<>(R.string.sk_settings_allow_remote_loading, R.string.sk_settings_allow_remote_loading_explanation, CheckableListItem.Style.SWITCH, GlobalUserPreferences.allowRemoteLoading, R.drawable.ic_fluent_communication_24_regular, ()->toggleCheckableItem(remoteLoadingItem)),
mentionRebloggerAutomaticallyItem=new CheckableListItem<>(R.string.mo_mention_reblogger_automatically, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.mentionRebloggerAutomatically, R.drawable.ic_fluent_comment_mention_24_regular, ()->toggleCheckableItem(mentionRebloggerAutomaticallyItem)),
hapticFeedbackItem=new CheckableListItem<>(R.string.mo_haptic_feedback, R.string.mo_setting_haptic_feedback_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.hapticFeedback, R.drawable.ic_fluent_phone_vibrate_24_regular,()->toggleCheckableItem(hapticFeedbackItem), true),
@@ -173,7 +174,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
GlobalUserPreferences.overlayMedia=overlayMediaItem.checked;
GlobalUserPreferences.useCustomTabs=customTabsItem.checked;
GlobalUserPreferences.altTextReminders=altTextItem.checked;
GlobalUserPreferences.confirmUnfollow=customTabsItem.checked;
GlobalUserPreferences.confirmUnfollow=confirmUnfollowItem.checked;
GlobalUserPreferences.confirmBoost=confirmBoostItem.checked;
GlobalUserPreferences.confirmDeletePost=confirmDeleteItem.checked;
GlobalUserPreferences.forwardReportDefault=forwardReportsItem.checked;
@@ -183,6 +184,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void> impleme
GlobalUserPreferences.mentionRebloggerAutomatically=mentionRebloggerAutomaticallyItem.checked;
GlobalUserPreferences.hapticFeedback=hapticFeedbackItem.checked;
GlobalUserPreferences.defaultToUnlistedReplies=unlistedRepliesItem.checked;
GlobalUserPreferences.showPostsWithoutAlt=showPostsWithoutAltItem.checked;
GlobalUserPreferences.save();
AccountLocalPreferences lp=getLocalPrefs();
lp.showBoosts=showBoostsItem.checked;

View File

@@ -43,7 +43,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
private CheckableListItem<Void> pronounsInUserListingsItem, pronounsInTimelinesItem, pronounsInThreadsItem;
// MOSHIDON
private CheckableListItem<Void> enableDoubleTapToSwipeItem, relocatePublishButtonItem;
private CheckableListItem<Void> enableDoubleTapToSwipeItem, relocatePublishButtonItem, showPostDividersItem, enableDoubleTapToSearchItem, showMediaPreviewItem;
private AccountLocalPreferences lp;
@@ -62,10 +62,12 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
relocatePublishButtonItem=new CheckableListItem<>(R.string.mo_relocate_publish_button, R.string.mo_setting_relocate_publish_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.relocatePublishButton, R.drawable.ic_fluent_arrow_autofit_down_24_regular, ()->toggleCheckableItem(relocatePublishButtonItem)),
revealCWsItem=new CheckableListItem<>(R.string.sk_settings_always_reveal_content_warnings, 0, CheckableListItem.Style.SWITCH, lp.revealCWs, R.drawable.ic_fluent_chat_warning_24_regular, ()->toggleCheckableItem(revealCWsItem)),
hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, lp.hideSensitiveMedia, R.drawable.ic_fluent_flag_24_regular, ()->toggleCheckableItem(hideSensitiveMediaItem)),
showMediaPreviewItem=new CheckableListItem<>(R.string.mo_show_media_preview, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showMediaPreview, R.drawable.ic_fluent_image_24_regular, ()->toggleCheckableItem(showMediaPreviewItem)),
interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, R.string.mo_setting_interaction_count_summary, CheckableListItem.Style.SWITCH, lp.showInteractionCounts, R.drawable.ic_fluent_number_row_24_regular, ()->toggleCheckableItem(interactionCountsItem)),
emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, lp.customEmojiInNames, R.drawable.ic_fluent_emoji_24_regular, ()->toggleCheckableItem(emojiInNamesItem)),
marqueeItem=new CheckableListItem<>(R.string.sk_settings_enable_marquee, R.string.mo_setting_marquee_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.toolbarMarquee, R.drawable.ic_fluent_text_more_24_regular, ()->toggleCheckableItem(marqueeItem)),
reduceMotionItem=new CheckableListItem<>(R.string.sk_settings_reduce_motion, R.string.mo_setting_reduced_motion_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.reduceMotion, R.drawable.ic_fluent_star_emphasis_24_regular, ()->toggleCheckableItem(reduceMotionItem)),
enableDoubleTapToSearchItem=new CheckableListItem<>(R.string.mo_double_tap_to_search, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.doubleTapToSearch, R.drawable.ic_fluent_search_24_regular, ()->toggleCheckableItem(enableDoubleTapToSearchItem)),
disableSwipeItem=new CheckableListItem<>(R.string.sk_settings_tabs_disable_swipe, R.string.mo_setting_disable_swipe_summary, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableSwipe, R.drawable.ic_fluent_swipe_right_24_regular, ()->toggleCheckableItem(disableSwipeItem)),
enableDoubleTapToSwipeItem=new CheckableListItem<>(R.string.mo_double_tap_to_swipe_between_tabs, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.doubleTapToSwipe, R.drawable.ic_fluent_double_tap_swipe_right_24_regular, ()->toggleCheckableItem(enableDoubleTapToSwipeItem)),
altIndicatorItem=new CheckableListItem<>(R.string.sk_settings_show_alt_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showAltIndicator, R.drawable.ic_fluent_scan_text_24_regular, ()->toggleCheckableItem(altIndicatorItem)),
@@ -74,6 +76,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
spectatorModeItem=new CheckableListItem<>(R.string.sk_settings_hide_interaction, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.spectatorMode, R.drawable.ic_fluent_star_off_24_regular, ()->toggleCheckableItem(spectatorModeItem)),
hideFabItem=new CheckableListItem<>(R.string.sk_settings_hide_fab, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.autoHideFab, R.drawable.ic_fluent_edit_24_regular, ()->toggleCheckableItem(hideFabItem)),
translateOpenedItem=new CheckableListItem<>(R.string.sk_settings_translate_only_opened, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.translateButtonOpenedOnly, R.drawable.ic_fluent_translate_24_regular, ()->toggleCheckableItem(translateOpenedItem)),
showPostDividersItem=new CheckableListItem<>(R.string.mo_enable_dividers, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showDividers, R.drawable.ic_fluent_timeline_24_regular, ()->toggleCheckableItem(showPostDividersItem)),
disablePillItem=new CheckableListItem<>(R.string.sk_disable_pill_shaped_active_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableM3PillActiveIndicator, R.drawable.ic_fluent_pill_24_regular, ()->toggleCheckableItem(disablePillItem)),
showNavigationLabelsItem=new CheckableListItem<>(R.string.sk_settings_show_labels_in_navigation_bar, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNavigationLabels, R.drawable.ic_fluent_tag_24_regular, ()->toggleCheckableItem(showNavigationLabelsItem), true),
pronounsInTimelinesItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_timelines, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInTimelines, 0, ()->toggleCheckableItem(pronounsInTimelinesItem)),
@@ -102,7 +105,9 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
boolean restartPlease=
GlobalUserPreferences.disableM3PillActiveIndicator!=disablePillItem.checked ||
GlobalUserPreferences.showNavigationLabels!=showNavigationLabelsItem.checked;
GlobalUserPreferences.showNavigationLabels!=showNavigationLabelsItem.checked ||
GlobalUserPreferences.showMediaPreview !=showMediaPreviewItem.checked ||
GlobalUserPreferences.showDividers!=showPostDividersItem.checked;
lp.revealCWs=revealCWsItem.checked;
lp.hideSensitiveMedia=hideSensitiveMediaItem.checked;
@@ -113,6 +118,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
GlobalUserPreferences.relocatePublishButton=relocatePublishButtonItem.checked;
GlobalUserPreferences.reduceMotion=reduceMotionItem.checked;
GlobalUserPreferences.disableSwipe=disableSwipeItem.checked;
GlobalUserPreferences.doubleTapToSearch=enableDoubleTapToSearchItem.checked;
GlobalUserPreferences.doubleTapToSwipe=enableDoubleTapToSwipeItem.checked;
GlobalUserPreferences.showAltIndicator=altIndicatorItem.checked;
GlobalUserPreferences.showNoAltIndicator=noAltIndicatorItem.checked;
@@ -120,11 +126,13 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
GlobalUserPreferences.spectatorMode=spectatorModeItem.checked;
GlobalUserPreferences.autoHideFab=hideFabItem.checked;
GlobalUserPreferences.translateButtonOpenedOnly=translateOpenedItem.checked;
GlobalUserPreferences.showDividers=showPostDividersItem.checked;
GlobalUserPreferences.disableM3PillActiveIndicator=disablePillItem.checked;
GlobalUserPreferences.showNavigationLabels=showNavigationLabelsItem.checked;
GlobalUserPreferences.displayPronounsInTimelines=pronounsInTimelinesItem.checked;
GlobalUserPreferences.displayPronounsInThreads=pronounsInThreadsItem.checked;
GlobalUserPreferences.displayPronounsInUserListings=pronounsInUserListingsItem.checked;
GlobalUserPreferences.showMediaPreview=showMediaPreviewItem.checked;
GlobalUserPreferences.save();
if(restartPlease) restartActivityToApplyNewTheme();
else E.post(new StatusDisplaySettingsChangedEvent(accountID));

View File

@@ -2,10 +2,14 @@ package org.joinmastodon.android.fragments.settings;
import android.os.Bundle;
import androidx.annotation.StringRes;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
import org.joinmastodon.android.fragments.HasAccountID;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
@@ -15,12 +19,13 @@ import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.Arrays;
import java.util.List;
import java.util.stream.IntStream;
import me.grishka.appkit.Nav;
public class SettingsInstanceFragment extends BaseSettingsFragment<Void> implements HasAccountID{
private CheckableListItem<Void> contentTypesItem, emojiReactionsItem, emojiReactionsInListsItem, localOnlyItem, glitchModeItem;
private ListItem<Void> defaultContentTypeItem;
private CheckableListItem<Void> contentTypesItem, emojiReactionsItem, localOnlyItem, glitchModeItem;
private ListItem<Void> defaultContentTypeItem, showEmojiReactionsItem;
private AccountLocalPreferences lp;
@Override
@@ -35,16 +40,16 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
new ListItem<>(R.string.sk_settings_posting, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/settings/preferences/other")),
new ListItem<>(R.string.sk_settings_auth, 0, R.drawable.ic_fluent_open_24_regular, ()->UiUtils.launchWebBrowser(getActivity(), "https://"+s.domain+"/auth/edit"), 0, true),
contentTypesItem=new CheckableListItem<>(R.string.sk_settings_content_types, R.string.sk_settings_content_types_explanation, CheckableListItem.Style.SWITCH, lp.contentTypesEnabled, R.drawable.ic_fluent_text_edit_style_24_regular, this::onContentTypeClick),
defaultContentTypeItem=new ListItem<>(R.string.sk_settings_default_content_type, lp.defaultContentType.getName(), R.drawable.ic_fluent_text_bold_24_regular, this::onDefaultContentTypeClick),
defaultContentTypeItem=new ListItem<>(R.string.sk_settings_default_content_type, lp.defaultContentType.getName(), R.drawable.ic_fluent_text_bold_24_regular, this::onDefaultContentTypeClick, 0, true),
emojiReactionsItem=new CheckableListItem<>(R.string.sk_settings_emoji_reactions, R.string.sk_settings_emoji_reactions_explanation, CheckableListItem.Style.SWITCH, lp.emojiReactionsEnabled, R.drawable.ic_fluent_emoji_laugh_24_regular, this::onEmojiReactionsClick),
emojiReactionsInListsItem=new CheckableListItem<>(R.string.sk_settings_emoji_reactions_in_lists, R.string.sk_settings_emoji_reactions_in_lists_explanation, CheckableListItem.Style.SWITCH, lp.showEmojiReactionsInLists, R.drawable.ic_fluent_emoji_24_regular, ()->toggleCheckableItem(emojiReactionsInListsItem)),
showEmojiReactionsItem=new ListItem<>(R.string.sk_settings_show_emoji_reactions, getShowEmojiReactionsString(), R.drawable.ic_fluent_emoji_24_regular, this::onShowEmojiReactionsClick, 0, true),
localOnlyItem=new CheckableListItem<>(R.string.sk_settings_support_local_only, R.string.sk_settings_local_only_explanation, CheckableListItem.Style.SWITCH, lp.localOnlySupported, R.drawable.ic_fluent_eye_24_regular, this::onLocalOnlyClick),
glitchModeItem=new CheckableListItem<>(R.string.sk_settings_glitch_instance, R.string.sk_settings_glitch_mode_explanation, CheckableListItem.Style.SWITCH, lp.glitchInstance, R.drawable.ic_fluent_eye_24_filled, ()->toggleCheckableItem(glitchModeItem))
));
contentTypesItem.checkedChangeListener=checked->onContentTypeClick();
defaultContentTypeItem.isEnabled=contentTypesItem.checked;
emojiReactionsItem.checkedChangeListener=checked->onEmojiReactionsClick();
emojiReactionsInListsItem.isEnabled=emojiReactionsItem.checked;
showEmojiReactionsItem.isEnabled=emojiReactionsItem.checked;
localOnlyItem.checkedChangeListener=checked->onLocalOnlyClick();
glitchModeItem.isEnabled=localOnlyItem.checked;
}
@@ -57,10 +62,10 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
super.onHidden();
lp.contentTypesEnabled=contentTypesItem.checked;
lp.emojiReactionsEnabled=emojiReactionsItem.checked;
lp.showEmojiReactionsInLists=emojiReactionsInListsItem.checked;
lp.localOnlySupported=localOnlyItem.checked;
lp.glitchInstance=glitchModeItem.checked;
lp.save();
E.post(new StatusDisplaySettingsChangedEvent(accountID));
}
private void onServerClick(){
@@ -107,11 +112,34 @@ public class SettingsInstanceFragment extends BaseSettingsFragment<Void> impleme
.show();
}
private void onShowEmojiReactionsClick(){
int selected=lp.showEmojiReactions.ordinal();
int[] newSelected={selected};
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.sk_settings_show_emoji_reactions)
.setSingleChoiceItems((String[]) IntStream.of(R.string.sk_settings_show_emoji_reactions_hide_empty, R.string.sk_settings_show_emoji_reactions_only_opened, R.string.sk_settings_show_emoji_reactions_always).mapToObj(this::getString).toArray(String[]::new),
selected, (dlg, item)->newSelected[0]=item)
.setPositiveButton(R.string.ok, (dlg, item)->{
lp.showEmojiReactions=AccountLocalPreferences.ShowEmojiReactions.values()[newSelected[0]];
showEmojiReactionsItem.subtitleRes=getShowEmojiReactionsString();
rebindItem(showEmojiReactionsItem);
})
.setNegativeButton(R.string.cancel, null)
.show();
}
private @StringRes int getShowEmojiReactionsString(){
return switch(lp.showEmojiReactions){
case HIDE_EMPTY -> R.string.sk_settings_show_emoji_reactions_hide_empty;
case ONLY_OPENED -> R.string.sk_settings_show_emoji_reactions_only_opened;
case ALWAYS -> R.string.sk_settings_show_emoji_reactions_always;
};
}
private void onEmojiReactionsClick(){
toggleCheckableItem(emojiReactionsItem);
emojiReactionsInListsItem.checked=false;
emojiReactionsInListsItem.isEnabled=emojiReactionsItem.checked;
rebindItem(emojiReactionsInListsItem);
showEmojiReactionsItem.isEnabled=emojiReactionsItem.checked;
rebindItem(showEmojiReactionsItem);
}
private void onLocalOnlyClick(){

View File

@@ -55,6 +55,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
onDataLoaded(List.of(
new ListItem<>(R.string.settings_behavior, 0, R.drawable.ic_fluent_settings_24_regular, this::onBehaviorClick),
new ListItem<>(R.string.settings_display, 0, R.drawable.ic_fluent_color_24_regular, this::onDisplayClick),
// new ListItem<>(R.string.settings_privacy, 0, R.drawable.ic_privacy_tip_24px, this::onPrivacyClick),
new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_fluent_alert_24_regular, this::onNotificationsClick),
new ListItem<>(R.string.sk_settings_instance, 0, R.drawable.ic_fluent_server_24_regular, this::onInstanceClick),
new ListItem<>(getString(R.string.about_app, getString(R.string.mo_app_name)), null, R.drawable.ic_fluent_info_24_regular, this::onAboutClick, null, 0, true),
@@ -133,6 +134,10 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
Nav.go(getActivity(), SettingsDisplayFragment.class, makeFragmentArgs());
}
// private void onPrivacyClick(){
// Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs());
// }
private void onFiltersClick(){
Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs());
}
@@ -152,6 +157,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
private void onLogOutClick(){
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.log_out)
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
.setPositiveButton(R.string.log_out, (dialog, which)->account.logOut(getActivity(), ()->{
loggedOut=true;

View File

@@ -0,0 +1,41 @@
package org.joinmastodon.android.fragments.settings;
import android.os.Bundle;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
import java.util.List;
public class SettingsPrivacyFragment extends BaseSettingsFragment<Void>{
private CheckableListItem<Void> discoverableItem, indexableItem;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setTitle(R.string.settings_privacy);
Account self=AccountSessionManager.get(accountID).self;
onDataLoaded(List.of(
discoverableItem=new CheckableListItem<>(R.string.settings_discoverable, 0, CheckableListItem.Style.SWITCH, self.discoverable, R.drawable.ic_thumbs_up_down_24px, ()->toggleCheckableItem(discoverableItem)),
indexableItem=new CheckableListItem<>(R.string.settings_indexable, 0, CheckableListItem.Style.SWITCH, self.source.indexable!=null ? self.source.indexable : true, R.drawable.ic_search_24px, ()->toggleCheckableItem(indexableItem))
));
if(self.source.indexable==null)
indexableItem.isEnabled=false;
}
@Override
protected void doLoadData(int offset, int count){}
@Override
public void onPause(){
super.onPause();
Account self=AccountSessionManager.get(accountID).self;
if(self.discoverable!=discoverableItem.checked || (self.source.indexable!=null && self.source.indexable!=indexableItem.checked)){
self.discoverable=discoverableItem.checked;
self.source.indexable=indexableItem.checked;
AccountSessionManager.get(accountID).savePreferencesLater();
}
}
}

View File

@@ -153,18 +153,21 @@ public class SettingsServerFragment extends AppKitFragment{
@NonNull
@Override
public SimpleViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
FrameLayout view=tabViews[viewType];
((ViewGroup)view.getParent()).removeView(view);
view.setVisibility(View.VISIBLE);
FrameLayout view=new FrameLayout(parent.getContext());
view.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
return new SimpleViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull SimpleViewHolder holder, int position){
FrameLayout view=tabViews[position];
if(view.getParent() instanceof ViewGroup parent)
parent.removeView(view);
view.setVisibility(View.VISIBLE);
((FrameLayout)holder.itemView).addView(view, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
Fragment fragment=getFragmentForPage(position);
if(!fragment.isAdded()){
getChildFragmentManager().beginTransaction().add(holder.itemView.getId(), fragment).commit();
getChildFragmentManager().beginTransaction().add(view.getId(), fragment).commit();
holder.itemView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){

View File

@@ -7,12 +7,17 @@ import androidx.annotation.Nullable;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.joinmastodon.android.api.requests.instance.GetInstance;
import org.parceler.Parcel;
import java.time.Instant;
import java.time.LocalDate;
import java.util.Collections;
import java.util.List;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
/**
* Represents a user of Mastodon and their associated profile.
*/
@@ -23,22 +28,22 @@ public class Account extends BaseModel implements Searchable{
/**
* The account id
*/
@RequiredField
// @RequiredField
public String id;
/**
* The username of the account, not including domain.
*/
@RequiredField
// @RequiredField
public String username;
/**
* The Webfinger account URI. Equal to username for local users, or username@domain for remote users.
*/
@RequiredField
// @RequiredField
public String acct;
/**
* The location of the user's profile page.
*/
@RequiredField
// @RequiredField
public String url;
// Display attributes
@@ -51,12 +56,12 @@ public class Account extends BaseModel implements Searchable{
/**
* The profile's bio / description.
*/
// @RequiredField
public String note;
/**
* An image icon that is shown next to statuses and in the profile.
*/
@RequiredField
// @RequiredField
public String avatar;
/**
* A static version of the avatar. Equal to avatar if its value is a static image; different if avatar is an animated GIF.
@@ -134,6 +139,7 @@ public class Account extends BaseModel implements Searchable{
* When a timed mute will expire, if applicable.
*/
public Instant muteExpiresAt;
public boolean noindex;
public List<Role> roles;
@@ -157,16 +163,26 @@ public class Account extends BaseModel implements Searchable{
if(fields!=null){
for(AccountField f:fields)
f.postprocess();
} else {
fields = Collections.emptyList();
}
if(emojis!=null){
for(Emoji e:emojis)
e.postprocess();
} else {
emojis = Collections.emptyList();
}
if(moved!=null)
moved.postprocess();
if(TextUtils.isEmpty(displayName))
displayName=username;
if(fqn == null) fqn = getFullyQualifiedName();
if(id == null) id = "";
if(username == null) username = "";
if(TextUtils.isEmpty(displayName))
displayName = !TextUtils.isEmpty(username) ? username : "";
if(acct == null) acct = "";
if(url == null) url = "";
if(note == null) note = "";
if(avatar == null) avatar = "";
}
public boolean isLocal(){
@@ -191,6 +207,8 @@ public class Account extends BaseModel implements Searchable{
}
public String getFullyQualifiedName() {
if (TextUtils.isEmpty(acct))
return "";
return fqn != null ? fqn : acct.split("@")[0] + "@" + getDomainFromURL();
}
@@ -221,6 +239,7 @@ public class Account extends BaseModel implements Searchable{
", source="+source+
", suspended="+suspended+
", muteExpiresAt="+muteExpiresAt+
", noindex="+noindex+
'}';
}
}

View File

@@ -0,0 +1,19 @@
package org.joinmastodon.android.model;
import org.jsoup.internal.StringUtil;
import java.util.EnumSet;
public class AltTextFilter extends LegacyFilter {
public AltTextFilter(FilterAction filterAction, FilterContext firstContext, FilterContext... restContexts) {
this.filterAction = filterAction;
isRemote = false;
context = EnumSet.of(firstContext, restContexts);
}
@Override
public boolean matches(Status status) {
return status.getContentStatus().mediaAttachments.stream().map(attachment -> attachment.description).anyMatch(StringUtil::isBlank);
}
}

View File

@@ -46,26 +46,26 @@ public class Attachment extends BaseModel{
public int getWidth(){
if(meta==null)
return 0;
return 1920;
if(meta.width>0)
return meta.width;
if(meta.original!=null && meta.original.width>0)
return meta.original.width;
if(meta.small!=null && meta.small.width>0)
return meta.small.width;
return 0;
return 1920;
}
public int getHeight(){
if(meta==null)
return 0;
return 1080;
if(meta.height>0)
return meta.height;
if(meta.original!=null && meta.original.height>0)
return meta.original.height;
if(meta.small!=null && meta.small.height>0)
return meta.small.height;
return 0;
return 1080;
}
public double getDuration(){

View File

@@ -41,6 +41,12 @@ public class Emoji extends BaseModel{
this.staticUrl = staticUrl;
}
public String getUrl(boolean playGifs){
String idealUrl=playGifs ? url : staticUrl;
if(idealUrl==null) return url==null ? staticUrl : url;
return idealUrl;
}
@Override
public String toString(){
return "Emoji{"+

View File

@@ -1,5 +1,6 @@
package org.joinmastodon.android.model;
import org.joinmastodon.android.GlobalUserPreferences;
import org.parceler.Parcel;
import java.util.ArrayList;
@@ -22,6 +23,12 @@ public class EmojiReaction {
public transient ImageLoaderRequest request;
public String getUrl(boolean playGifs){
String idealUrl=playGifs ? url : staticUrl;
if(idealUrl==null) return url==null ? staticUrl : url;
return idealUrl;
}
public static EmojiReaction of(Emoji info, Account me){
EmojiReaction reaction=new EmojiReaction();
reaction.me=true;

View File

@@ -23,6 +23,7 @@ public class Hashtag extends BaseModel implements DisplayItemsParent{
", following="+following+
", history="+history+
", statusesCount="+statusesCount+
", following="+following+
'}';
}
@@ -30,4 +31,19 @@ public class Hashtag extends BaseModel implements DisplayItemsParent{
public String getID(){
return name;
}
@Override
public boolean equals(Object o){
if(this==o) return true;
if(o==null || getClass()!=o.getClass()) return false;
Hashtag hashtag=(Hashtag) o;
return name.equals(hashtag.name);
}
@Override
public int hashCode(){
return name.hashCode();
}
}

View File

@@ -20,4 +20,22 @@ public class Mention extends BaseModel{
", url='"+url+'\''+
'}';
}
@Override
public boolean equals(Object o){
if(this==o) return true;
if(o==null || getClass()!=o.getClass()) return false;
Mention mention=(Mention) o;
if(!id.equals(mention.id)) return false;
return url.equals(mention.url);
}
@Override
public int hashCode(){
int result=id.hashCode();
result=31*result+url.hashCode();
return result;
}
}

View File

@@ -37,6 +37,8 @@ public class Source extends BaseModel{
* The number of pending follow requests.
*/
public int followRequestCount;
public Boolean indexable;
public boolean hideCollections;
@Override
public void postprocess() throws ObjectValidationException{
@@ -54,6 +56,8 @@ public class Source extends BaseModel{
", sensitive="+sensitive+
", language='"+language+'\''+
", followRequestCount="+followRequestCount+
", indexable="+indexable+
", hideCollections="+hideCollections+
'}';
}
}

View File

@@ -15,11 +15,12 @@ import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.StatusMuteChangedEvent;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.parceler.Parcel;
@@ -28,8 +29,6 @@ import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import androidx.annotation.NonNull;
@Parcel
public class Status extends BaseModel implements DisplayItemsParent, Searchable{
@RequiredField
@@ -120,8 +119,8 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
for(FilterResult fr:filtered)
fr.postprocess();
if(!TextUtils.isEmpty(spoilerText)) sensitive=true;
spoilerRevealed=TextUtils.isEmpty(spoilerText);
spoilerRevealed=!hasSpoiler();
if(!spoilerRevealed) sensitive=true;
sensitiveRevealed=!sensitive;
if(visibility.equals(StatusPrivacy.LOCAL)) localOnly=true;
if(emojiReactions!=null) reactions=emojiReactions;
@@ -181,6 +180,13 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
reblogged=ev.reblogged;
bookmarked=ev.bookmarked;
pinned=ev.pinned;
}
public void update(StatusMuteChangedEvent ev) {
muted=ev.muted;
}
public void update(EmojiReactionsUpdatedEvent ev){
reactions=ev.reactions;
}
@@ -194,6 +200,10 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
return strippedText;
}
public boolean hasSpoiler(){
return !TextUtils.isEmpty(spoilerText);
}
@NonNull
@Override
public Status clone(){

View File

@@ -0,0 +1,10 @@
package org.joinmastodon.android.model;
import org.joinmastodon.android.api.AllFieldsAreRequired;
@AllFieldsAreRequired
public class Translation extends BaseModel{
public String content;
public String detectedSourceLanguage;
public String provider;
}

View File

@@ -1,8 +1,10 @@
package org.joinmastodon.android.model.viewmodel;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AccountField;
@@ -24,9 +26,13 @@ public class AccountViewModel{
public AccountViewModel(Account account, String accountID){
this.account=account;
avaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(50), V.dp(50));
AccountSession session = AccountSessionManager.get(accountID);
avaRequest=new UrlImageLoaderRequest(
TextUtils.isEmpty(account.avatar) ? session.getDefaultAvatarUrl() :
GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic,
V.dp(50), V.dp(50));
emojiHelper=new CustomEmojiHelper();
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
if(session.getLocalPreferences().customEmojiInNames)
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
else
parsedName=account.displayName;

View File

@@ -130,7 +130,7 @@ public class AccountSwitcherSheet extends BottomSheet{
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
new M3AlertDialogBuilder(activity)
.setTitle(R.string.log_out)
.setMessage(activity.getString(R.string.confirm_log_out))
.setMessage(activity.getString(R.string.confirm_log_out, session.getFullUsername()))
.setPositiveButton(R.string.log_out, (dialog, which) -> logOut(accountID))
.setNegativeButton(R.string.cancel, null)
.show();

File diff suppressed because one or more lines are too long

View File

@@ -37,6 +37,16 @@ public class OutlineProviders{
}
};
private final static int BUTTON_BG_HEIGHT=V.dp(40);
public static final ViewOutlineProvider M3_BUTTON=new ViewOutlineProvider(){
@Override
public void getOutline(View view, Outline outline){
int viewHeight=view.getHeight();
int top=Math.floorDiv(viewHeight - BUTTON_BG_HEIGHT, 2);
outline.setRoundRect(0, top, view.getWidth(), top + BUTTON_BG_HEIGHT, V.dp(20));
}
};
public static ViewOutlineProvider roundedRect(int dp){
ViewOutlineProvider provider=roundedRects.get(dp);
if(provider!=null)

View File

@@ -15,6 +15,7 @@ import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Notification;
@@ -41,12 +42,13 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
public CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
public CharSequence parsedName, parsedBio;
public AccountCardStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Account account, Notification notification){
public AccountCardStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, String accountID, Account account, Notification notification){
super(parentID, parentFragment);
this.account=account;
this.notification=notification;
if(!TextUtils.isEmpty(account.avatar))
avaRequest=new UrlImageLoaderRequest(account.avatar, V.dp(50), V.dp(50));
avaRequest=new UrlImageLoaderRequest(
TextUtils.isEmpty(account.avatar) ? AccountSessionManager.get(accountID).getDefaultAvatarUrl() : account.avatar,
V.dp(50), V.dp(50));
if(!TextUtils.isEmpty(account.header))
coverRequest=new UrlImageLoaderRequest(account.header, 1000, 1000);
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), parentFragment.getAccountID());

View File

@@ -21,6 +21,7 @@ import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.requests.announcements.AddAnnouncementReaction;
@@ -31,11 +32,10 @@ import org.joinmastodon.android.api.requests.statuses.PleromaAddStatusReaction;
import org.joinmastodon.android.api.requests.statuses.PleromaDeleteStatusReaction;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.EmojiReactionsUpdatedEvent;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.account_list.StatusEmojiReactionsListFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Announcement;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.EmojiReaction;
import org.joinmastodon.android.model.Status;
@@ -44,8 +44,6 @@ import org.joinmastodon.android.ui.utils.TextDrawable;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.ProgressBarButton;
import java.util.Optional;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
@@ -62,25 +60,24 @@ import me.grishka.appkit.views.UsableRecyclerView;
public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
public final Status status;
private final Drawable placeholder;
private final boolean hideAdd, forAnnouncement;
private final boolean hideEmpty, forAnnouncement, playGifs;
private final String accountID;
private boolean hidden;
private static final float ALPHA_DISABLED=0.55f;
public EmojiReactionsStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status, String accountID, boolean hideAdd, boolean forAnnouncement) {
public EmojiReactionsStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status, String accountID, boolean hideEmpty, boolean forAnnouncement) {
super(parentID, parentFragment);
this.status=status;
this.hideAdd=hideAdd;
this.hideEmpty=hideEmpty;
this.forAnnouncement=forAnnouncement;
this.accountID=accountID;
placeholder=parentFragment.getContext().getDrawable(R.drawable.image_placeholder).mutate();
placeholder.setBounds(0, 0, V.sp(24), V.sp(24));
updateHidden();
playGifs=GlobalUserPreferences.playGifs;
}
@Override
public int getImageCount(){
return (int) status.reactions.stream().filter(r->r.url != null).count();
return (int) status.reactions.stream().filter(r->r.getUrl(playGifs)!=null).count();
}
@Override
@@ -94,11 +91,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
}
public boolean isHidden(){
return hidden;
}
private void updateHidden(){
hidden=status.reactions.isEmpty() && hideAdd;
return status.reactions.isEmpty() && hideEmpty;
}
// borrowed from ProfileFragment
@@ -178,8 +171,9 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
public void onBind(EmojiReactionsStatusDisplayItem item) {
if(emojiKeyboard != null) root.removeView(emojiKeyboard.getView());
AccountSession session=item.parentFragment.getSession();
item.status.reactions.forEach(r->
r.request=r.url != null ? new UrlImageLoaderRequest(r.url, V.sp(24), V.sp(24)) : null);
item.status.reactions.forEach(r->r.request=r.getUrl(item.playGifs)!=null
? new UrlImageLoaderRequest(r.getUrl(item.playGifs), V.sp(24), V.sp(24))
: null);
emojiKeyboard=new CustomEmojiPopupKeyboard(
(Activity) item.parentFragment.getContext(),
AccountSessionManager.getInstance().getCustomEmojis(session.domain),
@@ -187,12 +181,12 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
emojiKeyboard.setListener(this);
space.setVisibility(View.GONE);
root.addView(emojiKeyboard.getView());
item.updateHidden();
root.setVisibility(item.hidden ? View.GONE : View.VISIBLE);
line.setVisibility(item.hidden ? View.GONE : View.VISIBLE);
boolean hidden=item.isHidden();
root.setVisibility(hidden ? View.GONE : View.VISIBLE);
line.setVisibility(hidden ? View.GONE : View.VISIBLE);
line.setPadding(
list.getPaddingLeft(),
item.hidden ? 0 : V.dp(8),
hidden ? 0 : V.dp(8),
list.getPaddingRight(),
item.forAnnouncement ? V.dp(8) : 0
);
@@ -219,6 +213,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
}
private void addEmojiReaction(String emoji, Emoji info) {
int countBefore=item.status.reactions.size();
for(int i=0; i<item.status.reactions.size(); i++){
EmojiReaction r=item.status.reactions.get(i);
if(r.name.equals(emoji) && r.me){
@@ -261,7 +256,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
finalExisting.add(me);
adapter.notifyItemChanged(item.status.reactions.indexOf(finalExisting));
}
E.post(new StatusCountersUpdatedEvent(item.status, adapter.parentHolder));
E.post(new EmojiReactionsUpdatedEvent(item.status.id, item.status.reactions, countBefore==0, adapter.parentHolder));
}, resetBtn).exec(item.accountID);
}
@@ -291,7 +286,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
@Override
public void clearImage(int index){
if(item.status.reactions.get(index).url==null) return;
if(item.status.reactions.get(index).getUrl(item.playGifs)==null) return;
setImage(index, item.placeholder);
}
@@ -324,7 +319,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
@Override
public int getImageCountForItem(int position){
return item.status.reactions.get(position).url == null ? 0 : 1;
return item.status.reactions.get(position).getUrl(item.playGifs)==null ? 0 : 1;
}
@Override
@@ -364,7 +359,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
btn.setText(UiUtils.abbreviateNumber(reaction.count));
btn.setContentDescription(reaction.name);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) btn.setTooltipText(reaction.name);
if(reaction.url==null){
if(reaction.getUrl(parent.playGifs)==null){
Paint p=new Paint();
p.setTextSize(V.sp(18));
TextDrawable drawable=new TextDrawable(p, reaction.name);
@@ -392,7 +387,11 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
break;
}
E.post(new StatusCountersUpdatedEvent(parent.status, adapter.parentHolder));
if(parent.isHidden()){
adapter.parentHolder.root.setVisibility(View.GONE);
adapter.parentHolder.line.setVisibility(View.GONE);
}
E.post(new EmojiReactionsUpdatedEvent(parent.status.id, parent.status.reactions, parent.status.reactions.isEmpty(), adapter.parentHolder));
adapter.parentHolder.imgLoader.updateImages();
}, null).exec(parent.parentFragment.getAccountID());
});
@@ -406,7 +405,7 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
args.putString("statusID", parent.status.id);
int atSymbolIndex = emojiReaction.name.indexOf("@");
args.putString("emoji", atSymbolIndex != -1 ? emojiReaction.name.substring(0, atSymbolIndex) : emojiReaction.name);
args.putString("url", emojiReaction.url);
args.putString("url", emojiReaction.getUrl(parent.playGifs));
args.putInt("count", emojiReaction.count);
Nav.go(parent.parentFragment.getActivity(), StatusEmojiReactionsListFragment.class, args);
return true;

View File

@@ -1,7 +1,9 @@
package org.joinmastodon.android.ui.displayitems;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.media.Image;
import android.net.Uri;
import android.text.TextUtils;
import android.view.View;
@@ -14,10 +16,18 @@ import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.Card;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.SingleImagePhotoViewerListener;
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.ArrayList;
import java.util.List;
import me.grishka.appkit.Nav;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.utils.V;
public class FileStatusDisplayItem extends StatusDisplayItem{
private final Status status;
@@ -36,22 +46,31 @@ public class FileStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<FileStatusDisplayItem>{
private final TextView title, domain;
private final ImageView icon;
private final Context context;
public Holder(Context context, ViewGroup parent){
super(context, R.layout.display_item_file, parent);
title=findViewById(R.id.title);
domain=findViewById(R.id.domain);
icon=findViewById(R.id.imageView);
this.context=context;
findViewById(R.id.inner).setOnClickListener(this::onClick);
}
@Override
public void onBind(FileStatusDisplayItem item) {
Uri url = Uri.parse(getUrl());
title.setText(item.attachment.description != null
? item.attachment.description
: url.getLastPathSegment());
title.setEllipsize(item.attachment.description != null ? TextUtils.TruncateAt.END : TextUtils.TruncateAt.MIDDLE);
domain.setText(url.getHost());
icon.setImageDrawable(context.getDrawable(R.drawable.ic_fluent_attach_24_regular));
}
private void onClick(View v) {

View File

@@ -1,5 +1,8 @@
package org.joinmastodon.android.ui.displayitems;
import static org.joinmastodon.android.ui.utils.UiUtils.opacityIn;
import static org.joinmastodon.android.ui.utils.UiUtils.opacityOut;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;

View File

@@ -8,14 +8,21 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.drawables.SawtoothTearDrawable;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.time.Instant;
import me.grishka.appkit.utils.V;
// Mind the gap!
public class GapStatusDisplayItem extends StatusDisplayItem{
public boolean loading;
private Status status;
public GapStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment){
public GapStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status){
super(parentID, parentFragment);
this.status=status;
}
@Override
@@ -24,25 +31,53 @@ public class GapStatusDisplayItem extends StatusDisplayItem{
}
public static class Holder extends StatusDisplayItem.Holder<GapStatusDisplayItem>{
public final ProgressBar progress;
public final TextView text;
public final ProgressBar progressTop, progressBottom;
public final TextView textTop, gap, textBottom;
public final View top, bottom;
public Holder(Context context, ViewGroup parent){
super(context, R.layout.display_item_gap, parent);
progress=findViewById(R.id.progress);
text=findViewById(R.id.text);
itemView.setForeground(new SawtoothTearDrawable(context));
progressTop=findViewById(R.id.progress_top);
progressBottom=findViewById(R.id.progress_bottom);
textTop=findViewById(R.id.text_top);
textBottom=findViewById(R.id.text_bottom);
top=findViewById(R.id.top);
top.setOnClickListener(this::onViewClick);
bottom=findViewById(R.id.bottom);
bottom.setOnClickListener(this::onViewClick);
gap=findViewById(R.id.gap);
gap.setForeground(new SawtoothTearDrawable(context));
}
@Override
public void onBind(GapStatusDisplayItem item){
text.setVisibility(item.loading ? View.GONE : View.VISIBLE);
progress.setVisibility(item.loading ? View.VISIBLE : View.GONE);
if(!item.loading){
progressBottom.setVisibility(View.GONE);
progressTop.setVisibility(View.GONE);
}
top.setClickable(!item.loading);
bottom.setClickable(!item.loading);
StatusDisplayItem next=getNextVisibleDisplayItem().orElse(null);
Instant dateBelow=next instanceof HeaderStatusDisplayItem h ? h.status.createdAt
: next instanceof ReblogOrReplyLineStatusDisplayItem l ? l.status.createdAt
: null;
String text=dateBelow!=null && item.status.createdAt!=null && dateBelow.isBefore(item.status.createdAt)
? UiUtils.formatPeriodBetween(item.parentFragment.getContext(), dateBelow, item.status.createdAt)
: null;
gap.setText(text);
int p=text==null ? V.dp(6) : V.dp(20);
gap.setPadding(p, p, p, p);
}
private void onViewClick(View v){
if(item.loading) return;
boolean isTop=v==top;
(isTop ? textTop : textBottom).startAnimation(UiUtils.opacityOut);
V.setVisibilityAnimated((isTop ? progressTop : progressBottom), View.VISIBLE);
item.parentFragment.onGapClick(this, isTop);
}
@Override
public void onClick(){
item.parentFragment.onGapClick(this);
}
public void onClick(){}
}
}

View File

@@ -38,6 +38,7 @@ import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Announcement;
import org.joinmastodon.android.model.Mention;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.ScheduledStatus;
@@ -56,6 +57,7 @@ import java.time.format.FormatStyle;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Objects;
import java.util.function.Consumer;
import androidx.annotation.LayoutRes;
@@ -86,10 +88,14 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID, Status status, CharSequence extraText, Notification notification, ScheduledStatus scheduledStatus){
super(parentID, parentFragment);
user=scheduledStatus != null ? AccountSessionManager.getInstance().getAccount(accountID).self : user;
AccountSession session = AccountSessionManager.get(accountID);
user=scheduledStatus != null ? session.self : user;
this.user=user;
this.createdAt=createdAt;
avaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? user.avatar : user.avatarStatic, V.dp(50), V.dp(50));
avaRequest=new UrlImageLoaderRequest(
TextUtils.isEmpty(user.avatar) ? session.getDefaultAvatarUrl() :
GlobalUserPreferences.playGifs ? user.avatar : user.avatarStatic,
V.dp(50), V.dp(50));
this.accountID=accountID;
parsedName=new SpannableStringBuilder(user.displayName);
this.status=status;
@@ -134,13 +140,11 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<HeaderStatusDisplayItem> implements ImageLoaderViewHolder{
private final TextView name, time, username, extraText, pronouns;
private final View collapseBtn, timeUsernameSeparator;
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, markAsRead, collapseBtnIcon;
private final ImageView avatar, more, visibility, deleteNotification, unreadIndicator, markAsRead, collapseBtnIcon, botIcon;
private final PopupMenu optionsMenu;
private Relationship relationship;
private APIRequest<?> currentRelationshipRequest;
//TODO: readd
public Holder(Activity activity, ViewGroup parent){
this(activity, R.layout.display_item_header, parent);
}
@@ -150,6 +154,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
name=findViewById(R.id.name);
time=findViewById(R.id.time);
username=findViewById(R.id.username);
botIcon=findViewById(R.id.bot_icon);
timeUsernameSeparator=findViewById(R.id.separator);
avatar=findViewById(R.id.avatar);
more=findViewById(R.id.more);
@@ -159,7 +164,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
markAsRead=findViewById(R.id.mark_as_read);
collapseBtn=findViewById(R.id.collapse_btn);
collapseBtnIcon=findViewById(R.id.collapse_btn_icon);
// botIcon=findViewById(R.id.bot_icon);
extraText=findViewById(R.id.extra_text);
pronouns=findViewById(R.id.pronouns);
avatar.setOnClickListener(this::onAvaClick);
@@ -195,7 +199,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
}
}
boolean isPixelfed = item.parentFragment.isInstancePixelfed();
boolean textEmpty = TextUtils.isEmpty(item.status.content) && TextUtils.isEmpty(item.status.spoilerText);
boolean textEmpty = TextUtils.isEmpty(item.status.content) && !item.status.hasSpoiler();
if(!redraft && (isPixelfed || textEmpty)){
// pixelfed doesn't support /statuses/:id/source :/
if (isPixelfed) {
@@ -246,6 +250,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
UiUtils.confirmPinPost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, !item.status.pinned, s->{});
}else if(id==R.id.mute){
UiUtils.confirmToggleMuteUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, relationship!=null && relationship.muting, r->{});
}else if (id==R.id.mute_conversation || id==R.id.unmute_conversation) {
UiUtils.confirmToggleMuteConversation(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, ()->{});
}else if(id==R.id.block){
UiUtils.confirmToggleBlockUser(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), account, relationship!=null && relationship.blocking, r->{});
}else if(id==R.id.report){
@@ -325,13 +331,21 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
this.time.setVisibility(time==null ? View.GONE : View.VISIBLE);
if(time!=null) this.time.setText(time);
botIcon.setVisibility(item.user.bot ? View.VISIBLE : View.GONE);
botIcon.setColorFilter(username.getCurrentTextColor());
deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE);
if (item.hasVisibilityToggle){
boolean disabled = !item.status.sensitiveRevealed ||
(!TextUtils.isEmpty(item.status.spoilerText) &&
!item.status.spoilerRevealed);
visibility.setEnabled(!disabled);
V.setVisibilityAnimated(visibility, disabled ? View.INVISIBLE : View.VISIBLE);
boolean hidden = !item.status.sensitiveRevealed || (item.status.hasSpoiler() && !item.status.spoilerRevealed);
// doing this because V.setVisibilityAnimated ignores changes between INVISIBLE and GONE
int newVis=hidden ? View.INVISIBLE : View.VISIBLE;
if(newVis==View.INVISIBLE && visibility.getVisibility()==View.GONE)
visibility.setVisibility(newVis);
else
V.setVisibilityAnimated(visibility, newVis);
visibility.setEnabled(!hidden);
visibility.setContentDescription(item.parentFragment.getString(item.status.sensitiveRevealed ? R.string.spoiler_hide : R.string.spoiler_show));
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
visibility.setTooltipText(visibility.getContentDescription());
@@ -424,6 +438,8 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
}
private void onAvaClick(View v){
if (TextUtils.isEmpty(item.user.url))
return;
if (item.announcement != null) {
UiUtils.openURL(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.user.url);
return;
@@ -495,6 +511,14 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
menu.findItem(R.id.delete_and_redraft).setVisible(!isPostScheduled && item.status!=null && isOwnPost);
menu.findItem(R.id.pin).setVisible(!isPostScheduled && item.status!=null && isOwnPost && !item.status.pinned);
menu.findItem(R.id.unpin).setVisible(!isPostScheduled && item.status!=null && isOwnPost && item.status.pinned);
menu.findItem(R.id.mute_conversation).setVisible((item.status!=null && !item.status.muted && !isPostScheduled) && (isOwnPost || item.status.mentions.stream().anyMatch(m->{
if(m==null)
return false;
return AccountSessionManager.get(item.parentFragment.getAccountID()).self.id.equals(m.id) ||
AccountSessionManager.get(item.parentFragment.getAccountID()).self.getFullyQualifiedName().equals(m.username) ||
AccountSessionManager.get(item.parentFragment.getAccountID()).self.acct.equals(m.acct);
})));
menu.findItem(R.id.unmute_conversation).setVisible(item.status!=null && item.status.muted);
menu.findItem(R.id.open_in_browser).setVisible(!isPostScheduled && item.status!=null);
menu.findItem(R.id.copy_link).setVisible(!isPostScheduled && item.status!=null);
MenuItem blockDomain=menu.findItem(R.id.block_domain);

View File

@@ -27,10 +27,10 @@ public class LinkCardStatusDisplayItem extends StatusDisplayItem{
private final Status status;
private final UrlImageLoaderRequest imgRequest;
public LinkCardStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Status status){
public LinkCardStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Status status, boolean showImagePreview){
super(parentID, parentFragment);
this.status=status;
if(status.card.image!=null)
if(status.card.image!=null && showImagePreview)
imgRequest=new UrlImageLoaderRequest(status.card.image, 1000, 1000);
else
imgRequest=null;

View File

@@ -20,6 +20,8 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.model.Emoji;
@@ -53,7 +55,11 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
if(notification.type==Notification.Type.POLL){
text=parentFragment.getString(R.string.poll_ended);
}else{
avaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? notification.account.avatar : notification.account.avatarStatic, V.dp(50), V.dp(50));
AccountSession session = AccountSessionManager.get(accountID);
avaRequest=new UrlImageLoaderRequest(
TextUtils.isEmpty(notification.account.avatar) ? session.getDefaultAvatarUrl() :
GlobalUserPreferences.playGifs ? notification.account.avatar : notification.account.avatarStatic,
V.dp(50), V.dp(50));
SpannableStringBuilder parsedName=new SpannableStringBuilder(notification.account.displayName);
HtmlParser.parseCustomEmoji(parsedName, notification.account.emojis);
String str = parentFragment.getString(switch(notification.type){
@@ -107,7 +113,6 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<NotificationHeaderStatusDisplayItem> implements ImageLoaderViewHolder{
private final ImageView icon, avatar;
private final TextView text;
private final int selectableItemBackground;
public Holder(Activity activity, ViewGroup parent){
super(activity, R.layout.display_item_notification_header, parent);
@@ -118,10 +123,8 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
avatar.setOutlineProvider(OutlineProviders.roundedRect(8));
avatar.setClipToOutline(true);
itemView.setOnClickListener(this::onItemClick);
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
selectableItemBackground = outValue.resourceId;
icon.setOnClickListener(this::onItemClick);
avatar.setOnClickListener(this::onItemClick);
}
@Override
@@ -164,10 +167,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
case POLL -> R.attr.colorPoll;
default -> android.R.attr.colorAccent;
})));
itemView.setBackgroundResource(item.notification.type != Notification.Type.POLL
&& item.notification.type != Notification.Type.REPORT ?
selectableItemBackground : 0);
itemView.setClickable(item.notification.type != Notification.Type.POLL);
itemView.setBackgroundResource(0);
}
public void onItemClick(View v) {

View File

@@ -80,7 +80,7 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
progressBg=activity.getResources().getDrawable(R.drawable.bg_poll_option_voted, activity.getTheme()).mutate();
progressBgInset=activity.getResources().getDrawable(R.drawable.bg_poll_option_voted_inset, activity.getTheme()).mutate();
itemView.setOnClickListener(this::onButtonClick);
button.setOutlineProvider(OutlineProviders.roundedRect(24));
button.setOutlineProvider(OutlineProviders.M3_BUTTON);
button.setClipToOutline(true);
}

View File

@@ -0,0 +1,146 @@
package org.joinmastodon.android.ui.displayitems;
import android.app.Activity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.PhotoLayoutHelper;
import org.joinmastodon.android.ui.utils.PreviewlessMediaAttachmentViewController;
import org.joinmastodon.android.ui.views.FrameLayoutThatOnlyMeasuresFirstChild;
import org.joinmastodon.android.utils.TypedObjectPool;
import java.util.ArrayList;
import java.util.List;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.utils.V;
public class PreviewlessMediaGridStatusDisplayItem extends StatusDisplayItem{
private static final String TAG="PreviewlessMediaGridDisplayItem";
private PhotoLayoutHelper.TiledLayoutResult tiledLayout;
private final TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, PreviewlessMediaAttachmentViewController> viewPool;
private final List<Attachment> attachments;
private final ArrayList<ImageLoaderRequest> requests=new ArrayList<>();
public final Status status;
public String sensitiveTitle;
public PreviewlessMediaGridStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, PhotoLayoutHelper.TiledLayoutResult tiledLayout, List<Attachment> attachments, Status status){
super(parentID, parentFragment);
this.tiledLayout=tiledLayout;
this.viewPool=parentFragment.getPreviewlessAttachmentViewsPool();
this.attachments=attachments;
this.status=status;
// for(Attachment att:attachments){
// requests.add(new UrlImageLoaderRequest(switch(att.type){
// case IMAGE -> att.url;
// case VIDEO, GIFV -> att.previewUrl == null ? att.url : att.previewUrl;
// default -> throw new IllegalStateException("Unexpected value: "+att.url);
// }, 1000, 1000));
// }
}
@Override
public Type getType(){
return Type.PREVIEWLESS_MEDIA_GRID;
}
@Override
public int getImageCount(){
return attachments.size();
}
@Override
public ImageLoaderRequest getImageRequest(int index){
return requests.get(index);
}
public static class Holder extends StatusDisplayItem.Holder<PreviewlessMediaGridStatusDisplayItem> {
private final FrameLayout wrapper;
private final LinearLayout layout;
private final View.OnClickListener clickListener=this::onViewClick;
private final ArrayList<PreviewlessMediaAttachmentViewController> controllers=new ArrayList<>();
// private final FrameLayout hideSensitiveButton;
public Holder(Activity activity, ViewGroup parent){
super(new FrameLayoutThatOnlyMeasuresFirstChild(activity));
wrapper=(FrameLayout)itemView;
layout= new LinearLayout(activity);
layout.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layout.setLayoutParams(params);
wrapper.addView(layout);
wrapper.setClipToPadding(false);
// megalodon: no sensitive hide button because the visibility toggle looks prettier imo
// hideSensitiveButton=(FrameLayout) activity.getLayoutInflater().inflate(R.layout.alt_text_badge, overlays, false);
// ((TextView) hideSensitiveButton.findViewById(R.id.alt_button)).setText(R.string.hide);
// overlays.addView(hideSensitiveButton, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.END | Gravity.TOP));
// hideSensitiveButton.setOnClickListener(v->hideSensitive());
}
@Override
public void onBind(PreviewlessMediaGridStatusDisplayItem item){
wrapper.setPadding(0, 0, 0, 0); // item.inset ? 0 : V.dp(8));
// if(altTextAnimator!=null)
// altTextAnimator.cancel();
for(PreviewlessMediaAttachmentViewController c:controllers){
item.viewPool.reuse(c.type, c);
}
layout.removeAllViews();
controllers.clear();
int i=0;
// if (!item.attachments.isEmpty()) updateBlurhashInSensitiveOverlay();
for(Attachment att:item.attachments){
PreviewlessMediaAttachmentViewController c=item.viewPool.obtain(switch(att.type){
case IMAGE -> MediaGridStatusDisplayItem.GridItemType.PHOTO;
case VIDEO -> MediaGridStatusDisplayItem.GridItemType.VIDEO;
case GIFV -> MediaGridStatusDisplayItem.GridItemType.GIFV;
default -> throw new IllegalStateException("Unexpected value: "+att.type);
});
if(c.view.getLayoutParams()==null)
c.view.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
layout.addView(c.view);
c.view.setOnClickListener(clickListener);
c.view.setTag(i);
controllers.add(c);
c.bind(att, item.status);
i++;
}
boolean insetAndLast=item.inset && isLastDisplayItemForStatus();
wrapper.setClipToOutline(insetAndLast);
wrapper.setOutlineProvider(insetAndLast ? OutlineProviders.bottomRoundedRect(12) : null);
}
private void onViewClick(View v){
int index=(Integer)v.getTag();
item.parentFragment.openPreviewlessMediaPhotoViewer(item.parentID, item.status, index, this);
}
public PreviewlessMediaAttachmentViewController getViewController(int index){
return controllers.get(index);
}
public void setClipChildren(boolean clip){
layout.setClipChildren(clip);
wrapper.setClipChildren(clip);
}
public LinearLayout getLayout(){
return layout;
}
}
}

View File

@@ -15,8 +15,10 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
@@ -43,18 +45,21 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
public boolean needBottomPadding;
ReblogOrReplyLineStatusDisplayItem extra;
CharSequence fullText;
Status status;
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick) {
this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, text);
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, Status status) {
this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, text, status);
}
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, CharSequence fullText) {
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, CharSequence fullText, Status status) {
super(parentID, parentFragment);
SpannableStringBuilder ssb=new SpannableStringBuilder(text);
if(AccountSessionManager.get(parentFragment.getAccountID()).getLocalPreferences().customEmojiInNames)
HtmlParser.parseCustomEmoji(ssb, emojis);
this.text=ssb;
emojiHelper.setText(ssb);
this.icon=icon;
this.status=status;
this.handleClick=handleClick;
TypedValue outValue = new TypedValue();
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);

View File

@@ -6,9 +6,9 @@ import android.graphics.drawable.LayerDrawable;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Status;
@@ -29,11 +29,13 @@ public class SpoilerStatusDisplayItem extends StatusDisplayItem{
private final CharSequence parsedTitle;
private final CustomEmojiHelper emojiHelper;
private final Type type;
private final int attachmentCount;
public SpoilerStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, String title, Status statusForContent, Type type){
super(parentID, parentFragment);
this.status=statusForContent;
this.type=type;
this.attachmentCount=statusForContent.mediaAttachments.size();
if(TextUtils.isEmpty(title)){
parsedTitle=HtmlParser.parseCustomEmoji(statusForContent.spoilerText, statusForContent.emojis);
emojiHelper=new CustomEmojiHelper();
@@ -62,12 +64,14 @@ public class SpoilerStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<SpoilerStatusDisplayItem> implements ImageLoaderViewHolder{
private final TextView title, action;
private final View button;
private final ImageView mediaIcon;
public Holder(Context context, ViewGroup parent, Type type){
super(context, R.layout.display_item_spoiler, parent);
title=findViewById(R.id.spoiler_title);
action=findViewById(R.id.spoiler_action);
button=findViewById(R.id.spoiler_button);
mediaIcon=findViewById(R.id.media_icon);
button.setOutlineProvider(OutlineProviders.roundedRect(8));
button.setClipToOutline(true);
@@ -94,6 +98,10 @@ public class SpoilerStatusDisplayItem extends StatusDisplayItem{
itemView.getPaddingRight(),
item.inset ? itemView.getPaddingTop() : 0
);
mediaIcon.setVisibility(item.attachmentCount > 0 ? View.VISIBLE : View.GONE);
mediaIcon.setImageResource(item.attachmentCount > 1
? R.drawable.ic_fluent_image_multiple_24_regular
: R.drawable.ic_fluent_image_24_regular);
}
@Override

View File

@@ -1,5 +1,8 @@
package org.joinmastodon.android.ui.displayitems;
import static org.joinmastodon.android.api.session.AccountLocalPreferences.ShowEmojiReactions.ALWAYS;
import static org.joinmastodon.android.api.session.AccountLocalPreferences.ShowEmojiReactions.ONLY_OPENED;
import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
@@ -12,6 +15,7 @@ import android.view.ViewGroup;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
@@ -50,7 +54,7 @@ import me.grishka.appkit.views.UsableRecyclerView;
public abstract class StatusDisplayItem{
public final String parentID;
public final BaseStatusListFragment<?> parentFragment;
public boolean inset, insetPadding=true;
public boolean inset;
public int index;
public boolean
hasDescendantNeighbor = false,
@@ -65,6 +69,7 @@ public abstract class StatusDisplayItem{
public static final int FLAG_NO_HEADER=1 << 4;
public static final int FLAG_NO_TRANSLATE=1 << 5;
public static final int FLAG_NO_EMOJI_REACTIONS=1 << 6;
public static final int FLAG_NO_MEDIA_PREVIEW=1 << 7;
public void setAncestryInfo(
boolean hasDescendantNeighbor,
@@ -111,6 +116,7 @@ public abstract class StatusDisplayItem{
case GAP -> new GapStatusDisplayItem.Holder(activity, parent);
case EXTENDED_FOOTER -> new ExtendedFooterStatusDisplayItem.Holder(activity, parent);
case MEDIA_GRID -> new MediaGridStatusDisplayItem.Holder(activity, parent);
case PREVIEWLESS_MEDIA_GRID -> new PreviewlessMediaGridStatusDisplayItem.Holder(activity, parent);
case WARNING -> new WarningFilteredStatusDisplayItem.Holder(activity, parent);
case FILE -> new FileStatusDisplayItem.Holder(activity, parent);
case SPOILER, FILTER_SPOILER -> new SpoilerStatusDisplayItem.Holder(activity, parent, type);
@@ -120,19 +126,6 @@ public abstract class StatusDisplayItem{
};
}
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean showReactions, boolean addFooter, boolean disableTranslate, FilterContext filterContext) {
int flags=0;
if(inset)
flags|=FLAG_INSET;
if(!addFooter)
flags|=FLAG_NO_FOOTER;
if (disableTranslate)
flags|=FLAG_NO_TRANSLATE;
if (!showReactions)
flags|=FLAG_NO_EMOJI_REACTIONS;
return buildItems(fragment, status, accountID, parentObject, knownAccounts, filterContext, flags);
}
public static ReblogOrReplyLineStatusDisplayItem buildReplyLine(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parent, Account account, boolean threadReply) {
String parentID = parent.getID();
String text = threadReply ? fragment.getString(R.string.sk_show_thread)
@@ -144,7 +137,7 @@ public abstract class StatusDisplayItem{
: fragment.getString(R.string.in_reply_to, account.displayName);
return new ReblogOrReplyLineStatusDisplayItem(
parentID, fragment, text, account == null ? List.of() : account.emojis,
R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText
R.drawable.ic_fluent_arrow_reply_20sp_filled, null, null, fullText, status
);
}
@@ -179,7 +172,7 @@ public abstract class StatusDisplayItem{
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, text, status.account.emojis, R.drawable.ic_fluent_arrow_repeat_all_20sp_filled, isOwnPost ? status.visibility : null, i->{
args.putParcelable("profileAccount", Parcels.wrap(status.account));
Nav.go(fragment.getActivity(), ProfileFragment.class, args);
}, fullText));
}, fullText, status));
} else if (!(status.tags.isEmpty() ||
fragment instanceof HashtagTimelineFragment ||
fragment instanceof ListTimelineFragment
@@ -195,7 +188,7 @@ public abstract class StatusDisplayItem{
i -> {
args.putString("hashtag", hashtag.name);
Nav.go(fragment.getActivity(), HashtagTimelineFragment.class, args);
}
}, status
)));
}
@@ -229,7 +222,7 @@ public abstract class StatusDisplayItem{
}
ArrayList<StatusDisplayItem> contentItems;
if(!TextUtils.isEmpty(statusForContent.spoilerText)){
if(statusForContent.hasSpoiler()){
if (AccountSessionManager.get(accountID).getLocalPreferences().revealCWs) statusForContent.spoilerRevealed = true;
SpoilerStatusDisplayItem spoilerItem=new SpoilerStatusDisplayItem(parentID, fragment, null, statusForContent, Type.SPOILER);
items.add(spoilerItem);
@@ -261,7 +254,7 @@ public abstract class StatusDisplayItem{
}
List<Attachment> imageAttachments=statusForContent.mediaAttachments.stream().filter(att->att.type.isImage()).collect(Collectors.toList());
if(!imageAttachments.isEmpty()){
if(!imageAttachments.isEmpty() && (flags & FLAG_NO_MEDIA_PREVIEW)==0){
int color = UiUtils.getThemeColor(fragment.getContext(), R.attr.colorM3SurfaceVariant);
for (Attachment att : imageAttachments) {
if (att.blurhashPlaceholder == null) {
@@ -276,6 +269,10 @@ public abstract class StatusDisplayItem{
statusForContent.sensitiveRevealed=true;
contentItems.add(mediaGrid);
}
if((flags & FLAG_NO_MEDIA_PREVIEW)!=0){
contentItems.add(new PreviewlessMediaGridStatusDisplayItem(parentID, fragment, null, imageAttachments, statusForContent));
}
for(Attachment att:statusForContent.mediaAttachments){
if(att.type==Attachment.Type.AUDIO){
contentItems.add(new AudioStatusDisplayItem(parentID, fragment, statusForContent, att));
@@ -288,15 +285,17 @@ public abstract class StatusDisplayItem{
buildPollItems(parentID, fragment, statusForContent.poll, contentItems, statusForContent);
}
if(statusForContent.card!=null && statusForContent.mediaAttachments.isEmpty()){
contentItems.add(new LinkCardStatusDisplayItem(parentID, fragment, statusForContent));
contentItems.add(new LinkCardStatusDisplayItem(parentID, fragment, statusForContent, (flags & FLAG_NO_MEDIA_PREVIEW)==0));
}
if(contentItems!=items && statusForContent.spoilerRevealed){
items.addAll(contentItems);
}
if((flags & FLAG_NO_EMOJI_REACTIONS)==0
&& AccountSessionManager.get(accountID).getLocalPreferences().emojiReactionsEnabled){
AccountLocalPreferences lp=fragment.getLocalPrefs();
if((flags & FLAG_NO_EMOJI_REACTIONS)==0 && lp.emojiReactionsEnabled &&
(lp.showEmojiReactions!=ONLY_OPENED || fragment instanceof ThreadFragment)){
boolean isMainStatus=fragment instanceof ThreadFragment t && t.getMainStatus().id.equals(statusForContent.id);
items.add(new EmojiReactionsStatusDisplayItem(parentID, fragment, statusForContent, accountID, !isMainStatus, false));
boolean showAddButton=lp.showEmojiReactions==ALWAYS || isMainStatus;
items.add(new EmojiReactionsStatusDisplayItem(parentID, fragment, statusForContent, accountID, !showAddButton, false));
}
FooterStatusDisplayItem footer=null;
if((flags & FLAG_NO_FOOTER)==0){
@@ -304,12 +303,12 @@ public abstract class StatusDisplayItem{
footer.hideCounts=hideCounts;
items.add(footer);
if(status.hasGapAfter && !(fragment instanceof ThreadFragment))
items.add(new GapStatusDisplayItem(parentID, fragment));
items.add(new GapStatusDisplayItem(parentID, fragment, status));
}
int i=1;
boolean inset=(flags & FLAG_INSET)!=0;
// add inset dummy so last content item doesn't clip out of inset bounds
if(inset || footer==null){
if((inset || footer==null) && (flags & FLAG_CHECKABLE)==0){
items.add(new DummyStatusDisplayItem(parentID, fragment));
// in case we ever need the dummy to display a margin for the media grid again:
// (i forgot why we apparently don't need this anymore)
@@ -363,6 +362,7 @@ public abstract class StatusDisplayItem{
GAP,
EXTENDED_FOOTER,
MEDIA_GRID,
PREVIEWLESS_MEDIA_GRID,
WARNING,
FILE,
SPOILER,
@@ -401,24 +401,17 @@ public abstract class StatusDisplayItem{
}
return Optional.empty();
}
// int nextNextPos=getAbsoluteAdapterPosition() + 2;
// if(next.map(n->n instanceof EmojiReactionsStatusDisplayItem e && e.isHidden()).orElse(false)){
// List<StatusDisplayItem> displayItems=item.parentFragment.getDisplayItems();
// return displayItems.size() > nextNextPos
// ? Optional.of(displayItems.get(nextNextPos))
// : Optional.empty();
// }else{
// return next;
// }
public Optional<StatusDisplayItem> getNextDisplayItem(){
return getDisplayItemOffset(1);
}
public Optional<StatusDisplayItem> getDisplayItemOffset(int offset){
int nextPos=getAbsoluteAdapterPosition() + offset;
List<StatusDisplayItem> displayItems=item.parentFragment.getDisplayItems();
return displayItems.size() > nextPos
? Optional.of(displayItems.get(nextPos))
int thisPos=displayItems.indexOf(item);
int offsetPos=thisPos + offset;
return displayItems.size() > offsetPos && thisPos >= 0 && offsetPos >= 0
? Optional.of(displayItems.get(offsetPos))
: Optional.empty();
}

View File

@@ -143,7 +143,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
!item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) &&
item.status.language != null &&
// todo: compare to mastodon locale instead (how do i query that?!)
!item.status.language.equalsIgnoreCase(Locale.getDefault().getLanguage())));
!item.status.language.equalsIgnoreCase(Locale.getDefault().getLanguage())))
&& (!GlobalUserPreferences.translateButtonOpenedOnly || item.textSelectable);
translateWrap.setVisibility(translateVisible ? View.VISIBLE : View.GONE);
translateButton.setText(item.translationShown ? R.string.sk_translate_show_original : R.string.sk_translate_post);
translateInfo.setText(item.translationShown ? itemView.getResources().getString(R.string.sk_translated_using, bottomText != null ? "bottom-java" : item.status.translation.provider) : "");
@@ -184,11 +185,10 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
readMore.setText(item.status.textExpanded ? R.string.sk_collapse : R.string.sk_expand);
StatusDisplayItem next=getNextVisibleDisplayItem().orElse(null);
int bottomPadding=next instanceof FooterStatusDisplayItem
? V.dp(6)
: (!item.inset && next instanceof DummyStatusDisplayItem) ||
next instanceof EmojiReactionsStatusDisplayItem e && !e.isHidden()
? 0
if(next!=null && !next.parentID.equals(item.parentID)) next=null;
int bottomPadding=next instanceof FooterStatusDisplayItem ? V.dp(6)
: item.inset ? V.dp(12)
: (next instanceof EmojiReactionsStatusDisplayItem || next==null) ? 0
: V.dp(12);
itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), bottomPadding);

View File

@@ -4,18 +4,15 @@ import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.AltTextFilter;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.LegacyFilter;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.drawables.SawtoothTearDrawable;
import java.util.ArrayList;
import java.util.List;
// Mind the gap!
@@ -55,7 +52,8 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
@Override
public void onBind(WarningFilteredStatusDisplayItem item) {
filteredItems = item.filteredItems;
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.applyingFilter.title));
String title = item.applyingFilter instanceof AltTextFilter ? item.parentFragment.getString(R.string.sk_no_alt_text) : item.applyingFilter.title;
text.setText(item.parentFragment.getString(R.string.sk_filtered, title));
}
@Override

View File

@@ -99,15 +99,11 @@ public class BlurhashCrossfadeDrawable extends Drawable{
@Override
public int getIntrinsicWidth(){
if(width==0)
return imageDrawable==null ? 1920 : imageDrawable.getIntrinsicWidth();
return width;
}
@Override
public int getIntrinsicHeight(){
if(height==0)
return imageDrawable==null ? 1080 : imageDrawable.getIntrinsicHeight();
return height;
}

View File

@@ -23,9 +23,9 @@ import me.grishka.appkit.utils.V;
public class SawtoothTearDrawable extends Drawable{
private final Paint topPaint, bottomPaint;
private static final int TOP_SAWTOOTH_HEIGHT=5;
private static final int BOTTOM_SAWTOOTH_HEIGHT=3;
private static final int STROKE_WIDTH=2;
private static final int TOP_SAWTOOTH_HEIGHT=4;
private static final int BOTTOM_SAWTOOTH_HEIGHT=4;
private static final int STROKE_WIDTH=1;
private static final int SAWTOOTH_PERIOD=14;
public SawtoothTearDrawable(Context context){

View File

@@ -147,7 +147,7 @@ public class PhotoViewer implements ZoomPanView.Listener{
toolbarWrap.setPadding(0, 0, 0, 0);
videoControls.setPadding(0, 0, 0, 0);
}
insets=insets.replaceSystemWindowInsets(tappable.left, tappable.top, tappable.right, tappable.bottom);
insets=insets.replaceSystemWindowInsets(tappable.left, tappable.top, tappable.right, insets.getSystemWindowInsetBottom());
}
uiOverlay.dispatchApplyWindowInsets(insets);
int bottomInset=insets.getSystemWindowInsetBottom();
@@ -602,7 +602,7 @@ public class PhotoViewer implements ZoomPanView.Listener{
private void updateVideoPosition(){
if(videoPositionNeedsUpdating){
int currentPosition=videoInitialPosition+(int)(SystemClock.uptimeMillis()-videoInitialPositionTime);
int currentPosition=(videoInitialPosition+(int)(SystemClock.uptimeMillis()-videoInitialPositionTime))%videoDuration;
videoSeekBar.setProgress(Math.round((float)currentPosition/videoDuration*10000f));
updateVideoTimeText(currentPosition);
windowView.postOnAnimation(videoPositionUpdater);
@@ -878,6 +878,8 @@ public class PhotoViewer implements ZoomPanView.Listener{
@Override
public void onVideoSizeChanged(MediaPlayer mp, int width, int height){
if(width<=0 || height<=0)
return;
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) wrap.getLayoutParams();
params.width=width;
params.height=height;

View File

@@ -119,6 +119,9 @@ public class ZoomPanView extends FrameLayout implements ScaleGestureDetector.OnS
int width=right-left;
int height=bottom-top;
if(width==0 || height==0)
return;
float scale=Math.min(width/(float)child.getWidth(), height/(float)child.getHeight());
minScale=scale;
maxScale=Math.max(3f, height/(float)child.getHeight());
@@ -306,8 +309,6 @@ public class ZoomPanView extends FrameLayout implements ScaleGestureDetector.OnS
}, 1f).setMinimumVisibleChange(DynamicAnimation.MIN_VISIBLE_CHANGE_ALPHA));
}
}else{
if(animatingTransition)
Log.w(TAG, "updateViewTransform: ", new Throwable().fillInStackTrace());
child.setScaleX(matrixValues[Matrix.MSCALE_X]);
child.setScaleY(matrixValues[Matrix.MSCALE_Y]);
child.setTranslationX(matrixValues[Matrix.MTRANS_X]);

View File

@@ -1715,7 +1715,9 @@ public class TabLayout extends HorizontalScrollView implements CustomViewHelper{
child.getLayoutParams().height);
int childWidthMeasureSpec =
MeasureSpec.makeMeasureSpec(getMeasuredWidth(), MeasureSpec.EXACTLY);
MeasureSpec.makeMeasureSpec(
getMeasuredWidth() - getPaddingLeft() - getPaddingRight(),
MeasureSpec.EXACTLY);
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
}

View File

@@ -10,6 +10,7 @@ import android.widget.TextView;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.TimelineDefinition;
import java.util.EnumSet;
@@ -44,8 +45,8 @@ public class DiscoverInfoBannerHelper{
banner=((Activity)list.getContext()).getLayoutInflater().inflate(R.layout.discover_info_banner, list, false);
TextView text=banner.findViewById(R.id.banner_text);
text.setText(switch(type){
case TRENDING_POSTS -> list.getResources().getString(R.string.trending_posts_info_banner);
case TRENDING_LINKS -> list.getResources().getString(R.string.trending_links_info_banner);
case TRENDING_POSTS -> list.getResources().getString(R.string.sk_trending_posts_info_banner);
case TRENDING_LINKS -> list.getResources().getString(R.string.sk_trending_links_info_banner);
case FEDERATED_TIMELINE -> list.getResources().getString(R.string.sk_federated_timeline_info_banner);
case POST_NOTIFICATIONS -> list.getResources().getString(R.string.sk_notify_posts_info_banner);
case BUBBLE_TIMELINE -> list.getResources().getString(R.string.sk_bubble_timeline_info_banner);
@@ -57,8 +58,10 @@ public class DiscoverInfoBannerHelper{
case TRENDING_POSTS -> R.drawable.ic_fluent_arrow_trending_24_regular;
case TRENDING_LINKS -> R.drawable.ic_fluent_news_24_regular;
case ACCOUNTS -> R.drawable.ic_fluent_people_add_24_regular;
// no icon because those are displayed as timelines - with icon in top left
case LOCAL_TIMELINE, FEDERATED_TIMELINE, BUBBLE_TIMELINE, POST_NOTIFICATIONS -> 0;
case LOCAL_TIMELINE -> TimelineDefinition.LOCAL_TIMELINE.getDefaultIcon().iconRes;
case FEDERATED_TIMELINE -> TimelineDefinition.FEDERATED_TIMELINE.getDefaultIcon().iconRes;
case BUBBLE_TIMELINE -> TimelineDefinition.BUBBLE_TIMELINE.getDefaultIcon().iconRes;
case POST_NOTIFICATIONS -> TimelineDefinition.POSTS_TIMELINE.getDefaultIcon().iconRes;
});
adapter.addAdapter(new SingleViewRecyclerAdapter(banner));
}

View File

@@ -84,23 +84,18 @@ public class InsetStatusItemDecoration extends RecyclerView.ItemDecoration{
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
List<StatusDisplayItem> displayItems=listFragment.getDisplayItems();
// List<StatusDisplayItem> displayItems=listFragment.getDisplayItems();
RecyclerView.ViewHolder holder=parent.getChildViewHolder(view);
if(holder instanceof StatusDisplayItem.Holder<?> sdi){
boolean inset=sdi.getItem().inset;
int pos=holder.getAbsoluteAdapterPosition();
// int pos=holder.getAbsoluteAdapterPosition();
if(inset){
boolean topSiblingInset=pos>0 && displayItems.get(pos-1).inset;
boolean bottomSiblingInset=pos<displayItems.size()-1 && displayItems.get(pos+1).inset;
int pad;
// boolean topSiblingInset=pos>0 && displayItems.get(pos-1).inset;
// boolean bottomSiblingInset=pos<displayItems.size()-1 && displayItems.get(pos+1).inset;
// if(holder instanceof MediaGridStatusDisplayItem.Holder || holder instanceof LinkCardStatusDisplayItem.Holder)
pad=V.dp(16);
// else
// pad=V.dp(12);
boolean insetPadding=((StatusDisplayItem.Holder<?>) holder).getItem().insetPadding;
if(insetPadding)
int pad=V.dp(16);
// else pad=V.dp(12);
outRect.left=pad;
if(insetPadding)
outRect.right=pad;
// had to comment this out because animations with offsets aren't handled properly.

View File

@@ -0,0 +1,56 @@
package org.joinmastodon.android.ui.utils;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
import org.joinmastodon.android.ui.drawables.PlayIconDrawable;
public class PreviewlessMediaAttachmentViewController{
public final View view;
public final MediaGridStatusDisplayItem.GridItemType type;
private final TextView title, domain;
public final View inner;
private final ImageView icon;
private final Context context;
private Status status;
public PreviewlessMediaAttachmentViewController(Context context, MediaGridStatusDisplayItem.GridItemType type){
view=context.getSystemService(LayoutInflater.class).inflate(R.layout.display_item_file, null);
title=view.findViewById(R.id.title);
domain=view.findViewById(R.id.domain);
icon=view.findViewById(R.id.imageView);
inner=view.findViewById(R.id.inner);
this.context=context;
this.type=type;
}
public void bind(Attachment attachment, Status status){
this.status=status;
title.setText(attachment.description != null
? attachment.description
: context.getString(R.string.sk_no_alt_text));
title.setSingleLine(false);
domain.setText(status.sensitive ? context.getString(R.string.sensitive_content_explain) : null);
domain.setVisibility(status.sensitive ? View.VISIBLE : View.GONE);
if(attachment.type == Attachment.Type.IMAGE)
icon.setImageDrawable(context.getDrawable(R.drawable.ic_fluent_image_24_regular));
if(attachment.type == Attachment.Type.VIDEO)
icon.setImageDrawable(context.getDrawable(R.drawable.ic_fluent_video_clip_24_regular));
if(attachment.type == Attachment.Type.GIFV)
icon.setImageDrawable(context.getDrawable(R.drawable.ic_fluent_gif_24_regular));
}
}

View File

@@ -54,6 +54,8 @@ import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.ImageView;
@@ -69,7 +71,6 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.MastodonErrorResponse;
import org.joinmastodon.android.api.StatusInteractionController;
import org.joinmastodon.android.api.requests.accounts.GetAccountByHandle;
import org.joinmastodon.android.api.requests.accounts.SetAccountBlocked;
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
import org.joinmastodon.android.api.requests.accounts.SetAccountMuted;
@@ -83,9 +84,11 @@ import org.joinmastodon.android.api.requests.search.GetSearchResults;
import org.joinmastodon.android.api.requests.statuses.CreateStatus;
import org.joinmastodon.android.api.requests.statuses.DeleteStatus;
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
import org.joinmastodon.android.api.requests.statuses.SetStatusMuted;
import org.joinmastodon.android.api.requests.statuses.SetStatusPinned;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusMuteChangedEvent;
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.FollowRequestHandledEvent;
@@ -97,7 +100,6 @@ import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.fragments.settings.SettingsServerAboutFragment;
import org.joinmastodon.android.fragments.settings.SettingsServerFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AccountField;
@@ -139,7 +141,6 @@ import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiConsumer;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.BiPredicate;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -175,6 +176,19 @@ public class UiUtils {
private static final DateTimeFormatter TIME_FORMATTER=DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
public static int MAX_WIDTH, SCROLL_TO_TOP_DELTA;
public static final float ALPHA_PRESSED=0.55f;
public static final Animation opacityOut, opacityIn;
static {
opacityOut = new AlphaAnimation(1, ALPHA_PRESSED);
opacityOut.setDuration(300);
opacityOut.setInterpolator(CubicBezierInterpolator.DEFAULT);
opacityOut.setFillAfter(true);
opacityIn = new AlphaAnimation(ALPHA_PRESSED, 1);
opacityIn.setDuration(400);
opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT);
}
private UiUtils() {
}
@@ -194,28 +208,42 @@ public class UiUtils {
}
public static String formatRelativeTimestamp(Context context, Instant instant) {
long t = instant.toEpochMilli();
long now = System.currentTimeMillis();
return formatPeriodBetween(context, instant, null);
}
public static String formatPeriodBetween(Context context, Instant since, Instant until) {
boolean ago = until == null;
long t = since.toEpochMilli();
long now = ago ? System.currentTimeMillis() : until.toEpochMilli();
long diff = now - t;
if(diff<1000L){
return context.getString(R.string.time_now);
}else if(diff<60_000L){
return context.getString(R.string.time_seconds_ago_short, diff/1000L);
long time = diff/1000L;
return ago ?
context.getString(R.string.time_seconds_ago_short, time) :
context.getResources().getQuantityString(R.plurals.sk_time_seconds, (int) time, time);
}else if(diff<3600_000L){
return context.getString(R.string.time_minutes_ago_short, diff/60_000L);
long time = diff/60_000L;
return ago ?
context.getString(R.string.time_minutes_ago_short, time) :
context.getResources().getQuantityString(R.plurals.sk_time_minutes, (int) time, time);
}else if(diff<3600_000L*24L){
return context.getString(R.string.time_hours_ago_short, diff/3600_000L);
long time = diff/3600_000L;
return ago ?
context.getString(R.string.time_hours_ago_short, time) :
context.getResources().getQuantityString(R.plurals.sk_time_hours, (int) time, time);
} else {
int days = (int) (diff / (3600_000L * 24L));
if (days > 30) {
ZonedDateTime dt = instant.atZone(ZoneId.systemDefault());
if (ago && days > 30) {
ZonedDateTime dt = since.atZone(ZoneId.systemDefault());
if (dt.getYear() == ZonedDateTime.now().getYear()) {
return DATE_FORMATTER_SHORT.format(dt);
} else {
return DATE_FORMATTER_SHORT_WITH_YEAR.format(dt);
}
}
return context.getString(R.string.time_days_ago_short, days);
return ago ? context.getString(R.string.time_days_ago_short, days) : context.getResources().getQuantityString(R.plurals.sk_time_days, days, days);
}
}
@@ -605,7 +633,7 @@ public class UiUtils {
.exec(accountID);
})
.setNegativeButton(R.string.cancel, null)
.setIcon(currentlyMuted ? R.drawable.ic_fluent_speaker_0_28_regular : R.drawable.ic_fluent_speaker_off_28_regular)
.setIcon(currentlyMuted ? R.drawable.ic_fluent_speaker_2_28_regular : R.drawable.ic_fluent_speaker_off_28_regular)
.show();
}
@@ -638,6 +666,32 @@ public class UiUtils {
);
}
public static void confirmToggleMuteConversation(Activity activity, String accountID, Status status, Runnable resultCallback) {
showConfirmationAlert(activity,
status.muted ? R.string.mo_unmute_conversation : R.string.mo_mute_conversation,
status.muted ? R.string.mo_confirm_to_unmute_conversation : R.string.mo_confirm_to_mute_conversation,
status.muted ? R.string.do_unmute : R.string.do_mute,
status.muted ? R.drawable.ic_fluent_alert_28_regular : R.drawable.ic_fluent_alert_off_28_regular,
() -> new SetStatusMuted(status.id, !status.muted)
.setCallback(new Callback<Status>(){
@Override
public void onSuccess(Status result){
resultCallback.run();
Toast.makeText(activity, result.muted ? R.string.mo_muted_conversation_successfully : R.string.mo_unmuted_conversation_successfully, Toast.LENGTH_SHORT).show();
E.post(new StatusMuteChangedEvent(result));
}
@Override
public void onError(ErrorResponse error){
error.showToast(activity);
}
})
.wrapProgress(activity, status.muted ? R.string.mo_unmuting : R.string.mo_muting, false)
.exec(accountID)
);
}
public static void confirmDeleteScheduledPost(Activity activity, String accountID, ScheduledStatus status, Runnable resultCallback) {
boolean isDraft = status.scheduledAt.isAfter(CreateStatus.DRAFTS_AFTER_INSTANT);
showConfirmationAlert(activity,
@@ -792,7 +846,7 @@ public class UiUtils {
confirmToggleMuteUser(activity, accountID, account, true, resultCallback);
} else if (!relationship.following && !relationship.requested) {
follow(activity, accountID, account, true, progressCallback, resultCallback);
} else {
} else if (GlobalUserPreferences.confirmUnfollow){
showConfirmationAlert(activity,
activity.getString(R.string.mo_confirm_unfollow_title),
activity.getString(R.string.mo_confirm_unfollow, account.getDisplayUsername()),
@@ -800,8 +854,9 @@ public class UiUtils {
0,
() -> follow(activity, accountID, account, false, progressCallback, resultCallback),
() -> progressCallback.accept(false));
} else {
follow(activity, accountID, account, false, progressCallback, resultCallback);
}
}
private static void follow(Activity activity, String accountID, Account account, boolean followed, Consumer<Boolean> progressCallback, Consumer<Relationship> resultCallback) {
@@ -1172,7 +1227,7 @@ public class UiUtils {
return Optional.empty();
}
return Optional.of(new GetSearchResults(query.getQuery(), type, true).setCallback(new Callback<>() {
return Optional.of(new GetSearchResults(query.getQuery(), type, true, null, 0, 0).setCallback(new Callback<>() {
@Override
public void onSuccess(SearchResults results) {
Optional<T> result = extractResult.apply(results);
@@ -1269,7 +1324,7 @@ public class UiUtils {
}
public static MastodonAPIRequest<SearchResults> lookupAccountHandle(Context context, String accountID, Pair<String, Optional<String>> queryHandle, BiConsumer<Class<? extends Fragment>, Bundle> go) {
String fullHandle = ("@" + queryHandle.first) + (queryHandle.second.map(domain -> "@" + domain).orElse(""));
return new GetSearchResults(fullHandle, GetSearchResults.Type.ACCOUNTS, true)
return new GetSearchResults(fullHandle, GetSearchResults.Type.ACCOUNTS, true, null, 0, 0)
.setCallback(new Callback<>() {
@Override
public void onSuccess(SearchResults results) {
@@ -1332,7 +1387,7 @@ public class UiUtils {
})
.execNoAuth(uri.getHost()));
} else if (looksLikeMastodonUrl(url)) {
return Optional.of(new GetSearchResults(url, null, true)
return Optional.of(new GetSearchResults(url, null, true, null, 0, 0)
.setCallback(new Callback<>() {
@Override
public void onSuccess(SearchResults results) {

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