Compare commits

...

363 commits
3.27.1 ... main

Author SHA1 Message Date
Thomas
6d7faa996d Release 3.31.3 2025-04-01 18:28:14 +02:00
Thomas
19f5e4c801 Merge pull request 'Add more logos' (#1162) from 0xd9a/Fedilab:more_icons into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1162
2025-04-01 16:17:27 +00:00
Thomas
16fb7dcc1f Merge branch 'fix_527' into develop 2025-04-01 18:17:02 +02:00
Thomas
e7b9fd9f1d Display reaction buttons only if instance 2025-04-01 18:16:31 +02:00
0xd9a
97f9c78073 Add new logos 2025-04-01 20:27:02 +05:30
Thomas
c8c1e5e75b Improve a little more media layout with translations 2025-04-01 15:38:30 +02:00
Thomas
d901a50bba Merge remote-tracking branch 'origin/develop' into develop 2025-04-01 14:58:43 +02:00
Thomas
78a0c23e34 Remove permission FOREGROUND_SERVICE 2025-04-01 14:58:01 +02:00
Thomas
c69cf6e295 Remove permission FOREGROUND_SERVICE 2025-04-01 14:57:32 +02:00
Thomas
98a8ac0df3 Make logout/proxy button more visible in main menu 2025-04-01 10:11:11 +02:00
Thomas
90a6297c8f Fix status bar icons not visible in light theme with custom accent color 2025-04-01 09:43:53 +02:00
Максим Горпиніч
1981876fac
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (30 of 30 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-04-01 07:10:54 +02:00
Thomas
fed33cf600 Release 3.31.2 2025-03-31 18:34:23 +02:00
Thomas
02d6ef3bf5 Change the media activity status bar 2025-03-31 18:28:02 +02:00
Thomas
7bcb8dc9fb Merge remote-tracking branch 'origin/develop' into develop 2025-03-31 18:22:17 +02:00
Thomas
462f13f492 Downgrade Material lib until fix with the new Tonal Surface Color system 2025-03-31 18:21:58 +02:00
Thomas
5dfdb99c06 Merge branch 'fix_526' into develop 2025-03-31 15:06:29 +02:00
Thomas
62951a4a3a Change layout for media descriptions 2025-03-31 15:06:09 +02:00
Максим Горпиніч
27a9199e05
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (29 of 29 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-03-31 12:54:32 +02:00
Thomas
62fe2cde10 Fix issue #1161 - handle included twice when replying to a self user's boost 2025-03-31 08:33:27 +02:00
Hosted Weblate
f4a5c31f8f
Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/
Translation: Fedilab/description
2025-03-31 07:41:32 +02:00
Thomas
d0835834f7 Merge remote-tracking branch 'origin/develop' into develop 2025-03-31 07:41:23 +02:00
Thomas
40a7d6f29b Merge branch 'fix_526' into develop 2025-03-31 07:41:11 +02:00
Thomas
2f663d1bd9 Fix a crash when translating media descriptions 2025-03-31 07:40:50 +02:00
Ajeje Brazorf
5f509bb481
Translated using Weblate (Sardinian)
Currently translated at 100.0% (1200 of 1200 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2025-03-31 04:01:21 +02:00
Antonin Del Fabbro
7121cca1f1
Translated using Weblate (French)
Currently translated at 99.9% (1199 of 1200 strings)

Co-authored-by: Antonin Del Fabbro <message@antonin.one>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2025-03-31 04:01:19 +02:00
Thomas
19d64a778f #1160 - Use of fedilinks (scheme web+ap) / Fix url scheme to support with and without // 2025-03-30 12:34:35 +02:00
ButterflyOfFire
f7ca327572
Translated using Weblate (French)
Currently translated at 99.9% (1199 of 1200 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2025-03-30 12:01:15 +02:00
Thomas
aedfaaddbc #1160 - Open profile when receiving an intent 2025-03-29 16:50:36 +01:00
Thomas
db17df93f0 #1160 - Detects acct and intent in URL with scheme web+activitypub 2025-03-29 16:07:53 +01:00
ButterflyOfFire
67c455f057
Translated using Weblate (Kabyle)
Currently translated at 61.6% (740 of 1200 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/kab/
Translation: Fedilab/Strings
2025-03-29 07:02:50 +01:00
Thomas
b961145575 Release 3.31.1 2025-03-28 16:50:18 +01:00
Thomas
3f12ad0f2d #1122 - Support instance only for GoToSocial 2025-03-28 16:42:59 +01:00
Thomas
e83b4d1acf Merge remote-tracking branch 'origin/develop' into develop 2025-03-28 09:25:04 +01:00
Thomas
4387cac67f Use language of messages for translations with MinT 2025-03-28 09:24:48 +01:00
Thomas
6aa3fd738a Merge pull request 'Update README.md' (#1157) from 0xd9a/Fedilab:update_readme into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1157
2025-03-28 05:43:00 +00:00
0xd9a
f48753c780 Update README.md 2025-03-28 08:52:40 +05:30
Максим Горпиніч
969d4457d0
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (29 of 29 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-03-27 19:16:01 +01:00
Thomas
fec6b8510e Release 3.31.1 2025-03-27 16:39:38 +01:00
Thomas
9f57e77d77 Add MinT machine translation system support 2025-03-27 16:31:12 +01:00
Thomas
f3ae0a6cea Fix issue #1136 - Top bar coloring at scroll for conversations 2025-03-27 15:14:28 +01:00
Thomas
f2ad02bbda Fix issue #1154 - Back screen when going back from the Peertube section 2025-03-27 12:22:10 +01:00
Thomas
cb947a7d3c Fix a crash when unpinning timelines 2025-03-27 12:08:54 +01:00
Thomas
7bdc67f922 Merge remote-tracking branch 'origin/develop' into develop 2025-03-27 10:14:08 +01:00
Thomas
504816e21c Fix issue #1156 - GIF are not displayed in timelines 2025-03-27 09:55:56 +01:00
Максим Горпиніч
152d70e4d7
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (28 of 28 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-03-26 21:01:53 +01:00
大王叫我来巡山
3ba4b64952
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1198 of 1198 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2025-03-26 15:02:03 +01:00
josé m
d3ec23fad5
Translated using Weblate (Galician)
Currently translated at 100.0% (1198 of 1198 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2025-03-26 15:02:01 +01:00
Максим Горпиніч
4160a4be1b
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1198 of 1198 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-03-26 01:01:59 +01:00
Thomas
c982e5a452 Release 3.31.0 2025-03-25 17:08:16 +01:00
Thomas
5b8d589598 Merge branch 'Fix_523' into develop 2025-03-25 16:57:04 +01:00
Thomas
0590458738 Merge remote-tracking branch 'origin/develop' into develop 2025-03-25 16:56:25 +01:00
Thomas
2e66b1dad6 Fix issue #1152 - Add a pinned Trending timeline (can be hidden in Manage Timelines) 2025-03-25 16:55:55 +01:00
Максим Горпиніч
59dc4a5a9f
Translated using Weblate (Ukrainian)
Currently translated at 99.8% (1196 of 1198 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-03-25 11:55:03 +01:00
Thomas
8ddb02ddeb Add a fallback to default translator when the DeepL API key is empty 2025-03-25 10:59:35 +01:00
Thomas
b46eed26ba Fix issue #727 - Only a part of DeepL translations are shown 2025-03-25 10:30:08 +01:00
Thomas
1b711d03eb Merge remote-tracking branch 'origin/develop' into develop 2025-03-25 09:48:26 +01:00
Thomas
9fbdfc3db0 add icon for the pixelfed settings 2025-03-25 09:46:47 +01:00
Thomas
9f79620d58 Fix issue #1150 - Allow to disable fullscreen media for Pixelfed 2025-03-25 09:41:53 +01:00
Thomas
6f3433da03 - Fix Lingva truncated translations
- Improve deobfuscation process
2025-03-25 08:16:48 +01:00
Thomas
6f26a55ae8 Merge pull request 'Add tooltips for tabs in profile (Issue #104)' (#1151) from 0xd9a/Fedilab:profile_tabs_tooltips into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1151
2025-03-24 07:07:06 +00:00
Thomas
07b7347417 Fix a crash when fetching remote profiles 2025-03-24 07:47:54 +01:00
Thomas
a9c50ab41f Fix a crash when displaying Home cache charts 2025-03-24 07:38:27 +01:00
Thomas
524fb7dd2a Fix a crash when animating a custom emoji 2025-03-24 07:32:43 +01:00
0xd9a
58aecf8db9 Add tooltips for tabs in profile (Issue #104) 2025-03-23 07:00:35 +05:30
Thomas
657b63b201 Merge pull request 'Increase touch area of reply, menu buttons (Issue #741)' (#1149) from 0xd9a/Fedilab:a_bit_better_buttons into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1149
2025-03-18 13:06:30 +00:00
0xd9a
f7ac237d6c Increase touch area of reply, menu buttons (Issue #741) 2025-03-18 18:08:38 +05:30
Thomas
5cb3b43eeb Fix issue #1147 - Media description not updated when there are several 2025-03-18 09:05:24 +01:00
Thomas
1d5d874415 Merge pull request 'Show a dialog after settings export (Issue #5)' (#1146) from 0xd9a/Fedilab:develop into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1146
2025-03-17 06:29:12 +00:00
0xd9a
66b117b81f Show a dialog after settings export (Issue #5) 2025-03-17 11:29:19 +05:30
Vaclovas Intas
97db978c8a
Translated using Weblate (Lithuanian)
Currently translated at 25.9% (310 of 1194 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/lt/
Translation: Fedilab/Strings
2025-03-15 22:33:03 +01:00
大王叫我来巡山
721d18669a
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1194 of 1194 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2025-03-15 20:19:46 +01:00
Максим Горпиніч
71c183d8a7
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1194 of 1194 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-03-15 20:19:46 +01:00
josé m
aa0ad9d57e
Translated using Weblate (Galician)
Currently translated at 100.0% (1194 of 1194 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2025-03-15 13:30:20 +01:00
Максим Горпиніч
1bf44bad10
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1194 of 1194 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-03-14 19:16:48 +00:00
Максим Горпиніч
5b3bbee285
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (27 of 27 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-03-14 20:16:38 +01:00
Thomas
238f31e3fc Release 3.30.1 2025-03-14 17:21:30 +01:00
Thomas
88c18cc487 Follow Twitter/X tags through Nitter 2025-03-14 16:51:01 +01:00
Thomas
0d2ae2eedf Fix layout issues in small dialogs (padding) 2025-03-14 16:13:01 +01:00
Thomas
a63175ff7d Merge remote-tracking branch 'origin/develop' into develop 2025-03-14 15:58:50 +01:00
Thomas
9001676971 Fix async actions with cached notifications 2025-03-14 10:50:46 +01:00
Thomas
ef6319b735 Update Unifiedpush Android connector to 3.0.7 2025-03-14 07:37:46 +01:00
XblateX
e14d2c143a
Translated using Weblate (Russian)
Currently translated at 30.7% (8 of 26 strings)

Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ru/
Translation: Fedilab/description
2025-03-14 03:25:24 +01:00
Thomas
b0cc06a3e5 Fix issue #1142 - Filters not applied to media descriptions 2025-03-13 16:37:20 +01:00
Thomas
90da257037 Fix #1143 - Fix a crash when scrolling 2025-03-13 15:52:48 +01:00
Thomas
916fe40381 Fix a crash with threads and decorations 2025-03-13 10:36:45 +01:00
Thomas
4c23100021 Fix a crash with media when exiting the app 2025-03-13 10:36:25 +01:00
Thomas
440fb41f1c Reduce the buffering when looping through GIF 2025-03-13 10:36:03 +01:00
Thomas
41d98b88d2 remove automatic backup for Google 2025-03-10 11:51:34 +01:00
Максим Горпиніч
d9cdfc88e9
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (26 of 26 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-03-06 23:31:26 +01:00
Thomas
3a571b8a22 Merge pull request 'Update README.md: Change wiki to documentation' (#1138) from 0xd9a/Fedilab:update_readme into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1138
2025-03-06 21:02:53 +00:00
0xd9a
b51ba4d88b Update README.md: Change wiki to documentation 2025-03-07 02:28:39 +05:30
Thomas
a71bf2c6f3 Release 3.30.0 - quick link fix 2025-03-06 19:10:07 +01:00
Thomas
97d803e97f Release 3.30.0 2025-03-06 17:35:20 +01:00
Thomas
0b29f2ec0a Merge remote-tracking branch 'origin/develop' into develop 2025-03-06 17:31:01 +01:00
Thomas
de9c4f902f Fix admin reports not accessible 2025-03-06 17:30:52 +01:00
Максим Горпиніч
95a344b3c2
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (25 of 25 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-03-06 16:18:50 +01:00
Thomas
170a5dfd06 small fix with use a token 2025-03-06 16:01:14 +01:00
Thomas
f35e75572f Prepare release notes 2025-03-06 15:55:45 +01:00
Thomas
7cb1e2d920 Fix fetch more size 2025-03-06 14:46:57 +01:00
Thomas
0fad05c049 Merge remote-tracking branch 'origin/develop' into develop 2025-03-06 11:06:52 +01:00
Thomas
94ea385aff Fix issue #1095 - Drafts not saved when adding/editing media descriptions 2025-03-06 11:06:25 +01:00
Thomas
ab30fc7bf2 Fix a crash when adding a media 2025-03-06 10:16:16 +01:00
Hosted Weblate
f16b415f7a
Update translation files
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/
Translation: Fedilab/description
2025-03-06 10:06:39 +01:00
Thomas
65dea8bf56 Prepare some release notes 2025-03-06 10:05:47 +01:00
Thomas
f266b582df Merge remote-tracking branch 'origin/develop' into develop 2025-03-06 07:33:01 +01:00
Thomas
deef87ef9d Fix issue #1136 - Top bar coloring at scroll 2025-03-06 07:32:50 +01:00
大王叫我来巡山
827124b79b
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1193 of 1193 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2025-03-06 04:12:35 +01:00
Irene
ea677dc7c6
Translated using Weblate (Swedish)
Currently translated at 6.2% (4 of 64 strings)

Co-authored-by: Irene <ps86m042i@mozmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/sv/
Translation: Fedilab/description
2025-03-05 18:03:54 +01:00
Thomas
325fbf8f5f Fix issue #1128 - Move QR code to header 2025-03-05 17:42:46 +01:00
Thomas
592be1f057 Merge remote-tracking branch 'origin/develop' into develop 2025-03-05 17:01:44 +01:00
Thomas
28021b5047 Fix issue #1131 - User search suggestions have duplicates 2025-03-05 17:01:31 +01:00
Irene
52138618bd
Translated using Weblate (Swedish)
Currently translated at 3.1% (2 of 64 strings)

Co-authored-by: Irene <ps86m042i@mozmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/sv/
Translation: Fedilab/description
2025-03-05 14:33:01 +01:00
Thomas
7b2e44c407 Fix Crash when editing scheduled message with attachments 2025-03-05 11:30:40 +01:00
Thomas
acc9f84533 Merge remote-tracking branch 'origin/develop' into develop 2025-03-05 10:38:33 +01:00
Thomas
8f641c4071 Fix issue #113 - Android password manager with Peertube 2025-03-05 10:38:22 +01:00
Vaclovas Intas
82122e2269
Translated using Weblate (Lithuanian)
Currently translated at 24.8% (296 of 1193 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/lt/
Translation: Fedilab/Strings
2025-03-05 05:08:55 +01:00
Максим Горпиніч
da81d15771
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1193 of 1193 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-03-05 05:08:54 +01:00
josé m
fe714aca0b
Translated using Weblate (Galician)
Currently translated at 100.0% (1193 of 1193 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2025-03-05 05:08:53 +01:00
Vaclovas Intas
5e21096f8c
Translated using Weblate (Lithuanian)
Currently translated at 4.6% (3 of 64 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/lt/
Translation: Fedilab/description
2025-03-05 05:08:38 +01:00
Максим Горпиніч
2049abff1e
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (64 of 64 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-03-05 05:08:37 +01:00
Thomas
848d015fd8 Release 3.30.0-beta-2 2025-03-04 17:58:49 +01:00
Thomas
01109c3842 Allow to scroll buttons for larger screen in conversation 2025-03-04 17:50:03 +01:00
Thomas
cbed45da29 Merge remote-tracking branch 'origin/develop' into develop 2025-03-04 17:05:45 +01:00
Thomas
f8ebd3435d Allow to login with a token 2025-03-04 17:05:33 +01:00
Thomas
020be16f11 Fix a crash 2025-03-04 15:41:15 +01:00
Thomas
35cd1b7b3e Fix a crash 2025-03-04 15:37:33 +01:00
Thomas
0eb3552c3c Add margin to quoted messages 2025-03-04 15:34:55 +01:00
Thomas
8d3621dbe7 Fix Nitter instances 2025-03-04 15:19:51 +01:00
Vaclovas Intas
03cc39d2e1
Translated using Weblate (Lithuanian)
Currently translated at 23.1% (275 of 1189 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/lt/
Translation: Fedilab/Strings
2025-03-04 03:52:33 +01:00
Vaclovas Intas
b913f49918
Translated using Weblate (Lithuanian)
Currently translated at 22.0% (262 of 1189 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/lt/
Translation: Fedilab/Strings
2025-03-03 23:12:10 +01:00
Lukáš Jelínek
661c373a05
Translated using Weblate (Czech)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2025-03-02 15:22:52 +01:00
Thomas
fae30e63a8 Fix Nitter using web calls 2025-03-02 11:49:22 +01:00
Isard
eb40866ea2
Translated using Weblate (Catalan)
Currently translated at 94.1% (1119 of 1189 strings)

Co-authored-by: Isard <isard@puntnet.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2025-03-02 11:04:12 +01:00
Thomas
c6494d7e04 Fix issue #1130 - Use Pixelfed layout 2025-03-01 16:23:07 +01:00
Thomas
e0b8b60fed Fix issue #1130 - Follow Pixelfed instance from the discover timeline 2025-03-01 16:06:39 +01:00
josé m
cdb0890fac
Translated using Weblate (Galician)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2025-02-28 17:02:55 +00:00
Максим Горпиніч
b5902d7ac8
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (63 of 63 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-02-28 08:02:21 +01:00
Thomas
885e8eb5d8 Merge remote-tracking branch 'origin/develop' into develop 2025-02-27 16:59:35 +01:00
Thomas
0cfb1b1eae Prepares 2.30.0-beta-1 2025-02-27 16:59:10 +01:00
Thomas
ee89abe16f keep media proportion in timelines for Pixelfed 2025-02-27 16:50:06 +01:00
Thomas
310d6bf4aa Add like button on Pixelfed timelines 2025-02-27 15:06:51 +01:00
Thomas
f94251776b Fix Pixelfed view not used for Pixelfed accounts 2025-02-27 14:11:47 +01:00
Thomas
d98ba21957 Fix issue #1129 - Changed: Give more width to the detailed message in conversations 2025-02-27 11:28:47 +01:00
Thomas
02a9e26f2c UNICODE_CASE for regex 2025-02-27 11:04:03 +01:00
Thomas
55098c50f1 #1119 - Fix URLs not clickable when Markdown is enabled 2025-02-27 10:06:08 +01:00
Thomas
8c0b5032ec #1119 - Deal with URLs having spannable with space characters 2025-02-26 12:00:00 +01:00
Thomas
d28a114650 Fix issue #1112 - Don't lowercase xmpp url 2025-02-26 10:51:36 +01:00
Максим Горпиніч
90a42c6e04
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (62 of 62 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-02-26 09:49:25 +01:00
Languages add-on
9068a60b99
Added translation using Weblate (Lithuanian)
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2025-02-26 01:46:13 +01:00
Thomas
efc8d9d502 Release 3.29.2 2025-02-25 18:06:41 +01:00
Thomas
4c3e8b48dd Merge remote-tracking branch 'origin/develop' into develop 2025-02-25 17:50:16 +01:00
Thomas
23b6aa4c2b #1111 - Fix wrong muted time 2025-02-25 17:46:23 +01:00
Thomas
acff2ae390 #1112 - Fix xmpp links not opening xmpp client 2025-02-25 17:18:08 +01:00
Thomas
98adcc1abd Fix issue with names not displayed fully 2025-02-25 10:35:54 +01:00
Thomas
6d47a8736e Merge pull request 'Optimizations regarding push' (#1127) from s1m/Fedilab:optimizations_push into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1127
2025-02-25 09:28:21 +00:00
sim
ec60b63c68 Unregister push endpoint onUnregistered 2025-02-25 10:20:03 +01:00
sim
b26b10c651 Always register push endpoint
The mastodon server may remove the endpoint if the push server
has been in an inconsistent state (returning a 404), or the endpoint
may not be restored after a backup, or other edge cases
2025-02-25 10:19:43 +01:00
sim
f93533f95b Remove useless exclude 2025-02-25 10:17:09 +01:00
Thomas
ef50b5261a Lib update + fix TransactionTooLargeException 2025-02-25 09:47:53 +01:00
Vaclovas Intas
04e18c7518
Translated using Weblate (Lithuanian)
Currently translated at 25.9% (309 of 1190 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/lt/
Translation: Fedilab/Strings
2025-02-25 08:53:11 +01:00
Vaclovas Intas
a2338c5fca
Translated using Weblate (Lithuanian)
Currently translated at 24.7% (294 of 1190 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/lt/
Translation: Fedilab/Strings
2025-02-25 07:14:10 +00:00
Vaclovas Intas
7087f80c9c
Translated using Weblate (Lithuanian)
Currently translated at 4.9% (3 of 61 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/lt/
Translation: Fedilab/description
2025-02-25 08:13:55 +01:00
Vaclovas Intas
8512db5c01
Translated using Weblate (Lithuanian)
Currently translated at 24.5% (292 of 1190 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/lt/
Translation: Fedilab/Strings
2025-02-25 08:11:50 +01:00
Vaclovas Intas
5f53cb39bd
Translated using Weblate (Lithuanian)
Currently translated at 3.2% (2 of 61 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/lt/
Translation: Fedilab/description
2025-02-24 19:40:00 +01:00
Languages add-on
e3a862abff
Added translation using Weblate (Lithuanian)
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2025-02-24 17:57:10 +01:00
Thomas
a20f583dee Fix issue #1125 - Crash when changing the type of notifications 2025-02-24 11:36:02 +01:00
Thomas
efbfbfbc2f remove useless code 2025-02-24 10:41:05 +01:00
Максим Горпиніч
8a408c4925
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (61 of 61 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-02-24 01:03:36 +01:00
Thomas
5aa8cd909f Fix a crash in notifications for Sharkey 2025-02-23 10:51:50 +01:00
Thomas
2ddc0540a8 Release 3.29.1 2025-02-22 17:04:33 +01:00
Thomas
ef83f58648 Fix a crash 2025-02-22 16:51:05 +01:00
Thomas
91a2d61fd0 Change link for push notification helper 2025-02-22 16:11:43 +01:00
Thomas
f3265b439a Merge remote-tracking branch 'origin/develop' into develop 2025-02-22 15:49:47 +01:00
Thomas
1ca3670cb4 Fix emoji picker when there is no result 2025-02-22 15:49:23 +01:00
大王叫我来巡山
5f5cf2e3e5
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1190 of 1190 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2025-02-22 14:10:12 +01:00
josé m
37d319215c
Translated using Weblate (Galician)
Currently translated at 100.0% (1190 of 1190 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2025-02-22 14:10:12 +01:00
Thomas
661b7fb2b0 - Fix issue #961 - Quotes broken with Markdowns 2025-02-22 10:43:37 +01:00
Thomas
1a0131e05a - Fix a display bug from 2.29.0 2025-02-22 10:26:20 +01:00
Thomas
b034f6731a - Fix reports crashes after submitting
- Use full reports for profiles
2025-02-22 09:41:46 +01:00
Thomas
cb96f0df44 Merge remote-tracking branch 'origin/develop' into develop 2025-02-22 09:10:50 +01:00
Thomas
f39ba15194 Fix issue #1123 - Likes in Sharkey show up as new follows 2025-02-22 09:10:31 +01:00
Thomas
8b42c6d2b6 Remove registration for Google flavor 2025-02-22 08:51:59 +01:00
Максим Горпиніч
753cd5743b
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1190 of 1190 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-02-21 20:52:21 +01:00
Максим Горпиніч
39c7157b9f
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (60 of 60 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-02-21 20:52:11 +01:00
Anonymous
2d38090964
Translated using Weblate (Tamil)
Currently translated at 99.2% (1181 of 1190 strings)

Translated using Weblate (Gaelic)

Currently translated at 99.7% (1187 of 1190 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 54.8% (653 of 1190 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 99.7% (1187 of 1190 strings)

Translated using Weblate (Vietnamese)

Currently translated at 71.8% (855 of 1190 strings)

Translated using Weblate (Turkish)

Currently translated at 99.7% (1187 of 1190 strings)

Translated using Weblate (Sinhala)

Currently translated at 55.7% (664 of 1190 strings)

Translated using Weblate (Sardinian)

Currently translated at 99.7% (1187 of 1190 strings)

Translated using Weblate (Portuguese)

Currently translated at 84.6% (1007 of 1190 strings)

Translated using Weblate (Polish)

Currently translated at 99.7% (1187 of 1190 strings)

Translated using Weblate (Norwegian Bokmål)

Currently translated at 91.7% (1092 of 1190 strings)

Translated using Weblate (Dutch)

Currently translated at 92.5% (1101 of 1190 strings)

Translated using Weblate (Japanese)

Currently translated at 99.5% (1185 of 1190 strings)

Translated using Weblate (Italian)

Currently translated at 98.9% (1177 of 1190 strings)

Translated using Weblate (Hungarian)

Currently translated at 57.8% (689 of 1190 strings)

Translated using Weblate (Galician)

Currently translated at 99.7% (1187 of 1190 strings)

Translated using Weblate (French)

Currently translated at 99.6% (1186 of 1190 strings)

Translated using Weblate (Basque)

Currently translated at 95.7% (1139 of 1190 strings)

Translated using Weblate (Spanish)

Currently translated at 99.6% (1186 of 1190 strings)

Translated using Weblate (Esperanto)

Currently translated at 81.5% (970 of 1190 strings)

Translated using Weblate (Czech)

Currently translated at 99.7% (1187 of 1190 strings)

Translated using Weblate (Catalan)

Currently translated at 78.9% (939 of 1190 strings)

Translated using Weblate (Arabic)

Currently translated at 84.9% (1011 of 1190 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eo/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eu/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gd/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/hu/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/it/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nb_NO/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/nl/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pl/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pt/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/si/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ta/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/vi/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hant/
Translation: Fedilab/Strings
2025-02-21 17:09:46 +01:00
Thomas
daf1ff37ff Merge remote-tracking branch 'origin/develop' into develop 2025-02-21 16:57:03 +01:00
Thomas
759de7bca0 prepare release 3.29.0 2025-02-21 16:55:45 +01:00
Thomas
031c842ba7 Fix issue #1090 - Instant search of Hashtag repeats results 2025-02-21 16:44:27 +01:00
Thomas
7e78b5da6e Edit scheduled threads 2025-02-21 15:34:02 +01:00
Thomas
7d9d2346cc Allow to edit scheduled messages from server side 2025-02-21 11:32:34 +01:00
Thomas
92eb1ea3d1 Order list name alphabetically in profiles 2025-02-21 08:50:16 +01:00
Thomas
c49fe7901a Fix Peertube instances picker 2025-02-20 18:44:37 +01:00
Thomas
fc24e63319 Fix #1120 - Display a message when clicking a link without Internet connection 2025-02-20 17:29:04 +01:00
Thomas
97e30e00b4 Fallback to 34 + update libs 2025-02-20 11:38:50 +01:00
Thomas
38a630a4e5 Push notifications 2025-02-19 16:44:29 +01:00
ButterflyOfFire
a8e362273c
Translated using Weblate (Kabyle)
Currently translated at 61.5% (732 of 1189 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/kab/
Translation: Fedilab/Strings
2025-02-19 13:16:05 +01:00
Thomas
318a566e76 update libs + fix bugs 2025-02-18 16:10:06 +01:00
Thomas
96a43a7c32 Fix build issue 2025-02-18 12:13:56 +01:00
pitroig
dd0a432b02
Translated using Weblate (Catalan)
Currently translated at 6.7% (4 of 59 strings)

Co-authored-by: pitroig <ona@riseup.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ca/
Translation: Fedilab/description
2025-02-17 08:08:41 +01:00
Максим Горпиніч
4d29a2baf8
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-02-15 17:02:00 +01:00
XblateX
c9325d5a53
Translated using Weblate (Russian)
Currently translated at 84.2% (1002 of 1189 strings)

Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2025-02-15 17:01:58 +01:00
Mads Damgaard Mortensen
04e8f7318c
Translated using Weblate (Danish)
Currently translated at 8.4% (5 of 59 strings)

Co-authored-by: Mads Damgaard Mortensen <weblate.upcountry931@passmail.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/da/
Translation: Fedilab/description
2025-02-14 06:08:16 +01:00
XblateX
37428d8e24
Translated using Weblate (Russian)
Currently translated at 83.5% (993 of 1189 strings)

Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2025-02-09 03:02:40 +00:00
snue pirat
0914fd1166
Translated using Weblate (Danish)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: snue pirat <snue@proton.me>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/da/
Translation: Fedilab/Strings
2025-02-05 00:02:03 +01:00
snue pirat
3799bf4a48
Translated using Weblate (Danish)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: snue pirat <snue@proton.me>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/da/
Translation: Fedilab/Strings
2025-02-03 04:03:07 +01:00
Максим Горпиніч
992df41002
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-02-01 23:41:05 +01:00
snue pirat
a965922dd7
Translated using Weblate (Danish)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: snue pirat <snue@proton.me>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/da/
Translation: Fedilab/Strings
2025-02-01 23:41:04 +01:00
Максим Горпиніч
89eaa0ea3c
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (59 of 59 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-02-01 23:40:46 +01:00
Hosted Weblate
370fb94e21
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
Translation: Fedilab/Strings
2025-01-29 21:02:11 +01:00
ButterflyOfFire
c4ad7ff87a
Translated using Weblate (Kabyle)
Currently translated at 61.5% (732 of 1189 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/kab/
Translation: Fedilab/Strings
2025-01-29 21:02:08 +01:00
snue pirat
86c7ea4021
Translated using Weblate (Danish)
Currently translated at 6.7% (4 of 59 strings)

Co-authored-by: snue pirat <snue@proton.me>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/da/
Translation: Fedilab/description
2025-01-29 14:02:07 +01:00
Hosted Weblate
ff6a0c2298
Update translation files
Updated by "Remove blank strings" hook in Weblate.

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/
Translation: Fedilab/Strings
2025-01-29 07:02:13 +01:00
snue pirat
7c50126dd4
Translated using Weblate (Kabyle)
Currently translated at 61.6% (733 of 1189 strings)

Translated using Weblate (Danish)

Currently translated at 99.7% (1186 of 1189 strings)

Co-authored-by: snue pirat <snue@proton.me>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/da/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/kab/
Translation: Fedilab/Strings
2025-01-29 07:02:11 +01:00
Bob Idle
6ad9567215
Translated using Weblate (German)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Bob Idle <102661087+bobidle@users.noreply.github.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2025-01-21 09:00:33 +01:00
Bob Idle
e7203e1b4c
Translated using Weblate (German)
Currently translated at 16.9% (10 of 59 strings)

Co-authored-by: Bob Idle <102661087+bobidle@users.noreply.github.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2025-01-20 06:00:30 +01:00
Juli
b84ac60239
Translated using Weblate (Finnish)
Currently translated at 1.6% (1 of 59 strings)

Co-authored-by: Juli <julimiro@posteo.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/fi/
Translation: Fedilab/description
2025-01-17 10:12:09 +01:00
Bob Idle
7fb987a22b
Translated using Weblate (German)
Currently translated at 15.2% (9 of 59 strings)

Co-authored-by: Bob Idle <102661087+bobidle@users.noreply.github.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2025-01-17 10:12:09 +01:00
Juli
d47c5c44c0
Added translation using Weblate (Finnish)
Co-authored-by: Juli <julimiro@posteo.net>
2025-01-16 10:50:55 +01:00
大王叫我来巡山
9590a58b3c
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (59 of 59 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/zh_Hans/
Translation: Fedilab/description
2025-01-16 10:50:30 +01:00
Poesty Li
7369158e29
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (59 of 59 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/zh_Hans/
Translation: Fedilab/description
2025-01-16 06:01:00 +01:00
தமிழ்நேரம்
8d3111b6ab
Translated using Weblate (Tamil)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: தமிழ்நேரம் <anishprabu.t@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ta/
Translation: Fedilab/Strings
2024-12-26 13:02:34 +00:00
தமிழ்நேரம்
cbdb950e27
Translated using Weblate (Tamil)
Currently translated at 100.0% (59 of 59 strings)

Co-authored-by: தமிழ்நேரம் <anishprabu.t@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ta/
Translation: Fedilab/description
2024-12-26 14:00:42 +01:00
Languages add-on
263d332f37
Added translation using Weblate (Tamil)
Co-authored-by: Languages add-on <noreply-addon-languages@weblate.org>
2024-12-25 17:55:08 +01:00
josé m
ec40bf1a5e
Translated using Weblate (Galician)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2024-12-22 00:05:09 +01:00
josé m
a6ee4cb684
Translated using Weblate (Galician)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2024-12-21 04:00:32 +01:00
Miren
36d29c9765
Translated using Weblate (Basque)
Currently translated at 5.0% (3 of 59 strings)

Co-authored-by: Miren <librezale@miren.be>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/eu/
Translation: Fedilab/description
2024-11-25 05:00:29 +01:00
Miren
ca126dfc1e
Translated using Weblate (Basque)
Currently translated at 96.1% (1143 of 1189 strings)

Co-authored-by: Miren <librezale@miren.be>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eu/
Translation: Fedilab/Strings
2024-11-25 03:00:48 +01:00
phlostically
4620ebe7ff
Translated using Weblate (Esperanto)
Currently translated at 81.6% (971 of 1189 strings)

Co-authored-by: phlostically <phlostically@mailinator.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eo/
Translation: Fedilab/Strings
2024-11-19 14:00:35 +00:00
Free_squire
4c39cc28a9
Translated using Weblate (Russian)
Currently translated at 83.4% (992 of 1189 strings)

Co-authored-by: Free_squire <danil_pyankov_2004@mail.ru>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-11-18 00:00:46 +01:00
phlostically
3de3192797
Translated using Weblate (Esperanto)
Currently translated at 65.6% (780 of 1189 strings)

Co-authored-by: phlostically <phlostically@mailinator.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eo/
Translation: Fedilab/Strings
2024-11-18 00:00:46 +01:00
Free_squire
601c1e4bb3
Translated using Weblate (Russian)
Currently translated at 11.8% (7 of 59 strings)

Co-authored-by: Free_squire <danil_pyankov_2004@mail.ru>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ru/
Translation: Fedilab/description
2024-11-18 00:00:33 +01:00
XblateX
5b4199a570
Translated using Weblate (Russian)
Currently translated at 80.4% (956 of 1189 strings)

Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-10-11 06:56:47 +02:00
ButterflyOfFire
f3e4e9d177
Translated using Weblate (Kabyle)
Currently translated at 61.5% (732 of 1189 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/kab/
Translation: Fedilab/Strings
2024-10-09 05:15:55 +00:00
Nazar
0df166518f
Translated using Weblate (Ukrainian)
Currently translated at 69.7% (829 of 1189 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-09-12 02:09:33 +00:00
harc esz
0fdb76cd83
Translated using Weblate (Polish)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: harc esz <harcesz@riseup.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pl/
Translation: Fedilab/Strings
2024-09-12 02:09:32 +00:00
ButterflyOfFire
2ea1c52202
Translated using Weblate (French)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2024-08-30 08:09:27 +02:00
Nazar
d8eee9a010
Translated using Weblate (Ukrainian)
Currently translated at 67.9% (808 of 1189 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-08-25 00:09:16 +02:00
Nazar
822eb59051
Translated using Weblate (Ukrainian)
Currently translated at 66.4% (790 of 1189 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-08-24 04:09:19 +00:00
josé m
de326c7292
Translated using Weblate (Galician)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2024-08-21 19:09:17 +02:00
Nazar
a2c8b36b95
Translated using Weblate (Ukrainian)
Currently translated at 65.6% (780 of 1189 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-08-11 21:09:20 +02:00
Nazar
9ed18854ca
Translated using Weblate (Ukrainian)
Currently translated at 65.2% (776 of 1189 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-08-08 09:09:18 +02:00
Nazar
7e6cc8ddf8
Translated using Weblate (Ukrainian)
Currently translated at 64.6% (769 of 1189 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-08-07 19:09:16 +02:00
Nazar
2597425643
Translated using Weblate (Ukrainian)
Currently translated at 3.3% (2 of 59 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2024-08-06 23:09:28 +02:00
GunChleoc
7ab3bbbf98
Translated using Weblate (Gaelic)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: GunChleoc <fios@foramnagaidhlig.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gd/
Translation: Fedilab/Strings
2024-08-06 23:09:16 +02:00
Nazar
36c0816835
Translated using Weblate (Ukrainian)
Currently translated at 62.9% (748 of 1189 strings)

Co-authored-by: Nazar <balaraz@tuta.io>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-08-06 23:09:16 +02:00
Wydow
317e565b67
Translated using Weblate (French)
Currently translated at 99.6% (1185 of 1189 strings)

Co-authored-by: Wydow <wydow@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2024-08-05 06:09:23 +02:00
大王叫我来巡山
0afe1d61ef
Translated using Weblate (Chinese (Simplified))
Currently translated at 6.7% (4 of 59 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/zh_Hans/
Translation: Fedilab/description
2024-08-04 14:09:19 +00:00
大王叫我来巡山
0e0fa784d1
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2024-08-04 09:09:19 +02:00
ed tavinor
368d04e8e7
Translated using Weblate (Esperanto)
Currently translated at 62.9% (749 of 1189 strings)

Co-authored-by: ed tavinor <edtavinor@posteo.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/eo/
Translation: Fedilab/Strings
2024-08-04 09:09:17 +02:00
GunChleoc
379992a836
Translated using Weblate (Gaelic)
Currently translated at 98.4% (1170 of 1189 strings)

Co-authored-by: GunChleoc <fios@foramnagaidhlig.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gd/
Translation: Fedilab/Strings
2024-08-02 03:09:23 +00:00
gallegonovato
affa6623c3
Translated using Weblate (Spanish)
Currently translated at 20.3% (12 of 59 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/es/
Translation: Fedilab/description
2024-07-31 05:09:24 +02:00
Ajeje Brazorf
9dd6cc630f
Translated using Weblate (Sardinian)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2024-07-29 18:42:52 +02:00
Ajeje Brazorf
e9581dfb0a
Translated using Weblate (Sardinian)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2024-07-28 10:09:11 +02:00
gallegonovato
bf73c2c5ec
Translated using Weblate (Spanish)
Currently translated at 16.9% (10 of 59 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/es/
Translation: Fedilab/description
2024-07-23 00:00:26 +02:00
gallegonovato
8b566f8157
Translated using Weblate (Spanish)
Currently translated at 13.5% (8 of 59 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/es/
Translation: Fedilab/description
2024-07-13 23:09:44 +00:00
Cosmin Humeniuc
20705ef917
Translated using Weblate (Romanian)
Currently translated at 58.7% (699 of 1189 strings)

Co-authored-by: Cosmin Humeniuc <cosmin@hume.ro>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ro/
Translation: Fedilab/Strings
2024-07-13 03:09:18 +02:00
Cosmin Humeniuc
520cdd0524
Translated using Weblate (Romanian)
Currently translated at 58.2% (693 of 1189 strings)

Co-authored-by: Cosmin Humeniuc <cosmin@hume.ro>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ro/
Translation: Fedilab/Strings
2024-07-08 09:09:12 +02:00
Cosmin Humeniuc
308a8e8cfb
Translated using Weblate (Romanian)
Currently translated at 57.3% (682 of 1189 strings)

Co-authored-by: Cosmin Humeniuc <cosmin@hume.ro>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ro/
Translation: Fedilab/Strings
2024-07-07 20:09:23 +02:00
gallegonovato
df311466e8
Translated using Weblate (Spanish)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2024-06-30 09:09:19 +00:00
gallegonovato
7581218888
Translated using Weblate (Spanish)
Currently translated at 99.9% (1188 of 1189 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2024-06-23 00:09:22 +02:00
Roberto Michán Sánchez
e027f70665
Translated using Weblate (Spanish)
Currently translated at 99.9% (1188 of 1189 strings)

Co-authored-by: Roberto Michán Sánchez <robertoms258@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2024-06-23 00:09:22 +02:00
Buffy
275f8dfcf4
Translated using Weblate (Spanish)
Currently translated at 97.2% (1156 of 1189 strings)

Co-authored-by: Buffy <james6cuerdas@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2024-06-21 16:09:22 +02:00
Buffy
cf7ef6ca19
Translated using Weblate (Spanish)
Currently translated at 93.5% (1112 of 1189 strings)

Co-authored-by: Buffy <james6cuerdas@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2024-06-17 06:31:50 +02:00
Buffy
69fea8d8e3
Translated using Weblate (Spanish)
Currently translated at 90.2% (1073 of 1189 strings)

Co-authored-by: Buffy <james6cuerdas@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2024-06-15 21:16:51 +02:00
Cosmin Humeniuc
17fd8850fc
Translated using Weblate (Romanian)
Currently translated at 55.4% (659 of 1189 strings)

Co-authored-by: Cosmin Humeniuc <cosmin@hume.ro>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ro/
Translation: Fedilab/Strings
2024-06-15 04:09:27 +00:00
Buffy
58cc356ea1
Translated using Weblate (Spanish)
Currently translated at 89.4% (1064 of 1189 strings)

Co-authored-by: Buffy <james6cuerdas@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2024-06-15 04:09:25 +00:00
Buffy
b5f8d492a4
Translated using Weblate (Spanish)
Currently translated at 78.3% (931 of 1189 strings)

Co-authored-by: Buffy <james6cuerdas@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translation: Fedilab/Strings
2024-06-14 13:09:22 +02:00
Allen M
ad40cc7d4d
Translated using Weblate (Japanese)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Allen M <3point14159265358@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
Translation: Fedilab/Strings
2024-05-31 12:09:15 +02:00
XblateX
c4963f525a
Translated using Weblate (Russian)
Currently translated at 80.3% (955 of 1189 strings)

Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-05-30 01:09:14 +02:00
Software In Interlingua
c511cab2bb
Translated using Weblate (Interlingua)
Currently translated at 24.3% (290 of 1189 strings)

Co-authored-by: Software In Interlingua <softinterlingua@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ia/
Translation: Fedilab/Strings
2024-05-20 10:01:53 +02:00
XblateX
29073ebd0f
Translated using Weblate (Russian)
Currently translated at 80.2% (954 of 1189 strings)

Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-05-12 23:01:03 +02:00
Software In Interlingua
c17d5b42b2
Translated using Weblate (Interlingua)
Currently translated at 23.9% (285 of 1189 strings)

Co-authored-by: Software In Interlingua <softinterlingua@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ia/
Translation: Fedilab/Strings
2024-05-07 06:07:12 +02:00
XblateX
83d2fb85f0
Translated using Weblate (Ukrainian)
Currently translated at 59.1% (703 of 1189 strings)

Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-05-07 06:07:10 +02:00
XblateX
04347c10f1
Translated using Weblate (Ukrainian)
Currently translated at 59.0% (702 of 1189 strings)

Translated using Weblate (Russian)

Currently translated at 80.0% (952 of 1189 strings)

Co-authored-by: XblateX <blate@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2024-04-29 02:07:22 +02:00
Oğuz Ersen
b3b327f60a
Translated using Weblate (Turkish)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2024-04-25 08:07:28 +02:00
Ajeje Brazorf
93ac90156f
Translated using Weblate (Sardinian)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Ajeje Brazorf <lmelonimamo@yahoo.it>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/sc/
Translation: Fedilab/Strings
2024-04-07 08:02:00 +02:00
Oğuz Ersen
c82f171e07
Translated using Weblate (Turkish)
Currently translated at 99.9% (1188 of 1189 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2024-03-23 03:04:56 +01:00
josé m
a7b2a705f5
Translated using Weblate (Galician)
Currently translated at 25.4% (15 of 59 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/gl/
Translation: Fedilab/description
2024-03-22 18:02:23 +01:00
josé m
437fd6d0bd
Translated using Weblate (Galician)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2024-03-22 18:02:03 +01:00
Lukáš Jelínek
59d0a98729
Translated using Weblate (Czech)
Currently translated at 100.0% (1189 of 1189 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2024-03-22 00:48:59 +01:00
Anna K
3a13c0635f
Translated using Weblate (German)
Currently translated at 15.2% (9 of 59 strings)

Co-authored-by: Anna K <anna@montanha.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2024-03-22 00:47:58 +01:00
Thomas
b9b381a780 Release 3.28.2 2024-03-21 17:57:29 +01:00
Thomas
38b72e7732 align icon 2024-03-21 17:52:34 +01:00
Thomas
86e8e639a3 Create QR-Code for profile URL 2024-03-21 17:24:28 +01:00
Thomas
9907717638 Fix issue - Non clickable messages in threads 2024-03-21 09:53:30 +01:00
Thomas
f49fdfa2b9 Merge remote-tracking branch 'origin/develop' into develop 2024-03-21 09:37:18 +01:00
Thomas
91941a562d Fix issue #1047 - Long pronouns displace the user name 2024-03-21 09:36:12 +01:00
ButterflyOfFire
11361f50a6
Translated using Weblate (Kabyle)
Currently translated at 59.0% (701 of 1188 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/kab/
Translation: Fedilab/Strings
2024-03-17 02:02:07 +01:00
Lukáš Jelínek
963e10eb04
Translated using Weblate (Czech)
Currently translated at 100.0% (1188 of 1188 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2024-03-10 15:02:00 +01:00
ButterflyOfFire
7e82ec918a
Translated using Weblate (Kabyle)
Currently translated at 55.5% (660 of 1188 strings)

Translated using Weblate (Catalan)

Currently translated at 79.1% (940 of 1188 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/kab/
Translation: Fedilab/Strings
2024-03-09 09:01:53 +01:00
Max Harmathy
639297df1d
Translated using Weblate (Japanese)
Currently translated at 100.0% (1188 of 1188 strings)

Co-authored-by: Max Harmathy <max.harmathy@web.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ja/
Translation: Fedilab/Strings
2024-03-08 01:01:47 +01:00
Alfika07
b54f7ddaf5
Translated using Weblate (Hungarian)
Currently translated at 58.0% (690 of 1188 strings)

Co-authored-by: Alfika07 <alfika07@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/hu/
Translation: Fedilab/Strings
2024-03-04 21:01:45 +01:00
claleb
db4e48eb50
Translated using Weblate (German)
Currently translated at 100.0% (1188 of 1188 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2024-03-04 21:01:45 +01:00
Integral
43697263a8
Translated using Weblate (Chinese (Simplified))
Currently translated at 5.1% (3 of 58 strings)

Co-authored-by: Integral <integral@member.fsf.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/zh_Hans/
Translation: Fedilab/description
2024-03-04 12:01:52 +01:00
Poesty Li
c201b1b918
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (1188 of 1188 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/zh_Hans/
Translation: Fedilab/Strings
2024-03-02 06:02:04 +01:00
josé m
a0e4472ef2
Translated using Weblate (Galician)
Currently translated at 100.0% (1188 of 1188 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2024-02-24 20:02:15 +01:00
Thomas
9e7e100009 Release 3.28.1 2024-02-23 18:10:48 +01:00
Thomas
01d57755c2 Add more pronouns 2024-02-23 17:29:26 +01:00
Thomas
2ecd51230f Merge branch 'improve_pronouns_support' into develop 2024-02-23 15:57:31 +01:00
Thomas
f87c63acec Add more pronouns 2024-02-23 15:57:12 +01:00
Thomas
53b8f9e159 Fix a layout issue 2024-02-23 15:52:50 +01:00
Thomas
c89df20a25 update list for pronouns 2024-02-23 10:31:54 +01:00
Thomas
26d51caaf8 Allow to disable pronouns support - Default enabled 2024-02-23 10:29:36 +01:00
Thomas
b943309dd2 Add localization for pronons support 2024-02-23 10:17:55 +01:00
Thomas
ff026e260a Merge remote-tracking branch 'origin/develop' into develop 2024-02-23 09:39:10 +01:00
Thomas
70405221ea clean code 2024-02-23 09:37:54 +01:00
Thomas
d0fb1b09dc Fix layout overlays 2024-02-23 09:33:52 +01:00
Thomas
28ca138e43 Fix #1040 - Fix a crash when reporting messages 2024-02-22 15:49:42 +01:00
Thomas
ecd25badf7 Fix #1043 - Fix a crash when adding a followed tag in empty list 2024-02-22 09:10:17 +01:00
Thomas
13946fe56e Fix a crash with media 2024-02-22 07:42:31 +01:00
ButterflyOfFire
2bc6ba97f9
Translated using Weblate (Arabic)
Currently translated at 85.3% (1012 of 1186 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translation: Fedilab/Strings
2024-02-19 23:07:05 +01:00
Cosmin Humeniuc
29867ceaec
Translated using Weblate (Romanian)
Currently translated at 1.7% (1 of 57 strings)

Co-authored-by: Cosmin Humeniuc <cosmin@hume.ro>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ro/
Translation: Fedilab/description
2024-02-10 07:02:05 +01:00
v1s7
54771716f0
Translated using Weblate (Russian)
Currently translated at 79.5% (943 of 1186 strings)

Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-02-09 23:02:13 +01:00
Cosmin Humeniuc
acc1bcd183
Translated using Weblate (Romanian)
Currently translated at 55.4% (658 of 1186 strings)

Co-authored-by: Cosmin Humeniuc <cosmin@hume.ro>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ro/
Translation: Fedilab/Strings
2024-02-09 23:02:12 +01:00
v1s7
d6a69ee982
Translated using Weblate (Russian)
Currently translated at 78.9% (936 of 1186 strings)

Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-02-09 05:02:02 +01:00
v1s7
4b3bb1f073
Translated using Weblate (Russian)
Currently translated at 8.7% (5 of 57 strings)

Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ru/
Translation: Fedilab/description
2024-02-09 02:02:35 +01:00
Mikhail Kobuk
a9cd58ceab
Translated using Weblate (Russian)
Currently translated at 77.8% (923 of 1186 strings)

Co-authored-by: Mikhail Kobuk <arktixord@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-02-08 16:53:44 +01:00
v1s7
71de62a838
Translated using Weblate (Russian)
Currently translated at 77.8% (923 of 1186 strings)

Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-02-08 16:53:44 +01:00
Mikhail Kobuk
6ba902607c
Translated using Weblate (Russian)
Currently translated at 77.8% (923 of 1186 strings)

Co-authored-by: Mikhail Kobuk <arktixord@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-02-08 16:49:39 +01:00
v1s7
70f754040c
Translated using Weblate (Russian)
Currently translated at 77.8% (923 of 1186 strings)

Co-authored-by: v1s7 <v1s7@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2024-02-08 16:49:39 +01:00
ButterflyOfFire
d4819a19b7
Translated using Weblate (French)
Currently translated at 99.0% (1175 of 1186 strings)

Co-authored-by: ButterflyOfFire <boffire@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2024-02-08 16:49:39 +01:00
Thomas
2f11eaf315 Fix a crash with profiles 2024-02-02 18:44:23 +01:00
Thomas
096dc6e98c Fix a crash with back button 2024-02-02 18:28:33 +01:00
Thomas
227d2ef58b Fix a crash when switching to remote profiles 2024-02-02 18:15:42 +01:00
josé m
3b677fa0a1
Translated using Weblate (Galician)
Currently translated at 100.0% (1186 of 1186 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2024-01-31 11:57:07 +01:00
josé m
1b9d7fdb75
Translated using Weblate (Galician)
Currently translated at 17.5% (10 of 57 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/gl/
Translation: Fedilab/description
2024-01-31 11:56:58 +01:00
Thomas
c44330d291 Release 3.28.0 2024-01-30 17:51:42 +01:00
Thomas
8832e89539 Fix issue #1032 - Sharing videos only download them 2024-01-30 17:37:34 +01:00
Thomas
9a8d359592 Fix #1030 - Delay for timed mute sent in ms 2024-01-30 16:48:58 +01:00
Thomas
57decc15bd Merge remote-tracking branch 'origin/develop' into develop 2024-01-30 16:43:39 +01:00
Thomas
4b051a42ae Add position/time for videos 2024-01-30 16:43:10 +01:00
Thomas
6b75118926 Fix self pronouns applied in notifications 2024-01-30 16:12:27 +01:00
Thomas
ec44a6e4f3 parse html for pronouns 2024-01-30 15:53:12 +01:00
claleb
3bda4b3f79
Translated using Weblate (German)
Currently translated at 100.0% (1186 of 1186 strings)

Co-authored-by: claleb <weblate@claleb.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2024-01-30 06:01:58 +01:00
Thomas
0400f316e6 Release notes 2024-01-29 17:26:53 +01:00
Thomas
27436916ee Release 3.28-beta-1 2024-01-29 17:25:42 +01:00
Thomas
4055f1b8c5 Merge remote-tracking branch 'origin/develop' into develop 2024-01-29 17:20:44 +01:00
Thomas
40251607e5 Fix peertuble toggle button 2024-01-29 17:19:32 +01:00
Thomas
bdbfd005fa Fix controller with Media3 2024-01-29 15:24:34 +01:00
Thomas
1ad956e965 change currentAccount with a getter 2024-01-29 15:02:56 +01:00
Lukas
44f1a4faa0
Translated using Weblate (Polish)
Currently translated at 100.0% (1186 of 1186 strings)

Co-authored-by: Lukas <ox86udoo@duck.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/pl/
Translation: Fedilab/Strings
2024-01-27 23:01:57 +01:00
Lukas
5ecc2a5521
Translated using Weblate (Polish)
Currently translated at 60.0% (33 of 55 strings)

Co-authored-by: Lukas <ox86udoo@duck.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/pl/
Translation: Fedilab/description
2024-01-27 20:02:05 +01:00
josé m
275f3d78b6
Translated using Weblate (Galician)
Currently translated at 12.7% (7 of 55 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/gl/
Translation: Fedilab/description
2024-01-27 20:02:03 +01:00
Thomas
1274d83ee1 Merge remote-tracking branch 'origin/develop' into develop 2024-01-27 17:58:43 +01:00
Thomas
bba6a2edf1 Fix a crash with profiles 2024-01-27 17:58:14 +01:00
Oğuz Ersen
5f0435e447
Translated using Weblate (Turkish)
Currently translated at 100.0% (1186 of 1186 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2024-01-27 07:01:47 +01:00
Lukáš Jelínek
63ceca066f
Translated using Weblate (Czech)
Currently translated at 100.0% (1186 of 1186 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2024-01-26 10:01:53 +01:00
Salif Mehmed
7c5f1dccab
Translated using Weblate (Bulgarian)
Currently translated at 52.2% (620 of 1186 strings)

Co-authored-by: Salif Mehmed <mail@salif.eu>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/bg/
Translation: Fedilab/Strings
2024-01-25 05:01:51 +01:00
Thomas
d5aaa94045 Fix issue #1031 - Compile error for google flavor 2024-01-24 10:38:16 +01:00
Thomas
394d72bd01 Support pronouns 2024-01-23 19:03:41 +01:00
Thomas
7ab24d900b Indicator with pronouns 2024-01-23 18:48:42 +01:00
Thomas
773322b60a empty space with media 2024-01-23 17:50:58 +01:00
Thomas
ccce81c49c Merge branch 'develop' of https://codeberg.org/tom79/Fedilab into develop 2024-01-23 16:49:57 +01:00
Thomas
eb89b0a8b2 Merge branch 'fix_511' into develop 2024-01-23 16:49:48 +01:00
Thomas
067fc68402 clean 2024-01-23 16:02:28 +01:00
Thomas
dc72d9a8b0 improve media 2024-01-23 10:07:43 +01:00
Thomas
18b3f0cb26 improve media 2024-01-23 10:06:02 +01:00
Thomas
b16ecbbe72 improve media 2024-01-23 10:03:20 +01:00
Thomas
e18db746a0 Some changes 2024-01-22 17:16:09 +01:00
Thomas
a2c865a4b7 Some fixes 2024-01-22 09:49:08 +01:00
Oğuz Ersen
4de9b0bd85
Translated using Weblate (Turkish)
Currently translated at 100.0% (1185 of 1185 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/tr/
Translation: Fedilab/Strings
2024-01-21 14:42:34 +01:00
Thomas
c778c71306 Prepare Media3 2024-01-20 18:10:05 +01:00
633 changed files with 12786 additions and 4377 deletions

View file

@ -1,24 +1,46 @@
[![Translation status](https://hosted.weblate.org/widgets/fedilab/-/strings/svg-badge.svg)](https://hosted.weblate.org/engage/fedilab/)
&nbsp;&nbsp;&nbsp;[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
# Fedilab is a multi-accounts client for Mastodon, Pleroma, Friendica and Pixelfed
<img src="src/fdroid/fastlane/metadata/android/en/images/icon.png" width="100"/>
## Donate
# Fedilab
A multi-accounts client for Mastodon, Pleroma, Friendica and Pixelfed
[<img alt="Donate using Liberapay" src="https://img.shields.io/liberapay/patrons/tom79.svg?logo=liberapay"/>](https://liberapay.com/tom79/donate)
[![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg?style=for-the-badge)](https://www.gnu.org/licenses/gpl-3.0)
[![Weblate project translated](https://img.shields.io/weblate/progress/fedilab?server=https%3A%2F%2Fhosted.weblate.org&style=for-the-badge)](https://hosted.weblate.org/engage/fedilab/)
[![F-Droid Version](https://img.shields.io/f-droid/v/fr.gouv.etalab.mastodon?label=F-Droid&style=for-the-badge)](https://f-droid.org/app/fr.gouv.etalab.mastodon)
[![Liberapay patrons](https://img.shields.io/liberapay/patrons/tom79?label=Liberapay&style=for-the-badge)](https://liberapay.com/tom79/donate)
[![Open Collective backers and sponsors](https://img.shields.io/opencollective/all/fedilab?label=Open%20Collective&style=for-the-badge)](https://opencollective.com/fedilab)
## Screenshots
<img src="src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/1.png" width="150"/>
&nbsp;&nbsp;
<img src="src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/2.png" width="150"/>
&nbsp;&nbsp;
<img src="src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/4.png" width="150"/>
&nbsp;&nbsp;
<img src="src/fdroid/fastlane/metadata/android/en/images/phoneScreenshots/7.png" width="150"/>
## Download
[<img alt='Get it on Google Play' src='./images/get-it-on-play.png' height="80"/>](https://play.google.com/store/apps/details?id=app.fedilab.android)
&nbsp;&nbsp;[<img alt='Get it on F-Droid' src='./images/get-it-on-fdroid.png' height="80"/>](https://f-droid.org/app/fr.gouv.etalab.mastodon)
<img src='https://img.shields.io/f-droid/v/fr.gouv.etalab.mastodon?include_prereleases' />
[<img alt='Get it on F-Droid' src='./images/get-it-on-fdroid.png' height="80"/>](https://f-droid.org/app/fr.gouv.etalab.mastodon)&nbsp;&nbsp;[<img alt='Get it on Google Play' src='./images/get-it-on-play.png' height="80"/>](https://play.google.com/store/apps/details?id=app.fedilab.android)
## Translate
- [Weblate](https://hosted.weblate.org/engage/fedilab/)
## Donate
- [Liberapay](https://liberapay.com/tom79/donate)
- [Open Collective](https://opencollective.com/fedilab)
- [More...](https://fedilab.app/page/donations/)
## Resources
[WIKI](https://fedilab.app/wiki/home/)
- [Wiki](https://wiki.fedilab.app)
- [Releases + Changelogs](https://codeberg.org/tom79/Fedilab/releases)
[Release notes](https://codeberg.org/tom79/Fedilab/tags)
## Contact
- Fedi:<br>[toot.fedilab.app/@apps](https://toot.fedilab.app/@apps)
Lead developer: [toot.fedilab.app/@apps](https://toot.fedilab.app/@apps)

View file

@ -13,8 +13,8 @@ android {
defaultConfig {
minSdk 21
targetSdk 34
versionCode 511
versionName "3.27.1"
versionCode 528
versionName "3.31.3"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
flavorDimensions "default"
@ -52,7 +52,6 @@ android {
}
sourceSets {
playstore {
manifest.srcFile "src/playstore/AndroidManifest.xml"
java.srcDirs = ['src/main/java', 'src/playstore/java']
res.srcDirs = ['src/main/res', 'src/playstore/res']
}
@ -92,6 +91,7 @@ android {
abortOnError false
checkReleaseBuilds false
}
buildToolsVersion '35.0.0'
}
allprojects {
repositories {
@ -100,14 +100,17 @@ allprojects {
}
}
dependencies {
implementation 'org.unifiedpush.android:connector:3.0.7'
implementation 'androidx.appcompat:appcompat:1.6.1'
playstoreImplementation('org.unifiedpush.android:embedded-fcm-distributor:3.0.0')
implementation 'androidx.appcompat:appcompat:1.7.0'
implementation 'com.google.android.material:material:1.10.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "com.google.code.gson:gson:2.9.1"
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
implementation "com.google.code.gson:gson:2.10.1"
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.retrofit2:converter-simplexml:2.9.0'
@ -123,7 +126,7 @@ dependencies {
transitive = false
}
implementation "org.jsoup:jsoup:1.15.1"
implementation "org.jsoup:jsoup:1.18.1"
implementation 'com.github.mergehez:ArgPlayer:v3.1'
implementation project(':autoimageslider')
@ -132,15 +135,21 @@ dependencies {
implementation project(path: ':sparkbutton')
implementation project(path: ':colorPicker')
implementation project(path: ':mathjaxandroid')
implementation project(path: ':doubletapplayerview')
implementation 'com.burhanrashid52:photoeditor:1.5.1'
implementation("com.vanniktech:android-image-cropper:4.3.3")
annotationProcessor "com.github.bumptech.glide:compiler:4.12.0"
implementation 'jp.wasabeef:glide-transformations:4.3.0'
implementation 'com.github.penfeizhou.android.animation:glide-plugin:2.23.0'
implementation 'com.google.android.exoplayer:exoplayer:2.19.1'
implementation "androidx.viewpager2:viewpager2:1.0.0"
implementation 'androidx.media3:media3-exoplayer-hls:1.2.1'
implementation "androidx.media3:media3-exoplayer:1.2.1"
implementation "androidx.media3:media3-exoplayer-dash:1.2.1"
implementation "androidx.media3:media3-ui:1.2.1"
implementation "androidx.media3:media3-session:1.2.1"
implementation "androidx.viewpager2:viewpager2:1.1.0"
implementation 'com.github.piasy:rxandroidaudio:1.7.0'
implementation 'com.github.piasy:AudioProcessor:1.7.0'
implementation "androidx.work:work-runtime:2.9.0"
@ -150,42 +159,34 @@ dependencies {
implementation "ch.acra:acra-limiter:5.11.3"
implementation "ch.acra:acra-dialog:5.11.3"
implementation "com.madgag.spongycastle:bctls-jdk15on:1.58.0.0"
implementation 'com.github.UnifiedPush:android-connector:2.2.0'
// implementation 'com.github.UnifiedPush:android-foss_embedded_fcm_distributor:1.0.0-beta1'
playstoreImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.2.0') {
exclude group: 'com.google.firebase', module: 'firebase-core'
exclude group: 'com.google.firebase', module: 'firebase-analytics'
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
}
implementation 'com.burhanrashid52:photoeditor:1.5.1'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'com.github.PhilJay:MPAndroidChart:v3.1.0'
implementation 'androidx.lifecycle:lifecycle-livedata:2.6.2'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.6.2'
implementation 'androidx.navigation:navigation-fragment:2.7.5'
implementation 'androidx.navigation:navigation-ui:2.7.5'
implementation 'androidx.lifecycle:lifecycle-livedata:2.8.7'
implementation 'androidx.lifecycle:lifecycle-viewmodel:2.8.7'
implementation 'androidx.navigation:navigation-fragment:2.8.7'
implementation 'androidx.navigation:navigation-ui:2.8.7'
testImplementation 'junit:junit:'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'androidx.test.ext:junit:1.2.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1'
// debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
implementation 'com.r0adkll:slidableactivity:2.1.0'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.4'
implementation 'androidx.vectordrawable:vectordrawable:1.1.0'
implementation "androidx.fragment:fragment:1.6.2"
implementation 'androidx.vectordrawable:vectordrawable:1.2.0'
implementation "androidx.fragment:fragment:1.8.6"
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.browser:browser:1.7.0'
implementation 'androidx.browser:browser:1.8.0'
implementation 'androidx.documentfile:documentfile:1.0.1'
implementation 'com.github.amoskorir:avatarimagegenerator:1.5.0'
implementation 'com.google.android.exoplayer:extension-mediasession:2.19.1'
implementation "com.github.mabbas007:TagsEditText:1.0.5"
implementation "net.gotev:uploadservice:4.9.2"
implementation "net.gotev:uploadservice-okhttp:4.9.2"
implementation 'androidx.media:media:1.7.0'
implementation 'com.github.mancj:MaterialSearchBar:0.8.5'
implementation 'com.github.vkay94:DoubleTapPlayerView:1.0.0'
implementation 'com.github.androidmads:QRGenerator:1.0.1'
implementation 'io.noties.markwon:core:4.6.2'
implementation 'io.noties.markwon:ext-tables:4.6.2'
@ -197,10 +198,10 @@ dependencies {
//************ CAST **************///
//---> Google libs (google_full)
playstoreImplementation "com.google.android.gms:play-services-cast-tv:21.0.1"
playstoreImplementation "com.google.android.gms:play-services-cast:21.4.0"
playstoreImplementation "androidx.mediarouter:mediarouter:1.6.0"
playstoreImplementation 'com.google.android.gms:play-services-cast-framework:21.4.0'
playstoreImplementation "com.google.android.gms:play-services-cast-tv:21.1.1"
playstoreImplementation "com.google.android.gms:play-services-cast:22.0.0"
playstoreImplementation "androidx.mediarouter:mediarouter:1.7.0"
playstoreImplementation 'com.google.android.gms:play-services-cast-framework:22.0.0'
//----> Other flavors

View file

@ -28,9 +28,10 @@ import android.view.View;
import android.webkit.MimeTypeMap;
import androidx.appcompat.app.AlertDialog;
import androidx.media3.common.Player;
import androidx.media3.exoplayer.ExoPlayer;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.jetbrains.annotations.NotNull;

View file

@ -52,21 +52,21 @@ public abstract class PeertubeBaseMainActivity extends BaseActivity implements C
public static List<ChromeCast> chromeCasts;
public static ChromeCast chromeCast;
public static boolean chromecastActivated = false;
protected ActivityMainPeertubeBinding binding;
protected ActivityMainPeertubeBinding parentBinding;
private BroadcastReceiver manage_chromecast;
private VideoData.Video castedTube;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainPeertubeBinding.inflate(getLayoutInflater());
View view = binding.getRoot();
parentBinding = ActivityMainPeertubeBinding.inflate(getLayoutInflater());
View view = parentBinding.getRoot();
setContentView(view);
ChromeCastsListener chromeCastsListener = this;
ChromeCasts.registerListener(chromeCastsListener);
binding.castClose.setOnClickListener(v -> {
parentBinding.castClose.setOnClickListener(v -> {
Intent intentBC = new Intent(Helper.RECEIVE_CAST_SETTINGS);
Bundle b = new Bundle();
b.putInt("displayed", 0);
@ -75,12 +75,12 @@ public abstract class PeertubeBaseMainActivity extends BaseActivity implements C
sendBroadcast(intentBC);
});
binding.castTogglePlay.setOnClickListener(v -> {
parentBinding.castTogglePlay.setOnClickListener(v -> {
if (chromeCast != null) {
new Thread(() -> {
try {
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> binding.castTogglePlay.setVisibility(View.GONE);
Runnable myRunnable = () -> parentBinding.castTogglePlay.setVisibility(View.GONE);
mainHandler.post(myRunnable);
int icon = -1;
if (chromeCast.getMediaStatus().playerState == MediaStatus.PlayerState.PLAYING) {
@ -92,10 +92,10 @@ public abstract class PeertubeBaseMainActivity extends BaseActivity implements C
}
if (icon != -1) {
int finalIcon = icon;
myRunnable = () -> binding.castTogglePlay.setImageResource(finalIcon);
myRunnable = () -> parentBinding.castTogglePlay.setImageResource(finalIcon);
mainHandler.post(myRunnable);
}
myRunnable = () -> binding.castTogglePlay.setVisibility(View.VISIBLE);
myRunnable = () -> parentBinding.castTogglePlay.setVisibility(View.VISIBLE);
mainHandler.post(myRunnable);
} catch (IOException e) {
e.printStackTrace();
@ -131,14 +131,14 @@ public abstract class PeertubeBaseMainActivity extends BaseActivity implements C
if (displayed == 1) {
chromecastActivated = true;
if (castedTube != null) {
binding.castInfo.setVisibility(View.VISIBLE);
Helper.loadGiF(PeertubeBaseMainActivity.this, castedTube.getThumbnailPath(), binding.castView);
binding.castTitle.setText(castedTube.getTitle());
binding.castDescription.setText(castedTube.getDescription());
parentBinding.castInfo.setVisibility(View.VISIBLE);
Helper.loadGiF(PeertubeBaseMainActivity.this, castedTube.getThumbnailPath(), parentBinding.castView);
parentBinding.castTitle.setText(castedTube.getTitle());
parentBinding.castDescription.setText(castedTube.getDescription());
}
} else if (displayed == 0) {
chromecastActivated = false;
binding.castInfo.setVisibility(View.GONE);
parentBinding.castInfo.setVisibility(View.GONE);
new Thread(() -> {
try {
if (chromeCast != null) {
@ -173,8 +173,8 @@ public abstract class PeertubeBaseMainActivity extends BaseActivity implements C
}
try {
if (chromeCast.isAppRunning(Helper.CAST_ID) && chromeCast.getMediaStatus() != null && chromeCast.getMediaStatus().playerState != null) {
if (binding.castInfo.getVisibility() == View.GONE) {
binding.castInfo.setVisibility(View.VISIBLE);
if (parentBinding.castInfo.getVisibility() == View.GONE) {
parentBinding.castInfo.setVisibility(View.VISIBLE);
}
}
} catch (IOException e) {

View file

@ -11,8 +11,6 @@
tools:ignore="ScopedStorage" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-feature
android:name="android.hardware.camera"
@ -24,7 +22,7 @@
</queries>
<application
android:name="app.fedilab.android.MainApplication"
android:allowBackup="true"
android:allowBackup="false"
android:dataExtractionRules="@xml/extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:configChanges="orientation|screenSize"
@ -75,6 +73,333 @@
</intent-filter>
</activity>
<activity
android:name=".activities.LoginActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="backtofedilab"
android:scheme="fedilab" />
</intent-filter>
</activity>
<activity
android:name=".mastodon.activities.StatusHistoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/status_history"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ContextActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.DirectMessageActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.DraftActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.imageeditor.EditImageActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.ComposeActivity"
android:configChanges="orientation|screenSize"
android:label="@string/compose" />
<activity
android:name=".mastodon.activities.StatusInfoActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.FollowRequestActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.ProfileActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account" />
<activity
android:name=".mastodon.activities.admin.AdminAccountActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account" />
<activity
android:name=".mastodon.activities.AccountReportActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminReportActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/report"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ScheduledActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/scheduled" />
<activity
android:name="com.canhub.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat" />
<activity
android:name=".mastodon.activities.SearchResultTabActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/search"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.TrendsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/trending"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ReorderTimelinesActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/reorder_timelines"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.AboutActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.TimelineActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.CheckHomeCacheActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/home_cache"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminDomainBlockActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/blocked_domains"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.SuggestionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/Suggestions"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.DirectoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/Directory"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.PartnerShipActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ActionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/interactions"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminActionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/administration"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.MastodonListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_lists"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.FollowedTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/followed_tags"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.SettingsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/settings"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.HashTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.AnnouncementActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.MediaActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/Transparent" />
<activity
android:name=".mastodon.activities.ReportActivity"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.CustomSharingActivity"
android:label="@string/settings_title_custom_sharing"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.FilterActivity"
android:label="@string/filters"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.EditProfileActivity"
android:label="@string/edit_profile"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.CacheActivity"
android:label="@string/action_cache"
android:theme="@style/AppThemeBar" />
<activity android:name=".activities.WebActivityPub"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="web+ap" />
</intent-filter>
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<receiver
android:name=".mastodon.broadcastreceiver.ToastMessage"
android:exported="false">
<intent-filter>
<action android:name="RECEIVE_TOAST_MESSAGE" />
</intent-filter>
</receiver>
<service android:name=".mastodon.services.PushServiceImpl"
android:exported="false">
<intent-filter>
<action android:name="org.unifiedpush.android.connector.PUSH_EVENT"/>
</intent-filter>
</service>
<activity
android:name=".peertube.activities.PeertubeMainActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".peertube.activities.PeertubeActivity"
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
tools:targetApi="n" />
<activity
android:name=".peertube.activities.PeertubeEditUploadActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ShowChannelActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ShowAccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.MyAccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.SearchActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AllPlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AllLocalPlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.PlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.VideosTimelineActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.SepiaSearchActivity"
android:configChanges="orientation|screenSize"
android:label="@string/sepia_search"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ManageInstancesActivity"
android:configChanges="orientation|screenSize"
android:label="@string/instances_picker"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.WebviewActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".peertube.activities.LoginActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:windowSoftInputMode="stateAlwaysHidden">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="backtotubelab"
android:scheme="tubelab" />
</intent-filter>
</activity>
<activity
android:name=".peertube.activities.SettingsActivity"
android:configChanges="orientation|screenSize"
android:label="@string/settings"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.PeertubeUploadActivity"
android:configChanges="orientation|screenSize"
android:label="@string/upload_video"
android:windowSoftInputMode="stateAlwaysHidden" />
<service
android:name=".peertube.services.RetrieveInfoService"
android:foregroundServiceType="dataSync"
android:exported="false" />
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
<!-- ============ -->
<!-- CUSTOM ICONS -->
<!-- ============ -->
<activity-alias
android:name=".activities.MainActivity.Bubbles"
android:enabled="true"
@ -265,323 +590,164 @@
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity
android:name=".activities.LoginActivity"
android:configChanges="orientation|screenSize"
<activity-alias
android:name=".activities.MainActivity.Leaf"
android:enabled="false"
android:exported="true"
android:windowSoftInputMode="stateAlwaysHidden">
android:icon="@mipmap/ic_launcher_leaf"
android:roundIcon="@mipmap/ic_launcher_leaf_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="backtofedilab"
android:scheme="fedilab" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".mastodon.activities.StatusHistoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/status_history"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ContextActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.DirectMessageActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.DraftActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.imageeditor.EditImageActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.ComposeActivity"
android:configChanges="orientation|screenSize"
android:label="@string/compose" />
<activity
android:name=".mastodon.activities.StatusInfoActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.FollowRequestActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.ProfileActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account" />
<activity
android:name=".mastodon.activities.admin.AdminAccountActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account" />
<activity
android:name=".mastodon.activities.AccountReportActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/account"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminReportActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/report"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ScheduledActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/scheduled" />
<activity
android:name="com.canhub.cropper.CropImageActivity"
android:theme="@style/Base.Theme.AppCompat" />
<activity
android:name=".mastodon.activities.SearchResultTabActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/search"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.TrendsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/trending"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ReorderTimelinesActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/reorder_timelines"
android:theme="@style/AppThemeBar" />
<activity
android:name=".activities.AboutActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.TimelineActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.CheckHomeCacheActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/home_cache"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminDomainBlockActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/blocked_domains"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.SuggestionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/Suggestions"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.DirectoryActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/Directory"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.PartnerShipActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_about"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.ActionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/interactions"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.admin.AdminActionActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/administration"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.MastodonListActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/action_lists"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.FollowedTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/followed_tags"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.SettingsActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:label="@string/settings"
android:theme="@style/AppThemeBar" />
<activity
android:name=".mastodon.activities.HashTagActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.AnnouncementActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.MediaActivity"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/Transparent" />
<activity
android:name=".mastodon.activities.ReportActivity"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.CustomSharingActivity"
android:label="@string/settings_title_custom_sharing"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.FilterActivity"
android:label="@string/filters"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.EditProfileActivity"
android:label="@string/edit_profile"
android:theme="@style/AppThemeBar"
android:windowSoftInputMode="stateVisible" />
<activity
android:name=".mastodon.activities.CacheActivity"
android:label="@string/action_cache"
android:theme="@style/AppThemeBar" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<receiver
android:name=".mastodon.broadcastreceiver.ToastMessage"
android:exported="false">
<intent-filter>
<action android:name="RECEIVE_TOAST_MESSAGE" />
</intent-filter>
</receiver>
<receiver
android:name=".mastodon.services.CustomReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="org.unifiedpush.android.connector.MESSAGE" />
<action android:name="org.unifiedpush.android.connector.UNREGISTERED" />
<action android:name="org.unifiedpush.android.connector.NEW_ENDPOINT" />
<action android:name="org.unifiedpush.android.connector.REGISTRATION_FAILED" />
<action android:name="org.unifiedpush.android.connector.REGISTRATION_REFUSED" />
</intent-filter>
</receiver>
<activity
android:name=".peertube.activities.PeertubeMainActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".peertube.activities.PeertubeActivity"
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:launchMode="singleTask"
android:resizeableActivity="true"
android:supportsPictureInPicture="true"
tools:targetApi="n" />
<activity
android:name=".peertube.activities.PeertubeEditUploadActivity"
android:configChanges="orientation|screenSize"
android:exported="false"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ShowChannelActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ShowAccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.MyAccountActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.SearchActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AllPlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.AllLocalPlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.PlaylistsActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.VideosTimelineActivity"
android:configChanges="orientation|screenSize"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.SepiaSearchActivity"
android:configChanges="orientation|screenSize"
android:label="@string/sepia_search"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.ManageInstancesActivity"
android:configChanges="orientation|screenSize"
android:label="@string/instances_picker"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.WebviewActivity"
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".peertube.activities.LoginActivity"
android:configChanges="orientation|screenSize"
<activity-alias
android:name=".activities.MainActivity.Offset"
android:enabled="false"
android:exported="true"
android:windowSoftInputMode="stateAlwaysHidden">
android:icon="@mipmap/ic_launcher_offset"
android:roundIcon="@mipmap/ic_launcher_offset_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="backtotubelab"
android:scheme="tubelab" />
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity
android:name=".peertube.activities.SettingsActivity"
android:configChanges="orientation|screenSize"
android:label="@string/settings"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity
android:name=".peertube.activities.PeertubeUploadActivity"
android:configChanges="orientation|screenSize"
android:label="@string/upload_video"
android:windowSoftInputMode="stateAlwaysHidden" />
<activity-alias
android:name=".activities.MainActivity.Jungle"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_jungle"
android:roundIcon="@mipmap/ic_launcher_jungle_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<service
android:name=".peertube.services.RetrieveInfoService"
android:foregroundServiceType="dataSync"
android:exported="false" />
<activity-alias
android:name=".activities.MainActivity.Confetti"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_confetti"
android:roundIcon="@mipmap/ic_launcher_confetti_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
<activity-alias
android:name=".activities.MainActivity.Spaghetti"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_spaghetti"
android:roundIcon="@mipmap/ic_launcher_spaghetti_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Warm"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_warm"
android:roundIcon="@mipmap/ic_launcher_warm_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Purple1"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_purple_1"
android:roundIcon="@mipmap/ic_launcher_purple_1_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Purple2"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_purple_2"
android:roundIcon="@mipmap/ic_launcher_purple_2_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.YellowHeadedRedBubble"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_yellow_headed_red_bubble"
android:roundIcon="@mipmap/ic_launcher_yellow_headed_red_bubble_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
<activity-alias
android:name=".activities.MainActivity.Mosaic"
android:enabled="false"
android:exported="true"
android:icon="@mipmap/ic_launcher_mosaic"
android:roundIcon="@mipmap/ic_launcher_mosaic_round"
android:targetActivity=".activities.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/compose_shortcuts" />
</activity-alias>
</application>
</manifest>

View file

@ -1,4 +1,59 @@
[
{
"version": "3.31.3",
"code": "528",
"note": "Added:\n- Add new icon launchers (Settings > Interface)\n\nChanged:\n- Make logout/proxy button more visible in main menu\n- Remove permission FOREGROUND_SERVICE\n- Improve a little more media layout with translations\n\nFixed:\n- Fix status bar icons not visible in light theme with custom accent color\n- Reaction buttons not clickable for some instances"
},
{
"version": "3.31.2",
"code": "527",
"note": "Added:\n- Add support to URL scheme \"web+ap\" for opening profiles with the app\n\nChanged:\n- Layout for media descriptions\n\nFixed:\n- Fix a crash when translating media descriptions\n- Handle included twice when replying to a self user's boost\n- Fix color issues when using a custom theme"
},
{
"version": "3.31.1",
"code": "526",
"note": "Added:\n- Add MinT machine translation system support\n- Add support \"instance only\" for GoToSocial\n\nFixed:\n- GIF not displayed in timelines\n- Fix a crash when unpinning timelines\n- Top bar coloring at scroll for conversations\n- Black screen when going back from the Peertube section"
},
{
"version": "3.31.0",
"code": "524",
"note": "Added:\n- Pinned Trending Timeline (can be hidden in Manage Timelines)\n- Add a fallback to the default translator\n- New Pixelfed entry in Settings to disable fullscreen for media\n- Add tooltips for tabs in profiles\n\nChanged:\n- Increase touch area of reply buttons\n- Show a dialog after settings export\n\nFixed:\n- Fix media description not updated when there are several\n- Only a part of DeepL translations are shown\n- Fix Lingva truncated translations\n- Fix a crash when fetching remote profiles\n- Fix a crash with animated emoji\n- Fix a crash when displaying Home cache charts"
},
{
"version": "3.30.1",
"code": "523",
"note": "Added:\n- Follow Twitter tags\n\nChange:\n- Remove automatic backup (Google only)\n\nFixed:\n- Push notifications not working for some devices\n- Filters not applied to media description\n- Fix a crash with animated images in timelines\n- Fix a crash for long threads\n- Fix a crash due to some messages (happened in different timelines)"
},
{
"version": "3.30.0",
"code": "522",
"note": "Added:\n- Allow to follow the discover timelines of Pixelfed instances\n- Keep media proportions in timeline for Pixelfed\n- Add a like button in timelines for Pixelfed\n- Allow to login with a token\n\nChange:\n- Use Pixelfed layout when following Pixelfed instances\n- Allow to scroll buttons for larger screens in conversations\n- Move QR code into header\n\nFixed:\n- Not clickable URLs when Markdown is enabled\n- Nitter to follow Twitter accounts\n- Pixelfed timeline not displayed by default\n- Fix admin reports not accessible\n- Top bar coloring at scroll\n- Drafts not saved when adding/editing media descriptions\n- User search suggestions have duplicates\n- Some minor crashes"
},
{
"version": "3.29.2",
"code": "518",
"note": "Fixed:\n- Fix crash when changing the type of notifications\n- Fix issue with names not displayed fully\n- Fix a crash with notifications and Sharkey\n- Fix a crash when app is back to the foreground\n- Fix xmpp links not opening xmpp clients\n- Fix wrong muted time"
},
{
"version": "3.29.1",
"code": "517",
"note": "Added:\n- Allow to edit scheduled messages from server side\n\nChanged:\n- Order list name alphabetically in profiles\n- Remove registration for Google\n\nFixed:\n- Push notifications\n- Peertube instances picker\n- Edit scheduled threads (local)\n- Instant search of Hashtag repeats results\n- Quotes broken with Markdowns\n- Fix reports crashes after submitting\n- Fix emoji picker when there is no result\n- Fix other crashes"
},
{
"version": "3.28.2",
"code": "515",
"note": "Added:\n- Display a QR code on profiles\n\nFixed:\n- Fix tap on messages in conversations\n- Pronouns taking too much place"
},
{
"version": "3.28.1",
"code": "514",
"note": "Added:\n- Allow to disable pronouns support (default: enabled)\n- Add more support for pronouns (localization in different languages)\n\nFixed:\n- Fix a crash when reporting messages\n- Fix a crash when following tags\n- Fix some display issues\n- Several fixes from the last release (3.28.0)"
},
{
"version": "3.28.0",
"code": "513",
"note": "Added:\n- Pronouns support (Timeline/Compose/Autocomplete)\n\nChanged:\n- Use Media3 library\n\nFixed:\n- Timed mute duration too long\n- Sharing videos only download them\n- Crashes from previous release"
},
{
"version": "3.27.1",
"code": "511",
@ -213,30 +268,6 @@
"version": "3.14.3",
"code": "465",
"note": "Added:\n- Display date of the message instead of the boost (default: disabled)\n- Allow to disable release notes popup in Settings\n\nFixed:\n- Fix timelines slow down and stuttering after some scrolls\n- Fix color issues with follow buttons\n- Fix import from settings (import from login was OK)"
},
{
"version": "3.14.2",
"code": "464",
"note": "Added:\n- Display familiar followers on profiles\n- Display and filter Instance directory\n\nChanged:\n- Bot and reply icon indicators more visible\n- Single media are hidden with link previews\n\nFixed:\n- Fix a crash with Art timelines\n- Friendica: media cannot be downloaded/shared\n- Fix a crash with pinned timelines"
},
{
"version": "3.14.1",
"code": "463",
"note": "Added:\n- Search bar: display suggestions when starting by \"@\" or \"#\"\n\nChanged:\n- Preload media in timelines to avoid jumps\n- Search: Automatically switch to account tab if no results for tags\n\nFixed:\n- Fix jumps with the fetch more feature\n- Fix videos cannot be saved\n- Tags cannot be pinned when there are no custom tabs\n- PixelFed view: NSFW not honored\n- Fix crashes"
},
{
"version": "3.14.0",
"code": "462",
"note": "Added:\n\n- Add Bubble timeline support in extra-features with filters\n- Allow to display public profiles by default to get all messages (Settings > Interface)\n- Glitch: Allow to post messages locally (Can be turned off in Settings)\n- Pixelfed: Custom layout to display Media fully (Also works for other software when there are media)\n- Allow to align left action buttons in messages\n\nChanged:\n- Full rework on links in messages (also mentions and tags)\n- Add pinned tag in \"any\" to avoid to lose it when renaming timeline\n\nFixed:\n- Links to messages not handled by the app\n- CW when editing a message\n- Fix push notifications with several accounts\n- New messages or edition notifications not pushed\n- Fix quotes with tags/mentions\n- Fix notifications\n- Fix sending multiple media\n- Fix crashes"
},
{
"version": "3.13.7",
"code": "461",
"note": "Added:\n- Pixelfed: Custom layout to display Media fully \n*(Settings > Timelines > Pixelfed Presentation) - Also works for other softwares when there are media\n\nChanged:\n- Add pinned tag in \"any\" to avoid to lose it when renaming timeline\n\nFixed:\n- Fix push notifications with several accounts\n- Fix quotes with tags/mentions\n- Fix notifications\n- Fix sending multiple media\n- Some crashes"
},
{
"version": "3.13.6",
"code": "460",
"note": "Fixed:\n- Cross-compose: Wrong instance emojis\n- Custom emojis not displayed in notifications\n- Fav/Boost markers with shared messages\n- Empty notifications\n- Fix cw removed when replying\n- Fix expand media with fit preview images when sensitive\n- Fix an issue with fetch more displayed too often (cache clear will help or wait new messages)"
}
]

View file

@ -213,7 +213,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
public static boolean filterFetched;
public static boolean show_boosts, show_replies, show_dms, show_art_nsfw, show_self_boosts, show_self_replies, show_my_messages;
public static String regex_home, regex_local, regex_public;
public static BaseAccount currentAccount;
public static iconLauncher mLauncher = iconLauncher.BUBBLES;
public static boolean headerMenuOpen;
public static int currentNightMode;
@ -226,7 +225,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
Bundle args = intent.getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(BaseMainActivity.this).getBundle(bundleId, currentAccount, bundle -> {
new CachedBundle(BaseMainActivity.this).getBundle(bundleId, Helper.getCurrentAccount(BaseMainActivity.this), bundle -> {
if (bundle.getBoolean(Helper.RECEIVE_COMPOSE_ERROR_MESSAGE, false)) {
String errorMessage = bundle.getString(Helper.RECEIVE_ERROR_MESSAGE);
StatusDraft statusDraft = (StatusDraft) bundle.getSerializable(Helper.ARG_STATUS_DRAFT);
@ -239,7 +238,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
Intent intentCompose = new Intent(context, ComposeActivity.class);
Bundle args2 = new Bundle();
args2.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraft);
new CachedBundle(BaseMainActivity.this).insertBundle(args2, currentAccount, bundleId2 -> {
new CachedBundle(BaseMainActivity.this).insertBundle(args2, Helper.getCurrentAccount(BaseMainActivity.this), bundleId2 -> {
Bundle bundle2 = new Bundle();
bundle2.putLong(Helper.ARG_INTENT_ID, bundleId2);
intentCompose.putExtras(bundle2);
@ -262,13 +261,13 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
Bundle args = intent.getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(BaseMainActivity.this).getBundle(bundleId, currentAccount, bundle -> {
new CachedBundle(BaseMainActivity.this).getBundle(bundleId, Helper.getCurrentAccount(BaseMainActivity.this), bundle -> {
if (bundle.getBoolean(Helper.RECEIVE_REDRAW_TOPBAR, false)) {
List<MastodonList> mastodonLists = (List<MastodonList>) bundle.getSerializable(Helper.RECEIVE_MASTODON_LIST);
redrawPinned(mastodonLists);
}
if (bundle.getBoolean(Helper.RECEIVE_REDRAW_BOTTOM, false)) {
bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(currentAccount, binding.bottomNavView);
bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(Helper.getCurrentAccount(BaseMainActivity.this), binding.bottomNavView);
if (bottomMenu != null) {
//ManageClick on bottom menu items
if (binding.bottomNavView.findViewById(R.id.nav_home) != null) {
@ -321,7 +320,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
Intent intentContext = new Intent(BaseMainActivity.this, ContextActivity.class);
Bundle args2 = new Bundle();
args2.putSerializable(Helper.ARG_STATUS, statusSent);
new CachedBundle(BaseMainActivity.this).insertBundle(args2, currentAccount, bundleId2 -> {
new CachedBundle(BaseMainActivity.this).insertBundle(args2, Helper.getCurrentAccount(BaseMainActivity.this), bundleId2 -> {
Bundle bundle2 = new Bundle();
bundle2.putLong(Helper.ARG_INTENT_ID, bundleId2);
intentContext.putExtras(bundle2);
@ -360,18 +359,18 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
//Fetch some db values to initialize data
new Thread(() -> {
try {
if (currentAccount == null) {
if (Helper.getCurrentAccount(activity) == null) {
if (currentToken == null || currentToken.trim().isEmpty()) {
currentToken = sharedpreferences.getString(Helper.PREF_USER_TOKEN, null);
}
try {
currentAccount = new Account(activity).getConnectedAccount();
Helper.setCurrentAccount(new Account(activity).getConnectedAccount());
} catch (DBException e) {
e.printStackTrace();
}
}
if (currentAccount != null) {
MutedAccounts mutedAccounts = new MutedAccounts(activity).getMutedAccount(currentAccount);
if (Helper.getCurrentAccount(activity) != null) {
MutedAccounts mutedAccounts = new MutedAccounts(activity).getMutedAccount(Helper.getCurrentAccount(activity));
if (mutedAccounts != null && mutedAccounts.accounts != null) {
filteredAccounts = mutedAccounts.accounts;
}
@ -620,9 +619,9 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
}).start();
} else {
navigationView.getMenu().clear();
if (MainActivity.currentAccount.mastodon_account != null) {
if (Helper.getCurrentAccount(activity).mastodon_account != null) {
navigationView.inflateMenu(R.menu.activity_main_drawer);
} else if (MainActivity.currentAccount.peertube_account != null) {
} else if (Helper.getCurrentAccount(activity).peertube_account != null) {
navigationView.inflateMenu(R.menu.activity_main_drawer_peertube);
}
headerMainBinding.ownerAccounts.setImageResource(R.drawable.ic_baseline_arrow_drop_down_24);
@ -640,10 +639,10 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
if (itemId == R.id.action_logout_account) {
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(activity);
alt_bld.setTitle(R.string.action_logout);
if (currentAccount.mastodon_account != null && currentAccount.instance != null) {
alt_bld.setMessage(activity.getString(R.string.logout_account_confirmation, currentAccount.mastodon_account.username, currentAccount.instance));
} else if (currentAccount.peertube_account != null && currentAccount.instance != null) {
alt_bld.setMessage(activity.getString(R.string.logout_account_confirmation, currentAccount.peertube_account.getUsername(), currentAccount.instance));
if (Helper.getCurrentAccount(activity).mastodon_account != null && Helper.getCurrentAccount(activity).instance != null) {
alt_bld.setMessage(activity.getString(R.string.logout_account_confirmation, Helper.getCurrentAccount(activity).mastodon_account.username, Helper.getCurrentAccount(activity).instance));
} else if (Helper.getCurrentAccount(activity).peertube_account != null && Helper.getCurrentAccount(activity).instance != null) {
alt_bld.setMessage(activity.getString(R.string.logout_account_confirmation, Helper.getCurrentAccount(activity).peertube_account.getUsername(), Helper.getCurrentAccount(activity).instance));
} else {
alt_bld.setMessage(activity.getString(R.string.logout_account_confirmation, "", ""));
}
@ -677,14 +676,14 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
if (intent != null && intent.getExtras() != null) {
Bundle args = intent.getExtras();
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(activity).getBundle(bundleId, currentAccount, bundle -> {
new CachedBundle(activity).getBundle(bundleId, Helper.getCurrentAccount(activity), bundle -> {
app.fedilab.android.mastodon.client.entities.api.Account account = (app.fedilab.android.mastodon.client.entities.api.Account) bundle.getSerializable(Helper.INTENT_TARGETED_ACCOUNT);
Status status = (Status) bundle.getSerializable(Helper.INTENT_TARGETED_STATUS);
if (account != null) {
Intent intentAccount = new Intent(activity, ProfileActivity.class);
Bundle args2 = new Bundle();
args2.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(activity).insertBundle(args2, currentAccount, bundleId2 -> {
new CachedBundle(activity).insertBundle(args2, Helper.getCurrentAccount(activity), bundleId2 -> {
Bundle bundleCached = new Bundle();
bundleCached.putLong(Helper.ARG_INTENT_ID, bundleId2);
intentAccount.putExtras(bundleCached);
@ -695,7 +694,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
Intent intentContext = new Intent(activity, ContextActivity.class);
Bundle args2 = new Bundle();
args2.putSerializable(Helper.ARG_STATUS, status);
new CachedBundle(activity).insertBundle(args2, currentAccount, bundleId2 -> {
new CachedBundle(activity).insertBundle(args2, Helper.getCurrentAccount(activity), bundleId2 -> {
Bundle bundleCached = new Bundle();
bundleCached.putLong(Helper.ARG_INTENT_ID, bundleId2);
intentContext.putExtras(bundleCached);
@ -731,7 +730,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
args.putBoolean(ARG_REFRESH_NOTFICATION, true);
Intent intentBC = new Intent(Helper.RECEIVE_STATUS_ACTION);
intentBC.setPackage(BuildConfig.APPLICATION_ID);
new CachedBundle(activity).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(activity).insertBundle(args, Helper.getCurrentAccount(activity), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBC.putExtras(bundle);
@ -808,14 +807,14 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
} else if (extras.getInt(Helper.INTENT_ACTION) == Helper.OPEN_NOTIFICATION) {
openNotifications(activity, intent);
} else if (extras.getInt(Helper.INTENT_ACTION) == Helper.OPEN_WITH_ANOTHER_ACCOUNT) {
CrossActionHelper.fetchRemoteStatus(activity, MainActivity.currentAccount, urlOfMessage, new CrossActionHelper.Callback() {
CrossActionHelper.fetchRemoteStatus(activity, Helper.getCurrentAccount(activity), urlOfMessage, new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
if (status != null) {
Intent intent = new Intent(activity, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, status);
new CachedBundle(activity).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(activity).insertBundle(args, Helper.getCurrentAccount(activity), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -1041,26 +1040,26 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
Matcher matcherLink;
matcherLink = link.matcher(url);
if (matcherLink.find()) {
if (currentAccount == null) {
if (Helper.getCurrentAccount(activity) == null) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity);
if (currentToken == null || currentToken.trim().isEmpty()) {
currentToken = sharedpreferences.getString(Helper.PREF_USER_TOKEN, null);
}
try {
currentAccount = new Account(activity).getConnectedAccount();
Helper.setCurrentAccount(new Account(activity).getConnectedAccount());
} catch (DBException e) {
e.printStackTrace();
}
}
if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot
CrossActionHelper.fetchRemoteStatus(activity, currentAccount, url, new CrossActionHelper.Callback() {
CrossActionHelper.fetchRemoteStatus(activity, Helper.getCurrentAccount(activity), url, new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
if (status != null) {
Intent intent = new Intent(activity, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, status);
new CachedBundle(activity).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(activity).insertBundle(args, Helper.getCurrentAccount(activity), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -1077,7 +1076,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
}
});
} else {//It's an account
CrossActionHelper.fetchRemoteAccount(activity, currentAccount, matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() {
CrossActionHelper.fetchRemoteAccount(activity, Helper.getCurrentAccount(activity), matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
}
@ -1088,7 +1087,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
Intent intent = new Intent(activity, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(activity).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(activity).insertBundle(args, Helper.getCurrentAccount(activity), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -1148,27 +1147,26 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
permissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS);
}
NavHeaderMainBinding headerMainBinding = NavHeaderMainBinding.inflate(getLayoutInflater());
currentAccount = null;
//Update account details
new Thread(() -> {
try {
if (currentToken == null) {
currentToken = sharedpreferences.getString(PREF_USER_TOKEN, null);
}
currentAccount = new Account(BaseMainActivity.this).getConnectedAccount();
Helper.setCurrentAccount(new Account(BaseMainActivity.this).getConnectedAccount());
} catch (DBException e) {
e.printStackTrace();
}
//Apply the custom theme
if (currentAccount != null && currentInstance == null) {
currentInstance = currentAccount.instance;
currentUserID = currentAccount.user_id;
if (Helper.getCurrentAccount(BaseMainActivity.this) != null && currentInstance == null) {
currentInstance = Helper.getCurrentAccount(BaseMainActivity.this).instance;
currentUserID = Helper.getCurrentAccount(BaseMainActivity.this).user_id;
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = this::recreate;
mainHandler.post(myRunnable);
}
if (currentAccount != null && currentAccount.peertube_account != null) {
if (Helper.getCurrentAccount(BaseMainActivity.this) != null && Helper.getCurrentAccount(BaseMainActivity.this).peertube_account != null) {
//It is a peertube user
Intent intent = getIntent();
Intent myIntent = new Intent(this, PeertubeMainActivity.class);
@ -1189,7 +1187,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
return;
}
//If the attached account is null, the app will fetch remote instance to get up-to-date values
if (currentAccount != null && currentAccount.mastodon_account == null) {
if (Helper.getCurrentAccount(BaseMainActivity.this) != null && Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account == null) {
OkHttpClient okHttpClient = Helper.myOkHttpClient(getApplication().getApplicationContext());
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://" + (MainActivity.currentInstance != null ? IDN.toASCII(MainActivity.currentInstance, IDN.ALLOW_UNASSIGNED) : null) + "/api/v1/")
@ -1202,7 +1200,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
try {
retrofit2.Response<app.fedilab.android.mastodon.client.entities.api.Account> accountResponse = accountCall.execute();
if (accountResponse.isSuccessful()) {
currentAccount.mastodon_account = accountResponse.body();
Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account = accountResponse.body();
}
} catch (Exception e) {
e.printStackTrace();
@ -1211,9 +1209,9 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
if (currentAccount == null || (currentAccount.mastodon_account == null && currentAccount.peertube_account == null)) {
if (Helper.getCurrentAccount(BaseMainActivity.this) == null || (Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account == null && Helper.getCurrentAccount(BaseMainActivity.this).peertube_account == null)) {
//It is not, the user is redirected to the login page
if (currentAccount != null) {
if (Helper.getCurrentAccount(BaseMainActivity.this) != null) {
try {
Helper.removeAccount(BaseMainActivity.this);
} catch (DBException e) {
@ -1229,11 +1227,11 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
}
return;
}
bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(currentAccount, binding.bottomNavView);
if (currentAccount.mastodon_account.locked) {
bottomMenu = new BottomMenu(BaseMainActivity.this).hydrate(Helper.getCurrentAccount(BaseMainActivity.this), binding.bottomNavView);
if (Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account.locked) {
binding.navView.getMenu().findItem(R.id.nav_follow_requests).setVisible(true);
}
if (currentAccount.admin) {
if (Helper.getCurrentAccount(BaseMainActivity.this).admin) {
binding.navView.getMenu().findItem(R.id.nav_administration).setVisible(true);
}
if (bottomMenu != null) {
@ -1280,8 +1278,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
});
}
currentInstance = currentAccount.instance;
currentUserID = currentAccount.user_id;
currentInstance = Helper.getCurrentAccount(BaseMainActivity.this).instance;
currentUserID = Helper.getCurrentAccount(BaseMainActivity.this).user_id;
show_boosts = sharedpreferences.getBoolean(getString(R.string.SET_SHOW_BOOSTS) + currentUserID + currentInstance, true);
show_my_messages = sharedpreferences.getBoolean(getString(R.string.SET_SHOW_MY_MESSAGES) + currentUserID + currentInstance, true);
@ -1295,22 +1293,22 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
show_art_nsfw = sharedpreferences.getBoolean(getString(R.string.SET_ART_WITH_NSFW) + currentUserID + currentInstance, false);
binding.profilePicture.setOnClickListener(v -> binding.drawerLayout.openDrawer(GravityCompat.START));
Helper.loadPP(BaseMainActivity.this, binding.profilePicture, currentAccount);
headerMainBinding.accountAcc.setText(String.format("%s@%s", currentAccount.mastodon_account.username, currentAccount.instance));
if (currentAccount.mastodon_account.display_name == null || currentAccount.mastodon_account.display_name.isEmpty()) {
currentAccount.mastodon_account.display_name = currentAccount.mastodon_account.acct;
Helper.loadPP(BaseMainActivity.this, binding.profilePicture, Helper.getCurrentAccount(BaseMainActivity.this));
headerMainBinding.accountAcc.setText(String.format("%s@%s", Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account.username, Helper.getCurrentAccount(BaseMainActivity.this).instance));
if (Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account.display_name == null || Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account.display_name.isEmpty()) {
Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account.display_name = Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account.acct;
}
if (!isFinishing()) {
headerMainBinding.accountName.setText(
currentAccount.mastodon_account.getSpanDisplayNameEmoji(BaseMainActivity.this,
Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account.getSpanDisplayNameEmoji(BaseMainActivity.this,
new WeakReference<>(headerMainBinding.accountName)),
TextView.BufferType.SPANNABLE);
}
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
headerMainBinding.accountName.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
headerMainBinding.accountAcc.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
Helper.loadPP(BaseMainActivity.this, headerMainBinding.accountProfilePicture, currentAccount, false);
MastodonHelper.loadProfileMediaMastodon(BaseMainActivity.this, headerMainBinding.backgroundImage, currentAccount.mastodon_account, MastodonHelper.MediaAccountType.HEADER);
Helper.loadPP(BaseMainActivity.this, headerMainBinding.accountProfilePicture, Helper.getCurrentAccount(BaseMainActivity.this), false);
MastodonHelper.loadProfileMediaMastodon(BaseMainActivity.this, headerMainBinding.backgroundImage, Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account, MastodonHelper.MediaAccountType.HEADER);
headerMainBinding.backgroundImage.setAlpha(0.5f);
/*
* Some general data are loaded when the app starts such;
@ -1351,13 +1349,13 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
new ViewModelProvider(BaseMainActivity.this).get(AccountsVM.class).getConnectedAccount(currentInstance, currentToken)
.observe(BaseMainActivity.this, mastodonAccount -> {
//Initialize static var
if (mastodonAccount != null && currentAccount != null) {
currentAccount.mastodon_account = mastodonAccount;
if (mastodonAccount != null && Helper.getCurrentAccount(BaseMainActivity.this) != null) {
Helper.setCurrentAccountMastodonAccount(BaseMainActivity.this, mastodonAccount);
displayReleaseNotesIfNeeded(BaseMainActivity.this, false);
new Thread(() -> {
try {
//Update account in db
new Account(BaseMainActivity.this).insertOrUpdate(currentAccount);
new Account(BaseMainActivity.this).insertOrUpdate(Helper.getCurrentAccount(BaseMainActivity.this));
} catch (DBException e) {
e.printStackTrace();
}
@ -1374,6 +1372,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
filterFetched = false;
networkStateReceiver = new NetworkStateReceiver();
networkStateReceiver.addListener(this);
registerReceiver(networkStateReceiver, new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION));
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.toolbar);
@ -1463,7 +1462,6 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
bundle.putBoolean(Helper.ARG_PEERTUBE_NAV_REMOTE, true);
intent.putExtras(bundle);
startActivity(intent);
finish();
} else if (id == R.id.nav_about_instance) {
(new InstanceActivity()).show(getSupportFragmentManager(), null);
}
@ -1475,8 +1473,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
headerMainBinding.accountProfilePicture.setOnClickListener(v -> {
Intent intent = new Intent(BaseMainActivity.this, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, currentAccount.mastodon_account);
new CachedBundle(BaseMainActivity.this).insertBundle(args, currentAccount, bundleId -> {
args.putSerializable(Helper.ARG_ACCOUNT, Helper.getCurrentAccount(BaseMainActivity.this).mastodon_account);
new CachedBundle(BaseMainActivity.this).insertBundle(args, Helper.getCurrentAccount(BaseMainActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -1527,14 +1525,14 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
int[] to = new int[]{R.id.account_pp, R.id.account_un};
String searchGroup = matcherMention.group();
AccountsVM accountsVM = new ViewModelProvider(BaseMainActivity.this).get(AccountsVM.class);
MatrixCursor cursor = new MatrixCursor(new String[]{BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_ICON_1,
SearchManager.SUGGEST_COLUMN_TEXT_1});
accountsVM.searchAccounts(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, searchGroup, 5, false, false)
accountsVM.searchAccounts(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, searchGroup, 10, false, false)
.observe(BaseMainActivity.this, accounts -> {
if (accounts == null) {
return;
}
MatrixCursor cursor = new MatrixCursor(new String[]{BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_ICON_1,
SearchManager.SUGGEST_COLUMN_TEXT_1});
AccountsSearchTopBarAdapter cursorAdapter = new AccountsSearchTopBarAdapter(BaseMainActivity.this, accounts, R.layout.drawer_account_search, null, from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
binding.toolbarSearch.setSuggestionsAdapter(cursorAdapter);
new Thread(() -> {
@ -1562,8 +1560,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
String[] from = new String[]{SearchManager.SUGGEST_COLUMN_TEXT_1};
int[] to = new int[]{R.id.tag_name};
String searchGroup = matcherTag.group();
MatrixCursor cursor = new MatrixCursor(new String[]{BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1});
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, searchGroup, null,
"hashtags", false, true, false, 0,
null, null, 10).observe(BaseMainActivity.this,
@ -1571,6 +1568,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
if (results == null || results.hashtags == null) {
return;
}
MatrixCursor cursor = new MatrixCursor(new String[]{BaseColumns._ID,
SearchManager.SUGGEST_COLUMN_TEXT_1});
TagSearchTopBarAdapter cursorAdapter = new TagSearchTopBarAdapter(BaseMainActivity.this, results.hashtags, R.layout.drawer_tag_search, null, from, to, CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
binding.toolbarSearch.setSuggestionsAdapter(cursorAdapter);
int i = 0;
@ -1946,10 +1945,9 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
}
if (networkStateReceiver != null) {
try {
networkStateReceiver.removeListener(this);
unregisterReceiver(networkStateReceiver);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
} catch (Exception ignored) {}
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(BaseMainActivity.this);
boolean clearCacheExit = sharedpreferences.getBoolean(getString(R.string.SET_CLEAR_CACHE_EXIT), false);

View file

@ -15,8 +15,6 @@ package app.fedilab.android.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
@ -123,7 +121,7 @@ public class AboutActivity extends BaseBarActivity {
Intent intent = new Intent(AboutActivity.this, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(AboutActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(AboutActivity.this).insertBundle(args, Helper.getCurrentAccount(AboutActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -0,0 +1,102 @@
package app.fedilab.android.activities;
/* Copyright 2025 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import app.fedilab.android.mastodon.activities.ProfileActivity;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.helper.Helper;
public class WebActivityPub extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent appIntent = getIntent();
String acct = null;
String intent = null;
if(appIntent == null) {
finish();
return;
}
Uri uri = appIntent.getData();
if(uri == null) {
finish();
return;
}
String scheme = uri.getScheme();
String uriString = uri.toString();
if(!uriString.startsWith(scheme+"://")) {
uriString = uri.toString().replace(scheme+":",scheme+"://");
uri = Uri.parse(uriString);
if(uri == null) {
finish();
return;
}
}
String host = uri.getHost();
String path = uri.getPath();
String query = uri.getQuery();
if(path == null || path.isEmpty()) {
finish();
return;
}
if(query != null) {
String intentPatternString = "intent=(\\w+)";
final Pattern intentPattern = Pattern.compile(intentPatternString, Pattern.CASE_INSENSITIVE);
Matcher matcherIntent = intentPattern.matcher(query);
while (matcherIntent.find()) {
intent = matcherIntent.group(1);
}
}
if(path.startsWith("/@")) {
String[] params = path.split("@");
if(params.length == 2) {
acct = params[1] + "@" + host;
}
} else if(path.split("/").length > 2) {
String[] params = path.split("/");
String root = params[1].toLowerCase();
if (root.equals("users")) {
acct = params[2] + "@" + host;
}
}
if(acct != null) {
Intent intentProfile = new Intent(WebActivityPub.this, ProfileActivity.class);
Bundle args = new Bundle();
args.putString(Helper.ARG_MENTION, acct);
new CachedBundle(WebActivityPub.this).insertBundle(args, Helper.getCurrentAccount(WebActivityPub.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentProfile.putExtras(bundle);
intentProfile.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intentProfile);
});
}
finish();
}
}

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.app.Activity;
import android.graphics.PorterDuff;
import android.os.Bundle;
@ -69,7 +67,7 @@ public class AccountReportActivity extends BaseBarActivity {
Bundle args = getIntent().getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(AccountReportActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(AccountReportActivity.this).getBundle(bundleId, Helper.getCurrentAccount(AccountReportActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}

View file

@ -60,42 +60,43 @@ public class ActionActivity extends BaseBarActivity {
private void displayTimeline(Timeline.TimeLineEnum type) {
canGoBack = true;
if (type == Timeline.TimeLineEnum.MUTED_TIMELINE || type == Timeline.TimeLineEnum.BLOCKED_TIMELINE || type == Timeline.TimeLineEnum.MUTED_TIMELINE_HOME) {
fragmentMastodonAccount = new FragmentMastodonAccount();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentMastodonAccount.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonAccount);
fragmentTransaction.commit();
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentMastodonAccount = new FragmentMastodonAccount();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentMastodonAccount.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonAccount);
fragmentTransaction.commit();
});
} else if (type == Timeline.TimeLineEnum.BLOCKED_DOMAIN_TIMELINE) {
fragmentMastodonDomainBlock = new FragmentMastodonDomainBlock();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonDomainBlock);
fragmentTransaction.commit();
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentMastodonDomainBlock = new FragmentMastodonDomainBlock();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonDomainBlock);
fragmentTransaction.commit();
});
} else {
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
});
}

View file

@ -15,7 +15,9 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.currentNightMode;
import static app.fedilab.android.BaseMainActivity.currentUserID;
import android.annotation.SuppressLint;
import android.content.Context;
@ -24,9 +26,11 @@ import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
@ -71,8 +75,20 @@ public class BaseActivity extends AppCompatActivity {
}
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
boolean customAccentEnabled = sharedpreferences.getBoolean(getString(R.string.SET_CUSTOM_ACCENT) + currentUserID + currentInstance, false);
//Default automatic switch
currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if(customAccentEnabled && currentNightMode == Configuration.UI_MODE_NIGHT_NO) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR|View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
}
if (currentTheme.equals(getString(R.string.SET_DEFAULT_THEME))) {
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO -> {
@ -169,4 +185,11 @@ public class BaseActivity extends AppCompatActivity {
}
super.attachBaseContext(newBase);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.clear();
}
}

View file

@ -15,7 +15,9 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.currentNightMode;
import static app.fedilab.android.BaseMainActivity.currentUserID;
import android.annotation.SuppressLint;
import android.content.Context;
@ -24,9 +26,11 @@ import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.app.AppCompatDelegate;
@ -66,8 +70,16 @@ public class BaseBarActivity extends AppCompatActivity {
}
}
String currentTheme = sharedpreferences.getString(getString(R.string.SET_THEME_BASE), getString(R.string.SET_DEFAULT_THEME));
boolean customAccentEnabled = sharedpreferences.getBoolean(getString(R.string.SET_CUSTOM_ACCENT) + currentUserID + currentInstance, false);
//Default automatic switch
currentNightMode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
if(customAccentEnabled && currentNightMode == Configuration.UI_MODE_NIGHT_NO) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR|View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
}else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
}
}
if (currentTheme.equals(getString(R.string.SET_DEFAULT_THEME))) {
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO -> {
@ -144,4 +156,11 @@ public class BaseBarActivity extends AppCompatActivity {
super.attachBaseContext(newBase);
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.clear();
}
}

View file

@ -54,12 +54,12 @@ import java.util.List;
import java.util.Locale;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityCheckHomeCachetBinding;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.StatusCache;
import app.fedilab.android.mastodon.client.entities.app.TimelineCacheLogs;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import es.dmoral.toasty.Toasty;
@ -88,7 +88,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
if (MainActivity.currentAccount == null || MainActivity.currentAccount.mastodon_account == null) {
if (Helper.getCurrentAccount(CheckHomeCacheActivity.this) == null || Helper.getCurrentAccount(CheckHomeCacheActivity.this).mastodon_account == null) {
finish();
return;
}
@ -107,7 +107,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
try {
if (myRange == range.ALL) {
if (statuses == null) {
statuses = new StatusCache(this).getHome(MainActivity.currentAccount);
statuses = new StatusCache(this).getHome(Helper.getCurrentAccount(CheckHomeCacheActivity.this));
sortAsc(statuses);
}
} else if (myRange == range.DAY) {
@ -202,7 +202,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
IndexAxisValueFormatter formatter = new IndexAxisValueFormatter() {
@Override
public String getFormattedValue(float value) {
if (value < xVals.size()) {
if (value >= 0 && value < xVals.size()) {
return xVals.get((int) value);
} else
return "";
@ -247,7 +247,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
try {
if (myRange == range.ALL) {
if (timelineCacheLogsList == null) {
timelineCacheLogsList = new TimelineCacheLogs(this).getHome(MainActivity.currentAccount);
timelineCacheLogsList = new TimelineCacheLogs(this).getHome(Helper.getCurrentAccount(CheckHomeCacheActivity.this));
}
} else if (myRange == range.DAY) {
if (timelineCacheLogsDayList == null && timelineCacheLogsList != null) {
@ -363,7 +363,7 @@ public class CheckHomeCacheActivity extends BaseBarActivity {
IndexAxisValueFormatter formatter = new IndexAxisValueFormatter() {
@Override
public String getFormattedValue(float value) {
if (value < xVals2.size()) {
if (value >= 0 && value < xVals2.size()) {
return xVals2.get((int) value);
} else
return "";

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.emojis;
@ -123,14 +122,14 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
Bundle args = intent.getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(ComposeActivity.this).getBundle(bundleId, currentAccount, bundle -> {
new CachedBundle(ComposeActivity.this).getBundle(bundleId, Helper.getCurrentAccount(ComposeActivity.this), bundle -> {
String imgpath = bundle.getString("imgpath");
float focusX = bundle.getFloat("focusX", -2);
float focusY = bundle.getFloat("focusY", -2);
if (imgpath != null) {
int position = 0;
for (Status status : statusList) {
if (status.media_attachments != null && status.media_attachments.size() > 0) {
if (status.media_attachments != null && !status.media_attachments.isEmpty()) {
for (Attachment attachment : status.media_attachments) {
if (attachment.local_path != null && attachment.local_path.equalsIgnoreCase(imgpath)) {
if (focusX != -2) {
@ -492,7 +491,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
if (b != null) {
long bundleId = b.getLong(Helper.ARG_INTENT_ID, -1);
if (bundleId != -1) {
new CachedBundle(ComposeActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(ComposeActivity.this).getBundle(bundleId, Helper.getCurrentAccount(ComposeActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(b);
}
@ -513,7 +512,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
statusMention = (Status) b.getSerializable(Helper.ARG_STATUS_MENTION);
account = (BaseAccount) b.getSerializable(Helper.ARG_ACCOUNT);
if (account == null) {
account = currentAccount;
account = Helper.getCurrentAccount(ComposeActivity.this);
}
editMessageId = b.getString(Helper.ARG_EDIT_STATUS_ID, null);
instance = b.getString(Helper.ARG_INSTANCE, null);
@ -521,8 +520,8 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
visibility = b.getString(Helper.ARG_VISIBILITY, null);
if (visibility == null && statusReply != null) {
visibility = getVisibility(account, statusReply.visibility);
} else if (visibility == null && currentAccount != null && currentAccount.mastodon_account != null && currentAccount.mastodon_account.source != null) {
visibility = currentAccount.mastodon_account.source.privacy;
} else if (visibility == null && Helper.getCurrentAccount(ComposeActivity.this) != null && Helper.getCurrentAccount(ComposeActivity.this).mastodon_account != null && Helper.getCurrentAccount(ComposeActivity.this).mastodon_account.source != null) {
visibility = Helper.getCurrentAccount(ComposeActivity.this).mastodon_account.source.privacy;
}
mentionBooster = (Account) b.getSerializable(Helper.ARG_MENTION_BOOSTER);
accountMention = (Account) b.getSerializable(Helper.ARG_ACCOUNT_MENTION);
@ -552,24 +551,22 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
status.text = scheduledStatus.params.text;
status.in_reply_to_id = scheduledStatus.params.in_reply_to_id;
status.poll = scheduledStatus.params.poll;
if (scheduledStatus.params.media_ids != null && scheduledStatus.params.media_ids.size() > 0) {
if (scheduledStatus.params.media_ids != null && !scheduledStatus.params.media_ids.isEmpty()) {
status.media_attachments = new ArrayList<>();
new Thread(() -> {
StatusesVM statusesVM = new ViewModelProvider(ComposeActivity.this).get(StatusesVM.class);
for (String attachmentId : scheduledStatus.params.media_ids) {
statusesVM.getAttachment(instance, token, attachmentId)
.observe(ComposeActivity.this, attachment -> status.media_attachments.add(attachment));
}
}).start();
for (String attachmentId : scheduledStatus.params.media_ids) {
Attachment attachment = new Attachment();
attachment.id = attachmentId;
status.media_attachments.add(attachment);
}
}
status.sensitive = scheduledStatus.params.sensitive;
status.spoiler_text = scheduledStatus.params.spoiler_text;
status.visibility = scheduledStatus.params.visibility;
statuses.add(status);
statusDraft.statusDraftList = statuses;
}
if (account == null) {
account = currentAccount;
account = Helper.getCurrentAccount(ComposeActivity.this);
}
if (account == null) {
Toasty.error(ComposeActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
@ -672,7 +669,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
mention.username = mentionBooster.username;
boolean present = false;
for (Mention mentionTmp : statusDraftList.get(0).mentions) {
if (mentionTmp.acct.equalsIgnoreCase(mentionBooster.acct)) {
if (mentionTmp.acct.equalsIgnoreCase("@"+mentionBooster.acct)) {
present = true;
break;
}
@ -683,13 +680,13 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
}
if (statusReply.spoiler_text != null) {
statusDraftList.get(0).spoiler_text = statusReply.spoiler_text;
if (statusReply.spoiler_text.trim().length() > 0) {
if (!statusReply.spoiler_text.trim().isEmpty()) {
statusDraftList.get(0).spoilerChecked = true;
}
}
if (statusReply.language != null && !statusReply.language.isEmpty()) {
Set<String> storedLanguages = sharedpreferences.getStringSet(getString(R.string.SET_SELECTED_LANGUAGE), null);
if (storedLanguages == null || storedLanguages.size() == 0) {
if (storedLanguages == null || storedLanguages.isEmpty()) {
statusDraftList.get(0).language = statusReply.language;
} else {
if (storedLanguages.contains(statusReply.language)) {
@ -754,7 +751,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
}, 0, 10000);
}
if (sharedAttachments != null && sharedAttachments.size() > 0) {
if (sharedAttachments != null && !sharedAttachments.isEmpty()) {
for (Attachment attachment : sharedAttachments) {
composeAdapter.addAttachment(-1, attachment);
}
@ -845,7 +842,15 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
private void storeDraft(boolean sendMessage) {
storeDraft(sendMessage, null);
String scheduledDate = null;
if(scheduledStatus != null && scheduledStatus.scheduled_at != null) {
SimpleDateFormat sdf = new SimpleDateFormat(Helper.SCHEDULE_DATE_FORMAT, Locale.getDefault());
scheduledDate = sdf.format(scheduledStatus.scheduled_at.getTime());
} else if(statusDraft != null && statusDraft.scheduled_at != null) {
SimpleDateFormat sdf = new SimpleDateFormat(Helper.SCHEDULE_DATE_FORMAT, Locale.getDefault());
scheduledDate = sdf.format(statusDraft.scheduled_at.getTime());
}
storeDraft(sendMessage, scheduledDate);
}
private void storeDraft(boolean sendMessage, String scheduledDate) {
@ -867,14 +872,19 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
} else {
//Draft previously and date is changed
if (statusDraft.scheduled_at != null && scheduledDate != null && statusDraft.workerUuid != null) {
WorkManager.getInstance(ComposeActivity.this).cancelWorkById(statusDraft.workerUuid);
try {
new StatusDraft(ComposeActivity.this).removeScheduled(statusDraft);
WorkManager.getInstance(ComposeActivity.this).cancelWorkById(statusDraft.workerUuid);
} catch (DBException e) {
e.printStackTrace();
}
}
}
if (statusReplies.size() > 0) {
if (!statusReplies.isEmpty()) {
statusDraft.statusReplyList = new ArrayList<>();
statusDraft.statusReplyList.addAll(statusReplies);
}
if (statusDrafts.size() > 0) {
if (!statusDrafts.isEmpty()) {
statusDraft.statusDraftList = new ArrayList<>();
statusDraft.statusDraftList.addAll(statusDrafts);
}
@ -896,7 +906,6 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
materialAlertDialogBuilder.setPositiveButton(R.string.send_anyway, (dialog, id) -> {
sendMessage(true, scheduledDate);
dialog.dismiss();
});
materialAlertDialogBuilder.setNegativeButton(R.string.add_description, (dialog, id) -> {
composeAdapter.openMissingDescription();
@ -907,7 +916,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
} else {
Toasty.info(ComposeActivity.this, getString(R.string.toot_error_no_content), Toasty.LENGTH_SHORT).show();
}
if (statusDrafts.size() > 0) {
if (!statusDrafts.isEmpty()) {
statusDrafts.get(statusDrafts.size() - 1).submitted = false;
composeAdapter.notifyItemChanged(statusList.size() - 1);
}
@ -980,12 +989,14 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
mediaCount += status.media_attachments != null ? status.media_attachments.size() : 0;
}
if (mediaCount > 0) {
String scheduledStatusId = scheduledStatus!=null&&scheduledStatus.id!=null?scheduledStatus.id:null;
Data inputData = new Data.Builder()
.putString(Helper.ARG_STATUS_DRAFT_ID, String.valueOf(statusDraft.id))
.putString(Helper.ARG_INSTANCE, instance)
.putString(Helper.ARG_TOKEN, token)
.putString(Helper.ARG_EDIT_STATUS_ID, editMessageId)
.putString(Helper.ARG_USER_ID, account.user_id)
.putString(Helper.ARG_SCHEDULED_ID, scheduledStatusId)
.putString(Helper.ARG_SCHEDULED_DATE, scheduledDate).build();
OneTimeWorkRequest request = new OneTimeWorkRequest.Builder(ComposeWorker.class)
.setInputData(inputData)
@ -994,7 +1005,8 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
WorkManager.getInstance(ComposeActivity.this).enqueue(request);
} else {
new ThreadMessageService(ComposeActivity.this, instance, account.user_id, token, statusDraft, scheduledDate, editMessageId);
String scheduledStatusId = scheduledStatus!=null&&scheduledStatus.id!=null?scheduledStatus.id:null;
new ThreadMessageService(ComposeActivity.this, instance, account.user_id, token, statusDraft, scheduledDate, editMessageId, scheduledStatusId);
}
finish();
}
@ -1067,6 +1079,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
binding.description.setVisibility(View.GONE);
actionBar.show();
binding.recyclerView.setVisibility(View.VISIBLE);
promptSaveDraft = true;
composeAdapter.openDescriptionActivity(true, Objects.requireNonNull(binding.mediaDescription.getText()).toString().trim(), holder, attachment, messagePosition, mediaPosition);
});
binding.mediaCancel.setOnClickListener(v -> {

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import android.content.Intent;
@ -99,7 +98,7 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon
Bundle args = getIntent().getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(ContextActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(ContextActivity.this).getBundle(bundleId, Helper.getCurrentAccount(ContextActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
@ -111,7 +110,7 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon
remote_instance = bundle.getString(Helper.ARG_REMOTE_INSTANCE, null);
focusedStatusURI = bundle.getString(Helper.ARG_FOCUSED_STATUS_URI, null);
}
if (focusedStatus == null || currentAccount == null || currentAccount.mastodon_account == null) {
if (focusedStatus == null || Helper.getCurrentAccount(ContextActivity.this) == null || Helper.getCurrentAccount(ContextActivity.this).mastodon_account == null) {
finish();
return;
}
@ -127,18 +126,12 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon
loadRemotelyConversation(true);
invalidateOptionsMenu();
}
if(currentAccount != null) {
MastodonHelper.loadPPMastodon(binding.profilePicture, currentAccount.mastodon_account);
if (Helper.getCurrentAccount(ContextActivity.this) != null) {
MastodonHelper.loadPPMastodon(binding.profilePicture, Helper.getCurrentAccount(ContextActivity.this).mastodon_account);
}
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.clear();
}
private void manageTopBarScrolling(Toolbar toolbar, SharedPreferences sharedpreferences) {
final boolean topBarScrolling = !sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_TOPBAR_SCROLLING), false);
@ -159,7 +152,7 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, focusedStatus);
args.putString(Helper.ARG_REMOTE_INSTANCE, remote_instance);
new CachedBundle(ContextActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ContextActivity.this).insertBundle(args, Helper.getCurrentAccount(ContextActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
FragmentMastodonContext fragmentMastodonContext = new FragmentMastodonContext();
@ -289,7 +282,7 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon
args.putSerializable(Helper.ARG_STATUS, status);
args.putString(Helper.ARG_REMOTE_INSTANCE, finalInstance);
args.putString(Helper.ARG_FOCUSED_STATUS_URI, focusedStatusURI);
new CachedBundle(ContextActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ContextActivity.this).insertBundle(args, Helper.getCurrentAccount(ContextActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
FragmentMastodonContext fragmentMastodonContext = new FragmentMastodonContext();
@ -341,7 +334,7 @@ public class ContextActivity extends BaseActivity implements FragmentMastodonCon
args.putSerializable(Helper.ARG_STATUS, status);
args.putString(Helper.ARG_FOCUSED_STATUS_URI, focusedStatusURI);
args.putString(Helper.ARG_REMOTE_INSTANCE, finalInstance);
new CachedBundle(ContextActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ContextActivity.this).insertBundle(args, Helper.getCurrentAccount(ContextActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentContext.putExtras(bundle);

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.SharedPreferences;
import android.net.Uri;
@ -77,7 +76,7 @@ public class CustomSharingActivity extends BaseBarActivity implements OnCustomSh
status = null;
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(CustomSharingActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(CustomSharingActivity.this).getBundle(bundleId, Helper.getCurrentAccount(CustomSharingActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
@ -110,7 +109,7 @@ public class CustomSharingActivity extends BaseBarActivity implements OnCustomSh
bundle_thumbnailurl = status.account.avatar;
}
if (!bundle_creator.contains("@")) {
bundle_creator = bundle_creator + "@" + currentAccount.instance;
bundle_creator = bundle_creator + "@" + Helper.getCurrentAccount(CustomSharingActivity.this).instance;
}
binding.setCustomSharingTitle.setEllipsize(TextUtils.TruncateAt.END);

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.mastodon.activities.ComposeActivity.PICK_MEDIA;
import android.content.ClipData;
@ -72,7 +71,7 @@ public class DirectMessageActivity extends BaseActivity implements FragmentMasto
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
MastodonHelper.loadPPMastodon(binding.profilePicture, currentAccount.mastodon_account);
MastodonHelper.loadPPMastodon(binding.profilePicture, Helper.getCurrentAccount(DirectMessageActivity.this).mastodon_account);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
@ -82,7 +81,7 @@ public class DirectMessageActivity extends BaseActivity implements FragmentMasto
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(DirectMessageActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(DirectMessageActivity.this).getBundle(bundleId, Helper.getCurrentAccount(DirectMessageActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
@ -97,7 +96,7 @@ public class DirectMessageActivity extends BaseActivity implements FragmentMasto
remote_instance = bundle.getString(Helper.ARG_REMOTE_INSTANCE, null);
}
if (focusedStatus == null || currentAccount == null || currentAccount.mastodon_account == null) {
if (focusedStatus == null || Helper.getCurrentAccount(DirectMessageActivity.this) == null || Helper.getCurrentAccount(DirectMessageActivity.this).mastodon_account == null) {
finish();
return;
}
@ -106,7 +105,7 @@ public class DirectMessageActivity extends BaseActivity implements FragmentMasto
args.putSerializable(Helper.ARG_STATUS, focusedStatus);
args.putString(Helper.ARG_REMOTE_INSTANCE, remote_instance);
Status finalFocusedStatus = focusedStatus;
new CachedBundle(DirectMessageActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(DirectMessageActivity.this).insertBundle(args, Helper.getCurrentAccount(DirectMessageActivity.this), bundleId -> {
Bundle args2 = new Bundle();
args2.putLong(Helper.ARG_INTENT_ID, bundleId);
FragmentMastodonDirectMessage FragmentMastodonDirectMessage = new FragmentMastodonDirectMessage();

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.SharedPreferences;
import android.os.Bundle;
@ -45,6 +44,7 @@ import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.drawer.StatusDraftAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.TimelinesVM;
@ -82,7 +82,7 @@ public class DraftActivity extends BaseActivity implements StatusDraftAdapter.Dr
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
timelinesVM = new ViewModelProvider(DraftActivity.this).get(TimelinesVM.class);
timelinesVM.getDrafts(currentAccount)
timelinesVM.getDrafts(Helper.getCurrentAccount(DraftActivity.this))
.observe(DraftActivity.this, this::initializeDraftView);
}
@ -178,7 +178,7 @@ public class DraftActivity extends BaseActivity implements StatusDraftAdapter.Dr
super.onResume();
//We need to check if drafts changed (ie when coming back from the compose activity)
if (statusDrafts != null && timelinesVM != null) {
timelinesVM.getDrafts(currentAccount)
timelinesVM.getDrafts(Helper.getCurrentAccount(DraftActivity.this))
.observe(DraftActivity.this, this::updateDrafts);
}
}

View file

@ -14,7 +14,7 @@ package app.fedilab.android.mastodon.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.instanceInfo;
import android.annotation.SuppressLint;
@ -91,7 +91,7 @@ public class EditProfileActivity extends BaseBarActivity {
new ViewModelProvider(EditProfileActivity.this).get(AccountsVM.class).getConnectedAccount(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
.observe(EditProfileActivity.this, account -> {
if (account != null) {
currentAccount.mastodon_account = account;
Helper.setCurrentAccountMastodonAccount(EditProfileActivity.this, account);
initializeView();
} else {
Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error));
@ -103,19 +103,19 @@ public class EditProfileActivity extends BaseBarActivity {
@SuppressWarnings("deprecation")
private void initializeView() {
//Hydrate values
MastodonHelper.loadProfileMediaMastodon(EditProfileActivity.this, binding.bannerPp, currentAccount.mastodon_account, MastodonHelper.MediaAccountType.HEADER);
MastodonHelper.loadPPMastodon(binding.accountPp, currentAccount.mastodon_account);
binding.displayName.setText(currentAccount.mastodon_account.display_name);
binding.acct.setText(String.format(Locale.getDefault(), "%s@%s", currentAccount.mastodon_account.acct, BaseMainActivity.currentInstance));
MastodonHelper.loadProfileMediaMastodon(EditProfileActivity.this, binding.bannerPp, Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account, MastodonHelper.MediaAccountType.HEADER);
MastodonHelper.loadPPMastodon(binding.accountPp, Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account);
binding.displayName.setText(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.display_name);
binding.acct.setText(String.format(Locale.getDefault(), "%s@%s", Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.acct, BaseMainActivity.currentInstance));
String bio;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
bio = Html.fromHtml(currentAccount.mastodon_account.note, Html.FROM_HTML_MODE_LEGACY).toString();
bio = Html.fromHtml(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.note, Html.FROM_HTML_MODE_LEGACY).toString();
else
bio = Html.fromHtml(currentAccount.mastodon_account.note).toString();
bio = Html.fromHtml(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.note).toString();
binding.bio.setText(bio);
if (currentAccount.mastodon_account.source != null) {
binding.sensitive.setChecked(currentAccount.mastodon_account.source.sensitive);
switch (currentAccount.mastodon_account.source.privacy) {
if (Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.source != null) {
binding.sensitive.setChecked(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.source.sensitive);
switch (Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.source.privacy) {
case "public" -> binding.visibilityPublic.setChecked(true);
case "unlisted" -> binding.visibilityUnlisted.setChecked(true);
case "private" -> binding.visibilityPrivate.setChecked(true);
@ -126,15 +126,15 @@ public class EditProfileActivity extends BaseBarActivity {
binding.visibilityGroup.setVisibility(View.GONE);
}
binding.bot.setChecked(currentAccount.mastodon_account.bot);
binding.discoverable.setChecked(currentAccount.mastodon_account.discoverable);
binding.bot.setChecked(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.bot);
binding.discoverable.setChecked(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.discoverable);
if (currentAccount.mastodon_account.locked) {
if (Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.locked) {
binding.locked.setChecked(true);
} else {
binding.unlocked.setChecked(true);
}
List<Field> fields = currentAccount.mastodon_account.fields;
List<Field> fields = Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.fields;
if (fields != null && fields.size() > 0) {
for (Field field : fields) {
AccountFieldItemBinding fieldItemBinding = AccountFieldItemBinding.inflate(getLayoutInflater());
@ -214,11 +214,11 @@ public class EditProfileActivity extends BaseBarActivity {
if (account != null) {
sendBroadCast(account);
binding.avatarProgress.setVisibility(View.GONE);
currentAccount.mastodon_account = account;
Helper.setCurrentAccountMastodonAccount(EditProfileActivity.this, account);
Helper.recreateMainActivity(EditProfileActivity.this);
new Thread(() -> {
try {
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(Helper.getCurrentAccount(EditProfileActivity.this));
} catch (DBException e) {
e.printStackTrace();
}
@ -242,10 +242,10 @@ public class EditProfileActivity extends BaseBarActivity {
if (account != null) {
sendBroadCast(account);
binding.headerProgress.setVisibility(View.GONE);
currentAccount.mastodon_account = account;
Helper.setCurrentAccountMastodonAccount(EditProfileActivity.this, account);
new Thread(() -> {
try {
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(Helper.getCurrentAccount(EditProfileActivity.this));
} catch (DBException e) {
e.printStackTrace();
}
@ -262,7 +262,7 @@ public class EditProfileActivity extends BaseBarActivity {
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_PROFILE, true);
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(EditProfileActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(EditProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(EditProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
@ -342,10 +342,10 @@ public class EditProfileActivity extends BaseBarActivity {
)
.observe(EditProfileActivity.this, account -> {
if (account != null) {
currentAccount.mastodon_account = account;
Helper.setCurrentAccountMastodonAccount(EditProfileActivity.this, account);
new Thread(() -> {
try {
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(currentAccount);
new app.fedilab.android.mastodon.client.entities.app.Account(EditProfileActivity.this).insertOrUpdate(Helper.getCurrentAccount(EditProfileActivity.this));
sendBroadCast(account);
} catch (DBException e) {
e.printStackTrace();

View file

@ -150,7 +150,7 @@ public class FollowedTagActivity extends BaseBarActivity implements FollowedTagA
popupAddFollowedTagtBinding.addTag.setFilters(new InputFilter[]{new InputFilter.LengthFilter(255)});
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
String name = Objects.requireNonNull(popupAddFollowedTagtBinding.addTag.getText()).toString().trim();
if (tagList.contains(new Tag(name))) {
if (tagList != null && tagList.contains(new Tag(name))) {
Toasty.error(FollowedTagActivity.this, getString(R.string.tag_already_followed), Toasty.LENGTH_LONG).show();
return;
}
@ -207,19 +207,20 @@ public class FollowedTagActivity extends BaseBarActivity implements FollowedTagA
public void click(Tag tag) {
this.tag = tag;
canGoBack = true;
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_SEARCH_KEYWORD, tag.name);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TAG);
setTitle(tag.name);
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
invalidateOptionsMenu();
ThemeHelper.slideViewsToLeft(binding.recyclerView, binding.fragmentContainer, () -> {
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_SEARCH_KEYWORD, tag.name);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TAG);
setTitle(tag.name);
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
invalidateOptionsMenu();
});
}
}

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
@ -81,14 +79,14 @@ public class HashTagActivity extends BaseActivity {
Bundle args = getIntent().getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(HashTagActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(HashTagActivity.this).getBundle(bundleId, Helper.getCurrentAccount(HashTagActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
}
private void initializeAfterBundle(Bundle bundle) {
if( bundle != null) {
if (bundle != null) {
tag = bundle.getString(Helper.ARG_SEARCH_KEYWORD, null);
}
if (tag == null) {
@ -172,7 +170,7 @@ public class HashTagActivity extends BaseActivity {
statusDraft.statusDraftList = statuses;
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraft);
new CachedBundle(HashTagActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(HashTagActivity.this).insertBundle(args, Helper.getCurrentAccount(HashTagActivity.this), bundleId -> {
Bundle bundleCached = new Bundle();
bundleCached.putLong(Helper.ARG_INTENT_ID, bundleId);
intentToot.putExtras(bundleCached);
@ -207,7 +205,7 @@ public class HashTagActivity extends BaseActivity {
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(HashTagActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(HashTagActivity.this).insertBundle(args, Helper.getCurrentAccount(HashTagActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
@ -221,7 +219,7 @@ public class HashTagActivity extends BaseActivity {
} else {
new Thread(() -> {
try {
Pinned pinned = new Pinned(HashTagActivity.this).getPinned(currentAccount);
Pinned pinned = new Pinned(HashTagActivity.this).getPinned(Helper.getCurrentAccount(HashTagActivity.this));
boolean canBeAdded = true;
boolean update = true;
if (pinned == null) {
@ -267,7 +265,7 @@ public class HashTagActivity extends BaseActivity {
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(HashTagActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(HashTagActivity.this).insertBundle(args, Helper.getCurrentAccount(HashTagActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);

View file

@ -60,63 +60,63 @@ class InstanceHealthActivity : DialogFragment() {
private fun checkInstance() {
val instanceSocialVM =
ViewModelProvider(this@InstanceHealthActivity)[InstanceSocialVM::class.java]
ViewModelProvider(this@InstanceHealthActivity)[InstanceSocialVM::class.java]
instanceSocialVM.getInstances(BaseMainActivity.currentInstance.trim { it <= ' ' })
.observe(this@InstanceHealthActivity) { instanceSocialList: InstanceSocial? ->
val instance = instanceSocialList?.instances?.firstOrNull { instance ->
instance.name.equals(
BaseMainActivity.currentInstance.trim { it <= ' ' },
ignoreCase = true
)
.observe(this@InstanceHealthActivity) { instanceSocialList: InstanceSocial? ->
val instance = instanceSocialList?.instances?.firstOrNull { instance ->
instance.name.equals(
BaseMainActivity.currentInstance.trim { it <= ' ' },
ignoreCase = true
)
}
if (instance != null) {
instance.thumbnail?.takeIf { it != "null" }?.let { thumbnail ->
Glide.with(this@InstanceHealthActivity)
.asBitmap()
.placeholder(R.drawable.default_banner)
.load(thumbnail)
.into(binding.backgroundImage)
}
if (instance != null) {
instance.thumbnail?.takeIf { it != "null" }?.let { thumbnail ->
Glide.with(this@InstanceHealthActivity)
.asBitmap()
.placeholder(R.drawable.default_banner)
.load(thumbnail)
.into(binding.backgroundImage)
}
binding.name.text = instance.name
if (instance.up) {
binding.up.setText(R.string.is_up)
binding.up.setTextColor(
ThemeHelper.getAttColor(
requireContext(),
R.attr.colorPrimary
)
binding.name.text = instance.name
if (instance.up) {
binding.up.setText(R.string.is_up)
binding.up.setTextColor(
ThemeHelper.getAttColor(
requireContext(),
R.attr.colorPrimary
)
} else {
binding.up.setText(R.string.is_down)
binding.up.setTextColor(
ThemeHelper.getAttColor(
requireContext(),
R.attr.colorError
)
)
}
binding.uptime.text = getString(
R.string.instance_health_uptime,
instance.uptime * 100
)
if (instance.checked_at != null)
binding.checkedAt.text =
getString(
R.string.instance_health_checkedat,
Helper.dateToString(instance.checked_at)
)
binding.values.text = getString(
R.string.instance_health_indication,
instance.version,
Helper.withSuffix(instance.active_users.toLong()),
Helper.withSuffix(instance.statuses.toLong())
)
} else {
binding.instanceData.isVisible = false
binding.noInstance.isVisible = true
binding.up.setText(R.string.is_down)
binding.up.setTextColor(
ThemeHelper.getAttColor(
requireContext(),
R.attr.colorError
)
)
}
binding.loader.isVisible = false
binding.uptime.text = getString(
R.string.instance_health_uptime,
instance.uptime * 100
)
if (instance.checked_at != null)
binding.checkedAt.text =
getString(
R.string.instance_health_checkedat,
Helper.dateToString(instance.checked_at)
)
binding.values.text = getString(
R.string.instance_health_indication,
instance.version,
Helper.withSuffix(instance.active_users.toLong()),
Helper.withSuffix(instance.statuses.toLong())
)
} else {
binding.instanceData.isVisible = false
binding.noInstance.isVisible = true
}
binding.loader.isVisible = false
}
}
override fun onDestroyView() {

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.annotation.SuppressLint;
import android.content.Intent;
import android.os.Bundle;
@ -177,7 +175,7 @@ public class MastodonListActivity extends BaseBarActivity implements MastodonLis
timelinesVM.getAccountsInList(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mastodonList.id, null, null, 0)
.observe(MastodonListActivity.this, accounts -> {
if (accounts != null && accounts.size() > 0) {
accountsVM.muteAccountsHome(currentAccount, accounts);
accountsVM.muteAccountsHome(Helper.getCurrentAccount(MastodonListActivity.this), accounts);
}
});
dialog.dismiss();
@ -313,7 +311,7 @@ public class MastodonListActivity extends BaseBarActivity implements MastodonLis
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
args.putSerializable(Helper.RECEIVE_MASTODON_LIST, mastodonListList);
new CachedBundle(MastodonListActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(MastodonListActivity.this).insertBundle(args, Helper.getCurrentAccount(MastodonListActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
@ -353,7 +351,7 @@ public class MastodonListActivity extends BaseBarActivity implements MastodonLis
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
args.putSerializable(Helper.RECEIVE_MASTODON_LIST, mastodonListList);
new CachedBundle(MastodonListActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(MastodonListActivity.this).insertBundle(args, Helper.getCurrentAccount(MastodonListActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
@ -405,7 +403,7 @@ public class MastodonListActivity extends BaseBarActivity implements MastodonLis
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(MastodonListActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(MastodonListActivity.this).insertBundle(args, Helper.getCurrentAccount(MastodonListActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
@ -461,19 +459,20 @@ public class MastodonListActivity extends BaseBarActivity implements MastodonLis
this.mastodonList = mastodonList;
canGoBack = true;
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_LIST_ID, mastodonList.id);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.LIST);
setTitle(mastodonList.title);
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
invalidateOptionsMenu();
ThemeHelper.slideViewsToLeft(binding.recyclerView, binding.fragmentContainer, () -> {
fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_LIST_ID, mastodonList.id);
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.LIST);
setTitle(mastodonList.title);
fragmentMastodonTimeline.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentMastodonTimeline);
fragmentTransaction.commit();
invalidateOptionsMenu();
});
}

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static android.util.Patterns.WEB_URL;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.Manifest;
import android.app.DownloadManager;
@ -74,7 +73,7 @@ import app.fedilab.android.mastodon.ui.fragment.media.FragmentMediaProfile;
import es.dmoral.toasty.Toasty;
public class MediaActivity extends BaseTransparentActivity implements OnDownloadInterface {
public class MediaActivity extends BaseBarActivity implements OnDownloadInterface {
int flags;
private ArrayList<Attachment> attachments;
@ -96,7 +95,8 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
shareIntent.setType(cR.getType(uri));
try {
startActivity(shareIntent);
} catch (Exception ignored) {
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toasty.error(context, context.getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
@ -129,7 +129,7 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
Bundle args = getIntent().getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(MediaActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(MediaActivity.this).getBundle(bundleId, Helper.getCurrentAccount(MediaActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
@ -165,7 +165,7 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
binding.mediaViewpager.setAdapter(mPagerAdapter);
binding.mediaViewpager.setSaveEnabled(false);
binding.mediaViewpager.setCurrentItem(mediaPosition - 1);
ContextCompat.registerReceiver(MediaActivity.this, onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), ContextCompat.RECEIVER_NOT_EXPORTED);
ContextCompat.registerReceiver(MediaActivity.this, onDownloadComplete, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), ContextCompat.RECEIVER_EXPORTED);
String description = attachments.get(mediaPosition - 1).description;
handler = new Handler();
if (attachments.get(mediaPosition - 1).status != null) {
@ -173,7 +173,7 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
Intent intentContext = new Intent(MediaActivity.this, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, attachments.get(mediaPosition - 1).status);
new CachedBundle(MediaActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(MediaActivity.this).insertBundle(args, Helper.getCurrentAccount(MediaActivity.this), bundleId -> {
Bundle bundleCached = new Bundle();
bundleCached.putLong(Helper.ARG_INTENT_ID, bundleId);
intentContext.putExtras(bundleCached);
@ -186,16 +186,20 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
binding.mediaDescription.setMovementMethod(LinkMovementMethod.getInstance());
binding.mediaDescriptionTranslated.setMovementMethod(LinkMovementMethod.getInstance());
if (description != null && description.trim().length() > 0 && description.trim().compareTo("null") != 0) {
if (description != null && !description.trim().isEmpty() && description.trim().compareTo("null") != 0) {
binding.mediaDescription.setText(description);
binding.translate.setOnClickListener(v -> {
String descriptionToTranslate = attachments.get(mediaPosition - 1).description;
TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, translated -> {
TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, status!=null?status.language:"en", translated -> {
if (translated != null) {
attachments.get(mediaPosition - 1).translation = translated;
binding.mediaDescriptionTranslated.setText(translated);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
binding.mediaDescription.setVisibility(View.GONE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(false);
}
binding.translate.setVisibility(View.GONE);
} else {
Toasty.error(MediaActivity.this, getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show();
}
@ -203,10 +207,16 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
});
if (attachments.get(mediaPosition - 1).translation != null) {
binding.mediaDescription.setVisibility(View.GONE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(false);
}
binding.mediaDescriptionTranslated.setText(attachments.get(mediaPosition - 1).translation);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
} else {
binding.mediaDescription.setVisibility(View.VISIBLE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(true);
}
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
}
}
@ -225,17 +235,21 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
handler.removeCallbacksAndMessages(null);
}
handler = new Handler();
if (description != null && description.trim().length() > 0 && description.trim().compareTo("null") != 0) {
if (description != null && !description.trim().isEmpty() && description.trim().compareTo("null") != 0) {
binding.mediaDescription.setText(linkify(MediaActivity.this, description), TextView.BufferType.SPANNABLE);
}
binding.translate.setOnClickListener(v -> {
String descriptionToTranslate = attachments.get(position).description;
TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, translated -> {
TranslateHelper.translate(MediaActivity.this, descriptionToTranslate, status!=null?status.language:"en", translated -> {
if (translated != null) {
attachments.get(position).translation = translated;
binding.mediaDescriptionTranslated.setText(translated);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
binding.mediaDescription.setVisibility(View.GONE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(true);
}
binding.translate.setVisibility(View.GONE);
} else {
Toasty.error(MediaActivity.this, getString(R.string.toast_error_translate), Toast.LENGTH_LONG).show();
}
@ -244,14 +258,23 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
if (!fullscreen) {
if (attachments.get(position).translation != null) {
binding.mediaDescription.setVisibility(View.GONE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(false);
}
binding.mediaDescriptionTranslated.setText(attachments.get(position).translation);
binding.mediaDescriptionTranslated.setVisibility(View.VISIBLE);
} else {
binding.mediaDescription.setVisibility(View.VISIBLE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(true);
}
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
}
} else {
binding.mediaDescription.setVisibility(View.GONE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(false);
}
binding.mediaDescriptionTranslated.setVisibility(View.GONE);
}
}
@ -444,7 +467,6 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
@Override
public void onDownloaded(String saveFilePath, String downloadUrl, Error error) {
}
@Override
@ -475,14 +497,22 @@ public class MediaActivity extends BaseTransparentActivity implements OnDownload
this.fullscreen = fullscreen;
if (!fullscreen) {
showSystemUI();
binding.descriptionContainer.setVisibility(View.VISIBLE);
binding.mediaDescription.setVisibility(View.VISIBLE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(true);
}
binding.translate.setVisibility(View.VISIBLE);
if (mediaFromProfile) {
binding.originalMessage.setVisibility(View.VISIBLE);
}
} else {
hideSystemUI();
binding.descriptionContainer.setVisibility(View.GONE);
binding.mediaDescription.setVisibility(View.GONE);
if (mCurrentFragment != null) {
mCurrentFragment.toggleController(false);
}
binding.translate.setVisibility(View.GONE);
binding.originalMessage.setVisibility(View.INVISIBLE);
}

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
@ -82,7 +80,7 @@ public class PartnerShipActivity extends BaseBarActivity {
Intent intent = new Intent(PartnerShipActivity.this, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(PartnerShipActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(PartnerShipActivity.this).insertBundle(args, Helper.getCurrentAccount(PartnerShipActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -15,7 +15,9 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.mastodon.helper.LogoHelper.getMainLogo;
import android.content.BroadcastReceiver;
import android.content.ClipData;
@ -25,9 +27,13 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
@ -41,6 +47,7 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.inputmethod.EditorInfo;
import android.webkit.URLUtil;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
@ -51,6 +58,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.TooltipCompat;
import androidx.core.app.ActivityOptionsCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
@ -64,8 +72,12 @@ import com.bumptech.glide.request.transition.Transition;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.tabs.TabLayout;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
@ -74,12 +86,15 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import androidmads.library.qrgenearator.QRGContents;
import androidmads.library.qrgenearator.QRGEncoder;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.BuildConfig;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.ActivityProfileBinding;
import app.fedilab.android.databinding.NotificationsRelatedAccountsBinding;
import app.fedilab.android.databinding.PopupQrcodeBinding;
import app.fedilab.android.databinding.TabProfileCustomViewBinding;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
@ -135,7 +150,7 @@ public class ProfileActivity extends BaseActivity {
Bundle args = intent.getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(ProfileActivity.this).getBundle(bundleId, currentAccount, bundle -> {
new CachedBundle(ProfileActivity.this).getBundle(bundleId, Helper.getCurrentAccount(ProfileActivity.this), bundle -> {
Account accountReceived = (Account) bundle.getSerializable(Helper.ARG_ACCOUNT);
if (bundle.getBoolean(Helper.RECEIVE_REDRAW_PROFILE, false) && accountReceived != null) {
if (account != null && accountReceived.id != null && account.id != null && accountReceived.id.equalsIgnoreCase(account.id)) {
@ -180,7 +195,7 @@ public class ProfileActivity extends BaseActivity {
homeMuted = false;
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(ProfileActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(ProfileActivity.this).getBundle(bundleId, Helper.getCurrentAccount(ProfileActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
@ -202,7 +217,7 @@ public class ProfileActivity extends BaseActivity {
});
} else if (mention_str != null) {
accountsVM.searchAccounts(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, mention_str, 1, true, false).observe(ProfileActivity.this, accounts -> {
if (accounts != null && accounts.size() > 0) {
if (accounts != null && !accounts.isEmpty()) {
account = accounts.get(0);
initializeView(account);
} else {
@ -215,7 +230,7 @@ public class ProfileActivity extends BaseActivity {
finish();
}
//Check if account is homeMuted
accountsVM.isMuted(currentAccount, account).observe(this, result -> homeMuted = result != null && result);
accountsVM.isMuted(Helper.getCurrentAccount(ProfileActivity.this), account).observe(this, result -> homeMuted = result != null && result);
ContextCompat.registerReceiver(ProfileActivity.this, broadcast_data, new IntentFilter(Helper.BROADCAST_DATA), ContextCompat.RECEIVER_NOT_EXPORTED);
@ -234,24 +249,21 @@ public class ProfileActivity extends BaseActivity {
TabLayout.Tab followerTab = binding.accountTabLayout.getTabAt(2);
if (statusTab != null) {
statusTab.setText(getString(R.string.status_cnt, Helper.withSuffix(account.statuses_count)));
TooltipCompat.setTooltipText(statusTab.view, String.valueOf(account.statuses_count));
}
if (followingTab != null) {
followingTab.setText(getString(R.string.following_cnt, Helper.withSuffix(account.following_count)));
TooltipCompat.setTooltipText(followingTab.view, String.valueOf(account.following_count));
}
if (followerTab != null) {
followerTab.setText(getString(R.string.followers_cnt, Helper.withSuffix(account.followers_count)));
TooltipCompat.setTooltipText(followerTab.view, String.valueOf(account.followers_count));
}
}
}
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.clear();
}
private void initializeView(Account account) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ProfileActivity.this);
if (account == null) {
@ -277,19 +289,64 @@ public class ProfileActivity extends BaseActivity {
}
});
binding.qrCodeGenerator.setVisibility(View.VISIBLE);
binding.qrCodeGenerator.setOnClickListener(v->{
QRGEncoder qrgEncoder = new QRGEncoder(account.url, null, QRGContents.Type.TEXT, 400);
Drawable logoDrawable = ContextCompat.getDrawable(ProfileActivity.this, R.drawable.fedilab_logo_bubbles);
if (logoDrawable != null) {
Bitmap bitmap = qrgEncoder.getBitmap();
MaterialAlertDialogBuilder alertadd = new MaterialAlertDialogBuilder(ProfileActivity.this);
PopupQrcodeBinding popupQrcodeBinding = PopupQrcodeBinding.inflate(getLayoutInflater());
popupQrcodeBinding.qrcodeImage.setImageBitmap(bitmap);
alertadd.setView(popupQrcodeBinding.getRoot());
alertadd.setNeutralButton(R.string.close, (dialog, which) -> dialog.dismiss());
alertadd.setPositiveButton(R.string.save, (dlg, which) -> {
File path = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
File targeted_folder = new File(path, getString(R.string.app_name));
if (!targeted_folder.exists()) {
boolean created = targeted_folder.mkdir();
if (!created) {
Toasty.error(ProfileActivity.this, getString(R.string.toast_error), Toasty.LENGTH_SHORT).show();
return;
}
}
String fileName = URLUtil.guessFileName(account.url, null, null);
if (fileName.endsWith(".bin")) {
fileName = fileName.replace(".bin", ".png");
}
fileName = fileName.replaceAll("@","");
File backupFile = new File(targeted_folder.getAbsolutePath() + "/" + fileName);
try (FileOutputStream out = new FileOutputStream(backupFile)) {
final Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
Uri uri = Uri.fromFile(backupFile);
intent.setDataAndType(uri, "image/jpeg");
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, out);
Helper.notify_user(ProfileActivity.this, Helper.getCurrentAccount(ProfileActivity.this), intent, BitmapFactory.decodeResource(getResources(),
getMainLogo(ProfileActivity.this)), Helper.NotifType.STORE, getString(R.string.save_over), getString(R.string.download_from, fileName));
Toasty.success(ProfileActivity.this, getString(R.string.save_over), Toasty.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
});
alertadd.show();
}
});
//Retrieve relationship with the connected account
List<String> accountListToCheck = new ArrayList<>();
accountListToCheck.add(account.id);
//Retrieve relation ship
accountsVM.getRelationships(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountListToCheck).observe(ProfileActivity.this, relationShips -> {
if (relationShips != null && relationShips.size() > 0) {
if (relationShips != null && !relationShips.isEmpty()) {
this.relationship = relationShips.get(0);
updateAccount();
}
});
accountsVM.getFamiliarFollowers(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountListToCheck).observe(ProfileActivity.this, familiarFollowersList -> {
if (familiarFollowersList != null && familiarFollowersList.size() > 0) {
if (familiarFollowersList != null && !familiarFollowersList.isEmpty()) {
this.familiarFollowers = familiarFollowersList.get(0);
updateAccount();
}
@ -301,7 +358,7 @@ public class ProfileActivity extends BaseActivity {
updateAccount();
});
//Animate emojis
if (account.emojis != null && account.emojis.size() > 0) {
if (account.emojis != null && !account.emojis.isEmpty()) {
boolean disableAnimatedEmoji = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false);
if (!disableAnimatedEmoji) {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
@ -458,7 +515,7 @@ public class ProfileActivity extends BaseActivity {
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
args.putSerializable(Helper.ARG_CHECK_REMOTELY, true);
new CachedBundle(ProfileActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(ProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -468,7 +525,7 @@ public class ProfileActivity extends BaseActivity {
});
//Fields for profile
List<Field> fields = account.fields;
if (fields != null && fields.size() > 0) {
if (fields != null && !fields.isEmpty()) {
FieldAdapter fieldAdapter = new FieldAdapter(fields, account);
binding.fieldsContainer.setAdapter(fieldAdapter);
binding.fieldsContainer.setLayoutManager(new LinearLayoutManager(ProfileActivity.this));
@ -511,7 +568,7 @@ public class ProfileActivity extends BaseActivity {
attachments.add(attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
args.putInt(Helper.ARG_MEDIA_POSITION, 1);
new CachedBundle(ProfileActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(ProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -535,7 +592,7 @@ public class ProfileActivity extends BaseActivity {
attachments.add(attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
args.putInt(Helper.ARG_MEDIA_POSITION, 1);
new CachedBundle(ProfileActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(ProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -636,13 +693,13 @@ public class ProfileActivity extends BaseActivity {
* This methode is called to update the view once an action has been performed
*/
private void updateAccount() {
if (currentAccount == null || account == null) {
if (Helper.getCurrentAccount(ProfileActivity.this) == null || account == null) {
return;
}
//Manage indentity proofs if not yet displayed
if (identityProofList != null && identityProofList.size() > 0) {
if (identityProofList != null && !identityProofList.isEmpty()) {
ImageView identity_proofs_indicator = findViewById(R.id.identity_proofs_indicator);
identity_proofs_indicator.setVisibility(View.VISIBLE);
//Recyclerview for identity proof has not been inflated yet
@ -663,7 +720,7 @@ public class ProfileActivity extends BaseActivity {
}
}
if (familiarFollowers != null && familiarFollowers.accounts != null && familiarFollowers.accounts.size() > 0) {
if (familiarFollowers != null && familiarFollowers.accounts != null && !familiarFollowers.accounts.isEmpty()) {
binding.relatedAccounts.removeAllViews();
for (Account account : familiarFollowers.accounts) {
NotificationsRelatedAccountsBinding notificationsRelatedAccountsBinding = NotificationsRelatedAccountsBinding.inflate(LayoutInflater.from(ProfileActivity.this));
@ -673,7 +730,7 @@ public class ProfileActivity extends BaseActivity {
Intent intent = new Intent(ProfileActivity.this, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(ProfileActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(ProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -736,7 +793,7 @@ public class ProfileActivity extends BaseActivity {
//The value for account is from same server so id can be used
if (account.id.equals(currentAccount.user_id)) {
if (account.id.equals(Helper.getCurrentAccount(ProfileActivity.this).user_id)) {
binding.accountFollow.setVisibility(View.GONE);
binding.headerEditProfile.setVisibility(View.VISIBLE);
binding.headerEditProfile.bringToFront();
@ -948,7 +1005,7 @@ public class ProfileActivity extends BaseActivity {
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(ProfileActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(ProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
@ -1016,7 +1073,7 @@ public class ProfileActivity extends BaseActivity {
String[] codesArr;
String[] languagesArr;
boolean[] presentArr;
if (storedLanguages != null && storedLanguages.size() > 0) {
if (storedLanguages != null && !storedLanguages.isEmpty()) {
int i = 0;
codesArr = new String[storedLanguages.size()];
languagesArr = new String[storedLanguages.size()];
@ -1077,7 +1134,7 @@ public class ProfileActivity extends BaseActivity {
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT_MENTION, account);
args.putString(Helper.ARG_VISIBILITY, "direct");
new CachedBundle(ProfileActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(ProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -1088,7 +1145,7 @@ public class ProfileActivity extends BaseActivity {
TimelinesVM timelinesVM = new ViewModelProvider(ProfileActivity.this).get(TimelinesVM.class);
timelinesVM.getLists(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
.observe(ProfileActivity.this, mastodonLists -> {
if (mastodonLists == null || mastodonLists.size() == 0) {
if (mastodonLists == null || mastodonLists.isEmpty()) {
Toasty.info(ProfileActivity.this, getString(R.string.action_lists_empty), Toast.LENGTH_SHORT).show();
return;
}
@ -1097,6 +1154,7 @@ public class ProfileActivity extends BaseActivity {
if (mastodonListUserIs == null) {
mastodonListUserIs = new ArrayList<>();
}
Collections.sort(mastodonLists, (obj1, obj2) -> obj1.title.compareToIgnoreCase(obj2.title));
AlertDialog.Builder builderSingle = new MaterialAlertDialogBuilder(ProfileActivity.this);
builderSingle.setTitle(getString(R.string.action_lists_add_to));
builderSingle.setPositiveButton(R.string.close, (dialog, which) -> dialog.dismiss());
@ -1168,7 +1226,7 @@ public class ProfileActivity extends BaseActivity {
intent = new Intent(ProfileActivity.this, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT_MENTION, account);
new CachedBundle(ProfileActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(ProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -1217,7 +1275,7 @@ public class ProfileActivity extends BaseActivity {
builderInner.setNeutralButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
if (homeMuted) {
builderInner.setTitle(R.string.unmute_home);
builderInner.setPositiveButton(R.string.action_unmute, (dialog, which) -> accountsVM.unmuteHome(currentAccount, account)
builderInner.setPositiveButton(R.string.action_unmute, (dialog, which) -> accountsVM.unmuteHome(Helper.getCurrentAccount(ProfileActivity.this), account)
.observe(ProfileActivity.this, account -> {
homeMuted = false;
invalidateOptionsMenu();
@ -1225,7 +1283,7 @@ public class ProfileActivity extends BaseActivity {
}));
} else {
builderInner.setTitle(R.string.mute_home);
builderInner.setPositiveButton(R.string.action_mute, (dialog, which) -> accountsVM.muteHome(currentAccount, account)
builderInner.setPositiveButton(R.string.action_mute, (dialog, which) -> accountsVM.muteHome(Helper.getCurrentAccount(ProfileActivity.this), account)
.observe(ProfileActivity.this, account -> {
homeMuted = true;
invalidateOptionsMenu();
@ -1240,24 +1298,15 @@ public class ProfileActivity extends BaseActivity {
});
return true;
} else if (itemId == R.id.action_report) {
AlertDialog.Builder builderInner = new MaterialAlertDialogBuilder(ProfileActivity.this);
builderInner.setTitle(R.string.report_account);
//Text for report
EditText input = new EditText(ProfileActivity.this);
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
input.setLayoutParams(lp);
builderInner.setView(input);
builderInner.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
builderInner.setPositiveButton(R.string.yes, (dialog, which) -> {
String comment = null;
if (input.getText() != null)
comment = input.getText().toString();
accountsVM.report(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account.id, null, null, null, comment, false);
dialog.dismiss();
Intent intent = new Intent(ProfileActivity.this, ReportActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(ProfileActivity.this).insertBundle(args, Helper.getCurrentAccount(ProfileActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
startActivity(intent);
});
builderInner.show();
return true;
} else if (itemId == R.id.action_block) {
AlertDialog.Builder builderInner = new MaterialAlertDialogBuilder(ProfileActivity.this);

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
@ -202,7 +200,7 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart
} else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.peertube_instance) {
url = "https://" + instanceName + "/api/v1/videos/";
} else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.pixelfed_instance) {
url = "https://" + instanceName + "/api/v1/timelines/public";
url = "https://" + instanceName + "/api/pixelfed/v2/discover/posts/trending?range=daily";
} else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.misskey_instance) {
url = "https://" + instanceName + "/api/notes/local-timeline";
getCall = false;
@ -214,6 +212,10 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ReorderTimelinesActivity.this);
String nitterHost = sharedpreferences.getString(getString(R.string.SET_NITTER_HOST), getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase();
url = "https://" + nitterHost + "/" + instanceName.replaceAll("[ ]+", ",").replaceAll("\\s", "") + "/with_replies/rss";
}else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.twitter_tags) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(ReorderTimelinesActivity.this);
String nitterHost = sharedpreferences.getString(getString(R.string.SET_NITTER_HOST), getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase();
url = "https://" + nitterHost + "/search?f=tweets&q=" + instanceName.replaceAll("[ ]+", "+or+").replaceAll("\\s", "") + "&e-nativeretweets=on";
}
OkHttpClient client = new OkHttpClient.Builder()
.connectTimeout(10, TimeUnit.SECONDS)
@ -259,6 +261,8 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart
instanceType = RemoteInstance.InstanceType.GNU;
} else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.twitter_accounts) {
instanceType = RemoteInstance.InstanceType.NITTER;
} else if (popupSearchInstanceBinding.setAttachmentGroup.getCheckedRadioButtonId() == R.id.twitter_tags) {
instanceType = RemoteInstance.InstanceType.NITTER_TAG;
}
RemoteInstance remoteInstance = new RemoteInstance();
remoteInstance.type = instanceType;
@ -290,7 +294,7 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(ReorderTimelinesActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ReorderTimelinesActivity.this).insertBundle(args, Helper.getCurrentAccount(ReorderTimelinesActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
@ -383,7 +387,7 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_TOPBAR, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(ReorderTimelinesActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ReorderTimelinesActivity.this).insertBundle(args, Helper.getCurrentAccount(ReorderTimelinesActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
@ -396,7 +400,7 @@ public class ReorderTimelinesActivity extends BaseBarActivity implements OnStart
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_REDRAW_BOTTOM, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(ReorderTimelinesActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ReorderTimelinesActivity.this).insertBundle(args, Helper.getCurrentAccount(ReorderTimelinesActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.os.Bundle;
import android.view.MenuItem;
@ -23,8 +22,6 @@ import android.widget.RadioButton;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.LinearLayoutCompat;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
@ -77,7 +74,7 @@ public class ReportActivity extends BaseBarActivity {
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
if (bundleId != -1) {
new CachedBundle(ReportActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(ReportActivity.this).getBundle(bundleId, Helper.getCurrentAccount(ReportActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(args);
}
@ -236,22 +233,24 @@ public class ReportActivity extends BaseBarActivity {
fragment = new FragmentMastodonTimeline();
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.ACCOUNT_TIMELINE);
args.putSerializable(Helper.ARG_ACCOUNT, account);
args.putBoolean(Helper.ARG_SHOW_PINNED, false);
args.putBoolean(Helper.ARG_SHOW_REPLIES, true);
args.putBoolean(Helper.ARG_SHOW_REBLOGS, false);
args.putBoolean(Helper.ARG_CHECK_REMOTELY, false);
args.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_REPORT_" + account.acct);
if (account != null) {
args.putSerializable(Helper.ARG_CACHED_ACCOUNT_ID, account.id);
}
//Set to display statuses with less options
args.putBoolean(Helper.ARG_MINIFIED, true);
if (status != null) {
status.isChecked = true;
args.putSerializable(Helper.ARG_STATUS_REPORT, status);
}
new CachedBundle(ReportActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ReportActivity.this).insertBundle(args, Helper.getCurrentAccount(ReportActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
fragment.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fram_spam_container, fragment);
fragmentTransaction.commit();
Helper.addFragment(getSupportFragmentManager(), R.id.fram_spam_container, fragment, bundle, null, null);
});
binding.actionButton.setText(R.string.next);
@ -266,22 +265,24 @@ public class ReportActivity extends BaseBarActivity {
fragment = new FragmentMastodonTimeline();
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.ACCOUNT_TIMELINE);
args.putSerializable(Helper.ARG_ACCOUNT, account);
args.putBoolean(Helper.ARG_SHOW_PINNED, false);
args.putBoolean(Helper.ARG_SHOW_REPLIES, true);
args.putBoolean(Helper.ARG_SHOW_REBLOGS, false);
args.putBoolean(Helper.ARG_CHECK_REMOTELY, false);
args.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_REPORT_" + account.acct);
if (account != null) {
args.putSerializable(Helper.ARG_CACHED_ACCOUNT_ID, account.id);
}
//Set to display statuses with less options
args.putBoolean(Helper.ARG_MINIFIED, true);
if (status != null) {
status.isChecked = true;
args.putSerializable(Helper.ARG_STATUS_REPORT, status);
}
new CachedBundle(ReportActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(ReportActivity.this).insertBundle(args, Helper.getCurrentAccount(ReportActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
fragment.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fram_se_container, fragment);
fragmentTransaction.commit();
Helper.addFragment(getSupportFragmentManager(), R.id.fram_se_container, fragment, bundle, null, null);
});
binding.actionButton.setText(R.string.next);
binding.actionButton.setOnClickListener(v -> {

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.SharedPreferences;
import android.os.Bundle;
@ -29,6 +28,7 @@ import com.google.android.material.tabs.TabLayout;
import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityScheduledBinding;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.ui.pageadapter.FedilabScheduledPageAdapter;
@ -55,7 +55,7 @@ public class ScheduledActivity extends BaseActivity {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
float scale = sharedpreferences.getFloat(getString(R.string.SET_FONT_SCALE), 1.1f);
binding.title.setTextSize(TypedValue.COMPLEX_UNIT_SP, 18 * 1.1f / scale);
MastodonHelper.loadPPMastodon(binding.profilePicture, currentAccount.mastodon_account);
MastodonHelper.loadPPMastodon(binding.profilePicture, Helper.getCurrentAccount(ScheduledActivity.this).mastodon_account);
binding.title.setText(R.string.scheduled);
binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab().setText(getString(R.string.toots_server)));
binding.scheduleTablayout.addTab(binding.scheduleTablayout.newTab().setText(getString(R.string.toots_client)));

View file

@ -132,7 +132,7 @@ public class SearchResultTabActivity extends BaseBarActivity {
inflater.inflate(R.menu.menu_search, menu);
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
SearchView searchView = (SearchView) menu.findItem(R.id.action_search).getActionView();
if(searchView == null) {
if (searchView == null) {
return true;
}
if (search != null) {

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.activities;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.currentToken;
@ -75,7 +74,7 @@ public class StatusInfoActivity extends BaseActivity {
Bundle args = getIntent().getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(StatusInfoActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(StatusInfoActivity.this).getBundle(bundleId, Helper.getCurrentAccount(StatusInfoActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.activities;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.os.Bundle;
import android.view.MenuItem;
@ -48,7 +47,7 @@ public class TimelineActivity extends BaseBarActivity {
Bundle args = getIntent().getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(TimelineActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(TimelineActivity.this).getBundle(bundleId, Helper.getCurrentAccount(TimelineActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
@ -76,7 +75,7 @@ public class TimelineActivity extends BaseBarActivity {
if (status != null) {
args.putSerializable(Helper.ARG_STATUS, status);
}
new CachedBundle(TimelineActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(TimelineActivity.this).insertBundle(args, Helper.getCurrentAccount(TimelineActivity.this), bundleId -> {
Bundle bundle1 = new Bundle();
bundle1.putLong(Helper.ARG_INTENT_ID, bundleId);
fragmentMastodonTimeline.setArguments(bundle1);

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.activities.admin;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
@ -101,7 +99,7 @@ public class AdminAccountActivity extends BaseActivity {
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(AdminAccountActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(AdminAccountActivity.this).getBundle(bundleId, Helper.getCurrentAccount(AdminAccountActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
@ -355,7 +353,7 @@ public class AdminAccountActivity extends BaseActivity {
attachments.add(attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
args.putInt(Helper.ARG_MEDIA_POSITION, 1);
new CachedBundle(AdminAccountActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(AdminAccountActivity.this).insertBundle(args, Helper.getCurrentAccount(AdminAccountActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -14,7 +14,7 @@ package app.fedilab.android.mastodon.activities.admin;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.ACCOUNT;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.DOMAIN;
import static app.fedilab.android.mastodon.activities.admin.AdminActionActivity.AdminEnum.REPORT;
@ -68,7 +68,7 @@ public class AdminActionActivity extends BaseBarActivity {
Bundle args = intent.getExtras();
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(AdminActionActivity.this).getBundle(bundleId, currentAccount, bundle -> {
new CachedBundle(AdminActionActivity.this).getBundle(bundleId, Helper.getCurrentAccount(AdminActionActivity.this), bundle -> {
AdminDomainBlock adminDomainBlock = (AdminDomainBlock) bundle.getSerializable(Helper.ARG_ADMIN_DOMAINBLOCK);
AdminDomainBlock adminDomainBlockDelete = (AdminDomainBlock) bundle.getSerializable(Helper.ARG_ADMIN_DOMAINBLOCK_DELETE);
if (adminDomainBlock != null && adminDomainBlock.domain != null && fragmentAdminDomain != null) {
@ -132,43 +132,46 @@ public class AdminActionActivity extends BaseBarActivity {
private void displayTimeline(AdminEnum type) {
canGoBack = true;
if (type == REPORT) {
fragmentAdminReport = new FragmentAdminReport();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminReport.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminReport);
fragmentTransaction.commit();
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentAdminReport = new FragmentAdminReport();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminReport.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminReport);
fragmentTransaction.commit();
});
} else if (type == ACCOUNT) {
fragmentAdminAccount = new FragmentAdminAccount();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminAccount.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminAccount);
fragmentTransaction.commit();
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentAdminAccount = new FragmentAdminAccount();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminAccount.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminAccount);
fragmentTransaction.commit();
});
} else if (type == DOMAIN) {
fragmentAdminDomain = new FragmentAdminDomain();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminDomain.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminDomain);
fragmentTransaction.commit();
ThemeHelper.slideViewsToLeft(binding.buttonContainer, binding.fragmentContainer, () -> {
fragmentAdminDomain = new FragmentAdminDomain();
Bundle bundle = new Bundle();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, type);
bundle.putString(Helper.ARG_VIEW_MODEL_KEY, "FEDILAB_" + type.getValue());
fragmentAdminDomain.setArguments(bundle);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, fragmentAdminDomain);
fragmentTransaction.commit();
});
}
switch (type) {

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.activities.admin;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
@ -115,7 +113,7 @@ public class AdminDomainBlockActivity extends BaseBarActivity {
Intent intent = new Intent(Helper.BROADCAST_DATA);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ADMIN_DOMAINBLOCK, adminDomainBlockResult);
new CachedBundle(AdminDomainBlockActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(AdminDomainBlockActivity.this).insertBundle(args, Helper.getCurrentAccount(AdminDomainBlockActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -151,7 +149,7 @@ public class AdminDomainBlockActivity extends BaseBarActivity {
Intent intent = new Intent(Helper.BROADCAST_DATA);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ADMIN_DOMAINBLOCK_DELETE, adminDomainBlock);
new CachedBundle(AdminDomainBlockActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(AdminDomainBlockActivity.this).insertBundle(args, Helper.getCurrentAccount(AdminDomainBlockActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.activities.admin;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Intent;
@ -106,7 +104,7 @@ public class AdminReportActivity extends BaseBarActivity {
if (args != null) {
long bundleId = args.getLong(Helper.ARG_INTENT_ID, -1);
new CachedBundle(AdminReportActivity.this).getBundle(bundleId, currentAccount, this::initializeAfterBundle);
new CachedBundle(AdminReportActivity.this).getBundle(bundleId, Helper.getCurrentAccount(AdminReportActivity.this), this::initializeAfterBundle);
} else {
initializeAfterBundle(null);
}
@ -159,10 +157,10 @@ public class AdminReportActivity extends BaseBarActivity {
lastActive.append(Helper.shortDateToString(ip.used_at)).append(" - ").append(ip.ip).append("\r\n");
}
}
if (lastActive.toString().trim().length() == 0) {
if (lastActive.toString().trim().isEmpty()) {
binding.lastActiveContainer.setVisibility(View.GONE);
}
if (adminAccount.email == null || adminAccount.email.trim().length() == 0) {
if (adminAccount.email == null || adminAccount.email.trim().isEmpty()) {
binding.emailContainer.setVisibility(View.GONE);
}
binding.lastActive.setText(lastActive.toString());
@ -262,7 +260,7 @@ public class AdminReportActivity extends BaseBarActivity {
//Animate emojis
if (account.emojis != null && account.emojis.size() > 0) {
if (account.emojis != null && !account.emojis.isEmpty()) {
boolean disableAnimatedEmoji = sharedpreferences.getBoolean(getString(R.string.SET_DISABLE_ANIMATED_EMOJI), false);
if (!disableAnimatedEmoji) {
scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
@ -368,7 +366,7 @@ public class AdminReportActivity extends BaseBarActivity {
attachments.add(attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
args.putInt(Helper.ARG_MEDIA_POSITION, 1);
new CachedBundle(AdminReportActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(AdminReportActivity.this).insertBundle(args, Helper.getCurrentAccount(AdminReportActivity.this), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -21,6 +21,7 @@ import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Activity;
import app.fedilab.android.mastodon.client.entities.api.Emoji;
import app.fedilab.android.mastodon.client.entities.api.Instance;
import app.fedilab.android.mastodon.client.entities.api.InstanceV2;
import app.fedilab.android.mastodon.client.entities.api.Tag;
import retrofit2.Call;
import retrofit2.http.GET;
@ -32,6 +33,9 @@ public interface MastodonInstanceService {
@GET("instance")
Call<Instance> instance();
@GET("instance")
Call<InstanceV2> instanceV2();
@GET("instance/peers")
Call<List<String>> connectedInstance();

View file

@ -67,6 +67,7 @@ public interface MastodonNotificationsService {
@Field("subscription[endpoint]") String endpoint,
@Field("subscription[keys][p256dh]") String keys_p256dh,
@Field("subscription[keys][auth]") String keys_auth,
@Field("subscription[standard]") boolean standard,
@Field("data[alerts][follow]") boolean follow,
@Field("data[alerts][favourite]") boolean favourite,
@Field("data[alerts][reblog]") boolean reblog,

View file

@ -15,6 +15,7 @@ package app.fedilab.android.mastodon.client.endpoints;
* see <http://www.gnu.org/licenses>. */
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import app.fedilab.android.mastodon.client.entities.api.Account;
@ -25,14 +26,17 @@ import app.fedilab.android.mastodon.client.entities.api.Poll;
import app.fedilab.android.mastodon.client.entities.api.ScheduledStatus;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.api.StatusSource;
import app.fedilab.android.mastodon.client.entities.api.params.StatusParams;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.DELETE;
import retrofit2.http.Field;
import retrofit2.http.FormUrlEncoded;
import retrofit2.http.GET;
import retrofit2.http.Header;
import retrofit2.http.Headers;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.PUT;
@ -61,7 +65,8 @@ public interface MastodonStatusesService {
@Field("visibility") String visibility,
@Field("language") String language,
@Field("quote_id") String quote_id,
@Field("content_type") String content_type
@Field("content_type") String content_type,
@Field("local_only") Boolean local_only
);
@GET("statuses/{id}/source")
@ -74,6 +79,16 @@ public interface MastodonStatusesService {
@Header("Authorization") String token,
@Path("id") String id);
@Headers({"Accept: application/json"})
@PUT("statuses/{id}")
Call<Status> updateStatus(
@Header("Idempotency-Key") String idempotency_Key,
@Header("Authorization") String token,
@Path("id") String id,
@Body StatusParams statusParams
);
//Post a status
@FormUrlEncoded
@PUT("statuses/{id}")
@ -92,9 +107,9 @@ public interface MastodonStatusesService {
@Field("spoiler_text") String spoiler_text,
@Field("visibility") String visibility,
@Field("language") String language,
@Field("media_attributes[][id]") List<String> media_id,
@Field("media_attributes[][description]") List<String> media_description,
@Field("media_attributes[][focus]") List<String> focus
@Field("media_attributes[]") LinkedHashMap<String, String> media_id,
@Field("media_attributes[]") LinkedHashMap<String, String> media_description,
@Field("media_attributes[]") LinkedHashMap<String, String> focus
);
//Post a scheduled status

View file

@ -231,6 +231,11 @@ public interface MastodonTimelinesService {
Call<List<MisskeyNote>> getMisskey(@Body MisskeyNote.MisskeyParams params);
@GET("discover/posts/trending")
Call<List<Status>> getPixelDiscoverTrending(
@Query("range") String range
);
@GET("api/v3/post/list?sort=New")
Call<LemmyPost.LemmyPosts> getLemmyMain(@Query("limit") Integer limit,
@Query("page") String page);

View file

@ -0,0 +1,32 @@
package app.fedilab.android.mastodon.client.endpoints;
/* Copyright 2025 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import java.util.List;
import app.fedilab.android.mastodon.client.entities.api.Status;
import retrofit2.Call;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface PixelfedTimelinesService {
//Public timelines
@GET("discover/posts/trending")
Call<List<Status>> getTrending(
@Query("range") String range
);
}

View file

@ -88,6 +88,7 @@ public class Account implements Serializable {
@SerializedName("role")
public Role role;
public transient RelationShip relationShip;
public transient String pronouns = null;
public synchronized Spannable getSpanDisplayName(Context context, WeakReference<View> viewWeakReference) {

View file

@ -262,7 +262,7 @@ public class EmojiInstance implements Serializable {
} else {
emojiArrayList = emojis.get(instance);
}
if (emojiArrayList != null && emojiArrayList.size() > 0) {
if (emojiArrayList != null ) {
for (Emoji emoji : emojiArrayList) {
if (emoji.shortcode.contains(filter)) {
emojiFiltered.add(emoji);

View file

@ -2,6 +2,8 @@ package app.fedilab.android.mastodon.client.entities.api;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
/* Copyright 2021 Thomas Schneider
*
* This file is a part of Fedilab
@ -16,7 +18,7 @@ import com.google.gson.annotations.SerializedName;
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
public class History {
public class History implements Serializable {
@SerializedName("day")
public String day;
@SerializedName("uses")

View file

@ -0,0 +1,70 @@
package app.fedilab.android.mastodon.client.entities.api;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/* Copyright 2025 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
public class InstanceV2 implements Serializable {
@SerializedName("domain")
public String domain;
@SerializedName("title")
public String title;
@SerializedName("version")
public String version;
@SerializedName("source_url")
public String sourceUrl;
@SerializedName("description")
public String description;
@SerializedName("configuration")
public Configuration configuration;
public static String serialize(InstanceV2 instance) {
Gson gson = new Gson();
try {
return gson.toJson(instance);
} catch (Exception e) {
return null;
}
}
public static InstanceV2 restore(String serialized) {
Gson gson = new Gson();
try {
return gson.fromJson(serialized, InstanceV2.class);
} catch (Exception e) {
return null;
}
}
public static class Configuration implements Serializable {
@SerializedName("vapid")
public VapId vapId;
}
public static class VapId implements Serializable {
@SerializedName("public_key")
public String publicKey;
}
}

View file

@ -22,6 +22,8 @@ public class PushSubscription {
public String id;
@SerializedName("endpoint")
public String endpoint;
@SerializedName("standard")
public String standard;
@SerializedName("policy")
public String policy;
@SerializedName("alerts")

View file

@ -28,7 +28,6 @@ import java.lang.ref.WeakReference;
import java.util.Date;
import java.util.List;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.SpannableHelper;
import de.timfreiheit.mathjax.android.MathJaxView;
@ -113,6 +112,7 @@ public class Status implements Serializable, Cloneable {
@SerializedName("reactions")
public List<Reaction> reactions;
public String attachedNotification = null;
public transient boolean isFetchMore = false;
public transient boolean isFetching = false;
@ -144,6 +144,8 @@ public class Status implements Serializable, Cloneable {
public transient MathJaxView mathJaxView;
public String lemmy_post_id;
public transient String pronouns = null;
@Override
public boolean equals(@Nullable Object obj) {
boolean same = false;

View file

@ -0,0 +1,65 @@
package app.fedilab.android.mastodon.client.entities.api.params;
/* Copyright 2025 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import com.google.gson.annotations.SerializedName;
import java.io.Serializable;
import java.util.List;
public class StatusParams implements Serializable {
@SerializedName("id")
public String id;
@SerializedName("status")
public String status;
@SerializedName("media_ids")
public List<String> media_ids;
@SerializedName("poll")
public PollParams pollParams;
@SerializedName("in_reply_to_id")
public String in_reply_to_id;
@SerializedName("sensitive")
public Boolean sensitive;
@SerializedName("spoiler_text")
public String spoiler_text;
@SerializedName("visibility")
public String visibility;
@SerializedName("language")
public String language;
@SerializedName("media_attributes")
public List<MediaParams> media_attributes;
public static class PollParams implements Serializable{
@SerializedName("options")
public List<String> poll_options;
@SerializedName("expires_in")
public Integer poll_expire_in;
@SerializedName("multiple")
public Boolean poll_multiple;
@SerializedName("hide_totals")
public Boolean poll_hide_totals;
}
public static class MediaParams implements Serializable {
@SerializedName("id")
public String id;
@SerializedName("description")
public String description;
@SerializedName("focus")
public String focus;
}
}

View file

@ -14,8 +14,12 @@ package app.fedilab.android.mastodon.client.entities.app;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.mastodon.helper.Helper.PREF_USER_ID;
import static app.fedilab.android.mastodon.helper.Helper.PREF_USER_INSTANCE;
import android.content.ContentValues;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
@ -24,6 +28,8 @@ import android.os.Looper;
import android.os.Parcel;
import android.util.Base64;
import androidx.preference.PreferenceManager;
import com.google.gson.annotations.SerializedName;
import java.io.BufferedOutputStream;
@ -108,7 +114,8 @@ public class CachedBundle {
Account account = null;
try {
account = (Account) bundle.getSerializable(Helper.ARG_ACCOUNT);
}catch (ClassCastException ignored){}
} catch (ClassCastException ignored) {
}
if (account != null) {
bundleAccount.putSerializable(Helper.ARG_ACCOUNT, account);
valuesAccount.put(Sqlite.COL_BUNDLE, serializeBundle(bundleAccount));
@ -127,7 +134,8 @@ public class CachedBundle {
Status status = null;
try {
status = (Status) bundle.getSerializable(Helper.ARG_STATUS);
}catch (ClassCastException ignored){}
} catch (ClassCastException ignored) {
}
if (status != null) {
bundleStatus.putSerializable(Helper.ARG_STATUS, status);
valuesAccount.put(Sqlite.COL_BUNDLE, serializeBundle(bundleStatus));
@ -170,7 +178,7 @@ public class CachedBundle {
}
} catch (DBException ignored) {
}
if( bundle == null) {
if (bundle == null) {
bundle = new Bundle();
}
Handler mainHandler = new Handler(Looper.getMainLooper());
@ -204,9 +212,15 @@ public class CachedBundle {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
if (account == null || target_id == null) {
if (target_id == null) {
return null;
}
if (account == null) {
account = new BaseAccount();
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
account.user_id = sharedpreferences.getString(PREF_USER_ID, null);
account.instance = sharedpreferences.getString(PREF_USER_INSTANCE, null);
}
try {
Cursor c = db.query(Sqlite.TABLE_INTENT, null, Sqlite.COL_USER_ID + " = '" + account.user_id + "' AND "
+ Sqlite.COL_INSTANCE + " = '" + account.instance + "' AND "
@ -233,9 +247,15 @@ public class CachedBundle {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
if (account == null || target_id == null) {
if (target_id == null) {
return null;
}
if (account == null) {
account = new BaseAccount();
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
account.user_id = sharedpreferences.getString(PREF_USER_ID, null);
account.instance = sharedpreferences.getString(PREF_USER_INSTANCE, null);
}
try {
Cursor c = db.query(Sqlite.TABLE_INTENT, null, Sqlite.COL_USER_ID + " = '" + account.user_id + "' AND "
+ Sqlite.COL_INSTANCE + " = '" + account.instance + "' AND "
@ -283,7 +303,7 @@ public class CachedBundle {
String dateStr = Helper.dateToString(date);
try {
db.delete(Sqlite.TABLE_INTENT, Sqlite.COL_CREATED_AT + " < ?", new String[]{dateStr});
}catch (Exception e) {
} catch (Exception e) {
e.printStackTrace();
}
}

View file

@ -23,7 +23,7 @@ public class MarkdownConverter {
public List<MarkdownItem> markdownItems;
public MarkdownItem getByPosition(int position) {
if (markdownItems != null && markdownItems.size() > 0 && position < markdownItems.size()) {
if (markdownItems != null && !markdownItems.isEmpty() && position < markdownItems.size()) {
for (MarkdownItem markdownItem : markdownItems) {
if (markdownItem.position == position) {
return markdownItem;

View file

@ -46,6 +46,8 @@ public class RemoteInstance implements Serializable {
PEERTUBE("PEERTUBE"),
@SerializedName("NITTER")
NITTER("NITTER"),
@SerializedName("NITTER_TAG")
NITTER_TAG("NITTER_TAG"),
@SerializedName("MISSKEY")
MISSKEY("MISSKEY"),
@SerializedName("LEMMY")

View file

@ -14,6 +14,8 @@ package app.fedilab.android.mastodon.client.entities.app;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.mastodon.helper.Helper.TAG;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
@ -289,7 +291,6 @@ public class StatusCache {
if (statusCache.type != null) {
query += " AND " + Sqlite.COL_TYPE + " = '" + statusCache.type.getValue() + "'";
}
Cursor mCount = db.rawQuery(query, null);
mCount.moveToFirst();
int count = mCount.getInt(0);
@ -352,7 +353,11 @@ public class StatusCache {
values.put(Sqlite.COL_STATUS, mastodonStatusToStringStorage(statusCache.status));
}
if (statusCache.notification != null) {
values.put(Sqlite.COL_STATUS, mastodonNotificationToStringStorage(statusCache.notification));
Notification currentNotification = getCachedNotification(statusCache);
if(currentNotification != null && currentNotification.status != null) {
currentNotification.status = statusCache.notification.status;
values.put(Sqlite.COL_STATUS, mastodonNotificationToStringStorage(currentNotification));
}
}
if (statusCache.conversation != null) {
values.put(Sqlite.COL_STATUS, mastodonConversationToStringStorage(statusCache.conversation));
@ -594,6 +599,15 @@ public class StatusCache {
}
}
public Notification getCachedNotification(StatusCache statusCache) throws DBException {
if (db == null) {
throw new DBException("db is null. Wrong initialization.");
}
Cursor c = db.query(Sqlite.TABLE_STATUS_CACHE, null, Sqlite.COL_STATUS_ID + " = ? AND " + Sqlite.COL_USER_ID + " = ? AND " + Sqlite.COL_INSTANCE + " =?",
new String[]{statusCache.status_id, statusCache.user_id, statusCache.instance}, null, null, null, "1");
c.moveToFirst();
return convertCursorToNotification(c);
}
/**
* Get paginated conversations from db

View file

@ -14,10 +14,12 @@ package app.fedilab.android.mastodon.client.entities.nitter;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import androidx.annotation.NonNull;
import org.jsoup.select.Elements;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Namespace;
@ -29,6 +31,7 @@ import java.net.IDN;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -82,7 +85,8 @@ public class Nitter implements Serializable {
status.text = feedItem.title;
status.content = status.content.replaceAll("<img [^>]*src=\"[^\"]+\"[^>]*>", "");
status.visibility = "public";
status.created_at = Helper.stringToDateWithFormat(context, feedItem.pubDate, "EEE, dd MMM yyyy HH:mm:ss zzz");
String dateFormat = "E', 'dd' 'MMM' 'yyyy' 'hh:m:s' GMT'";
status.created_at = Helper.stringToDateWithFormat(context, feedItem.pubDate, dateFormat);
status.uri = feedItem.guid;
status.url = feedItem.link;
if (!accounts.containsKey(feedItem.creator)) {
@ -177,4 +181,83 @@ public class Nitter implements Serializable {
}
public static Status nitterHTMLParser(Context context, org.jsoup.nodes.Element timelineItem, String nitterInstance) {
if(timelineItem == null) {
return null;
}
Status status = new Status();
Account account = new Account();
String fedilabInstance = "nitter.fedilab.app";
org.jsoup.nodes.Element messageLink;
if(timelineItem.select(".quote-text").html().isEmpty()) {
status.content = timelineItem.select(".tweet-content").html();
status.text = timelineItem.select(".tweet-content").text();
status.url = "https://"+ nitterInstance +timelineItem.select(".tweet-link").attr("href");
messageLink = timelineItem.select(".tweet-link").first();
} else {
status.content = timelineItem.select(".quote-text").html();
status.text = timelineItem.select(".quote-text").text();
status.url = "https://"+ nitterInstance +timelineItem.select(".quote-link").attr("href");
messageLink = timelineItem.select(".quote-link").first();
}
status.uri = status.url;
String status_id = String.valueOf(ThreadLocalRandom.current().nextLong(10,10000000));;
if(messageLink != null){
String[] splitLink = messageLink.attr("href").split("/");
status_id = splitLink[splitLink.length-1];
}
String pubDate = timelineItem.select(".tweet-date").select("a").attr("title");
org.jsoup.nodes.Element nameElement = timelineItem.select(".fullname").first();
String name = nameElement!= null?nameElement.text():"";
org.jsoup.nodes.Element userNameElement = timelineItem.select(".username").first();
String userName = userNameElement!= null?userNameElement.text().replace("@",""):"";
String avatar = "https://" + fedilabInstance + timelineItem.select(".avatar").attr("src");
account.id = userName;
account.acct = userName;
if(timelineItem.select(".replying-to").html().isEmpty()) {
account.username = userName;
account.display_name = name;
} else {
account.display_name = timelineItem.select(".fullname").text() +"&nbsp;" +timelineItem.select(".replying-to").text();
}
account.avatar = avatar;
account.avatar_static = avatar;
account.url = "https://"+ nitterInstance +"/" + userName;
status.id = status_id;
status.account = account;
Elements imageElements = timelineItem.select(".attachments").select("img");
Elements videoElements = timelineItem.select(".attachments").select("video");
ArrayList<Attachment> attachmentList = new ArrayList<>();
for(org.jsoup.nodes.Element imageElement: imageElements) {
Attachment attachment = new Attachment();
attachment.type = "image";
attachment.url = "https://"+fedilabInstance+imageElement.attr("src");
attachment.preview_url = "https://"+fedilabInstance+imageElement.attr("src");
attachment.id = imageElement.attr("src");
attachmentList.add(attachment);
}
for(org.jsoup.nodes.Element videoElement: videoElements) {
Attachment attachment = new Attachment();
attachment.type = "video";
attachment.url = "https://"+fedilabInstance+videoElement.child(0).attr("src");
attachment.preview_url = "https://"+fedilabInstance+videoElement.attr("poster");
attachment.id = videoElement.attr("poster");
attachmentList.add(attachment);
}
status.visibility = "public";
status.media_attachments = attachmentList;
String dateFormat = "MMM d', 'yyyy' · 'h:m a' UTC'";
status.created_at = Helper.stringToDateWithFormat(context, pubDate, dateFormat);
return status;
}
}

View file

@ -69,20 +69,20 @@ class BlurHashDecoder {
val g = (value / 19) % 19
val b = value % 19
return floatArrayOf(
signedPow2((r - 9) / 9.0f) * maxAc,
signedPow2((g - 9) / 9.0f) * maxAc,
signedPow2((b - 9) / 9.0f) * maxAc
signedPow2((r - 9) / 9.0f) * maxAc,
signedPow2((g - 9) / 9.0f) * maxAc,
signedPow2((b - 9) / 9.0f) * maxAc
)
}
private fun signedPow2(value: Float) = value.pow(2f).withSign(value)
private fun composeBitmap(
width: Int,
height: Int,
numCompX: Int,
numCompY: Int,
colors: Array<FloatArray>
width: Int,
height: Int,
numCompX: Int,
numCompY: Int,
colors: Array<FloatArray>
): Bitmap {
val imageArray = IntArray(width * height)
for (y in 0 until height) {
@ -100,7 +100,7 @@ class BlurHashDecoder {
}
}
imageArray[x + width * y] =
Color.rgb(linearToSrgb(r), linearToSrgb(g), linearToSrgb(b))
Color.rgb(linearToSrgb(r), linearToSrgb(g), linearToSrgb(b))
}
}
return Bitmap.createBitmap(imageArray, width, height, Bitmap.Config.ARGB_8888)
@ -116,12 +116,12 @@ class BlurHashDecoder {
}
private val charMap = listOf(
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '#', '$', '%', '*', '+', ',',
'-', '.', ':', ';', '=', '?', '@', '[', ']', '^', '_', '{', '|', '}', '~'
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '#', '$', '%', '*', '+', ',',
'-', '.', ':', ';', '=', '?', '@', '[', ']', '^', '_', '{', '|', '}', '~'
)
.mapIndexed { i, c -> c to i }
.toMap()
.mapIndexed { i, c -> c to i }
.toMap()
}

View file

@ -18,24 +18,23 @@ import android.content.Context;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.media3.database.ExoDatabaseProvider;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSourceFactory;
import androidx.media3.datasource.DefaultHttpDataSource;
import androidx.media3.datasource.FileDataSource;
import androidx.media3.datasource.cache.CacheDataSink;
import androidx.media3.datasource.cache.CacheDataSource;
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor;
import androidx.media3.datasource.cache.SimpleCache;
import androidx.media3.exoplayer.upstream.DefaultBandwidthMeter;
import androidx.preference.PreferenceManager;
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
import com.google.android.exoplayer2.upstream.FileDataSource;
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
import java.io.File;
import app.fedilab.android.R;
@androidx.annotation.OptIn(markerClass = androidx.media3.common.util.UnstableApi.class)
public class CacheDataSourceFactory implements DataSource.Factory {
private static SimpleCache sDownloadCache;

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.helper;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
@ -149,7 +148,7 @@ public class CrossActionHelper {
}
searchVM.search(ownerAccount.instance, ownerAccount.token, search, null, "accounts", false, true, false, 0, null, null, 1)
.observe((LifecycleOwner) context, results -> {
if (results.accounts != null && results.accounts.size() > 0) {
if (results != null && results.accounts != null && !results.accounts.isEmpty()) {
app.fedilab.android.mastodon.client.entities.api.Account account = results.accounts.get(0);
applyAction(context, actionType, ownerAccount, account, null);
} else {
@ -159,7 +158,7 @@ public class CrossActionHelper {
} else if (targetedStatus != null) {
searchVM.search(ownerAccount.instance, ownerAccount.token, targetedStatus.uri, null, "statuses", false, true, false, 0, null, null, 1)
.observe((LifecycleOwner) context, results -> {
if (results != null && results.statuses != null && results.statuses.size() > 0) {
if (results != null && results.statuses != null && !results.statuses.isEmpty()) {
Status status = results.statuses.get(0);
applyAction(context, actionType, ownerAccount, null, status);
} else {
@ -251,7 +250,7 @@ public class CrossActionHelper {
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS_REPLY, targetedStatus);
args.putSerializable(Helper.ARG_ACCOUNT, ownerAccount);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -262,7 +261,7 @@ public class CrossActionHelper {
Intent intentCompose = new Intent(context, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, ownerAccount);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentCompose.putExtras(bundle);
@ -445,7 +444,7 @@ public class CrossActionHelper {
final BaseAccount account = accountArray[which];
Intent intentToot = new Intent(context, ComposeActivity.class);
bundle.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(context).insertBundle(bundle, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(bundle, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundleCached = new Bundle();
bundleCached.putLong(Helper.ARG_INTENT_ID, bundleId);
intentToot.putExtras(bundleCached);

View file

@ -106,7 +106,9 @@ public class CustomEmoji extends ReplacementSpan {
if (drawableCallBack != null) {
drawableCallBack.invalidateDrawable(drawable);
}
view.invalidate();
if(view != null) {
view.invalidate();
}
}
@Override

View file

@ -69,7 +69,6 @@ public class DividerDecoration extends RecyclerView.ItemDecoration {
StatusAdapter statusAdapter = ((StatusAdapter) parent.getAdapter());
if (statusAdapter != null && statusAdapter.getItemCount() > position && position > 0) {
Status status = statusAdapter.getItem(position);
int start = (int) Helper.convertDpToPixel(
6 * fontScale * CommentDecorationHelper.getIndentation(status.in_reply_to_id, statusList, indentationMax),
_mContext);
@ -95,7 +94,6 @@ public class DividerDecoration extends RecyclerView.ItemDecoration {
int indentation = Math.min(
CommentDecorationHelper.getIndentation(status.in_reply_to_id, statusList, indentationMax),
indentationMax);
if (indentation > 0) {
Paint paint = new Paint();
paint.setDither(false);
@ -109,12 +107,7 @@ public class DividerDecoration extends RecyclerView.ItemDecoration {
startPx = c.getWidth() - startPx;
float bottomPx = view.getBottom();
int color;
if (j >= colorList.size()) {
color = colorList.get(j - colorList.size());
} else {
color = colorList.get(j);
}
int color = colorList.get(j%(colorList.size()-1));
paint.setColor(ResourcesCompat.getColor(_mContext.getResources(), color, _mContext.getTheme()));
if (j == indentationMax - 1) {
paint.setPathEffect(new DashPathEffect(

View file

@ -1,289 +0,0 @@
package app.fedilab.android.mastodon.helper;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
import androidx.preference.PreferenceManager;
import org.spongycastle.asn1.ASN1ObjectIdentifier;
import org.spongycastle.asn1.x9.ECNamedCurveTable;
import org.spongycastle.asn1.x9.X9ECParameters;
import org.spongycastle.crypto.params.ECNamedDomainParameters;
import org.spongycastle.crypto.params.ECPrivateKeyParameters;
import org.spongycastle.crypto.params.ECPublicKeyParameters;
import org.spongycastle.jce.spec.ECNamedCurveSpec;
import org.spongycastle.jce.spec.ECParameterSpec;
import org.spongycastle.jce.spec.ECPrivateKeySpec;
import org.spongycastle.jce.spec.ECPublicKeySpec;
import org.spongycastle.math.ec.ECCurve;
import org.spongycastle.math.ec.ECPoint;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.KeyAgreement;
public class ECDH {
public static final String kp_public = "kp_public";
public static final String peer_public = "peer_public";
public static final String PROVIDER = org.spongycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;
public static final String kp_private = "kp_private";
public static final String KEGEN_ALG = "ECDH";
public static final String name = "prime256v1";
private static final String kp_public_affine_x = "kp_public_affine_x";
private static final String kp_public_affine_y = "kp_public_affine_y";
private static ECDH instance;
static {
Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
}
public final KeyFactory kf;
private final KeyPairGenerator kpg;
private final String slug;
public ECDH(String slug) throws Exception {
if (slug == null) {
throw new Exception("slug cannot be null");
}
try {
kf = KeyFactory.getInstance(KEGEN_ALG, PROVIDER);
kpg = KeyPairGenerator.getInstance(KEGEN_ALG, PROVIDER);
this.slug = slug;
} catch (NoSuchAlgorithmException | NoSuchProviderException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static synchronized ECDH getInstance(String slug) throws Exception {
if (instance == null) {
instance = new ECDH(slug);
}
return instance;
}
public static String base64Encode(byte[] b) {
return Base64.encodeToString(
b, Base64.URL_SAFE | Base64.NO_PADDING | Base64.NO_WRAP);
}
static byte[] base64Decode(String str) {
return Base64.decode(str, Base64.URL_SAFE);
}
synchronized KeyPair generateKeyPair()
throws Exception {
ECGenParameterSpec ecParamSpec = new ECGenParameterSpec(name);
kpg.initialize(ecParamSpec);
return kpg.generateKeyPair();
}
private byte[] generateSecret(PrivateKey myPrivKey, PublicKey otherPubKey) throws Exception {
KeyAgreement keyAgreement = KeyAgreement.getInstance(KEGEN_ALG);
keyAgreement.init(myPrivKey);
keyAgreement.doPhase(otherPubKey, true);
return keyAgreement.generateSecret();
}
synchronized KeyPair readKeyPair(Context context)
throws Exception {
return new KeyPair(readMyPublicKey(context), readMyPrivateKey(context));
}
@SuppressLint("ApplySharedPref")
public KeyPair newPair(Context context) {
SharedPreferences.Editor prefsEditor = PreferenceManager
.getDefaultSharedPreferences(context).edit();
KeyPair kp;
try {
kp = generateKeyPair();
} catch (Exception e) {
e.printStackTrace();
return null;
}
ECPublicKey key = (ECPublicKey) kp.getPublic();
byte[] x = key.getW().getAffineX().toByteArray();
byte[] y = key.getW().getAffineY().toByteArray();
BigInteger xbi = new BigInteger(1, x);
BigInteger ybi = new BigInteger(1, y);
X9ECParameters x9 = ECNamedCurveTable.getByName(name);
ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name);
ECCurve curve = x9.getCurve();
ECPoint point = curve.createPoint(xbi, ybi);
ECNamedDomainParameters dParams = new ECNamedDomainParameters(oid,
x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
ECPublicKeyParameters pubKey = new ECPublicKeyParameters(point, dParams);
ECPrivateKeyParameters privateKey = new ECPrivateKeyParameters(new BigInteger(kp.getPrivate().getEncoded()), pubKey.getParameters());
byte[] privateKeyBytes = privateKey.getD().toByteArray();
String keyString = base64Encode(pubKey.getQ().getEncoded(false));
String keypString = base64Encode(privateKeyBytes);
prefsEditor.putString(kp_public + slug, keyString);
prefsEditor.putString(kp_public_affine_x + slug, key.getW().getAffineX().toString());
prefsEditor.putString(kp_public_affine_y + slug, key.getW().getAffineY().toString());
prefsEditor.putString(kp_private + slug, keypString);
prefsEditor.commit();
return kp;
}
synchronized PublicKey readMyPublicKey(Context context) throws Exception {
X9ECParameters x9 = ECNamedCurveTable.getByName(name);
ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name);
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
BigInteger xbi = new BigInteger(prefs.getString(kp_public_affine_x + slug, "0"));
BigInteger ybi = new BigInteger(prefs.getString(kp_public_affine_y + slug, "0"));
ECNamedDomainParameters dParams = new ECNamedDomainParameters(oid,
x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
ECNamedCurveSpec ecNamedCurveSpec = new ECNamedCurveSpec(name, dParams.getCurve(), dParams.getG(), dParams.getN());
java.security.spec.ECPoint w = new java.security.spec.ECPoint(xbi, ybi);
return kf.generatePublic(new java.security.spec.ECPublicKeySpec(w, ecNamedCurveSpec));
}
public String uncryptMessage(Context context, String cyphered) {
byte[] privateKey = getSharedSecret(context);
try {
Cipher outCipher = Cipher.getInstance("ECIES", PROVIDER);
PrivateKey ddd = readPrivateKey(privateKey);
outCipher.init(Cipher.DECRYPT_MODE, readPrivateKey(privateKey));
byte[] plaintext = outCipher.doFinal(base64Decode(cyphered));
return new String(plaintext);
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public PublicKey readPublicKey(String keyStr) throws Exception {
ECParameterSpec parameterSpec = org.spongycastle.jce.ECNamedCurveTable.getParameterSpec(name);
ECCurve curve = parameterSpec.getCurve();
ECPoint point = curve.decodePoint(base64Decode(keyStr));
ECPublicKeySpec pubSpec = new ECPublicKeySpec(point, parameterSpec);
return kf.generatePublic(pubSpec);
}
public PrivateKey readPrivateKey(byte[] key) throws Exception {
ECParameterSpec parameterSpec = org.spongycastle.jce.ECNamedCurveTable.getParameterSpec(name);
ECPrivateKeySpec pubSpec = new ECPrivateKeySpec(new BigInteger(1, key), parameterSpec);
return kf.generatePrivate(pubSpec);
}
synchronized PrivateKey readMyPrivateKey(Context context) throws Exception {
X9ECParameters x9 = ECNamedCurveTable.getByName(name);
ASN1ObjectIdentifier oid = ECNamedCurveTable.getOID(name);
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
BigInteger ybi = new BigInteger(prefs.getString(kp_public_affine_y + slug, "0"));
ECNamedDomainParameters dParams = new ECNamedDomainParameters(oid,
x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed());
ECNamedCurveSpec ecNamedCurveSpec = new ECNamedCurveSpec(name, dParams.getCurve(), dParams.getG(), dParams.getN());
return kf.generatePrivate(new java.security.spec.ECPrivateKeySpec(ybi, ecNamedCurveSpec));
}
private synchronized KeyPair getPair(Context context) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
String strPub = prefs.getString(kp_public + slug, "");
String strPriv = prefs.getString(kp_private + slug, "");
if (strPub.trim().isEmpty() || strPriv.trim().isEmpty()) {
return newPair(context);
}
try {
return readKeyPair(context);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
PublicKey getServerKey(Context context) throws Exception {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
String serverKey = prefs.getString(peer_public + slug, "");
return readPublicKey(serverKey);
}
@SuppressWarnings({"unused", "RedundantSuppression"})
public byte[] getSharedSecret(Context context) {
try {
KeyPair keyPair = getPair(context);
if (keyPair != null) {
return generateSecret(keyPair.getPrivate(), getServerKey(context));
}
} catch (Exception e) {
e.printStackTrace();
return null;
}
return null;
}
public String getPublicKey(Context context) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
return prefs.getString(kp_public + slug, "");
}
@SuppressLint("ApplySharedPref")
public void saveServerKey(Context context, String strPeerPublic) {
SharedPreferences.Editor prefsEditor = PreferenceManager
.getDefaultSharedPreferences(context).edit();
prefsEditor.putString(peer_public + slug, strPeerPublic);
prefsEditor.commit();
}
}

View file

@ -1,239 +0,0 @@
package app.fedilab.android.mastodon.helper;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.mastodon.client.entities.app.StatusCache.restoreNotificationFromString;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
import androidx.preference.PreferenceManager;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyAgreement;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import app.fedilab.android.mastodon.client.entities.api.Notification;
public class ECDHFedilab {
public static final String kp_public = "kp_public";
public static final String peer_public = "peer_public";
public static final String name = "prime256v1";
private static final byte[] P256_HEAD = new byte[]{(byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a,
(byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86,
(byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x03, (byte) 0x42, (byte) 0x00};
static {
Security.addProvider(new org.spongycastle.jce.provider.BouncyCastleProvider());
}
private final KeyPairGenerator kpg;
private final PublicKey publicKey;
private final String encodedPublicKey;
private final byte[] authKey;
private final String slug;
private final String pushPublicKey;
private final String encodedAuthKey;
private final String pushAccountID;
private final String pushPrivateKey;
PrivateKey privateKey;
private String pushPrivateKe;
public ECDHFedilab(Context context, String slug) throws Exception {
if (slug == null) {
throw new Exception("slug cannot be null");
}
try {
kpg = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec spec = new ECGenParameterSpec("prime256v1");
kpg.initialize(spec);
KeyPair keyPair = kpg.generateKeyPair();
publicKey = keyPair.getPublic();
privateKey = keyPair.getPrivate();
encodedPublicKey = Base64.encodeToString(serializeRawPublicKey(publicKey), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
authKey = new byte[16];
SecureRandom secureRandom = new SecureRandom();
secureRandom.nextBytes(authKey);
byte[] randomAccountID = new byte[16];
secureRandom.nextBytes(randomAccountID);
pushPrivateKey = Base64.encodeToString(privateKey.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
pushPublicKey = Base64.encodeToString(publicKey.getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
encodedAuthKey = Base64.encodeToString(authKey, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
pushAccountID = Base64.encodeToString(randomAccountID, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
SharedPreferences.Editor prefsEditor = PreferenceManager
.getDefaultSharedPreferences(context).edit();
prefsEditor.putString("pushPrivateKey" + slug, pushPrivateKey);
prefsEditor.putString("pushPublicKey" + slug, pushPublicKey);
prefsEditor.putString("encodedAuthKey" + slug, encodedAuthKey);
prefsEditor.putString("pushAccountID" + slug, pushAccountID);
prefsEditor.apply();
this.slug = slug;
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static String getServerKey(Context context, String slug) {
SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(context);
return sharedPreferences.getString("server_key" + slug, null);
}
private static byte[] serializeRawPublicKey(PublicKey key) {
ECPoint point = ((ECPublicKey) key).getW();
byte[] x = point.getAffineX().toByteArray();
byte[] y = point.getAffineY().toByteArray();
if (x.length > 32)
x = Arrays.copyOfRange(x, x.length - 32, x.length);
if (y.length > 32)
y = Arrays.copyOfRange(y, y.length - 32, y.length);
byte[] result = new byte[65];
result[0] = 4;
System.arraycopy(x, 0, result, 1 + (32 - x.length), x.length);
System.arraycopy(y, 0, result, result.length - y.length, y.length);
return result;
}
public static Notification decryptNotification(Context context, String slug, byte[] messageEncrypted) {
SharedPreferences sharedPreferences = PreferenceManager
.getDefaultSharedPreferences(context);
String pushPrivateKey = sharedPreferences.getString("pushPrivateKey" + slug, null);
String pushPublicKey = sharedPreferences.getString("pushPublicKey" + slug, null);
String encodedAuthKey = sharedPreferences.getString("encodedAuthKey" + slug, null);
sharedPreferences.getString("pushAccountID" + slug, null);
PublicKey serverKey = null;
serverKey = deserializeRawPublicKey(Base64.decode(getServerKey(context, slug), Base64.URL_SAFE));
PrivateKey privateKey;
PublicKey publicKey;
byte[] authKey;
try {
KeyFactory kf = KeyFactory.getInstance("EC");
privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(Base64.decode(pushPrivateKey, Base64.URL_SAFE)));
publicKey = kf.generatePublic(new X509EncodedKeySpec(Base64.decode(pushPublicKey, Base64.URL_SAFE)));
authKey = Base64.decode(encodedAuthKey, Base64.URL_SAFE);
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
e.printStackTrace();
return null;
}
byte[] sharedSecret;
try {
KeyAgreement keyAgreement = KeyAgreement.getInstance("ECDH");
keyAgreement.init(privateKey);
keyAgreement.doPhase(serverKey, true);
sharedSecret = keyAgreement.generateSecret();
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
return null;
}
byte[] secondSaltInfo = "Content-Encoding: auth\0".getBytes(StandardCharsets.UTF_8);
byte[] deriveKey;
try {
deriveKey = deriveKey(authKey, sharedSecret, secondSaltInfo, 32);
} catch (NoSuchAlgorithmException | InvalidKeyException e) {
e.printStackTrace();
return null;
}
String decryptedStr;
try {
SecretKeySpec aesKey = new SecretKeySpec(deriveKey, "AES");
byte[] iv = Arrays.copyOfRange(messageEncrypted, 0, 12);
byte[] ciphertext = Arrays.copyOfRange(messageEncrypted, 12, messageEncrypted.length); // Separate ciphertext (the MAC is implicitly separated from the ciphertext)
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
GCMParameterSpec gCMParameterSpec = new GCMParameterSpec(128, iv);
cipher.init(Cipher.DECRYPT_MODE, aesKey, gCMParameterSpec);
byte[] decrypted = cipher.doFinal(ciphertext);
decryptedStr = new String(decrypted, 2, decrypted.length - 2, StandardCharsets.UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException |
InvalidAlgorithmParameterException | InvalidKeyException | BadPaddingException |
IllegalBlockSizeException e) {
e.printStackTrace();
return null;
}
return restoreNotificationFromString(decryptedStr);
}
protected static PublicKey deserializeRawPublicKey(byte[] rawBytes) {
if (rawBytes.length != 65 && rawBytes.length != 64)
return null;
try {
KeyFactory kf = KeyFactory.getInstance("EC");
ByteArrayOutputStream os = new ByteArrayOutputStream();
os.write(P256_HEAD);
if (rawBytes.length == 64)
os.write(4);
os.write(rawBytes);
return kf.generatePublic(new X509EncodedKeySpec(os.toByteArray()));
} catch (NoSuchAlgorithmException | InvalidKeySpecException | IOException e) {
e.printStackTrace();
}
return null;
}
private static byte[] deriveKey(byte[] firstSalt, byte[] secondSalt, byte[] info, int length) throws NoSuchAlgorithmException, InvalidKeyException {
Mac hmacContext = Mac.getInstance("HmacSHA256");
hmacContext.init(new SecretKeySpec(firstSalt, "HmacSHA256"));
byte[] hmac = hmacContext.doFinal(secondSalt);
hmacContext.init(new SecretKeySpec(hmac, "HmacSHA256"));
hmacContext.update(info);
byte[] result = hmacContext.doFinal(new byte[]{1});
return result.length <= length ? result : Arrays.copyOfRange(result, 0, length);
}
public String getPublicKey() {
return this.encodedPublicKey;
}
public String getAuthKey() {
return this.encodedAuthKey;
}
}

View file

@ -15,7 +15,7 @@ package app.fedilab.android.mastodon.helper;
* see <http://www.gnu.org/licenses>. */
import static android.content.Context.DOWNLOAD_SERVICE;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.networkAvailable;
import static app.fedilab.android.mastodon.activities.BaseActivity.currentThemeId;
import static app.fedilab.android.mastodon.helper.LogoHelper.getNotificationIcon;
import static app.fedilab.android.mastodon.helper.ThemeHelper.fetchAccentColor;
@ -58,6 +58,7 @@ import android.os.Looper;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.text.Html;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@ -165,6 +166,7 @@ import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.OauthVM;
import app.fedilab.android.mastodon.watermark.androidwm.WatermarkBuilder;
import app.fedilab.android.mastodon.watermark.androidwm.bean.WatermarkText;
import app.fedilab.android.peertube.client.data.AccountData;
import es.dmoral.toasty.Toasty;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
@ -218,6 +220,7 @@ public class Helper {
public static final String ARG_NOTIFICATION_TYPE = "ARG_NOTIFICATION_TYPE";
public static final String ARG_EXCLUDED_NOTIFICATION_TYPE = "ARG_EXCLUDED_NOTIFICATION_TYPE";
public static final String ARG_STATUS = "ARG_STATUS";
public static final String ARG_QR_CODE_URL = "ARG_QR_CODE_URL";
public static final String ARG_FOCUSED_STATUS_URI = "ARG_FOCUSED_STATUS_URI";
public static final String ARG_TIMELINE_REFRESH_ALL = "ARG_TIMELINE_REFRESH_ALL";
public static final String ARG_REFRESH_NOTFICATION = "ARG_REFRESH_NOTFICATION";
@ -291,6 +294,7 @@ public class Helper {
public static final String ARG_MEDIA_ARRAY_PROFILE = "ARG_MEDIA_ARRAY_PROFILE";
public static final String ARG_VISIBILITY = "ARG_VISIBILITY";
public static final String ARG_SCHEDULED_DATE = "ARG_SCHEDULED_DATE";
public static final String ARG_SCHEDULED_ID = "ARG_SCHEDULED_ID";
public static final String WORKER_REFRESH_NOTIFICATION = "WORKER_REFRESH_NOTIFICATION";
public static final String WORKER_REFRESH_HOME = "WORKER_REFRESH_HOME";
@ -423,6 +427,7 @@ public class Helper {
private static int notificationId = 1;
//Allow to store in shared preference first visible fragment when the app starts
private static String slugOfFirstFragment;
private static BaseAccount baseAccount;
static {
LinkedHashMap<PatternType, Pattern> aMap = new LinkedHashMap<>();
@ -433,7 +438,6 @@ public class Helper {
patternHashMap = Collections.unmodifiableMap(aMap);
}
/**
* Manage downloads with URLs
*
@ -477,7 +481,6 @@ public class Helper {
}
}
/***
* Check if the user is connected to Internet
* @return boolean
@ -643,19 +646,13 @@ public class Helper {
*/
public static Date stringToDateWithFormat(Context context, String stringDate, String format) {
if (stringDate == null)
return null;
Locale userLocale;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
userLocale = context.getResources().getConfiguration().getLocales().get(0);
} else {
userLocale = context.getResources().getConfiguration().locale;
}
SimpleDateFormat dateFormat = new SimpleDateFormat(format, userLocale);
Date date = null;
return new Date();
SimpleDateFormat dateFormat = new SimpleDateFormat(format, Locale.US);
Date date = new Date();
try {
date = dateFormat.parse(stringDate);
} catch (java.text.ParseException ignored) {
ignored.printStackTrace();
}
return date;
}
@ -683,6 +680,10 @@ public class Helper {
if (url == null) {
return;
}
/*if(networkAvailable == BaseMainActivity.status.DISCONNECTED){
Toasty.warning(context, context.getString(R.string.toast_error_internet), Toast.LENGTH_LONG).show();
return;
}*/
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean customTab = sharedpreferences.getBoolean(context.getString(R.string.SET_CUSTOM_TABS), true);
if (customTab) {
@ -696,20 +697,32 @@ public class Helper {
try {
customTabsIntent.launchUrl(context, Uri.parse(url).normalizeScheme());
} catch (Exception e) {
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
if(url.toLowerCase().startsWith("xmpp:")) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setData(Uri.parse("https://xmpp.link/#" + url.replace("xmpp:","")).normalizeScheme());
context.startActivity(intent);
} else {
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
}
}
} else {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
if (!url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://") && !url.toLowerCase().startsWith("gemini://")) {
if (!url.toLowerCase().startsWith("http://") && !url.toLowerCase().startsWith("https://") && !url.toLowerCase().startsWith("gemini://") && !url.toLowerCase().startsWith("xmpp:")) {
url = "http://" + url;
}
intent.setData(Uri.parse(url).normalizeScheme());
try {
context.startActivity(intent);
} catch (Exception e) {
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
if(url.toLowerCase().startsWith("xmpp:")) {
intent.setData(Uri.parse("https://xmpp.link/#" + url.replace("xmpp:","")).normalizeScheme());
context.startActivity(intent);
} else {
Toasty.error(context, context.getString(R.string.toast_error), Toast.LENGTH_LONG).show();
}
}
}
}
@ -876,7 +889,7 @@ public class Helper {
args.putString(RECEIVE_TOAST_TYPE, type);
args.putString(RECEIVE_TOAST_CONTENT, content);
intentBC.setAction(Helper.RECEIVE_TOAST_MESSAGE);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBC.putExtras(bundle);
@ -907,9 +920,14 @@ public class Helper {
fragment = _fragment;
} else {
if (args != null) fragment.setArguments(args);
ft = fragmentManager.beginTransaction();
ft.add(containerViewId, fragment, tag);
if (backStackName != null) ft.addToBackStack(backStackName);
if(!fragmentManager.isDestroyed()) {
if (backStackName != null) {
try {
ft.addToBackStack(backStackName);
}catch (Exception ignored){}
}
if (!fragmentManager.isDestroyed()) {
ft.commit();
}
}
@ -917,7 +935,6 @@ public class Helper {
return fragment;
}
/**
* Load a media into a view
*
@ -960,11 +977,11 @@ public class Helper {
OauthVM oauthVM = new ViewModelProvider((ViewModelStoreOwner) activity).get(OauthVM.class);
if (currentAccount != null) {
if (Helper.getCurrentAccount(activity) != null) {
//Revoke the token
oauthVM.revokeToken(currentAccount.instance, currentAccount.token, currentAccount.client_id, currentAccount.client_secret);
oauthVM.revokeToken(Helper.getCurrentAccount(activity).instance, Helper.getCurrentAccount(activity).token, Helper.getCurrentAccount(activity).client_id, Helper.getCurrentAccount(activity).client_secret);
//Log out the current user
accountDB.removeUser(currentAccount);
accountDB.removeUser(Helper.getCurrentAccount(activity));
}
BaseAccount newAccount = accountDB.getLastUsedAccount();
SharedPreferences.Editor editor = sharedpreferences.edit();
@ -978,7 +995,7 @@ public class Helper {
activity.startActivity(loginActivity);
activity.finish();
} else {
currentAccount = newAccount;
Helper.setCurrentAccount(newAccount);
editor.putString(PREF_USER_TOKEN, newAccount.token);
editor.putString(PREF_USER_SOFTWARE, newAccount.software);
editor.putString(PREF_USER_INSTANCE, newAccount.instance);
@ -1366,7 +1383,6 @@ public class Helper {
}).start();
}
public static void createFileFromUri(Context context, Uri uri, OnFileCopied callBack) {
new Thread(() -> {
InputStream selectedFileInputStream;
@ -1525,7 +1541,7 @@ public class Helper {
Bundle args = new Bundle();
args.putBoolean(Helper.RECEIVE_RECREATE_ACTIVITY, true);
Intent intentBD = new Intent(Helper.BROADCAST_DATA);
new CachedBundle(activity).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(activity).insertBundle(args, Helper.getCurrentAccount(activity), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBD.putExtras(bundle);
@ -1692,7 +1708,6 @@ public class Helper {
}
}
public static String dateDiffFull(Date dateToot) {
SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.MEDIUM, Locale.getDefault());
try {
@ -1702,7 +1717,6 @@ public class Helper {
}
}
public static String dateDiffFullShort(Date dateToot) {
SimpleDateFormat df = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.getDefault());
try {
@ -1933,7 +1947,7 @@ public class Helper {
Intent intent = new Intent(activity, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(activity).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(activity).insertBundle(args, Helper.getCurrentAccount(activity), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2021,7 +2035,6 @@ public class Helper {
Runtime.getRuntime().exit(0);
}
public static void forwardToBrowser(Activity activity, Intent i) {
Intent intent = new Intent();
intent.setAction(android.content.Intent.ACTION_VIEW);
@ -2046,7 +2059,6 @@ public class Helper {
}
}
public static int dialogStyle() {
if (R.style.AppThemeBar == currentThemeId || R.style.AppTheme == currentThemeId) {
return R.style.AppThemeAlertDialog;
@ -2075,6 +2087,33 @@ public class Helper {
}
}
public static BaseAccount getCurrentAccount(Context context) {
if (baseAccount == null && context != null) {
baseAccount = new BaseAccount();
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
baseAccount.user_id = sharedpreferences.getString(PREF_USER_ID, null);
baseAccount.instance = sharedpreferences.getString(PREF_USER_INSTANCE, null);
baseAccount.token = sharedpreferences.getString(PREF_USER_TOKEN, null);
}
return baseAccount;
}
public static void setCurrentAccount(BaseAccount newBaseAccount) {
baseAccount = newBaseAccount;
}
public static void setCurrentAccountMastodonAccount(Context context, app.fedilab.android.mastodon.client.entities.api.Account newAccount) {
BaseAccount tempBaseAccount = getCurrentAccount(context);
tempBaseAccount.mastodon_account = newAccount;
setCurrentAccount(tempBaseAccount);
}
public static void setCurrentAccountPeertubeAccount(Context context, AccountData.PeertubeAccount newAccount) {
BaseAccount tempBaseAccount = getCurrentAccount(context);
tempBaseAccount.peertube_account = newAccount;
setCurrentAccount(tempBaseAccount);
}
public static boolean isNumeric(String str) {
try {
Double.parseDouble(str);
@ -2100,6 +2139,15 @@ public class Helper {
.build();
}
public static String parseHtml(String html) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
return Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY).toString();
} else {
//noinspection deprecation
return Html.fromHtml(html).toString();
}
}
//Enum that described actions to replace inside a toot content
public enum PatternType {
MENTION,

View file

@ -239,9 +239,9 @@ public class MastodonHelper {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean disableGif = sharedpreferences.getBoolean(context.getString(R.string.SET_DISABLE_GIF), false);
@DrawableRes int placeholder = type == MediaAccountType.AVATAR ? R.drawable.ic_person : R.drawable.default_banner;
if (Helper.isValidContextForGlide(activity != null ? activity : context)) {
if (Helper.isValidContextForGlide(activity != null ? activity.getApplicationContext() : context.getApplicationContext())) {
if (account == null) {
Glide.with(activity != null ? activity : context)
Glide.with(activity != null ? activity.getApplicationContext() : context.getApplicationContext())
.asDrawable()
.load(placeholder)
.thumbnail(0.1f)
@ -253,7 +253,7 @@ public class MastodonHelper {
if (targetedUrl != null) {
if (disableGif || (!targetedUrl.endsWith(".gif"))) {
try {
Glide.with(activity != null ? activity : context)
Glide.with(activity != null ? activity.getApplicationContext() : context.getApplicationContext())
.asDrawable()
.load(targetedUrl)
.thumbnail(0.1f)
@ -263,7 +263,7 @@ public class MastodonHelper {
e.printStackTrace();
}
} else {
Glide.with(activity != null ? activity : context)
Glide.with(activity != null ? activity.getApplicationContext() : context.getApplicationContext())
.asGif()
.load(targetedUrl)
.thumbnail(0.1f)
@ -271,7 +271,7 @@ public class MastodonHelper {
.into(view);
}
} else {
Glide.with(activity != null ? activity : context)
Glide.with(activity != null ? activity.getApplicationContext() : context.getApplicationContext())
.asDrawable()
.load(placeholder)
.thumbnail(0.1f)
@ -499,7 +499,7 @@ public class MastodonHelper {
accountId = account.id;
acct = account.acct;
}
accountsVM.mute(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountId, true, (int) delayToPass)
accountsVM.mute(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountId, true, (int) delayToPass / 1000)
.observe((LifecycleOwner) context, relationShip -> {
if (listener != null) {
listener.onTimedMute(relationShip);

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.helper;
* see <http://www.gnu.org/licenses>. */
import static android.content.Context.DOWNLOAD_SERVICE;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.mastodon.helper.LogoHelper.getMainLogo;
import android.app.Activity;
@ -172,7 +171,7 @@ public class MediaHelper {
intent.setDataAndType(uri, mime);
MediaScannerConnection.scanFile(context, new String[]{backupFile.getAbsolutePath()}, null, null);
if (!share) {
Helper.notify_user(context, currentAccount, intent, BitmapFactory.decodeResource(context.getResources(),
Helper.notify_user(context, Helper.getCurrentAccount(context), intent, BitmapFactory.decodeResource(context.getResources(),
getMainLogo(context)), Helper.NotifType.STORE, context.getString(R.string.save_over), context.getString(R.string.download_from, fileName));
Toasty.success(context, context.getString(R.string.save_over), Toasty.LENGTH_LONG).show();
} else {

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.helper;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.currentUserID;
import static app.fedilab.android.BaseMainActivity.show_boosts;
@ -57,6 +56,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;
import app.fedilab.android.BaseMainActivity;
@ -184,15 +184,18 @@ public class PinnedTimelineHelper {
}
}
}
if (extraFeatures) {
try {
Pinned pinnedAll = new Pinned(activity).getAllPinned(currentAccount);
if (pinnedAll == null) {
pinnedAll = new Pinned();
pinnedAll.user_id = currentUserID;
pinnedAll.instance = currentInstance;
pinnedAll.pinnedTimelines = new ArrayList<>();
}
//Create other default timelines
try {
Pinned pinnedAll = new Pinned(activity).getAllPinned(Helper.getCurrentAccount(activity));
if (pinnedAll == null) {
pinnedAll = new Pinned();
pinnedAll.user_id = currentUserID;
pinnedAll.instance = currentInstance;
pinnedAll.pinnedTimelines = new ArrayList<>();
}
if (extraFeatures) {
//Bubble timeline
boolean createDefaultBubbleAtTop = true;
for (PinnedTimeline pinnedTimeline : pinnedAll.pinnedTimelines) {
if (pinnedTimeline.type == Timeline.TimeLineEnum.BUBBLE) {
@ -212,11 +215,34 @@ public class PinnedTimelineHelper {
new Pinned(activity).insertPinned(pinned);
}
}
} catch (DBException e) {
e.printStackTrace();
}
//Trend timeline
boolean createDefaultTrendAtTop = true;
for (PinnedTimeline pinnedTimeline : pinnedAll.pinnedTimelines) {
if (pinnedTimeline.type == Timeline.TimeLineEnum.TREND_MESSAGE) {
createDefaultTrendAtTop = false;
break;
}
}
if (createDefaultTrendAtTop) {
PinnedTimeline pinnedTimelineBubble = new PinnedTimeline();
pinnedTimelineBubble.type = Timeline.TimeLineEnum.TREND_MESSAGE;
pinnedTimelineBubble.position = pinnedAll.pinnedTimelines != null ? pinnedAll.pinnedTimelines.size() : 0;
pinned.pinnedTimelines.add(pinnedTimelineBubble);
boolean exist = new Pinned(activity).pinnedExist(pinned);
if (exist) {
new Pinned(activity).updatePinned(pinned);
} else {
new Pinned(activity).insertPinned(pinned);
}
}
} catch (DBException e) {
e.printStackTrace();
}
sortPositionAsc(pinnedTimelines);
//Check if changes occurred, if mastodonLists is null it does need, because it is the first call to draw pinned
boolean needRedraw = mastodonLists == null;
@ -262,7 +288,7 @@ public class PinnedTimelineHelper {
for (MastodonList mastodonList : mastodonLists) {
boolean present = false;
try {
Pinned pinnedAll = new Pinned(activity).getAllPinned(currentAccount);
Pinned pinnedAll = new Pinned(activity).getAllPinned(Helper.getCurrentAccount(activity));
if (pinnedAll == null) {
pinnedAll = pinned;
}
@ -303,12 +329,18 @@ public class PinnedTimelineHelper {
}
//Pinned tab position will start after BOTTOM_TIMELINE_COUNT (ie 5)
activityMainBinding.tabLayout.removeAllTabs();
if(activityMainBinding.viewPager.getAdapter() != null) {
activityMainBinding.viewPager.getAdapter().notifyDataSetChanged();
}
int toRemove = FedilabPageAdapter.BOTTOM_TIMELINE_COUNT;
if (!singleBar) {
//Small hack to hide first tabs (they represent the item of the bottom menu)
toRemove = itemToRemoveInBottomMenu(activity);
for (int i = 0; i < (FedilabPageAdapter.BOTTOM_TIMELINE_COUNT - toRemove); i++) {
activityMainBinding.tabLayout.addTab(activityMainBinding.tabLayout.newTab(), false);
if(activityMainBinding.viewPager.getAdapter() != null) {
activityMainBinding.viewPager.getAdapter().notifyDataSetChanged();
}
((ViewGroup) activityMainBinding.tabLayout.getChildAt(0)).getChildAt(i).setVisibility(View.GONE);
}
}
@ -342,10 +374,10 @@ public class PinnedTimelineHelper {
break;
case REMOTE:
name = pinnedTimeline.remoteInstance.host;
if (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) {
if (pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER || pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG) {
String remoteInstance = sharedpreferences.getString(activity.getString(R.string.SET_NITTER_HOST), activity.getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase();
//Custom name for Nitter instances
if (pinnedTimeline.remoteInstance.displayName != null && pinnedTimeline.remoteInstance.displayName.trim().length() > 0) {
if (pinnedTimeline.remoteInstance.displayName != null && !pinnedTimeline.remoteInstance.displayName.trim().isEmpty()) {
name = pinnedTimeline.remoteInstance.displayName;
}
ident = "@R@" + remoteInstance;
@ -379,6 +411,7 @@ public class PinnedTimelineHelper {
case MISSKEY:
tabCustomViewBinding.icon.setImageResource(R.drawable.misskey);
break;
case NITTER_TAG:
case NITTER:
tabCustomViewBinding.icon.setImageResource(R.drawable.nitter);
break;
@ -413,6 +446,9 @@ public class PinnedTimelineHelper {
case BUBBLE:
tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.ic_baseline_bubble_chart_24);
break;
case TREND_MESSAGE:
tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.baseline_moving_24);
break;
}
tab.setCustomView(tabCustomDefaultViewBinding.getRoot());
}
@ -420,6 +456,9 @@ public class PinnedTimelineHelper {
String slug = pinnedTimeline.type.getValue() + (ident != null ? "|" + ident : "");
tab.setTag(slug);
activityMainBinding.tabLayout.addTab(tab, false);
if(activityMainBinding.viewPager.getAdapter() != null){
activityMainBinding.viewPager.getAdapter().notifyDataSetChanged();
}
pinnedTimelineVisibleList.add(pinnedTimeline);
}
}
@ -472,9 +511,10 @@ public class PinnedTimelineHelper {
case PIXELFED:
item.setIcon(R.drawable.pixelfed);
break;
case NITTER_TAG:
case NITTER:
item.setIcon(R.drawable.nitter);
if (pinnedTimeline.remoteInstance.displayName != null && pinnedTimeline.remoteInstance.displayName.trim().length() > 0) {
if (pinnedTimeline.remoteInstance.displayName != null && !pinnedTimeline.remoteInstance.displayName.trim().isEmpty()) {
item.setTitle(pinnedTimeline.remoteInstance.displayName);
} else {
item.setTitle(pinnedTimeline.remoteInstance.host);
@ -526,7 +566,7 @@ public class PinnedTimelineHelper {
bubbleClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString());
break;
case REMOTE:
if (pinnedTimelineVisibleList.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER) {
if (pinnedTimelineVisibleList.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER && pinnedTimelineVisibleList.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER_TAG) {
instanceClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString());
} else {
nitterClick(activity, finalPinned, v, activityMainBinding, finalI, activityMainBinding.tabLayout.getTabAt(finalI).getTag().toString());
@ -534,6 +574,7 @@ public class PinnedTimelineHelper {
break;
case HOME:
case LOCAL:
case TREND_MESSAGE:
case PUBLIC:
defaultClick(activity, pinnedTimelineVisibleList.get(position).type, v, activityMainBinding, finalI);
break;
@ -547,6 +588,7 @@ public class PinnedTimelineHelper {
activityMainBinding.tabLayout.clearOnTabSelectedListeners();
FedilabPageAdapter fedilabPageAdapter = new FedilabPageAdapter(activity, activity.getSupportFragmentManager(), pinned, bottomMenu);
activityMainBinding.viewPager.setAdapter(fedilabPageAdapter);
activityMainBinding.viewPager.setOffscreenPageLimit(tabStrip.getChildCount());
activityMainBinding.viewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(activityMainBinding.tabLayout));
if (!singleBar) {
@ -793,7 +835,7 @@ public class PinnedTimelineHelper {
int toRemove = 0;
try {
//If some menu items have been hidden we should not create tab for them
bottomMenuDb = new BottomMenu(activity).getAllBottomMenu(currentAccount);
bottomMenuDb = new BottomMenu(activity).getAllBottomMenu(Helper.getCurrentAccount(activity));
if (bottomMenuDb != null) {
List<BottomMenu.MenuItem> menuItemList = bottomMenuDb.bottom_menu;
if (menuItemList != null) {
@ -1528,6 +1570,12 @@ public class PinnedTimelineHelper {
PopupMenu popup = new PopupMenu(activity, view);
popup.getMenuInflater()
.inflate(R.menu.option_nitter_timeline, popup.getMenu());
if(remoteInstance.type == RemoteInstance.InstanceType.NITTER_TAG) {
MenuItem item = popup.getMenu().findItem(R.id.action_nitter_manage_accounts);
if(item != null) {
item.setTitle(R.string.manage_tags);
}
}
int finalOffSetPosition = offSetPosition;
popup.setOnMenuItemClickListener(item -> {
int itemId = item.getItemId();
@ -1547,7 +1595,7 @@ public class PinnedTimelineHelper {
}
dialogBuilder.setPositiveButton(R.string.validate, (dialog, id) -> {
String values = editTextName.getText().toString();
if (values.trim().length() == 0) {
if (values.trim().isEmpty()) {
values = remoteInstance.displayName;
}
remoteInstance.displayName = values;

View file

@ -0,0 +1,46 @@
package app.fedilab.android.mastodon.helper;
/* Copyright 2024 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import java.util.ArrayList;
import java.util.List;
public class PronounsHelper {
public static List<String> pronouns = new ArrayList<>() {
{
add("pronoun");
add("pronouns");
add("pronoms");
add("pronom");
add("pronombres");
add("לשון פנייה");
add("כינויי גוף");
add("pronomen");
add("pronomina");
add("称谓");
add("pronomes");
add("pronome");
add("pronomi");
add("pronomoj");
add("zaimki");
add("voornaamwoorden");
add("riochdairean");
add("כינויי גוף");
add("personlig pronomen");
add("人称");
add("人稱");
}
};
}

View file

@ -35,20 +35,26 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.unifiedpush.android.connector.UnifiedPush;
import java.util.ArrayList;
import java.net.IDN;
import java.util.List;
import java.util.concurrent.TimeUnit;
import app.fedilab.android.R;
import app.fedilab.android.mastodon.client.endpoints.MastodonInstanceService;
import app.fedilab.android.mastodon.client.entities.api.InstanceV2;
import app.fedilab.android.mastodon.client.entities.app.Account;
import app.fedilab.android.mastodon.client.entities.app.BaseAccount;
import app.fedilab.android.mastodon.jobs.NotificationsWorker;
import okhttp3.OkHttpClient;
import retrofit2.Call;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
public class PushHelper {
public static void startStreaming(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
String typeOfNotification = prefs.getString(context.getString(R.string.SET_NOTIFICATION_TYPE), "PUSH_NOTIFICATIONS");
switch (typeOfNotification) {
@ -57,12 +63,12 @@ public class PushHelper {
List<BaseAccount> accounts = new Account(context).getPushNotificationAccounts();
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> {
List<String> distributors = UnifiedPush.getDistributors(context, new ArrayList<>());
if (distributors.size() == 0) {
List<String> distributors = UnifiedPush.getDistributors(context);
if (distributors.isEmpty()) {
AlertDialog.Builder alert = new MaterialAlertDialogBuilder(context);
alert.setTitle(R.string.no_distributors_found);
final TextView message = new TextView(context);
String link = "https://fedilab.app/wiki/features/push-notifications/";
String link = "https://fedilab.app/docs/fedilab/faq/";
final SpannableString s =
new SpannableString(context.getString(R.string.no_distributors_explanation, link));
Linkify.addLinks(s, Linkify.WEB_URLS);
@ -94,8 +100,10 @@ public class PushHelper {
WorkManager.getInstance(context).cancelAllWorkByTag(Helper.WORKER_REFRESH_NOTIFICATION);
new Thread(() -> {
List<BaseAccount> accounts = new Account(context).getPushNotificationAccounts();
for (BaseAccount account : accounts) {
((Activity) context).runOnUiThread(() -> UnifiedPush.unregisterApp(context, account.user_id + "@" + account.instance));
if(accounts != null) {
for (BaseAccount account : accounts) {
((Activity) context).runOnUiThread(() -> UnifiedPush.unregister(context, account.user_id + "@" + account.instance));
}
}
}).start();
break;
@ -108,7 +116,7 @@ public class PushHelper {
List<BaseAccount> accounts = new Account(context).getPushNotificationAccounts();
if (accounts != null) {
for (BaseAccount account : accounts) {
((Activity) context).runOnUiThread(() -> UnifiedPush.unregisterApp(context, account.user_id + "@" + account.instance));
((Activity) context).runOnUiThread(() -> UnifiedPush.unregister(context, account.user_id + "@" + account.instance));
}
}
}).start();
@ -125,28 +133,49 @@ public class PushHelper {
if (accounts == null) {
return;
}
List<String> distributors = UnifiedPush.getDistributors(context, new ArrayList<>());
if (distributors.size() == 1 || !UnifiedPush.getDistributor(context).isEmpty()) {
List<String> distributors = UnifiedPush.getDistributors(context);
if (!distributors.isEmpty()) {
if (distributors.size() == 1) {
UnifiedPush.saveDistributor(context, distributors.get(0));
}
final OkHttpClient okHttpClient = Helper.myOkHttpClient(context.getApplicationContext());
for (BaseAccount account : accounts) {
UnifiedPush.registerApp(context, account.user_id + "@" + account.instance, new ArrayList<>(), "");
}
return;
}
AlertDialog.Builder alert = new MaterialAlertDialogBuilder(context);
alert.setTitle(R.string.select_distributors);
String[] distributorsStr = distributors.toArray(new String[0]);
alert.setSingleChoiceItems(distributorsStr, -1, (dialog, item) -> {
String distributor = distributorsStr[item];
UnifiedPush.saveDistributor(context, distributor);
for (BaseAccount account : accounts) {
UnifiedPush.registerApp(context, account.user_id + "@" + account.instance, new ArrayList<>(), "");
new Thread(()->{
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://" + (account.instance != null ? IDN.toASCII(account.instance, IDN.ALLOW_UNASSIGNED) : null) + "/api/v2/")
.addConverterFactory(GsonConverterFactory.create(Helper.getDateBuilder()))
.client(okHttpClient)
.build();
MastodonInstanceService mastodonInstanceService = retrofit.create(MastodonInstanceService.class);
Call<InstanceV2> instanceV2Call = mastodonInstanceService.instanceV2();
String vapid = null;
if (instanceV2Call != null) {
try {
Response<InstanceV2> instanceResponse = instanceV2Call.execute();
if (instanceResponse.isSuccessful()) {
InstanceV2 instanceV2 = instanceResponse.body();
if (instanceV2 != null && instanceV2.configuration.vapId != null) {
vapid = instanceV2.configuration.vapId.publicKey;
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Handler mainHandler = new Handler(Looper.getMainLooper());
String finalVapid = vapid!=null?vapid.replaceAll("=",""):null;
Runnable myRunnable = () -> {
try {
UnifiedPush.register(context, account.user_id + "@" + account.instance, null, finalVapid);
}catch (Exception e){
e.printStackTrace();
}
};
mainHandler.post(myRunnable);
}).start();
}
dialog.dismiss();
});
alert.show();
}
}
}

View file

@ -15,14 +15,18 @@ package app.fedilab.android.mastodon.helper;
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;
import org.unifiedpush.android.connector.data.PushEndpoint;
import java.net.IDN;
import app.fedilab.android.R;
@ -40,23 +44,31 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class PushNotifications {
public static void unregisterPushNotifications(Context context, String slug) {
new Thread(() -> {
String[] slugArray = slug.split("@");
BaseAccount accountDb = null;
try {
accountDb = new Account(context).getUniqAccount(slugArray[0], slugArray[1]);
} catch (DBException e) {
e.printStackTrace();
}
public static void registerPushNotifications(Context context, String endpoint, String slug) {
if (accountDb == null) {
return;
}
MastodonNotificationsService mastodonNotificationsService = init(context, accountDb.instance);
mastodonNotificationsService.deletePushsubscription(accountDb.token);
});
}
public static void registerPushNotifications(Context context, PushEndpoint pushEndpoint, String slug) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(context);
ECDHFedilab ecdh = null;
try {
ecdh = new ECDHFedilab(context, slug);
} catch (Exception e) {
e.printStackTrace();
}
if (ecdh == null) {
return;
}
String pubKey = ecdh.getPublicKey();
String auth = ecdh.getAuthKey();
String pubKey = pushEndpoint.getPubKeySet().getPubKey();
String auth =pushEndpoint.getPubKeySet().getAuth();
boolean notif_follow = prefs.getBoolean(context.getString(R.string.SET_NOTIF_FOLLOW), true);
@ -84,9 +96,10 @@ public class PushNotifications {
PushSubscription pushSubscription;
Call<PushSubscription> pushSubscriptionCall = mastodonNotificationsService.pushSubscription(
accountDb.token,
endpoint,
pushEndpoint.getUrl(),
pubKey,
auth,
true,
notif_follow,
notif_fav,
notif_share,
@ -101,6 +114,7 @@ public class PushNotifications {
Response<PushSubscription> pushSubscriptionResponse = pushSubscriptionCall.execute();
if (pushSubscriptionResponse.isSuccessful()) {
pushSubscription = pushSubscriptionResponse.body();
if (pushSubscription != null) {
pushSubscription.server_key = pushSubscription.server_key.replace('/', '_');
pushSubscription.server_key = pushSubscription.server_key.replace('+', '-');

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.helper;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentNightMode;
import android.app.Activity;
@ -149,7 +148,9 @@ public class SpannableHelper {
if (status != null && status.mentions != null) {
mentions.addAll(status.mentions);
}
text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?/?>)&gt;(((?!(<\\s?br\\s?/?>|<\\s?/s?p\\s?>)).)*))", "$2<blockquote>$3</blockquote>");
if(!convertMarkdown) {
text = text.replaceAll("((<\\s?p\\s?>|<\\s?br\\s?/?>)&gt;(((?!(<\\s?br\\s?/?>|<\\s?/s?p\\s?>)).)*))", "$2<blockquote>$3</blockquote>");
}
text = text.trim().replaceAll("\\s{3}", "&nbsp;&nbsp;&nbsp;");
text = text.trim().replaceAll("\\s{2}", "&nbsp;&nbsp;");
SpannableString initialContent;
@ -178,11 +179,12 @@ public class SpannableHelper {
markdownItem.position = position;
// get all spans in this range
URLSpan[] spans = initialContent.getSpans(i, next, URLSpan.class);
if (spans != null && spans.length > 0) {
markdownItem.urlSpan = spans[0];
}
if (markdownItem.code.trim().length() > 0) {
if (!markdownItem.code.trim().isEmpty()) {
markdownConverter.markdownItems.add(markdownItem);
position++;
}
@ -209,9 +211,9 @@ public class SpannableHelper {
for (MarkdownConverter.MarkdownItem markdownItem : markdownConverter.markdownItems) {
String sb = Pattern.compile("\\A[\\p{L}0-9_]").matcher(markdownItem.code).find() ? "\\b" : "";
String eb = Pattern.compile("[\\p{L}0-9_]\\z").matcher(markdownItem.code).find() ? "\\b" : "\\B";
Pattern p = Pattern.compile(sb + "(" + Pattern.quote(markdownItem.code) + ")" + eb, Pattern.UNICODE_CASE);
String sb = Pattern.compile("\\A[\\p{L}0-9_]").matcher(markdownItem.code.trim()).find() ? "\\b" : "";
String eb = Pattern.compile("[\\p{L}0-9_]\\z").matcher(markdownItem.code.trim()).find() ? "\\b" : "\\B";
Pattern p = Pattern.compile(sb + "(" + Pattern.quote(markdownItem.code.trim()) + ")" + eb, Pattern.UNICODE_CASE);
Matcher m = p.matcher(content);
int fetchPosition = 1;
while (m.find()) {
@ -236,6 +238,7 @@ public class SpannableHelper {
if (start < 0 || end > content.length()) {
continue;
}
boolean sameContent = (content.subSequence(start,end).toString().trim().equals(url.trim()));
content.removeSpan(span);
//Get the matching word associated to the URL
String word = content.subSequence(start, end).toString();
@ -290,7 +293,7 @@ public class SpannableHelper {
intent = new Intent(context, HashTagActivity.class);
args = new Bundle();
args.putString(Helper.ARG_SEARCH_KEYWORD, word.trim());
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -306,7 +309,7 @@ public class SpannableHelper {
for (Mention mention : mentions) {
if (word.compareToIgnoreCase("@" + mention.username) == 0) {
if(!checkRemotely) {
if (!checkRemotely) {
targetedMention = mention;
} else {
acct = mention.acct;
@ -317,12 +320,12 @@ public class SpannableHelper {
if (targetedMention != null) {
args.putString(Helper.ARG_USER_ID, targetedMention.id);
} else if( acct != null){
} else if (acct != null) {
args.putString(Helper.ARG_MENTION, acct);
} else {
args.putString(Helper.ARG_MENTION, word);
}
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -345,7 +348,7 @@ public class SpannableHelper {
}, start, end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
} else {
makeLinks(context, status, content, url, start, end);
makeLinks(context, status, content, url, start, end, sameContent);
}
replaceQuoteSpans(context, content);
emails(context, content, status);
@ -375,7 +378,7 @@ public class SpannableHelper {
CustomEmoji customEmoji = new CustomEmoji(new WeakReference<>(view));
content = customEmoji.makeEmoji(content, emojiList, animate, callback);
if (imagesToReplace.size() > 0) {
if (!imagesToReplace.isEmpty()) {
for (Map.Entry<String, String> entry : imagesToReplace.entrySet()) {
String key = entry.getKey();
String url = entry.getValue();
@ -395,14 +398,14 @@ public class SpannableHelper {
}
private static void makeLinks(Context context, Status status, SpannableStringBuilder content, String url, int start, int end) {
private static void makeLinks(Context context, Status status, SpannableStringBuilder content, String url, int start, int end, boolean sameContent) {
String newUrl = url;
boolean validUrl = URLUtil.isValidUrl(url) && url.length() == (end - start);
boolean validUrl = URLUtil.isValidUrl(url) && sameContent;
if (validUrl) {
newUrl = Helper.transformURL(context, url);
}
//If URL has been transformed
if (validUrl && newUrl.compareTo(url) != 0) {
content.replace(start, end, newUrl);
@ -645,14 +648,14 @@ public class SpannableHelper {
Pattern userWithoutAt = Pattern.compile("https?://([\\da-z.-]+\\.[a-z.]{2,10})/(users/([\\w._-]*[0-9]*))/statuses/([0-9]+)");
Matcher matcherUserWithoutAt = userWithoutAt.matcher(finalUrl);
if (matcherLink.find() && !finalUrl.contains("medium.com")) {
if (matcherLink.group(3) != null && Objects.requireNonNull(matcherLink.group(3)).length() > 0) { //It's a toot
CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() {
if (matcherLink.group(3) != null && !Objects.requireNonNull(matcherLink.group(3)).isEmpty()) { //It's a toot
CrossActionHelper.fetchRemoteStatus(context, Helper.getCurrentAccount(context), finalUrl, new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, status);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -666,7 +669,7 @@ public class SpannableHelper {
}
});
} else {//It's an account
CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() {
CrossActionHelper.fetchRemoteAccount(context, Helper.getCurrentAccount(context), matcherLink.group(2) + "@" + matcherLink.group(1), new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
}
@ -676,7 +679,7 @@ public class SpannableHelper {
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -687,14 +690,14 @@ public class SpannableHelper {
});
}
} else if (matcherLinkLong.find() && !finalUrl.contains("medium.com")) {
if (matcherLinkLong.group(3) != null && Objects.requireNonNull(matcherLinkLong.group(3)).length() > 0) { //It's a toot
CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() {
if (matcherLinkLong.group(3) != null && !Objects.requireNonNull(matcherLinkLong.group(3)).isEmpty()) { //It's a toot
CrossActionHelper.fetchRemoteStatus(context, Helper.getCurrentAccount(context), finalUrl, new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, status);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -708,7 +711,7 @@ public class SpannableHelper {
}
});
} else if (matcherLinkLong.group(2) != null) {//It's an account
CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherLinkLong.group(2), new CrossActionHelper.Callback() {
CrossActionHelper.fetchRemoteAccount(context, Helper.getCurrentAccount(context), matcherLinkLong.group(2), new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
}
@ -718,7 +721,7 @@ public class SpannableHelper {
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -729,14 +732,14 @@ public class SpannableHelper {
});
}
} else if (matcherUserWithoutAt.find() && !finalUrl.contains("medium.com")) {
if (matcherUserWithoutAt.group(4) != null && Objects.requireNonNull(matcherUserWithoutAt.group(4)).length() > 0) { //It's a toot
CrossActionHelper.fetchRemoteStatus(context, currentAccount, finalUrl, new CrossActionHelper.Callback() {
if (matcherUserWithoutAt.group(4) != null && !Objects.requireNonNull(matcherUserWithoutAt.group(4)).isEmpty()) { //It's a toot
CrossActionHelper.fetchRemoteStatus(context, Helper.getCurrentAccount(context), finalUrl, new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, status);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -750,7 +753,7 @@ public class SpannableHelper {
}
});
} else {//It's an account
CrossActionHelper.fetchRemoteAccount(context, currentAccount, matcherUserWithoutAt.group(3) + "@" + matcherUserWithoutAt.group(1), new CrossActionHelper.Callback() {
CrossActionHelper.fetchRemoteAccount(context, Helper.getCurrentAccount(context), matcherUserWithoutAt.group(3) + "@" + matcherUserWithoutAt.group(1), new CrossActionHelper.Callback() {
@Override
public void federatedStatus(Status status) {
}
@ -760,7 +763,7 @@ public class SpannableHelper {
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -946,7 +949,7 @@ public class SpannableHelper {
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account.moved);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -41,6 +41,7 @@ import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.mastodon.client.endpoints.MastodonFiltersService;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Filter;
import app.fedilab.android.mastodon.client.entities.api.Notification;
import app.fedilab.android.mastodon.client.entities.api.Status;
@ -94,7 +95,7 @@ public class TimelineHelper {
}
//If there are filters:
if (BaseMainActivity.mainFilters != null && BaseMainActivity.mainFilters.size() > 0 && statuses != null && statuses.size() > 0) {
if (BaseMainActivity.mainFilters != null && !BaseMainActivity.mainFilters.isEmpty() && statuses != null && !statuses.isEmpty()) {
//Loop through filters
for (Filter filter : BaseMainActivity.mainFilters) {
@ -113,7 +114,7 @@ public class TimelineHelper {
} else {
if (!filter.context.contains("public")) continue;
}
if (filter.keywords != null && filter.keywords.size() > 0) {
if (filter.keywords != null && !filter.keywords.isEmpty()) {
for (Filter.KeywordsAttributes filterKeyword : filter.keywords) {
String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).find() ? "\\b" : "";
String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).find() ? "\\b" : "";
@ -150,6 +151,19 @@ public class TimelineHelper {
Matcher ms = p.matcher(spoilerText);
if (ms.find()) {
status.filteredByApp = filter;
continue;
}
}
List<Attachment> mediaAttachments = status.reblog != null ? status.reblog.media_attachments : status.media_attachments;
if(mediaAttachments != null && !mediaAttachments.isEmpty()) {
for(Attachment attachment : mediaAttachments) {
if(attachment.description != null) {
Matcher ms = p.matcher(attachment.description );
if (ms.find()) {
status.filteredByApp = filter;
break;
}
}
}
}
}
@ -157,13 +171,13 @@ public class TimelineHelper {
}
}
}
if (statuses != null && statuses.size() > 0) {
if (statuses != null && !statuses.isEmpty()) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean groupReblogs = sharedpreferences.getBoolean(context.getString(R.string.SET_GROUP_REBLOGS), true);
if (filterTimeLineType == Timeline.TimeLineEnum.HOME) {
for (int i = 0; i < statuses.size(); i++) {
if (filteredAccounts != null && filteredAccounts.size() > 0) {
if (filteredAccounts != null && !filteredAccounts.isEmpty()) {
for (Account account : filteredAccounts) {
if (account.acct.equals(statuses.get(i).account.acct) || (statuses.get(i).reblog != null && account.acct.equals(statuses.get(i).reblog.account.acct))) {
Filter filterCustom = new Filter();
@ -220,7 +234,7 @@ public class TimelineHelper {
}
}
//If there are filters:
if (BaseMainActivity.mainFilters != null && BaseMainActivity.mainFilters.size() > 0 && notifications != null && notifications.size() > 0) {
if (BaseMainActivity.mainFilters != null && !BaseMainActivity.mainFilters.isEmpty() && notifications != null && !notifications.isEmpty()) {
//Loop through filters
for (Filter filter : BaseMainActivity.mainFilters) {
@ -231,7 +245,7 @@ public class TimelineHelper {
}
if (!filter.context.contains("notifications")) continue;
if (filter.keywords != null && filter.keywords.size() > 0) {
if (filter.keywords != null && !filter.keywords.isEmpty()) {
for (Filter.KeywordsAttributes filterKeyword : filter.keywords) {
String sb = Pattern.compile("\\A[A-Za-z0-9_]").matcher(filterKeyword.keyword).find() ? "\\b" : "";
String eb = Pattern.compile("[A-Za-z0-9_]\\z").matcher(filterKeyword.keyword).find() ? "\\b" : "";

View file

@ -38,7 +38,7 @@ import es.dmoral.toasty.Toasty;
public class TranslateHelper {
public static void translate(Context context, String toTranslate, Translate callback) {
public static void translate(Context context, String toTranslate, String languageSource, Translate callback) {
String statusToTranslate;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
statusToTranslate = Html.fromHtml(toTranslate, Html.FROM_HTML_MODE_LEGACY).toString();
@ -51,6 +51,8 @@ public class TranslateHelper {
et = MyTransL.translatorEngine.LIBRETRANSLATE;
} else if (translator.compareToIgnoreCase("LINGVA") == 0) {
et = MyTransL.translatorEngine.LINGVA;
} else if (translator.compareToIgnoreCase("MINT") == 0) {
et = MyTransL.translatorEngine.MINT;
} else {
et = MyTransL.translatorEngine.DEEPL;
}
@ -59,7 +61,15 @@ public class TranslateHelper {
Params params = new Params();
params.setSplit_sentences(false);
params.setFormat(Params.fType.TEXT);
params.setSource_lang("auto");
if(et != MyTransL.translatorEngine.MINT) {
params.setSource_lang("auto");
} else {
if(languageSource != null && !languageSource.isEmpty()) {
params.setSource_lang(languageSource);
} else {
params.setSource_lang("en");
}
}
if (translator.compareToIgnoreCase("FEDILAB") == 0) {
myTransL.setLibretranslateDomain("translate.fedilab.app");
} else if (translator.compareToIgnoreCase("LINGVA") == 0) {
@ -68,12 +78,25 @@ public class TranslateHelper {
host = context.getString(R.string.SET_TRANSLATOR_HOST_LINGVA);
}
myTransL.setLingvaDomain(host);
} else {
} else if (translator.compareToIgnoreCase("MINT") == 0) {
String host = sharedpreferences.getString(context.getString(R.string.SET_TRANSLATOR_DOMAIN_MINT), context.getString(R.string.SET_TRANSLATOR_HOST_MINT));
if (host == null || host.trim().isEmpty()) {
host = context.getString(R.string.SET_TRANSLATOR_HOST_MINT);
}
myTransL.setMintDomain(host);
}else {
String translatorVersion = sharedpreferences.getString(context.getString(R.string.SET_TRANSLATOR_VERSION), "PRO");
params.setPro(translatorVersion.equals("PRO"));
String apikey = sharedpreferences.getString(context.getString(R.string.SET_TRANSLATOR_API_KEY), null);
if (apikey != null) {
if (apikey != null && !apikey.trim().isEmpty()) {
myTransL.setDeeplAPIKey(apikey.trim());
} else { //Issue with API key (empty or null)
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(context.getString(R.string.SET_TRANSLATOR), "FEDILAB");
editor.commit();
et = MyTransL.translatorEngine.LIBRETRANSLATE;
myTransL.setTranslator(et);
myTransL.setLibretranslateDomain("translate.fedilab.app");
}
}

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.helper;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.mastodon.helper.LogoHelper.getMainLogo;
import static app.fedilab.android.sqlite.Sqlite.DB_NAME;
import static app.fedilab.android.sqlite.Sqlite.db;
@ -33,6 +32,8 @@ import android.widget.Toast;
import androidx.preference.PreferenceManager;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
@ -111,7 +112,13 @@ public class ZipHelper {
Uri uri = Uri.parse("file://" + zipFile);
intentOpen.setDataAndType(uri, "application/zip");
String title = context.getString(R.string.data_export_settings);
Helper.notify_user(context, currentAccount, intentOpen, BitmapFactory.decodeResource(context.getResources(),
new MaterialAlertDialogBuilder(context)
.setTitle(R.string.export_settings)
.setMessage(message + "\n\n" + uri.getPath())
.setIcon(R.drawable.ic_baseline_check_24)
.setNeutralButton(R.string.close, (dialogInterface, i) -> dialogInterface.dismiss())
.show();
Helper.notify_user(context, Helper.getCurrentAccount(context), intentOpen, BitmapFactory.decodeResource(context.getResources(),
getMainLogo(context)), Helper.NotifType.BACKUP, title, message);
}
}

View file

@ -1,8 +1,6 @@
package app.fedilab.android.mastodon.imageeditor;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
@ -330,7 +328,7 @@ public class EditImageActivity extends BaseActivity implements OnPhotoEditorList
args.putFloat("focusX", focusX);
args.putFloat("focusY", focusY);
}
new CachedBundle(EditImageActivity.this).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(EditImageActivity.this).insertBundle(args, Helper.getCurrentAccount(EditImageActivity.this), bundleId -> {
intentImage.putExtras(args);
intentImage.setPackage(BuildConfig.APPLICATION_ID);
sendBroadcast(intentImage);

View file

@ -16,6 +16,7 @@ package app.fedilab.android.mastodon.jobs;
import static android.content.Context.NOTIFICATION_SERVICE;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationChannel;
@ -46,6 +47,7 @@ import com.google.gson.Gson;
import java.io.IOException;
import java.net.IDN;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
@ -58,6 +60,7 @@ import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Poll;
import app.fedilab.android.mastodon.client.entities.api.ScheduledStatus;
import app.fedilab.android.mastodon.client.entities.api.Status;
import app.fedilab.android.mastodon.client.entities.api.params.StatusParams;
import app.fedilab.android.mastodon.client.entities.app.Account;
import app.fedilab.android.mastodon.client.entities.app.BaseAccount;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
@ -114,7 +117,7 @@ public class ComposeWorker extends Worker {
MastodonStatusesService mastodonStatusesService = init(context, dataPost.instance);
boolean error = false;
Status firstSendMessage = null;
if (dataPost.statusDraft != null && dataPost.statusDraft.statusDraftList != null && dataPost.statusDraft.statusDraftList.size() > 0) {
if (dataPost.statusDraft != null && dataPost.statusDraft.statusDraftList != null && !dataPost.statusDraft.statusDraftList.isEmpty()) {
//If state is null, it is created (typically when submitting the status the first time)
if (dataPost.statusDraft.state == null) {
dataPost.statusDraft.state = new PostState();
@ -137,7 +140,7 @@ public class ComposeWorker extends Worker {
List<Status> statuses = dataPost.statusDraft.statusDraftList;
String in_reply_to_status = null;
if (dataPost.statusDraft.statusReplyList != null && dataPost.statusDraft.statusReplyList.size() > 0) {
if (dataPost.statusDraft.statusReplyList != null && !dataPost.statusDraft.statusReplyList.isEmpty()) {
in_reply_to_status = dataPost.statusDraft.statusReplyList.get(dataPost.statusDraft.statusReplyList.size() - 1).id;
}
totalMediaSize = 0;
@ -146,13 +149,13 @@ public class ComposeWorker extends Worker {
boolean watermark = sharedPreferences.getBoolean(context.getString(R.string.SET_WATERMARK), false);
String watermarkText = sharedPreferences.getString(context.getString(R.string.SET_WATERMARK_TEXT) + BaseMainActivity.currentUserID + BaseMainActivity.currentInstance, null);
for (int i = startingPosition; i < statuses.size(); i++) {
if (statuses.get(i).media_attachments != null && statuses.get(i).media_attachments.size() > 0) {
if (statuses.get(i).media_attachments != null && !statuses.get(i).media_attachments.isEmpty()) {
for (Attachment attachment : statuses.get(i).media_attachments) {
totalMediaSize += attachment.size;
}
}
}
if (watermarkText == null || watermarkText.trim().length() == 0) {
if (watermarkText == null || watermarkText.trim().isEmpty()) {
try {
BaseAccount account = new Account(context).getAccountByToken(dataPost.token);
watermarkText = account.mastodon_account.username + "@" + account.instance;
@ -163,9 +166,8 @@ public class ComposeWorker extends Worker {
}
dataPost.messageToSend = statuses.size() - startingPosition;
dataPost.messageSent = 0;
List<String> media_edit_id = null;
List<String> media_edit_description = null;
List<String> media_edit_focus = null;
List<StatusParams.MediaParams> media_attributes = null;
for (int i = startingPosition; i < statuses.size(); i++) {
if (dataPost.notificationBuilder != null) {
dataPost.notificationBuilder.setProgress(100, dataPost.messageSent * 100 / dataPost.messageToSend, true);
@ -174,19 +176,19 @@ public class ComposeWorker extends Worker {
}
//post media first
List<String> attachmentIds = null;
if (statuses.get(i).media_attachments != null && statuses.get(i).media_attachments.size() > 0) {
if (statuses.get(i).media_attachments != null && !statuses.get(i).media_attachments.isEmpty()) {
attachmentIds = new ArrayList<>();
for (Attachment attachment : statuses.get(i).media_attachments) {
if (attachment.id != null) {
if (media_edit_id == null) {
media_edit_id = new ArrayList<>();
media_edit_description = new ArrayList<>();
media_edit_focus = new ArrayList<>();
if (media_attributes == null) {
media_attributes = new ArrayList<>();
}
StatusParams.MediaParams mediaParams = new StatusParams.MediaParams();
mediaParams.id = attachment.id;
mediaParams.description = attachment.description;
mediaParams.focus = attachment.focus;
attachmentIds.add(attachment.id);
media_edit_id.add(attachment.id);
media_edit_description.add(attachment.description);
media_edit_focus.add(attachment.focus);
media_attributes.add(mediaParams);
} else {
MultipartBody.Part fileMultipartBody;
if (watermark && attachment.mimeType != null && attachment.mimeType.contains("image")) {
@ -206,7 +208,6 @@ public class ComposeWorker extends Worker {
attachmentIds.add(replyId);
}
}
}
}
List<String> poll_options = null;
@ -248,7 +249,7 @@ public class ComposeWorker extends Worker {
statuses.get(i).text += " \uD83D\uDC41";
}
//Record tags
if (statuses.get(i).text != null && statuses.get(i).text.length() > 0) {
if (statuses.get(i).text != null && !statuses.get(i).text.isEmpty()) {
Matcher matcher = Helper.hashtagPattern.matcher(statuses.get(i).text);
while (matcher.find()) {
int matchStart = matcher.start(1);
@ -257,7 +258,7 @@ public class ComposeWorker extends Worker {
if (matchStart >= 0 && matchEnd < statuses.get(i).text.length()) {
String tag = statuses.get(i).text.substring(matchStart, matchEnd);
tag = tag.replace("#", "");
if (tag.length() > 0) {
if (!tag.isEmpty()) {
try {
new CamelTag(context).insert(tag);
} catch (DBException e) {
@ -271,12 +272,27 @@ public class ComposeWorker extends Worker {
if (dataPost.scheduledDate == null) {
if (dataPost.statusEditId == null) {
statusCall = mastodonStatusesService.createStatus(null, dataPost.token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in,
poll_multiple, poll_hide_totals, statuses.get(i).quote_id == null ? in_reply_to_status : null, statuses.get(i).sensitive, statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null, statuses.get(i).visibility.toLowerCase(), statuses.get(i).language, statuses.get(i).quote_id, statuses.get(i).content_type);
poll_multiple, poll_hide_totals, statuses.get(i).quote_id == null ? in_reply_to_status : null, statuses.get(i).sensitive, statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null, statuses.get(i).visibility.toLowerCase(), statuses.get(i).language, statuses.get(i).quote_id, statuses.get(i).content_type, statuses.get(i).local_only);
} else { //Status is edited
statusCall = mastodonStatusesService.updateStatus(null, dataPost.token, dataPost.statusEditId, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in,
poll_multiple, poll_hide_totals, statuses.get(i).quote_id == null ? in_reply_to_status : null, statuses.get(i).sensitive,
statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null, statuses.get(i).visibility.toLowerCase(), statuses.get(i).language,
media_edit_id, media_edit_description, media_edit_focus);
StatusParams statusParams = new StatusParams();
statusParams.status = statuses.get(i).text;
statusParams.media_ids = attachmentIds;
if(poll_options != null) {
statusParams.pollParams = new StatusParams.PollParams();
statusParams.pollParams.poll_options = poll_options;
statusParams.pollParams.poll_expire_in = poll_expire_in;
statusParams.pollParams.poll_multiple = poll_multiple;
statusParams.pollParams.poll_hide_totals = poll_hide_totals;
}
statusParams.in_reply_to_id = statuses.get(i).quote_id == null ? in_reply_to_status : null;
statusParams.sensitive = statuses.get(i).sensitive;
statusParams.spoiler_text = statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null;
statusParams.visibility = statuses.get(i).visibility.toLowerCase();
statusParams.language = statuses.get(i).language;
statusParams.media_attributes = media_attributes;
statusCall = mastodonStatusesService.updateStatus(null, dataPost.token,
dataPost.statusEditId,
statusParams);
}
try {
Response<Status> statusResponse = statusCall.execute();
@ -363,6 +379,14 @@ public class ComposeWorker extends Worker {
return;
}
} else {
Call<Void> voidCall = mastodonStatusesService.deleteScheduledStatus(dataPost.token, dataPost.scheduledId);
if (voidCall != null) {
try {
voidCall.execute();
} catch (Exception e) {
e.printStackTrace();
}
}
Call<ScheduledStatus> scheduledStatusCall = mastodonStatusesService.createScheduledStatus(null, dataPost.token, statuses.get(i).text, attachmentIds, poll_options, poll_expire_in,
poll_multiple, poll_hide_totals, statuses.get(i).quote_id == null ? in_reply_to_status : null, statuses.get(i).sensitive, statuses.get(i).spoilerChecked ? statuses.get(i).spoiler_text : null, statuses.get(i).visibility.toLowerCase(), dataPost.scheduledDate, statuses.get(i).language);
try {
@ -489,6 +513,7 @@ public class ComposeWorker extends Worker {
}
}
String token = inputData.getString(Helper.ARG_TOKEN);
String scheduledId = inputData.getString(Helper.ARG_SCHEDULED_ID);
String instance = inputData.getString(Helper.ARG_INSTANCE);
String userId = inputData.getString(Helper.ARG_USER_ID);
String scheduledDate = inputData.getString(Helper.ARG_SCHEDULED_DATE);
@ -503,6 +528,7 @@ public class ComposeWorker extends Worker {
DataPost dataPost = new DataPost();
dataPost.instance = instance;
dataPost.token = token;
dataPost.scheduledId = scheduledId;
dataPost.userId = userId;
dataPost.statusDraft = statusDraft;
dataPost.scheduledDate = scheduledDate;
@ -582,6 +608,7 @@ public class ComposeWorker extends Worker {
public String instance;
public String token;
public String userId;
public String scheduledId;
public String statusEditId;
public StatusDraft statusDraft;
public int messageToSend;

View file

@ -1,92 +0,0 @@
package app.fedilab.android.mastodon.services;
/* Copyright 2022 Thomas Schneider
*
* This file is a part of Fedilab
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU General Public License as published by the Free Software Foundation; either version 3 of the
* License, or (at your option) any later version.
*
* Fedilab is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.unifiedpush.android.connector.MessagingReceiver;
import app.fedilab.android.R;
import app.fedilab.android.mastodon.helper.NotificationsHelper;
import app.fedilab.android.mastodon.helper.PushNotifications;
public class CustomReceiver extends MessagingReceiver {
public CustomReceiver() {
super();
}
@Override
public void onMessage(@NotNull Context context, @NotNull byte[] message, @NotNull String slug) {
// Called when a new message is received. The message contains the full POST body of the push message
new Thread(() -> {
try {
/*Notification notification = ECDHFedilab.decryptNotification(context, slug, message);
Log.v(Helper.TAG,"notification: " + notification);
if(notification != null) {
Log.v(Helper.TAG,"id: " + notification.id);
}
*/
NotificationsHelper.task(context, slug);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
@Override
public void onReceive(@NonNull Context context, @NonNull Intent intent) {
super.onReceive(context, intent);
}
@Override
public void onNewEndpoint(@Nullable Context context, @NotNull String endpoint, @NotNull String slug) {
if (context != null) {
synchronized (this) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
String storedEnpoint = sharedpreferences.getString(context.getString(R.string.SET_STORED_ENDPOINT) + slug, null);
if (storedEnpoint == null || !storedEnpoint.equals(endpoint)) {
PushNotifications
.registerPushNotifications(context, endpoint, slug);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(context.getString(R.string.SET_STORED_ENDPOINT) + slug, endpoint);
editor.commit();
}
}
}
}
@Override
public void onRegistrationFailed(@Nullable Context context, @NotNull String s) {
}
@Override
public void onUnregistered(@Nullable Context context, @NotNull String s) {
}
}

View file

@ -0,0 +1,68 @@
package app.fedilab.android.mastodon.services;
import android.content.Context;
import androidx.annotation.NonNull;
import org.unifiedpush.android.connector.FailedReason;
import org.unifiedpush.android.connector.PushService;
import org.unifiedpush.android.connector.data.PushEndpoint;
import org.unifiedpush.android.connector.data.PushMessage;
import app.fedilab.android.mastodon.helper.NotificationsHelper;
import app.fedilab.android.mastodon.helper.PushNotifications;
public class PushServiceImpl extends PushService {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onMessage(@NonNull PushMessage pushMessage, @NonNull String slug) {
new Thread(() -> {
try {
/*if( pushMessage.getDecrypted()) {
String decryptedMessage = new String(pushMessage.getContent(), StandardCharsets.UTF_8);
JSONObject decryptedMessageJSON = new JSONObject(decryptedMessage);
} else {
}*/
NotificationsHelper.task(getApplicationContext(), slug);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
@Override
public void onNewEndpoint(@NonNull PushEndpoint pushEndpoint, @NonNull String slug) {
Context context = getApplicationContext();
if (context != null) {
synchronized (this) {
PushNotifications
.registerPushNotifications(context, pushEndpoint, slug);
}
}
}
@Override
public void onRegistrationFailed(@NonNull FailedReason failedReason, @NonNull String s) {
}
@Override
public void onUnregistered(@NonNull String slug) {
Context context = getApplicationContext();
if (context != null) {
synchronized (this) {
PushNotifications
.unregisterPushNotifications(context, slug);
}
}
}
}

View file

@ -15,6 +15,7 @@ package app.fedilab.android.mastodon.services;
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
@ -22,7 +23,7 @@ import app.fedilab.android.mastodon.jobs.ComposeWorker;
public class ThreadMessageService {
public ThreadMessageService(Context context, String instance, String userId, String token, StatusDraft statusDraft, String scheduledDate, String editMessageId) {
public ThreadMessageService(Context context, String instance, String userId, String token, StatusDraft statusDraft, String scheduledDate, String editMessageId, String scheduledStatusId) {
ComposeWorker.DataPost dataPost = new ComposeWorker.DataPost();
dataPost.instance = instance;
dataPost.userId = userId;
@ -30,6 +31,7 @@ public class ThreadMessageService {
dataPost.scheduledDate = scheduledDate;
dataPost.statusDraft = statusDraft;
dataPost.statusEditId = editMessageId;
dataPost.scheduledId = scheduledStatusId;
ComposeWorker.publishMessage(context, dataPost);
}
}

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -95,9 +93,9 @@ public class AccountAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
accountViewHolder.binding.muteHome.setChecked(muted);
accountViewHolder.binding.muteHome.setOnClickListener(v -> {
if (muted) {
accountsVM.unmuteHome(currentAccount, account).observe((LifecycleOwner) context, account1 -> adapter.notifyItemChanged(accountViewHolder.getLayoutPosition()));
accountsVM.unmuteHome(Helper.getCurrentAccount(context), account).observe((LifecycleOwner) context, account1 -> adapter.notifyItemChanged(accountViewHolder.getLayoutPosition()));
} else {
accountsVM.muteHome(currentAccount, account).observe((LifecycleOwner) context, account1 -> adapter.notifyItemChanged(accountViewHolder.getLayoutPosition()));
accountsVM.muteHome(Helper.getCurrentAccount(context), account).observe((LifecycleOwner) context, account1 -> adapter.notifyItemChanged(accountViewHolder.getLayoutPosition()));
}
});
} else {
@ -114,7 +112,7 @@ public class AccountAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -130,7 +128,7 @@ public class AccountAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, accountSearch);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
@ -106,7 +105,7 @@ public class AccountFollowRequestAdapter extends RecyclerView.Adapter<RecyclerVi
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -15,6 +15,7 @@ package app.fedilab.android.mastodon.ui.drawer;
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.content.SharedPreferences;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -23,14 +24,19 @@ import android.widget.Filter;
import android.widget.Filterable;
import androidx.annotation.NonNull;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.databinding.DrawerAccountSearchBinding;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Field;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.helper.PronounsHelper;
public class AccountsSearchAdapter extends ArrayAdapter<Account> implements Filterable {
@ -116,6 +122,23 @@ public class AccountsSearchAdapter extends ArrayAdapter<Account> implements Filt
holder.binding.accountUn.setText(String.format("@%s", account.acct));
holder.binding.accountDn.setText(account.display_name);
holder.binding.accountDn.setVisibility(View.VISIBLE);
account.pronouns = null;
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(getContext());
boolean pronounsSupport = sharedpreferences.getBoolean(getContext().getString(R.string.SET_PRONOUNS_SUPPORT), true);
if(pronounsSupport) {
for (Field field : account.fields) {
if (PronounsHelper.pronouns.contains(field.name.toLowerCase().trim())) {
account.pronouns = Helper.parseHtml(field.value);
break;
}
}
}
if (account.pronouns != null) {
holder.binding.pronouns.setText(account.pronouns);
holder.binding.pronouns.setVisibility(View.VISIBLE);
} else {
holder.binding.pronouns.setVisibility(View.GONE);
}
MastodonHelper.loadPPMastodon(holder.binding.accountPp, account);
return holder.view;
}

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
@ -67,7 +66,7 @@ public class AccountsSearchTopBarAdapter extends SimpleCursorAdapter {
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, accountList.get(position));
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -16,7 +16,6 @@ package app.fedilab.android.mastodon.ui.drawer;
import static android.content.Context.INPUT_METHOD_SERVICE;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.emojis;
import static app.fedilab.android.BaseMainActivity.instanceInfo;
import static app.fedilab.android.mastodon.activities.ComposeActivity.MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE;
@ -113,6 +112,7 @@ import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Emoji;
import app.fedilab.android.mastodon.client.entities.api.EmojiInstance;
import app.fedilab.android.mastodon.client.entities.api.Field;
import app.fedilab.android.mastodon.client.entities.api.Mention;
import app.fedilab.android.mastodon.client.entities.api.Poll;
import app.fedilab.android.mastodon.client.entities.api.Status;
@ -128,10 +128,12 @@ import app.fedilab.android.mastodon.helper.ComposeHelper;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.LongClickLinkMovementMethod;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.helper.PronounsHelper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.imageeditor.EditImageActivity;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.SearchVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.StatusesVM;
import de.timfreiheit.mathjax.android.MathJaxConfig;
import de.timfreiheit.mathjax.android.MathJaxView;
import es.dmoral.toasty.Toasty;
@ -891,8 +893,8 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
tag.name = camelTag;
if (!results.hashtags.contains(tag)) {
for(Tag realTag: results.hashtags) {
if(realTag.name.equalsIgnoreCase(camelTag)) {
for (Tag realTag : results.hashtags) {
if (realTag.name.equalsIgnoreCase(camelTag)) {
tag.history = realTag.history;
break;
}
@ -1132,12 +1134,12 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
if (statusList.size() > position && statusList.get(position).media_attachments != null) {
holder.binding.attachmentsList.removeAllViews();
List<Attachment> attachmentList = statusList.get(position).media_attachments;
if (attachmentList != null && attachmentList.size() > 0) {
if (attachmentList != null && !attachmentList.isEmpty()) {
holder.binding.sensitiveMedia.setVisibility(View.VISIBLE);
if (!statusList.get(position).sensitive) {
if (currentAccount != null && currentAccount.mastodon_account != null && currentAccount.mastodon_account.source != null) {
holder.binding.sensitiveMedia.setChecked(currentAccount.mastodon_account.source.sensitive);
statusList.get(position).sensitive = currentAccount.mastodon_account.source.sensitive;
if (Helper.getCurrentAccount(context) != null && Helper.getCurrentAccount(context).mastodon_account != null && Helper.getCurrentAccount(context).mastodon_account.source != null) {
holder.binding.sensitiveMedia.setChecked(Helper.getCurrentAccount(context).mastodon_account.source.sensitive);
statusList.get(position).sensitive = Helper.getCurrentAccount(context).mastodon_account.source.sensitive;
} else {
statusList.get(position).sensitive = false;
}
@ -1146,6 +1148,23 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
holder.binding.sensitiveMedia.setOnCheckedChangeListener((buttonView, isChecked) -> statusList.get(position).sensitive = isChecked);
int mediaPosition = 0;
for (Attachment attachment : attachmentList) {
if(attachment.url == null) {
StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class);
statusesVM.getAttachment(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, attachment.id)
.observe((LifecycleOwner) context, attachmentReceived -> {
if(attachmentReceived != null) {
List<Attachment> attachments = statusList.get(position).media_attachments;
for(Attachment attach : attachments) {
if(attach.id != null && attach.id.equals(attachment.id)) {
statusList.get(position).media_attachments.remove(attachment);
break;
}
}
statusList.get(position).media_attachments.add(attachmentReceived);
notifyItemChanged(position);
}
});
}
ComposeAttachmentItemBinding composeAttachmentItemBinding = ComposeAttachmentItemBinding.inflate(LayoutInflater.from(context), holder.binding.attachmentsList, false);
composeAttachmentItemBinding.buttonPlay.setVisibility(View.GONE);
String attachmentPath = attachment.local_path != null && !attachment.local_path.trim().isEmpty() ? attachment.local_path : attachment.preview_url;
@ -1358,6 +1377,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
if (getItemViewType(position) == TYPE_NORMAL) {
Status status = statusList.get(position);
StatusSimpleViewHolder holder = (StatusSimpleViewHolder) viewHolder;
if (status.media_attachments != null && status.media_attachments.size() > 0) {
holder.binding.simpleMedia.removeAllViews();
List<Attachment> attachmentList = statusList.get(position).media_attachments;
@ -1378,7 +1398,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
ArrayList<Attachment> attachments = new ArrayList<>();
attachments.add(attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);
@ -1421,13 +1441,33 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
} else if (getItemViewType(position) == TYPE_COMPOSE) {
Status statusDraft = statusList.get(position);
if (position > 0 && getItemViewType(position - 1) == TYPE_NORMAL) {
Status statusFromUser = statusList.get(position - 1);
Account accountFromUser = statusFromUser.account;
statusFromUser.pronouns = null;
boolean pronounsSupport = sharedpreferences.getBoolean(context.getString(R.string.SET_PRONOUNS_SUPPORT), true);
if(pronounsSupport) {
if (accountFromUser.fields != null && accountFromUser.fields.size() > 0) {
for (Field field : accountFromUser.fields) {
if (PronounsHelper.pronouns.contains(field.name.toLowerCase().trim())) {
statusList.get(position).pronouns = Helper.parseHtml(field.value);
break;
}
}
}
}
}
ComposeViewHolder holder = (ComposeViewHolder) viewHolder;
boolean extraFeatures = sharedpreferences.getBoolean(context.getString(R.string.SET_EXTAND_EXTRA_FEATURES) + MainActivity.currentUserID + MainActivity.currentInstance, false);
boolean mathsComposer = sharedpreferences.getBoolean(context.getString(R.string.SET_MATHS_COMPOSER), true);
boolean forwardTag = sharedpreferences.getBoolean(context.getString(R.string.SET_FORWARD_TAGS_IN_REPLY), false);
if (statusDraft.pronouns != null) {
holder.binding.genders.setVisibility(View.VISIBLE);
holder.binding.pronouns.setText(statusDraft.pronouns);
} else {
holder.binding.genders.setVisibility(View.GONE);
}
if (mathsComposer) {
holder.binding.buttonMathsComposer.setVisibility(View.VISIBLE);
holder.binding.buttonMathsComposer.setOnClickListener(v -> {
@ -1585,8 +1625,8 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
if (statusDraft.visibility == null) {
if (position > 0) {
statusDraft.visibility = statusList.get(position - 1).visibility;
} else if (currentAccount.mastodon_account != null && currentAccount.mastodon_account.source != null) {
statusDraft.visibility = currentAccount.mastodon_account.source.privacy;
} else if (Helper.getCurrentAccount(context).mastodon_account != null && Helper.getCurrentAccount(context).mastodon_account.source != null) {
statusDraft.visibility = Helper.getCurrentAccount(context).mastodon_account.source.privacy;
} else {
statusDraft.visibility = "public";
}
@ -2136,7 +2176,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
builder.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
builder.setTitle(R.string.insert_emoji);
CustomEmojiPickerBinding customEmojiPickerBinding = CustomEmojiPickerBinding.inflate(LayoutInflater.from(context), new LinearLayout(context), false);
if (emojis != null && emojis.size() > 0) {
if (emojis != null && !emojis.isEmpty()) {
customEmojiPickerBinding.gridview.setAdapter(new EmojiAdapter(emojis.get(instance)));
customEmojiPickerBinding.gridview.setOnItemClickListener((parent, view, position, id) -> {
holder.binding.content.getText().insert(holder.binding.content.getSelectionStart(), " :" + Objects.requireNonNull(emojis.get(instance)).get(position).shortcode + ": ");
@ -2150,7 +2190,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
imm.hideSoftInputFromWindow(customEmojiPickerBinding.toolbarSearch.getWindowToken(), 0);
try {
new EmojiInstance(context).getEmojiListFiltered(instance, query.trim(), emojiList -> {
if (emojiList != null && emojiList.size() > 0) {
if (emojiList != null) {
customEmojiPickerBinding.gridview.setAdapter(new EmojiAdapter(emojiList));
customEmojiPickerBinding.gridview.setOnItemClickListener((parent, view, position, id) -> {
holder.binding.content.getText().insert(holder.binding.content.getSelectionStart(), " :" + emojiList.get(position).shortcode + ": ");
@ -2168,7 +2208,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
public boolean onQueryTextChange(String newText) {
try {
new EmojiInstance(context).getEmojiListFiltered(instance, newText.trim(), emojiList -> {
if (emojiList != null && emojiList.size() > 0) {
if (emojiList != null) {
customEmojiPickerBinding.gridview.setAdapter(new EmojiAdapter(emojiList));
customEmojiPickerBinding.gridview.setOnItemClickListener((parent, view, position, id) -> {
holder.binding.content.getText().insert(holder.binding.content.getSelectionStart(), " :" + emojiList.get(position).shortcode + ": ");

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentNightMode;
import android.annotation.SuppressLint;
@ -225,7 +224,7 @@ public class ConversationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, conversation.last_status);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -243,7 +242,7 @@ public class ConversationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, conversation.last_status);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.app.Activity;
import android.content.Context;
@ -79,7 +78,7 @@ public class ImageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
args.putInt(Helper.ARG_MEDIA_POSITION, position + 1);
args.putBoolean(Helper.ARG_MEDIA_ARRAY_PROFILE, true);
if (attachment != null) {
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);
@ -99,7 +98,7 @@ public class ImageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
} else {
return false;
}
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentContext.putExtras(bundle);

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentNightMode;
import static app.fedilab.android.mastodon.ui.drawer.StatusAdapter.statusManagement;
@ -141,56 +140,70 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
String type = notificationList.get(position).type;
if (type != null) {
switch (type) {
case "follow":
case "follow" -> {
return TYPE_FOLLOW;
case "follow_request":
}
case "follow_request" -> {
return TYPE_FOLLOW_REQUEST;
case "mention":
}
case "mention" -> {
if (notificationList.get(position).status != null) {
return TYPE_MENTION;
} else {
return TYPE_HIDDEN;
}
case "reblog":
}
case "reblog" -> {
if (notificationList.get(position).status != null) {
return TYPE_REBLOG;
} else {
return TYPE_HIDDEN;
}
case "update":
}
case "update" -> {
if (notificationList.get(position).status != null) {
return TYPE_UPDATE;
} else {
return TYPE_HIDDEN;
}
case "favourite":
}
case "favourite" -> {
if (notificationList.get(position).status != null) {
return TYPE_FAVOURITE;
} else {
return TYPE_HIDDEN;
}
case "poll":
}
case "poll" -> {
if (notificationList.get(position).status != null) {
return TYPE_POLL;
} else {
return TYPE_HIDDEN;
}
case "status":
}
case "status" -> {
if (notificationList.get(position).status != null) {
return TYPE_STATUS;
} else {
return TYPE_HIDDEN;
}
case "admin.sign_up":
}
case "admin.sign_up" -> {
return TYPE_ADMIN_SIGNUP;
case "admin.report":
}
case "admin.report" -> {
return TYPE_ADMIN_REPORT;
case "pleroma:emoji_reaction":
}
case "pleroma:emoji_reaction" -> {
if (notificationList.get(position).status != null) {
return TYPE_REACTION;
} else {
return TYPE_HIDDEN;
}
}
default -> {
return TYPE_HIDDEN;
}
}
}
return super.getItemViewType(position);
@ -274,7 +287,7 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, notification.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -321,7 +334,7 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
notification.filteredByApp = null;
notifyItemChanged(position);
});
} else if (notification.status != null) {
} else if (notification.status != null && getItemViewType(position) != TYPE_HIDDEN) {
StatusAdapter.StatusViewHolder holderStatus = (StatusAdapter.StatusViewHolder) viewHolder;
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
if (sharedpreferences.getBoolean(context.getString(R.string.SET_CARDVIEW), false)) {
@ -366,28 +379,32 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
SearchVM searchVM = new ViewModelProvider((ViewModelStoreOwner) context).get(SearchVM.class);
if (notification.status != null) {
notification.status.cached = notification.cached;
notification.status.attachedNotification = notification.id;
}
statusManagement(context, statusesVM, searchVM, holderStatus, mRecyclerView, this, null, notification.status, Timeline.TimeLineEnum.NOTIFICATION, false, true, false, null);
holderStatus.bindingNotification.status.dateShort.setText(Helper.dateDiff(context, notification.created_at));
holderStatus.bindingNotification.status.pronouns.setVisibility(View.GONE);
if (getItemViewType(position) == TYPE_MENTION || getItemViewType(position) == TYPE_STATUS || getItemViewType(position) == TYPE_REACTION) {
holderStatus.bindingNotification.status.actionButtons.setVisibility(View.VISIBLE);
String title = "";
if (getItemViewType(position) == TYPE_MENTION) {
title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_mention));
//title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_mention));
title = notification.account.display_name;
} else if (getItemViewType(position) == TYPE_STATUS) {
title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_status));
// title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_status));
title = notification.account.display_name;
} else if (getItemViewType(position) == TYPE_REACTION) {
if (notification.emoji == null) {
notification.emoji = "";
}
title = String.format(Locale.getDefault(), "%s reacted with %s", notification.account.username, notification.emoji);
//title = String.format(Locale.getDefault(), "%s reacted with %s", notification.account.username, notification.emoji);
title = notification.account.username;
MastodonHelper.loadPPMastodon(holderStatus.bindingNotification.status.avatar, notification.account);
holderStatus.bindingNotification.status.statusUserInfo.setOnClickListener(v -> {
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, notification.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -412,17 +429,20 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
String title = "";
MastodonHelper.loadPPMastodon(holderStatus.binding.avatar, notification.account);
if (getItemViewType(position) == TYPE_FAVOURITE) {
title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_favourite));
// title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_favourite));
title = notification.account.display_name;
} else if (getItemViewType(position) == TYPE_REBLOG) {
title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_reblog));
// title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_reblog));
title = notification.account.display_name;
} else if (getItemViewType(position) == TYPE_UPDATE) {
title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_update));
// title = String.format(Locale.getDefault(), "%s %s", notification.account.display_name, context.getString(R.string.notif_update));
title = notification.account.display_name;
} else if (getItemViewType(position) == TYPE_POLL) {
title = context.getString(R.string.notif_poll);
} else if (getItemViewType(position) == TYPE_POLL) {
title = context.getString(R.string.notif_poll);
}
if (notification.relatedNotifications != null && notification.relatedNotifications.size() > 0) {
if (notification.relatedNotifications != null && !notification.relatedNotifications.isEmpty()) {
if (notification.type.equals("favourite")) {
holderStatus.bindingNotification.typeOfConcat.setText(R.string.also_favourite_by);
} else if (notification.type.equals("reblog")) {
@ -437,7 +457,7 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, relativeNotif.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -454,7 +474,7 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, notification.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -465,7 +485,7 @@ public class NotificationAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, notification.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -74,7 +74,7 @@ public class ReleaseNoteAdapter extends RecyclerView.Adapter<ReleaseNoteAdapter.
holder.binding.containerTrans.setVisibility(View.GONE);
holder.binding.translate.setVisibility(View.VISIBLE);
}
holder.binding.translate.setOnClickListener(v -> TranslateHelper.translate(context, note.note, translated -> {
holder.binding.translate.setOnClickListener(v -> TranslateHelper.translate(context, note.note, "en", translated -> {
if (translated != null) {
note.noteTranslated = translated;
notifyItemChanged(holder.getBindingAdapterPosition());

View file

@ -100,14 +100,15 @@ public class ReorderTabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
case GNU:
holder.binding.icon.setImageResource(R.drawable.ic_gnu_social);
break;
case NITTER_TAG:
case NITTER:
holder.binding.icon.setImageResource(R.drawable.nitter);
break;
}
if (pinned.pinnedTimelines.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER) {
if (pinned.pinnedTimelines.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER && pinned.pinnedTimelines.get(position).remoteInstance.type != RemoteInstance.InstanceType.NITTER_TAG) {
holder.binding.text.setText(pinned.pinnedTimelines.get(position).remoteInstance.host);
} else {
if (pinned.pinnedTimelines.get(position).remoteInstance.displayName != null && pinned.pinnedTimelines.get(position).remoteInstance.displayName.trim().length() > 0) {
if (pinned.pinnedTimelines.get(position).remoteInstance.displayName != null && !pinned.pinnedTimelines.get(position).remoteInstance.displayName.trim().isEmpty()) {
holder.binding.text.setText(pinned.pinnedTimelines.get(position).remoteInstance.displayName);
} else {
holder.binding.text.setText(pinned.pinnedTimelines.get(position).remoteInstance.host);
@ -149,6 +150,10 @@ public class ReorderTabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
holder.binding.icon.setImageResource(R.drawable.ic_baseline_bubble_chart_24);
holder.binding.text.setText(R.string.bubble);
break;
case TREND_MESSAGE:
holder.binding.icon.setImageResource(R.drawable.baseline_moving_24);
holder.binding.text.setText(R.string.trending);
break;
}

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.app.Activity;
import android.content.Context;
@ -75,13 +74,13 @@ public class SliderAdapter extends SliderViewAdapter<SliderAdapter.SliderAdapter
if (status.sensitive) {
Glide.with(viewHolder.itemView)
.load(sliderItem.preview_url)
.centerCrop()
.fitCenter()
.apply(new RequestOptions().transform(new BlurTransformation(50, 3)))
.into(viewHolder.binding.ivAutoImageSlider);
} else {
Glide.with(viewHolder.itemView)
.load(sliderItem.preview_url)
.centerCrop()
.fitCenter()
.into(viewHolder.binding.ivAutoImageSlider);
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
@ -108,7 +107,7 @@ public class SliderAdapter extends SliderViewAdapter<SliderAdapter.SliderAdapter
Bundle args = new Bundle();
args.putInt(Helper.ARG_MEDIA_POSITION, position + 1);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(status.media_attachments));
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);

View file

@ -16,7 +16,6 @@ package app.fedilab.android.mastodon.ui.drawer;
import static android.content.Context.INPUT_METHOD_SERVICE;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.BaseMainActivity.currentNightMode;
import static app.fedilab.android.BaseMainActivity.currentUserID;
import static app.fedilab.android.BaseMainActivity.emojis;
@ -35,6 +34,8 @@ import static app.fedilab.android.mastodon.helper.Helper.PREF_USER_ID;
import static app.fedilab.android.mastodon.helper.Helper.PREF_USER_INSTANCE;
import static app.fedilab.android.mastodon.helper.Helper.PREF_USER_SOFTWARE;
import static app.fedilab.android.mastodon.helper.Helper.PREF_USER_TOKEN;
import static app.fedilab.android.mastodon.helper.Helper.TAG;
import static app.fedilab.android.mastodon.helper.Helper.getCurrentAccount;
import android.annotation.SuppressLint;
import android.app.Activity;
@ -58,6 +59,7 @@ import android.os.Looper;
import android.text.Html;
import android.text.SpannableString;
import android.text.TextUtils;
import android.util.Log;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@ -88,6 +90,16 @@ import androidx.fragment.app.Fragment;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.exoplayer.DefaultLoadControl;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.LoadControl;
import androidx.media3.exoplayer.source.ProgressiveMediaSource;
import androidx.media3.exoplayer.upstream.DefaultAllocator;
import androidx.media3.ui.PlayerView;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@ -97,13 +109,6 @@ import com.bumptech.glide.ListPreloader;
import com.bumptech.glide.RequestBuilder;
import com.bumptech.glide.request.RequestOptions;
import com.github.stom79.mytransl.MyTransL;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSource;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.smarteist.autoimageslider.SliderAnimations;
import com.smarteist.autoimageslider.SliderView;
@ -147,6 +152,8 @@ import app.fedilab.android.mastodon.activities.StatusInfoActivity;
import app.fedilab.android.mastodon.activities.TimelineActivity;
import app.fedilab.android.mastodon.activities.admin.AdminAccountActivity;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.Field;
import app.fedilab.android.mastodon.client.entities.api.Notification;
import app.fedilab.android.mastodon.client.entities.api.Poll;
import app.fedilab.android.mastodon.client.entities.api.Reaction;
import app.fedilab.android.mastodon.client.entities.api.Status;
@ -169,6 +176,7 @@ import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.LongClickLinkMovementMethod;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.helper.MediaHelper;
import app.fedilab.android.mastodon.helper.PronounsHelper;
import app.fedilab.android.mastodon.helper.SpannableHelper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.helper.TimelineHelper;
@ -203,6 +211,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
public FetchMoreCallBack fetchMoreCallBack;
private Context context;
private boolean visiblePixelfed;
private boolean pixelfedFullScreenMedia;
private RecyclerView mRecyclerView;
public StatusAdapter(List<Status> statuses, Timeline.TimeLineEnum timelineType, boolean minified, boolean canBeFederated, boolean checkRemotely) {
@ -301,6 +310,47 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Status statusToDeal,
Status statusReturned,
boolean remote) {
manageSubAction(context, holder, typeOfAction, statusToDeal, statusReturned, remote);
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
}
/***
* Methode that will deal with results of actions (bookmark, favourite, boost)
* @param context Context
* @param adapter RecyclerView.Adapter<RecyclerView.ViewHolder>
* @param holder StatusViewHolder used by the reycler
* @param typeOfAction CrossActionHelper.TypeOfCrossAction
* @param statusToDeal Status that received the action
* @param statusReturned Status returned by the API
* @param remote boolean - it's a remote message
*/
private static void manageAction(Context context,
SliderAdapter adapter,
StatusViewHolder holder,
CrossActionHelper.TypeOfCrossAction typeOfAction,
Status statusToDeal,
Status statusReturned,
boolean remote) {
manageSubAction(context, holder, typeOfAction, statusToDeal, statusReturned, remote);
adapter.notifyDataSetChanged();
}
/***
* Methode that will deal with results of actions (bookmark, favourite, boost)
* @param context Context
* @param holder StatusViewHolder used by the reycler
* @param typeOfAction CrossActionHelper.TypeOfCrossAction
* @param statusToDeal Status that received the action
* @param statusReturned Status returned by the API
* @param remote boolean - it's a remote message
*/
private static void manageSubAction(Context context,
StatusViewHolder holder,
CrossActionHelper.TypeOfCrossAction typeOfAction,
Status statusToDeal,
Status statusReturned,
boolean remote) {
if (statusReturned == null) {
switch (typeOfAction) {
case BOOKMARK_ACTION -> statusToDeal.bookmarked = true;
@ -364,8 +414,16 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
StatusCache statusCache = new StatusCache();
statusCache.instance = BaseMainActivity.currentInstance;
statusCache.user_id = BaseMainActivity.currentUserID;
statusCache.status = statusToDeal;
statusCache.status_id = statusToDeal.id;
if(statusToDeal.attachedNotification != null) {
statusCache.notification = new Notification();
statusCache.notification.status = statusToDeal;
statusCache.status_id = statusToDeal.attachedNotification;
statusCache.type = Timeline.TimeLineEnum.NOTIFICATION;
} else {
statusCache.status_id = statusToDeal.id;
statusCache.status = statusToDeal;
}
try {
new StatusCache(context).updateIfExists(statusCache);
} catch (DBException e) {
@ -374,9 +432,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}).start();
}
sendAction(context, Helper.ARG_STATUS_ACTION, statusToDeal, null);
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
}
/**
* Manage status, this method is also reused in notifications timelines
*
@ -390,6 +448,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
* @param status {@link Status}
*/
@SuppressLint("ClickableViewAccessibility")
@androidx.annotation.OptIn(markerClass = androidx.media3.common.util.UnstableApi.class)
public static void statusManagement(Context context,
StatusesVM statusesVM,
SearchVM searchVM,
@ -450,6 +509,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
LinearLayoutCompat.MarginLayoutParams psc = (LinearLayoutCompat.MarginLayoutParams) holder.binding.statusContent.getLayoutParams();
psc.setMarginStart((int) Helper.convertDpToPixel(6, context));
holder.binding.statusContent.setLayoutParams(psc);
LinearLayoutCompat.MarginLayoutParams psq = (LinearLayoutCompat.MarginLayoutParams) holder.binding.quotedMessage.cardviewContainer.getLayoutParams();
psq.setMarginStart((int) Helper.convertDpToPixel(6, context));
holder.binding.quotedMessage.cardviewContainer.setLayoutParams(psq);
LinearLayoutCompat.MarginLayoutParams pct = (LinearLayoutCompat.MarginLayoutParams) holder.binding.containerTrans.getLayoutParams();
pct.setMarginStart((int) Helper.convertDpToPixel(6, context));
holder.binding.containerTrans.setLayoutParams(psc);
@ -477,10 +539,34 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
LinearLayoutCompat.MarginLayoutParams pab = (LinearLayoutCompat.MarginLayoutParams) holder.binding.actionButtons.getLayoutParams();
pab.setMarginStart((int) Helper.convertDpToPixel(6, context));
holder.binding.actionButtons.setLayoutParams(pab);
} else {
LinearLayoutCompat.MarginLayoutParams psq = (LinearLayoutCompat.MarginLayoutParams) holder.binding.quotedMessage.cardviewContainer.getLayoutParams();
psq.setMarginStart((int) Helper.convertDpToPixel(48, context));
holder.binding.quotedMessage.cardviewContainer.setLayoutParams(psq);
}
String loadMediaType = sharedpreferences.getString(context.getString(R.string.SET_LOAD_MEDIA_TYPE), "ALWAYS");
boolean pronounsSupport = sharedpreferences.getBoolean(context.getString(R.string.SET_PRONOUNS_SUPPORT), true);
if(pronounsSupport) {
if (statusToDeal.pronouns == null && statusToDeal.account.fields != null && statusToDeal.account.fields.size() > 0) {
for (Field field : statusToDeal.account.fields) {
if (PronounsHelper.pronouns.contains(field.name.toLowerCase().trim())) {
statusToDeal.pronouns = Helper.parseHtml(field.value);
break;
}
}
if (statusToDeal.pronouns == null) {
statusToDeal.pronouns = "none";
}
}
}
if (statusToDeal.pronouns != null && !statusToDeal.pronouns.equalsIgnoreCase("none")) {
holder.binding.pronouns.setVisibility(View.VISIBLE);
holder.binding.pronouns.setText(statusToDeal.pronouns);
} else {
holder.binding.pronouns.setVisibility(View.GONE);
}
if (statusToDeal.quote != null && (statusToDeal.spoiler_text == null || statusToDeal.spoiler_text.trim().isEmpty() || statusToDeal.isExpended)) {
holder.binding.quotedMessage.cardviewContainer.setCardElevation((int) Helper.convertDpToPixel(5, context));
holder.binding.quotedMessage.dividerCard.setVisibility(View.GONE);
@ -502,15 +588,19 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}
return;
}
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, statusToDeal.quote);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
context.startActivity(intent);
});
if (!remote) {
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, statusToDeal.quote);
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
context.startActivity(intent);
});
} else {
Helper.openBrowser(context,statusToDeal.quote.url);
}
});
holder.binding.quotedMessage.cardviewContainer.setStrokeColor(ThemeHelper.getAttColor(context, R.attr.colorPrimary));
holder.binding.quotedMessage.statusContent.setText(
@ -541,15 +631,17 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
holder.binding.quotedMessage.cardviewContainer.setVisibility(View.GONE);
}
if (currentAccount != null && currentAccount.api == Account.API.PLEROMA || status.reactions != null) {
if (status.pleroma != null && status.pleroma.emoji_reactions != null && status.pleroma.emoji_reactions.size() > 0) {
if (extraFeatures && displayReactions) {
holder.binding.statusAddCustomEmoji.setVisibility(View.VISIBLE);
holder.binding.statusEmoji.setVisibility(View.VISIBLE);
if (status.pleroma != null && status.pleroma.emoji_reactions != null && !status.pleroma.emoji_reactions.isEmpty()) {
holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE);
ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.pleroma.emoji_reactions, true);
holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter);
LinearLayoutManager layoutManager
= new LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false);
holder.binding.layoutReactions.reactionsView.setLayoutManager(layoutManager);
} else if (status.reactions != null && status.reactions.size() > 0) {
} else if (status.reactions != null && !status.reactions.isEmpty()) {
holder.binding.layoutReactions.getRoot().setVisibility(View.VISIBLE);
ReactionAdapter reactionAdapter = new ReactionAdapter(status.id, status.reactions, true, false);
holder.binding.layoutReactions.reactionsView.setAdapter(reactionAdapter);
@ -711,6 +803,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}
builder.show();
});
} else {
holder.binding.statusAddCustomEmoji.setVisibility(View.GONE);
holder.binding.statusEmoji.setVisibility(View.GONE);
}
int truncate_toots_size = sharedpreferences.getInt(context.getString(R.string.SET_TRUNCATE_TOOTS_SIZE), 0);
@ -721,15 +816,6 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
} else {
holder.binding.actionButtonQuote.setVisibility(View.GONE);
}
if (displayReactions) {
holder.binding.statusAddCustomEmoji.setVisibility(View.VISIBLE);
holder.binding.statusEmoji.setVisibility(View.VISIBLE);
} else {
holder.binding.statusAddCustomEmoji.setVisibility(View.GONE);
holder.binding.statusEmoji.setVisibility(View.GONE);
}
}
if (status.isMaths == null) {
@ -940,7 +1026,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, fetchedStatus.reblog != null ? fetchedStatus.reblog.account : fetchedStatus.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -954,7 +1040,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, status.reblog != null ? status.reblog.account : status.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -972,7 +1058,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, fetchedStatus.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -986,7 +1072,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, status.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -1388,15 +1474,24 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
//--- BOOSTER INFO ---
if (status.reblog != null) {
MastodonHelper.loadPPMastodon(holder.binding.statusBoosterAvatar, status.account);
if(status.account.avatar != null) {
MastodonHelper.loadPPMastodon(holder.binding.statusBoosterAvatar, status.account);
holder.binding.statusBoosterAvatar.setVisibility(View.VISIBLE);
} else {
holder.binding.statusBoosterAvatar.setVisibility(View.GONE);
}
holder.binding.statusBoosterDisplayName.setText(
status.account.getSpanDisplayName(context,
new WeakReference<>(holder.binding.statusBoosterDisplayName)),
TextView.BufferType.SPANNABLE);
holder.binding.statusBoosterInfo.setVisibility(View.VISIBLE);
holder.binding.statusBoosterUsername.setText(String.format("@%s", status.account.acct));
if(status.account.acct != null) {
holder.binding.statusBoosterUsername.setText(String.format("@%s", status.account.acct));
holder.binding.statusBoosterUsername.setVisibility(View.VISIBLE);
} else {
holder.binding.statusBoosterUsername.setVisibility(View.GONE);
}
} else {
holder.binding.statusBoosterInfo.setVisibility(View.GONE);
}
@ -1511,9 +1606,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
//--- MEDIA ATTACHMENT ---
boolean cardDisplayed = (statusToDeal.card != null && (display_card || statusToDeal.isFocused) && statusToDeal.quote_id == null);
if (statusToDeal.media_attachments != null && statusToDeal.media_attachments.size() > 0 && (!hideSingleMediaWithCard || !cardDisplayed || statusToDeal.media_attachments.size() > 1)) {
if ((loadMediaType.equals("ASK") || (loadMediaType.equals("WIFI") && !TimelineHelper.isOnWIFI(context))) && !statusToDeal.canLoadMedia) {
holder.binding.mediaContainer.setVisibility(View.GONE);
holder.binding.media.mediaContainer.setVisibility(View.GONE);
holder.binding.displayMedia.setVisibility(View.VISIBLE);
holder.binding.displayMedia.setOnClickListener(v -> {
statusToDeal.canLoadMedia = true;
@ -1522,6 +1617,8 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
}
});
} else {
holder.binding.displayMedia.setVisibility(View.GONE);
holder.binding.media.mediaContainer.setVisibility(View.VISIBLE);
int mediaPosition = 1;
boolean autoplaygif = sharedpreferences.getBoolean(context.getString(R.string.SET_AUTO_PLAY_GIG_MEDIA), true);
if (!fullAttachement || statusToDeal.sensitive) {
@ -1642,7 +1739,18 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
.createMediaSource(mediaItem);
}
try {
ExoPlayer player = new ExoPlayer.Builder(context).build();
int MIN_BUFFER_DURATION = 1024;
int MIN_PLAYBACK_RESUME_BUFFER = 1024;
int MIN_PLAYBACK_START_BUFFER = 1024;
DefaultLoadControl defaultLoadControl = new DefaultLoadControl.Builder()
.setAllocator(new DefaultAllocator(true, 16))
.setBufferDurationsMs(MIN_BUFFER_DURATION,
MIN_BUFFER_DURATION*5,
MIN_PLAYBACK_START_BUFFER,
MIN_PLAYBACK_RESUME_BUFFER)
.setTargetBufferBytes(-1)
.setPrioritizeTimeOverSizeThresholds(true).build();
ExoPlayer player = new ExoPlayer.Builder(context).setLoadControl(defaultLoadControl).build();
player.setRepeatMode(Player.REPEAT_MODE_ONE);
layoutMediaBinding.mediaVideo.setPlayer(player);
player.setMediaSource(videoSource);
@ -1677,7 +1785,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Bundle args = new Bundle();
args.putInt(Helper.ARG_MEDIA_POSITION, finalMediaPosition);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(statusToDeal.media_attachments));
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);
@ -1714,7 +1822,18 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
.createMediaSource(mediaItem);
}
try {
ExoPlayer player = new ExoPlayer.Builder(context).build();
int MIN_BUFFER_DURATION = 1024;
int MIN_PLAYBACK_RESUME_BUFFER = 1024;
int MIN_PLAYBACK_START_BUFFER = 1024;
DefaultLoadControl defaultLoadControl = new DefaultLoadControl.Builder()
.setAllocator(new DefaultAllocator(true, 16))
.setBufferDurationsMs(MIN_BUFFER_DURATION,
MIN_BUFFER_DURATION*5,
MIN_PLAYBACK_START_BUFFER,
MIN_PLAYBACK_RESUME_BUFFER)
.setTargetBufferBytes(-1)
.setPrioritizeTimeOverSizeThresholds(true).build();
ExoPlayer player = new ExoPlayer.Builder(context).setLoadControl(defaultLoadControl).build();
player.setRepeatMode(Player.REPEAT_MODE_ONE);
layoutMediaBinding.mediaVideo.setPlayer(player);
player.setMediaSource(videoSource);
@ -1748,7 +1867,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Bundle args = new Bundle();
args.putInt(Helper.ARG_MEDIA_POSITION, finalMediaPosition);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(statusToDeal.media_attachments));
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);
@ -1789,7 +1908,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
args.putSerializable(Helper.ARG_STATUS, statusToDeal);
args.putSerializable(Helper.ARG_TYPE_OF_INFO, StatusInfoActivity.typeOfInfo.BOOSTED_BY);
args.putBoolean(Helper.ARG_CHECK_REMOTELY, remote);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -1805,7 +1924,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
args.putSerializable(Helper.ARG_STATUS, statusToDeal);
args.putSerializable(Helper.ARG_TYPE_OF_INFO, StatusInfoActivity.typeOfInfo.LIKED_BY);
args.putBoolean(Helper.ARG_CHECK_REMOTELY, remote);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2028,7 +2147,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
if (context instanceof ContextActivity && !remote) {
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, statusToDeal);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
Fragment fragment = Helper.addFragment(((AppCompatActivity) context).getSupportFragmentManager(), R.id.nav_host_fragment_content_main, new FragmentMastodonContext(), bundle, null, FragmentMastodonContext.class.getName());
@ -2044,7 +2163,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
args.putString(Helper.ARG_LEMMY_POST_ID, status.lemmy_post_id);
args.putSerializable(Helper.ARG_STATUS, status);
Intent intent = new Intent(context, TimelineActivity.class);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2061,7 +2180,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, fetchedStatus);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2088,7 +2207,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, statusToDeal);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2105,11 +2224,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
// Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(() -> holder.binding.statusContent.invalidate(), 0, 100, TimeUnit.MILLISECONDS);
if (remote) {
holder.binding.actionButtonMore.setVisibility(View.GONE);
holder.binding.actionButtonMoreContainer.setVisibility(View.GONE);
} else {
holder.binding.actionButtonMore.setVisibility(View.VISIBLE);
holder.binding.actionButtonMoreContainer.setVisibility(View.VISIBLE);
}
holder.binding.actionButtonMore.setOnClickListener(v -> {
holder.binding.actionButtonMoreContainer.setOnClickListener(v -> {
boolean isOwner = statusToDeal.account.id.compareTo(BaseMainActivity.currentUserID) == 0;
PopupMenu popup = new PopupMenu(context, holder.binding.actionButtonMore);
popup.getMenuInflater()
@ -2149,7 +2268,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
popup.getMenu().findItem(R.id.action_block_domain).setVisible(false);
stringArrayConf = context.getResources().getStringArray(R.array.more_action_confirm);
}
popup.getMenu().findItem(R.id.action_admin).setVisible(currentAccount.admin);
popup.getMenu().findItem(R.id.action_admin).setVisible(Helper.getCurrentAccount(context).admin);
boolean custom_sharing = sharedpreferences.getBoolean(context.getString(R.string.SET_CUSTOM_SHARING), false);
if (custom_sharing && statusToDeal.visibility.equals("public"))
@ -2180,7 +2299,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraft);
args.putSerializable(Helper.ARG_STATUS_REPLY_ID, statusDeleted.in_reply_to_id);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2210,7 +2329,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
args.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraft);
args.putString(Helper.ARG_EDIT_STATUS_ID, statusToDeal.id);
args.putString(Helper.ARG_STATUS_REPLY_ID, statusToDeal.in_reply_to_id);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2226,7 +2345,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, AdminAccountActivity.class);
Bundle args = new Bundle();
args.putString(Helper.ARG_ACCOUNT_ID, statusToDeal.account.id);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2283,7 +2402,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
builderInner.setTitle(R.string.mute_home);
builderInner.setMessage(statusToDeal.account.acct);
builderInner.setNeutralButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
builderInner.setPositiveButton(R.string.action_mute, (dialog, which) -> accountsVM.muteHome(currentAccount, statusToDeal.account)
builderInner.setPositiveButton(R.string.action_mute, (dialog, which) -> accountsVM.muteHome(Helper.getCurrentAccount(context), statusToDeal.account)
.observe((LifecycleOwner) context, account -> Toasty.info(context, context.getString(R.string.toast_mute), Toasty.LENGTH_LONG).show()));
builderInner.show();
} else if (itemId == R.id.action_mute_conversation) {
@ -2327,7 +2446,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ReportActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, statusToDeal);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2388,7 +2507,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, CustomSharingActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, statusToDeal);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2398,7 +2517,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS_MENTION, statusToDeal);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2433,7 +2552,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
BaseMainActivity.currentToken = account.token;
BaseMainActivity.currentUserID = account.user_id;
BaseMainActivity.currentInstance = account.instance;
currentAccount = account;
Helper.setCurrentAccount(account);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(PREF_USER_TOKEN, account.token);
editor.putString(PREF_USER_SOFTWARE, account.software);
@ -2459,7 +2578,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
BaseMainActivity.currentToken = account.token;
BaseMainActivity.currentUserID = account.user_id;
BaseMainActivity.currentInstance = account.instance;
currentAccount = account;
Helper.setCurrentAccount(account);
SharedPreferences.Editor editor = sharedpreferences.edit();
editor.putString(PREF_USER_TOKEN, account.token);
editor.putString(PREF_USER_SOFTWARE, account.software);
@ -2486,7 +2605,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
popup.show();
});
holder.binding.actionButtonReply.setOnLongClickListener(v -> {
holder.binding.actionButtonReplyContainer.setOnLongClickListener(v -> {
CrossActionHelper.doCrossAction(context, CrossActionHelper.TypeOfCrossAction.REPLY_ACTION, null, statusToDeal);
return true;
});
@ -2494,14 +2613,14 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_QUOTED_MESSAGE, statusToDeal);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
context.startActivity(intent);
});
});
holder.binding.actionButtonReply.setOnClickListener(v -> {
holder.binding.actionButtonReplyContainer.setOnClickListener(v -> {
if (remote) {
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
@ -2511,7 +2630,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS_REPLY, fetchedStatus);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2528,7 +2647,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
if (status.reblog != null) {
args.putSerializable(Helper.ARG_MENTION_BOOSTER, status.account);
}
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -2545,6 +2664,8 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
if (status.isFetchMore && fetchMoreCallBack != null) {
if (!autofetch) {
DrawerFetchMoreBinding drawerFetchMoreBinding = DrawerFetchMoreBinding.inflate(LayoutInflater.from(context));
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
drawerFetchMoreBinding.fetchMoreContainer.setLayoutParams(lp);
if (status.positionFetchMore == Status.PositionFetchMore.BOTTOM) {
holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
holder.binding.fetchMoreContainerTop.setVisibility(View.VISIBLE);
@ -2640,7 +2761,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
statusToTranslate = Html.fromHtml(statusToDeal.content).toString();
int countMorseChar = ComposeAdapter.countMorseChar(statusToTranslate);
if (countMorseChar < 4) {
TranslateHelper.translate(context, statusToDeal.content, translated -> {
TranslateHelper.translate(context, statusToDeal.content, statusToDeal.language, translated -> {
if (translated != null) {
statusToDeal.translationShown = true;
statusToDeal.translationContent = translated;
@ -2803,7 +2924,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Bundle args = new Bundle();
args.putInt(Helper.ARG_MEDIA_POSITION, mediaPosition);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(statusToDeal.media_attachments));
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);
@ -2871,7 +2992,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
args.putBoolean(ARG_TIMELINE_REFRESH_ALL, true);
}
Intent intentBC = new Intent(Helper.RECEIVE_STATUS_ACTION);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentBC.putExtras(bundle);
@ -3051,8 +3172,14 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
if (isVisible(timelineType, statusList.get(position), statusList)) {
if (visiblePixelfed && isVisiblePixelfed(statusList.get(position)) && timelineType != Timeline.TimeLineEnum.UNKNOWN) {
return STATUS_PIXELFED;
} else {
return STATUS_VISIBLE;
} else if(timelineType == Timeline.TimeLineEnum.REMOTE && pinnedTimeline != null && pinnedTimeline.remoteInstance != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.PIXELFED){
return STATUS_PIXELFED;
}else {
if(pixelfedFullScreenMedia && timelineType != Timeline.TimeLineEnum.UNKNOWN && getCurrentAccount(context).software != null && getCurrentAccount(context).software.trim().toLowerCase().equals("pixelfed")) {
return STATUS_PIXELFED;
} else {
return STATUS_VISIBLE;
}
}
} else {
return STATUS_HIDDEN;
@ -3068,6 +3195,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
context = parent.getContext();
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
visiblePixelfed = sharedpreferences.getBoolean(context.getString(R.string.SET_PIXELFED_PRESENTATION) + MainActivity.currentUserID + MainActivity.currentInstance, false);
pixelfedFullScreenMedia = sharedpreferences.getBoolean(context.getString(R.string.SET_PIXELFED_FULL_MEDIA) + MainActivity.currentUserID + MainActivity.currentInstance, true);
if (viewType == STATUS_HIDDEN) { //Hidden statuses - ie: filtered
DrawerStatusHiddenBinding itemBinding = DrawerStatusHiddenBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new StatusViewHolder(itemBinding);
@ -3262,7 +3390,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, status.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -3277,7 +3405,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
ArrayList<Attachment> attachments = new ArrayList<>();
attachments.add(status.art_attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);
@ -3293,7 +3421,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, status);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -3303,14 +3431,36 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
} else if (viewHolder.getItemViewType() == STATUS_PIXELFED) {
Status statusToDeal = status.reblog != null ? status.reblog : status;
StatusViewHolder holder = (StatusViewHolder) viewHolder;
if (measuredWidthArt <= 0) {
holder.bindingPixelfed.artMedia.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
holder.bindingPixelfed.artMedia.getViewTreeObserver().removeOnGlobalLayoutListener(this);
measuredWidthArt = holder.bindingPixelfed.artMedia.getWidth();
notifyItemChanged(0, statusList.size());
}
});
}
ConstraintLayout.LayoutParams lp;
if(!status.media_attachments.isEmpty() && status.media_attachments.get(0).meta != null && status.media_attachments.get(0).meta.getSmall() != null) {
float mediaH = status.media_attachments.get(0).meta.getSmall().height;
float mediaW = status.media_attachments.get(0).meta.getSmall().width;
float ratio = measuredWidthArt > 0 ? measuredWidthArt / mediaW : 1.0f;
lp = new ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.MATCH_PARENT, (int) (mediaH * ratio));
//holder.bindingPixelfed.artMedia.setScaleType(ImageView.ScaleType.FIT_CENTER);
holder.bindingPixelfed.artMedia.setLayoutParams(lp);
}
if (status.reblog != null) {
MastodonHelper.loadPPMastodon(holder.bindingPixelfed.artReblogPp, status.account);
holder.bindingPixelfed.artReblogPp.setVisibility(View.VISIBLE);
} else {
holder.bindingPixelfed.artReblogPp.setVisibility(View.GONE);
}
boolean remote = timelineType == Timeline.TimeLineEnum.REMOTE || checkRemotely;
SearchVM searchVM = new ViewModelProvider((ViewModelStoreOwner) context).get(SearchVM.class);
StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean confirmFav = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION_FAV), false);
MastodonHelper.loadPPMastodon(holder.bindingPixelfed.artPp, statusToDeal.account);
SliderAdapter adapter = new SliderAdapter(statusToDeal);
holder.bindingPixelfed.artMedia.setSliderAdapter(adapter);
@ -3319,6 +3469,83 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
holder.bindingPixelfed.artMedia.setScrollTimeInSec(4);
holder.bindingPixelfed.artMedia.startAutoCycle();
holder.bindingPixelfed.commentNumber.setText(String.valueOf(statusToDeal.replies_count));
holder.bindingPixelfed.actionButtonLike.setActiveImage(R.drawable.ic_heart_filled_24);
holder.bindingPixelfed.actionButtonLike.setInactiveImage(R.drawable.ic_heart_24);
holder.bindingPixelfed.actionButtonLike.setActiveImageTint(R.color.red_color_picker);
holder.bindingPixelfed.actionButtonLike.setChecked(statusToDeal.favourited);
float normalSize = Helper.convertDpToPixel(28, context);
final float scaleIcon = sharedpreferences.getFloat(context.getString(R.string.SET_FONT_SCALE_ICON), 1.1f);
holder.bindingPixelfed.actionButtonLike.setImageSize((int) (normalSize * scaleIcon));
holder.bindingPixelfed.actionButtonLike.setOnLongClickListener(v -> {
if (statusToDeal.visibility.equals("direct") || (statusToDeal.visibility.equals("private"))) {
return true;
}
CrossActionHelper.doCrossAction(context, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, null, statusToDeal);
return true;
});
holder.bindingPixelfed.actionButtonLike.setOnClickListener(v -> {
if (confirmFav) {
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(context);
if (status.favourited) {
alt_bld.setMessage(context.getString(R.string.favourite_remove));
} else {
alt_bld.setMessage(context.getString(R.string.favourite_add));
}
alt_bld.setPositiveButton(R.string.yes, (dialog, id) -> {
if (remote) {
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
.observe((LifecycleOwner) context, results -> {
if (results != null && results.statuses != null && !results.statuses.isEmpty()) {
Status fetchedStatus = results.statuses.get(0);
statusesVM.favourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchedStatus.id)
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, holder, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, true));
} else {
Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show();
}
});
} else {
if (status.favourited) {
statusesVM.unFavourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, holder, CrossActionHelper.TypeOfCrossAction.UNFAVOURITE_ACTION, statusToDeal, _status, false));
} else {
((SparkButton) v).playAnimation();
statusesVM.favourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, holder, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, false));
}
}
dialog.dismiss();
});
alt_bld.setNegativeButton(R.string.cancel, (dialog, id) -> dialog.dismiss());
AlertDialog alert = alt_bld.create();
alert.show();
} else {
if (remote) {
Toasty.info(context, context.getString(R.string.retrieve_remote_status), Toasty.LENGTH_SHORT).show();
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.uri, null, "statuses", false, true, false, 0, null, null, 1)
.observe((LifecycleOwner) context, results -> {
if (results != null && results.statuses != null && !results.statuses.isEmpty()) {
Status fetchedStatus = results.statuses.get(0);
statusesVM.favourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, fetchedStatus.id)
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, holder, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, true));
} else {
Toasty.info(context, context.getString(R.string.toast_error_search), Toasty.LENGTH_SHORT).show();
}
});
} else {
if (statusToDeal.favourited) {
statusesVM.unFavourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, holder, CrossActionHelper.TypeOfCrossAction.UNFAVOURITE_ACTION, statusToDeal, _status, false));
} else {
((SparkButton) v).playAnimation();
statusesVM.favourite(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, statusToDeal.id)
.observe((LifecycleOwner) context, _status -> manageAction(context, adapter, holder, CrossActionHelper.TypeOfCrossAction.FAVOURITE_ACTION, statusToDeal, _status, false));
}
}
}
});
holder.bindingPixelfed.artUsername.setText(
statusToDeal.account.getSpanDisplayName(context,
new WeakReference<>(holder.bindingPixelfed.artUsername)),
@ -3328,7 +3555,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, statusToDeal.account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -3339,7 +3566,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
Intent intent = new Intent(context, ContextActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS, statusToDeal);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -15,7 +15,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import static app.fedilab.android.mastodon.ui.drawer.StatusAdapter.prepareRequestBuilder;
import android.app.Activity;
@ -49,17 +48,17 @@ import androidx.core.content.ContextCompat;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ViewModelProvider;
import androidx.lifecycle.ViewModelStoreOwner;
import androidx.media3.common.MediaItem;
import androidx.media3.common.Player;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.source.ProgressiveMediaSource;
import androidx.media3.ui.PlayerView;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.RequestBuilder;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSource;
import org.jetbrains.annotations.NotNull;
@ -196,7 +195,7 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter<RecyclerVie
Bundle args = new Bundle();
args.putInt(Helper.ARG_MEDIA_POSITION, mediaPosition);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(status.media_attachments));
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);
@ -675,7 +674,7 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter<RecyclerVie
Bundle args = new Bundle();
args.putInt(Helper.ARG_MEDIA_POSITION, finalMediaPosition);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, new ArrayList<>(status.media_attachments));
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
mediaIntent.putExtras(bundle);

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -106,7 +104,7 @@ public class StatusDraftAdapter extends RecyclerView.Adapter<StatusDraftAdapter.
Intent intent = new Intent(context, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraft);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -137,9 +135,9 @@ public class StatusDraftAdapter extends RecyclerView.Adapter<StatusDraftAdapter.
}
}
//If there are media, we need to remove them first.
if (attachments.size() > 0) {
if (!attachments.isEmpty()) {
for (Attachment attachment : attachments) {
if (attachment.local_path != null) {
if (attachment != null && attachment.local_path != null) {
File fileToDelete = new File(attachment.local_path);
if (fileToDelete.exists()) {
//noinspection ResultOfMethodCallIgnored

View file

@ -16,7 +16,7 @@ package app.fedilab.android.mastodon.ui.drawer;
import static androidx.core.text.HtmlCompat.FROM_HTML_MODE_LEGACY;
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
@ -46,6 +46,7 @@ import app.fedilab.android.R;
import app.fedilab.android.databinding.DrawerStatusScheduledBinding;
import app.fedilab.android.mastodon.activities.ComposeActivity;
import app.fedilab.android.mastodon.client.entities.api.ScheduledStatus;
import app.fedilab.android.mastodon.client.entities.api.Tag;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.client.entities.app.ScheduledBoost;
import app.fedilab.android.mastodon.client.entities.app.StatusDraft;
@ -127,11 +128,15 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
}
holder.binding.cardviewContainer.setOnClickListener(v -> {
if (statusDraft != null) {
if (statusDraftList != null || scheduledStatuses != null) {
Intent intent = new Intent(context, ComposeActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraft);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
if(statusDraftList != null) {
args.putSerializable(Helper.ARG_STATUS_DRAFT, statusDraftList.get(position));
} else {
args.putSerializable(Helper.ARG_STATUS_SCHEDULED, scheduledStatuses.get(position));
}
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -150,7 +155,7 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
.observe((LifecycleOwner) context, unused -> {
if (scheduledStatuses != null) {
scheduledStatuses.remove(scheduledStatus);
if (scheduledStatuses.size() == 0) {
if (scheduledStatuses.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);
@ -162,7 +167,7 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
WorkManager.getInstance(context).cancelWorkById(statusDraft.workerUuid);
if (statusDraftList != null) {
statusDraftList.remove(statusDraft);
if (statusDraftList.size() == 0) {
if (statusDraftList.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);
@ -176,7 +181,7 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
WorkManager.getInstance(context).cancelWorkById(scheduledBoost.workerUuid);
if (scheduledBoosts != null) {
scheduledBoosts.remove(scheduledBoost);
if (scheduledBoosts.size() == 0) {
if (scheduledBoosts.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -90,7 +88,7 @@ public class SuggestionAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
Intent intent = new Intent(context, ProfileActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, account);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -14,7 +14,6 @@ package app.fedilab.android.mastodon.ui.drawer;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
@ -105,7 +104,7 @@ public class TagAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
Intent intent = new Intent(context, HashTagActivity.class);
Bundle args = new Bundle();
args.putString(Helper.ARG_SEARCH_KEYWORD, tag.name.trim());
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);

View file

@ -14,6 +14,7 @@ package app.fedilab.android.mastodon.ui.drawer;
* You should have received a copy of the GNU General Public License along with Fedilab; if not,
* see <http://www.gnu.org/licenses>. */
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
@ -30,6 +31,7 @@ import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.mastodon.activities.HashTagActivity;
import app.fedilab.android.mastodon.client.entities.api.Tag;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.helper.Helper;
@ -63,9 +65,15 @@ public class TagSearchTopBarAdapter extends SimpleCursorAdapter {
if (tags != null && tags.size() > position) {
Intent intent = new Intent(context, HashTagActivity.class);
Bundle b = new Bundle();
b.putString(Helper.ARG_SEARCH_KEYWORD, tags.get(position).name.trim());
intent.putExtras(b);
context.startActivity(intent);
String tag = tags.get(position).name.trim().replace("#","");
b.putString(Helper.ARG_SEARCH_KEYWORD, tag.trim());
new CachedBundle(context).insertBundle(b, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
});
}
});
}

View file

@ -11,8 +11,6 @@ import android.widget.Filterable;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import com.github.mikephil.charting.data.Entry;
import java.util.ArrayList;
import java.util.List;
@ -125,7 +123,7 @@ public class TagsSearchAdapter extends ArrayAdapter<Tag> implements Filterable {
stat += Integer.parseInt(history.accounts);
}
}
if(stat > 0 ) {
if (stat > 0) {
holder.binding.tagCount.setText("(" + context.getString(R.string.talking_about, stat) + ")");
holder.binding.tagCount.setVisibility(View.VISIBLE);
} else {

View file

@ -15,8 +15,6 @@ package app.fedilab.android.mastodon.ui.drawer.admin;
* see <http://www.gnu.org/licenses>. */
import static app.fedilab.android.BaseMainActivity.currentAccount;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -82,7 +80,7 @@ public class AdminAccountAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Intent intent = new Intent(context, AdminAccountActivity.class);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_ACCOUNT, adminAccount);
new CachedBundle(context).insertBundle(args, currentAccount, bundleId -> {
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
@ -97,7 +95,7 @@ public class AdminAccountAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
holder.binding.email.setText(adminAccount.email);
if (adminAccount.ip != null) {
holder.binding.ip.setText(adminAccount.ip);
} else if (adminAccount.ips != null && adminAccount.ips.size() > 0) {
} else if (adminAccount.ips != null && !adminAccount.ips.isEmpty()) {
holder.binding.lastActive.setText(Helper.shortDateToString(adminAccount.ips.get(0).used_at));
holder.binding.ip.setText(adminAccount.ips.get(0).ip);
} else {

View file

@ -33,6 +33,7 @@ import app.fedilab.android.databinding.DrawerReportBinding;
import app.fedilab.android.mastodon.activities.AccountReportActivity;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.admin.AdminReport;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MastodonHelper;
@ -61,8 +62,8 @@ public class ReportAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
AdminReport report = reports.get(position);
Account account = report.account.account;
Account target_account = report.target_account.account;
if (account.display_name == null || account.display_name.trim().equals("")) {
if (account.display_name != null && !account.display_name.trim().equals(""))
if (account.display_name == null || account.display_name.trim().isEmpty()) {
if (account.display_name != null && !account.display_name.trim().isEmpty())
holder.binding.accountDnReporter.setText(account.display_name);
else
holder.binding.accountDnReporter.setText(account.username.replace("@", ""));
@ -91,10 +92,15 @@ public class ReportAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
holder.binding.mainContainer.setOnClickListener(view -> {
Intent intent = new Intent(context, AccountReportActivity.class);
Bundle b = new Bundle();
b.putSerializable(Helper.ARG_REPORT, report);
intent.putExtras(b);
context.startActivity(intent);
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_REPORT, report);
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
});
});
}

View file

@ -116,7 +116,7 @@ public class FragmentAdminReport extends Fragment {
.observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
});
if (adminReports == null || adminReports.adminReports == null || adminReports.adminReports.size() == 0) {
if (adminReports == null || adminReports.adminReports == null || adminReports.adminReports.isEmpty()) {
binding.noAction.setVisibility(View.VISIBLE);
return;
}
@ -188,7 +188,7 @@ public class FragmentAdminReport extends Fragment {
return;
}
binding.loadingNextElements.setVisibility(View.GONE);
if (adminReports != null && admReports != null && admReports.adminReports != null && admReports.adminReports.size() > 0) {
if (adminReports != null && admReports != null && admReports.adminReports != null && !admReports.adminReports.isEmpty()) {
flagLoading = admReports.pagination.max_id == null;
//There are some adminReports present in the timeline
int startId = adminReports.size();

View file

@ -21,7 +21,6 @@ import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -30,21 +29,23 @@ import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.media3.common.MediaItem;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.DataSource;
import androidx.media3.datasource.DefaultDataSource;
import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.source.ProgressiveMediaSource;
import androidx.preference.PreferenceManager;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DefaultDataSource;
import com.r0adkll.slidr.Slidr;
import com.r0adkll.slidr.model.SlidrConfig;
import com.r0adkll.slidr.model.SlidrInterface;
@ -78,6 +79,7 @@ public class FragmentMedia extends Fragment {
}
@OptIn(markerClass = UnstableApi.class)
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -86,10 +88,20 @@ public class FragmentMedia extends Fragment {
if (bundle != null) {
attachment = (Attachment) bundle.getSerializable(Helper.ARG_MEDIA_ATTACHMENT);
}
binding.controls.hide();
return binding.getRoot();
}
@OptIn(markerClass = UnstableApi.class)
public void toggleController(boolean display) {
if (display) {
binding.controls.show();
} else {
binding.controls.hide();
}
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
@ -198,6 +210,9 @@ public class FragmentMedia extends Fragment {
@Override
public void onLoadFailed(@Nullable Drawable errorDrawable) {
if (binding == null || !isAdded() || getActivity() == null) {
return;
}
scheduleStartPostponedTransition(binding.mediaPicture);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
boolean autofetch = sharedpreferences.getBoolean(getString(R.string.SET_FETCH_REMOTE_MEDIA), false);
@ -227,9 +242,7 @@ public class FragmentMedia extends Fragment {
);
}
switch (type.toLowerCase()) {
case "video":
case "audio":
case "gifv":
case "video", "audio", "gifv" -> {
if (attachment.peertubeId != null) {
//It's a peertube video, we are fetching data
TimelinesVM timelinesVM = new ViewModelProvider(requireActivity()).get(TimelinesVM.class);
@ -244,11 +257,11 @@ public class FragmentMedia extends Fragment {
} else {
loadVideo(url, type);
}
break;
}
}
}
@androidx.annotation.OptIn(markerClass = androidx.media3.common.util.UnstableApi.class)
private void loadVideo(String url, String type) {
if (binding == null || !isAdded() || getActivity() == null || url == null) {
return;
@ -275,14 +288,6 @@ public class FragmentMedia extends Fragment {
player.setRepeatMode(Player.REPEAT_MODE_ONE);
binding.mediaVideo.setUseController(false);
}
binding.mediaVideo.setOnTouchListener((view, motionEvent) -> {
if (binding.controls.getVisibility() != View.VISIBLE) {
binding.controls.setVisibility(View.VISIBLE);
final Handler handler = new Handler(Looper.getMainLooper());
handler.postDelayed(() -> binding.controls.setVisibility(View.GONE), 2000);
}
return false;
});
binding.mediaVideo.setPlayer(player);
binding.controls.setPlayer(player);
binding.loader.setVisibility(View.GONE);

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