Compare commits

...

108 commits
3.32.0 ... main

Author SHA1 Message Date
Thomas
cf022002c5 Release 3.33.1 2025-06-06 18:53:44 +02:00
Thomas
4b4b6c49b2 Release 3.33.0 2025-06-06 15:28:38 +02:00
Thomas
49cc9a187e some release notes 2025-06-06 15:21:47 +02:00
Thomas
b954708e3a Fix issue #1238 - Improve language picker when filtered with some languages 2025-06-06 14:52:00 +02:00
Thomas
0fcd1c6d4b Merge remote-tracking branch 'origin/develop' into develop 2025-06-06 11:29:29 +02:00
Thomas
1c2c6f404a Add/Remove featured tags from profile editor 2025-06-06 11:29:00 +02:00
Thomas
2e33cd58f5 Add some margin to delete buttons 2025-06-06 10:42:08 +02:00
Thomas
c5e096728e Change layout for featured hashtags 2025-06-06 10:34:34 +02:00
Thomas
b0c11f5c2c Change layout for custom fields 2025-06-06 10:16:28 +02:00
Thomas
c0b6bbd4ea Change profile activity to manage featured hashtags 2025-06-06 09:50:06 +02:00
Christof Damian
442e27760a
Translated using Weblate (German)
Currently translated at 99.0% (1218 of 1230 strings)

Co-authored-by: Christof Damian <christof@damian.net>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2025-06-06 03:01:52 +02:00
Thomas
d514c7b8d6 Featured tags displayed in profiles 2025-06-05 17:34:51 +02:00
Thomas
5b843291a7 improve fields 2025-06-05 15:39:57 +02:00
Thomas
8a9b0d897f Fix embedded quotes not displayed 2025-06-05 11:56:54 +02:00
Thomas
e051bec7a0 Fix a memory leak for not cropped media 2025-06-05 11:22:50 +02:00
Thomas
6a74a35efe Merge remote-tracking branch 'origin/develop' into develop 2025-06-05 10:33:04 +02:00
Thomas
723771e464 Fix a memory leak for not cropped media 2025-06-05 10:32:39 +02:00
Thomas
b1b3c5230c Change regex for bottom tags 2025-06-05 09:37:57 +02:00
Thomas
764e3a1762 Fix a crash with long threads 2025-06-05 07:35:17 +02:00
大王叫我来巡山
a71fa29f72
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1230 of 1230 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-06-04 17:02:18 +02:00
josé m
cb2c811970
Translated using Weblate (Galician)
Currently translated at 100.0% (1230 of 1230 strings)

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

Translated using Weblate (Ukrainian)

Currently translated at 100.0% (1228 of 1228 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic4@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-06-04 17:02:09 +02:00
Thomas
a79121a8dd #1214 - Support Trending Links 2025-06-03 16:38:00 +02:00
Thomas
293a811392 #1219 - highlight bottom hashtags 2025-06-03 11:38:31 +02:00
Thomas
1df2cba3d0 Merge remote-tracking branch 'origin/develop' into develop 2025-06-03 09:15:57 +02:00
Thomas
5e2e91df3d Merge branch '0xd9a-update_peertube_picker_drawer' into develop 2025-06-03 09:15:01 +02:00
dicaeffe
b06a5731bd
Translated using Weblate (Italian)
Currently translated at 20.0% (7 of 35 strings)

Co-authored-by: dicaeffe <dicaeffe@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/it/
Translation: Fedilab/description
2025-06-02 19:37:18 +02:00
dicaeffe
dfe30f9bfb
Translated using Weblate (Italian)
Currently translated at 99.5% (1220 of 1226 strings)

Co-authored-by: dicaeffe <dicaeffe@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/it/
Translation: Fedilab/Strings
2025-06-02 19:37:05 +02:00
Thomas
477b2bfc3b #1237 - Wrong messages deleted for scheduled (messages and boosts) 2025-06-02 07:58:08 +02:00
Thomas
e6a8a45e03 Merge remote-tracking branch 'origin/develop' into develop 2025-06-01 10:46:09 +02:00
Thomas
e93d6660f1 #1222 - Open toot by tapping on Scheduled Boost 2025-06-01 10:45:58 +02:00
Thomas
65383b8787 #1165 - Improve animated emoji 2025-06-01 09:53:17 +02:00
Yurt Page
5d78347d3f
Translated using Weblate (Russian)
Currently translated at 93.3% (1144 of 1226 strings)

Co-authored-by: Yurt Page <yurtpage@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2025-05-28 01:06:31 +02:00
Thomas
02a066a253 Avoid a crash when max_char defined by the instance is not an integer 2025-05-27 08:06:16 +02:00
Thomas
749aefe858 Merge remote-tracking branch 'origin/develop' into develop 2025-05-26 12:06:30 +02:00
Thomas
15e10958b8 Add confirmation dialog when long pressing the boost button 2025-05-26 12:03:14 +02:00
Thomas
a12e2910c5 Fix issue #1217 - Pleroma instances cannot select media 2025-05-26 10:18:41 +02:00
Thomas
7e6d0a5c6e Fix issue #1220 - Limits number of fetch for filters 2025-05-26 09:41:31 +02:00
Moonshadow
e9ce3bd664
Translated using Weblate (Kabyle)
Currently translated at 2.8% (1 of 35 strings)

Co-authored-by: Moonshadow <moonshadow@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/kab/
Translation: Fedilab/description
2025-05-25 17:42:43 +02:00
abdelbasset jabrane
7dc61b8aaf
Translated using Weblate (Arabic)
Currently translated at 51.4% (18 of 35 strings)

Co-authored-by: abdelbasset jabrane <naminio201@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ar/
Translation: Fedilab/description
2025-05-21 19:03:43 +00:00
abdelbasset jabrane
ebdaa79c81
Translated using Weblate (Arabic)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: abdelbasset jabrane <naminio201@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ar/
Translation: Fedilab/Strings
2025-05-18 12:01:48 +02:00
Максим Горпиніч
d8abb4213e
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic4@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-05-17 05:02:42 +00:00
0xd9a
b77d87ccb1 Make pickup button more visible 2025-05-13 20:04:54 +05:30
0xd9a
c611438172 Update Peertube Instance Picker Drawer 2025-05-13 19:41:24 +05:30
Jean-Luc Tibaux
7aa02a8b15
Translated using Weblate (French)
Currently translated at 99.3% (1218 of 1226 strings)

Co-authored-by: Jean-Luc Tibaux <eugentoptic@outlook.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2025-05-12 00:03:12 +02:00
Wydow
e1da85235d
Translated using Weblate (French)
Currently translated at 99.3% (1218 of 1226 strings)

Co-authored-by: Wydow <wydow@tutanota.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2025-05-12 00:03:12 +02:00
Dream X
cca71af7c2
Translated using Weblate (French)
Currently translated at 99.3% (1218 of 1226 strings)

Translated using Weblate (Spanish)

Currently translated at 97.3% (1194 of 1226 strings)

Translated using Weblate (Welsh)

Currently translated at 52.2% (640 of 1226 strings)

Co-authored-by: Dream X <nodem49316@daupload.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cy/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/es/
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fr/
Translation: Fedilab/Strings
2025-05-12 00:03:12 +02:00
Dream X
c83acd6b17
Translated using Weblate (Spanish)
Currently translated at 8.5% (3 of 35 strings)

Co-authored-by: Dream X <nodem49316@daupload.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/es/
Translation: Fedilab/description
2025-05-12 00:03:00 +02:00
Joan Pujolar
df50f40843
Translated using Weblate (Catalan)
Currently translated at 100.0% (35 of 35 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ca/
Translation: Fedilab/description
2025-05-09 05:02:03 +00:00
Joan Pujolar
d6e78e78ba
Translated using Weblate (Catalan)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2025-05-08 20:03:17 +02:00
Joan Pujolar
cbea08af24
Translated using Weblate (Catalan)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2025-05-08 04:03:09 +02:00
Joan Pujolar
db984a485f
Translated using Weblate (Catalan)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2025-05-07 09:01:52 +00:00
Bob Idle
a09d08b826
Translated using Weblate (German)
Currently translated at 98.5% (1208 of 1226 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-05-06 08:06:17 +02:00
Joan Pujolar
200488fa6a
Translated using Weblate (Catalan)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2025-05-06 08:06:17 +02:00
Joan Pujolar
18ae76c6f7
Translated using Weblate (Catalan)
Currently translated at 17.1% (6 of 35 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/ca/
Translation: Fedilab/description
2025-05-05 08:56:41 +02:00
Joan Pujolar
7e2b3d0c8f
Translated using Weblate (Catalan)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2025-05-05 08:56:30 +02:00
Bob Idle
e889b19673
Translated using Weblate (German)
Currently translated at 98.5% (1208 of 1226 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-05-05 05:30:51 +02:00
Joan Pujolar
e1cb74911a
Translated using Weblate (Catalan)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: Joan Pujolar <joan.pujolar@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ca/
Translation: Fedilab/Strings
2025-05-05 05:30:51 +02:00
Vaclovas Intas
1f4503cd96
Translated using Weblate (Lithuanian)
Currently translated at 31.8% (391 of 1226 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/lt/
Translation: Fedilab/Strings
2025-05-02 11:12:48 +00:00
Vaclovas Intas
5a51c48302
Translated using Weblate (Lithuanian)
Currently translated at 8.5% (3 of 35 strings)

Co-authored-by: Vaclovas Intas <Gateway_31@protonmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/lt/
Translation: Fedilab/description
2025-05-02 12:02:19 +02:00
Poesty Li
c821c96396
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (35 of 35 strings)

Co-authored-by: Poesty Li <poesty7450@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/zh_Hans/
Translation: Fedilab/description
2025-04-28 07:01:52 +02:00
josé m
1374bfdca9
Translated using Weblate (Galician)
Currently translated at 45.7% (16 of 35 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/gl/
Translation: Fedilab/description
2025-04-26 05:29:57 +02:00
Максим Горпиніч
5f83abff97
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (35 of 35 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-04-25 22:25:46 +02:00
Thomas
e69c46661d Merge remote-tracking branch 'origin/main' 2025-04-25 15:40:57 +02:00
Thomas
66f2bd4639 Release 3.32.3 2025-04-25 15:40:32 +02:00
Thomas
96fa8abbfa Fix trend messages repeated in the timeline 2025-04-25 15:18:49 +02:00
Thomas
9216c86658 Merge pull request 'Add Misskey URL basic support' (#1180) from AntoninDelFabbro/Fedilab:misskey-url into main
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1180
2025-04-25 04:53:18 +00:00
0xd9a
786a4bc846 Fix: Polls without CWs not viewable 2025-04-24 02:15:17 +05:30
josé m
b06fc3e952
Translated using Weblate (Galician)
Currently translated at 100.0% (1226 of 1226 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2025-04-23 10:14:58 +02:00
大王叫我来巡山
4ea7e592a2
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1226 of 1226 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-04-23 02:03:20 +00:00
Jean-Luc Tibaux
36d4c6dc11
Translated using Weblate (German)
Currently translated at 98.1% (1203 of 1226 strings)

Co-authored-by: Jean-Luc Tibaux <eugentoptic@outlook.de>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/de/
Translation: Fedilab/Strings
2025-04-23 02:03:18 +00:00
Максим Горпиніч
caba5201f9
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (34 of 34 strings)

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

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/uk/
Translation: Fedilab/Strings
2025-04-21 23:01:50 +00:00
Thomas
cb0bac8ff6 Release 3.32.2 2025-04-21 18:19:31 +02:00
Antonin Del Fabbro
1d77fd9106
Add Misskey URL basic support 2025-04-21 16:05:27 +02:00
Thomas
6e932b6fd8 Release notes 2025-04-21 10:32:54 +02:00
Thomas
d044d1d36f Disable by default the mention to the booster when replying. Can be enabled in Settings > Compose (per account) 2025-04-21 10:27:56 +02:00
Thomas
bbd9c909b7 Merge branch 'fix_530' into develop 2025-04-21 10:03:02 +02:00
Thomas
ea6cb35b73 Gif media not animated by default 2025-04-21 10:02:08 +02:00
Thomas
fd00042f4d Downgrade animated emoji lib 2025-04-21 09:57:51 +02:00
Thomas
dd2a4dcf28 Merge branch '0xd9a-cw_hide_polls' into develop 2025-04-21 09:55:12 +02:00
0xd9a
78a4b51e4e Make username, displayname in nav drawer clickable
(This restores the previous behavior,
which toggled the accounts panel when clicked)
2025-04-20 18:43:20 +05:30
Alireza Rashidi
c465858eaa
Translated using Weblate (Persian)
Currently translated at 100.0% (1223 of 1223 strings)

Co-authored-by: Alireza Rashidi <alirezarashidigoorabi@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fa/
Translation: Fedilab/Strings
2025-04-18 04:02:49 +00:00
0xd9a
7747a99585 Hide polls with CWs 2025-04-18 00:50:51 +05:30
Alireza Rashidi
75283ef507
Translated using Weblate (Persian)
Currently translated at 100.0% (1223 of 1223 strings)

Co-authored-by: Alireza Rashidi <alirezarashidigoorabi@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fa/
Translation: Fedilab/Strings
2025-04-17 04:47:12 +02:00
Alireza Rashidi
e60d5e9882
Translated using Weblate (Persian)
Currently translated at 9.0% (3 of 33 strings)

Co-authored-by: Alireza Rashidi <alirezarashidigoorabi@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/fa/
Translation: Fedilab/description
2025-04-17 04:47:04 +02:00
Alireza Rashidi
a9386d6927
Translated using Weblate (Persian)
Currently translated at 57.3% (702 of 1223 strings)

Co-authored-by: Alireza Rashidi <alirezarashidigoorabi@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/fa/
Translation: Fedilab/Strings
2025-04-16 22:34:43 +02:00
Haui
cc234a6aee
Translated using Weblate (German)
Currently translated at 15.1% (5 of 33 strings)

Co-authored-by: Haui <hauisminecraft@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/de/
Translation: Fedilab/description
2025-04-16 18:28:32 +02:00
Yurt Page
a5c6a60a20
Translated using Weblate (Russian)
Currently translated at 92.8% (1136 of 1223 strings)

Co-authored-by: Yurt Page <yurtpage@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/ru/
Translation: Fedilab/Strings
2025-04-15 02:08:00 +02:00
XblateX
d8a417983a
Translated using Weblate (Russian)
Currently translated at 92.5% (1132 of 1223 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-04-13 04:01:51 +00:00
Lukáš Jelínek
df27c45434
Translated using Weblate (Czech)
Currently translated at 100.0% (1223 of 1223 strings)

Co-authored-by: Lukáš Jelínek <devel@aiken.cz>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/cs/
Translation: Fedilab/Strings
2025-04-13 04:01:48 +00:00
Thomas
6d5dbb2585 Merge pull request 'Add an outline around media' (#1174) from 0xd9a/Fedilab:media_borders into develop
Reviewed-on: https://codeberg.org/tom79/Fedilab/pulls/1174
2025-04-12 08:50:30 +00:00
Thomas
578c9b3d66 Fix issue #1173 - Refresh and pagination broken for the Trending timeline 2025-04-12 10:49:34 +02:00
0xd9a
fb932b293f Add an outline around media 2025-04-10 10:07:18 +05:30
Thomas
3bde1ae578 Fix a potential crash when translating with MinT 2025-04-09 15:57:45 +02:00
Thomas
78fccc9578 Fix issue #810 - Wrong preview picture on share from another app 2025-04-09 12:28:30 +02:00
ButterflyOfFire
1be12f1fe1
Translated using Weblate (Kabyle)
Currently translated at 61.2% (749 of 1223 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-04-09 02:20:00 +02:00
Максим Горпиніч
4fefda1f68
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (33 of 33 strings)

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-04-08 20:33:32 +02:00
ButterflyOfFire
59952c8203
Translated using Weblate (Kabyle)
Currently translated at 61.0% (747 of 1223 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-04-08 20:33:23 +02:00
Thomas
fdc2cb07c8 Release 3.32.1 2025-04-08 18:01:42 +02:00
Thomas
a8b16b1956 Merge remote-tracking branch 'origin/develop' into develop 2025-04-08 17:51:19 +02:00
Thomas
edbe7689bf - Fix layout issues with media descriptions
- Fix a crash when taping the media to open original message
2025-04-08 17:51:07 +02:00
0xd9a
c4cf8f58a1 re-hide quote button by default 2025-04-08 16:29:58 +05:30
大王叫我来巡山
d1e8a6ce43
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (1223 of 1223 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-04-08 12:49:44 +02:00
josé m
7547d4e681
Translated using Weblate (Galician)
Currently translated at 100.0% (1223 of 1223 strings)

Co-authored-by: josé m <correoxm@disroot.org>
Translate-URL: https://hosted.weblate.org/projects/fedilab/strings/gl/
Translation: Fedilab/Strings
2025-04-08 05:05:50 +02:00
0xd9a
b99d55e5ff Add an id for ConstraintLayout Flow 2025-04-07 23:45:24 +05:30
Максим Горпиніч
b57de8254c
Translated using Weblate (Ukrainian)
Currently translated at 100.0% (1223 of 1223 strings)

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

Co-authored-by: Максим Горпиніч <maksimgorpinic2005a@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/fedilab/description/uk/
Translation: Fedilab/description
2025-04-07 20:06:18 +02:00
158 changed files with 4439 additions and 1373 deletions

View file

@ -13,8 +13,8 @@ android {
defaultConfig {
minSdk 21
targetSdk 34
versionCode 529
versionName "3.32.0"
versionCode 534
versionName "3.33.1"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
flavorDimensions "default"
@ -100,7 +100,7 @@ allprojects {
}
}
dependencies {
implementation 'org.unifiedpush.android:connector:3.0.7'
implementation 'org.unifiedpush.android:connector:3.0.9'
playstoreImplementation('org.unifiedpush.android:embedded-fcm-distributor:3.0.0')
@ -141,7 +141,7 @@ dependencies {
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:3.0.4'
implementation 'com.github.penfeizhou.android.animation:glide-plugin:3.0.5'
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"

View file

@ -72,6 +72,10 @@
android:host="*"
android:pathPrefix="/@"
android:scheme="https" />
<data
android:host="*"
android:pathPrefix="/notes"
android:scheme="https" />
</intent-filter>
</activity>
@ -230,7 +234,7 @@
android:configChanges="keyboardHidden|orientation|screenSize" />
<activity
android:name=".mastodon.activities.MediaActivity"
android:hardwareAccelerated="false"
android:hardwareAccelerated="true"
android:configChanges="keyboardHidden|orientation|screenSize"
android:theme="@style/Transparent" />
@ -753,4 +757,4 @@
android:resource="@xml/compose_shortcuts" />
</activity-alias>
</application>
</manifest>
</manifest>

View file

@ -1,4 +1,24 @@
[
{
"version": "3.33.1",
"code": "534",
"note": "Added:\n- Highlight bottom hashtags\n- Support Trending Links\n- Featured tags displayed in profiles\n- Add/Remove featured tags from the profile editor\n\nChanged:\n- Add confirmation dialog when long pressing the boost button\n- Open messages by tapping on Scheduled Boost\n- Improve language picker when filtered with some languages\n\nFixed:\n- Limits number of fetch for filters\n- Pleroma instances cannot select media\n- Wrong messages deleted for scheduled (messages and boosts)\n- Fix a crash with long threads\n- Fix a potential memory issue for not cropped media\n- Fix embedded quotes not displayed\n- Some crashes"
},
{
"version": "3.32.3",
"code": "532",
"note": "Fixed:\n- Polls not displayed\n- Pagination with trends\n- Push notifications not working on some devices"
},
{
"version": "3.32.2",
"code": "531",
"note": "Added:\n- An outline around media\n\nChanged:\n- Make username, display name in nav drawer clickable\n- Gif media not animated by default\n- Disable by default the mention to the booster when replying. Can be enabled in Settings > Compose (per account)\n\nFixed:\n- Wrong preview picture on share from another app\n- Crash when translating with MinT\n- Refresh and pagination broken for the Trending timeline\n- Fix lags / Crashes"
},
{
"version": "3.32.1",
"code": "530",
"note": "Fixed:\n- Fix a crash on some devices\n- Hide quote button\n- Fix a layout issue with pictures in landscape\n- Fix a crash when opening the original message from a picture"
},
{
"version": "3.32.0",
"code": "529",

View file

@ -212,6 +212,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
public static List<Filter> mainFilters;
public static List<app.fedilab.android.mastodon.client.entities.api.Account> filteredAccounts;
public static boolean filterFetched;
public static int filterFetchedRetry = 0;
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 iconLauncher mLauncher = iconLauncher.BUBBLES;
@ -1358,6 +1359,7 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
filteredAccounts = new ArrayList<>();
filterFetched = false;
filterFetchedRetry = 0;
networkStateReceiver = new NetworkStateReceiver();
networkStateReceiver.addListener(this);
registerReceiver(networkStateReceiver, new IntentFilter(android.net.ConnectivityManager.CONNECTIVITY_ACTION));
@ -1473,6 +1475,8 @@ public abstract class BaseMainActivity extends BaseActivity implements NetworkSt
});
TooltipCompat.setTooltipText(headerMainBinding.ownerAccounts, getString(R.string.manage_accounts));
headerMainBinding.accountName.setOnClickListener(v -> headerMainBinding.ownerAccounts.performClick());
headerMainBinding.accountAcc.setOnClickListener(v -> headerMainBinding.ownerAccounts.performClick());
headerMainBinding.ownerAccounts.setOnClickListener(v -> {
headerMenuOpen = !headerMenuOpen;
manageDrawerMenu(BaseMainActivity.this, binding.navView, headerMainBinding);

View file

@ -502,6 +502,7 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
private void initializeAfterBundle(Bundle b) {
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(this);
new Thread(() -> {
if (b != null) {
statusReply = (Status) b.getSerializable(Helper.ARG_STATUS_REPLY);
@ -514,6 +515,8 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
if (account == null) {
account = Helper.getCurrentAccount(ComposeActivity.this);
}
boolean setMentionBooster = sharedpreferences.getBoolean(getString(R.string.SET_MENTION_BOOSTER) + account.user_id + account.instance, false);
editMessageId = b.getString(Helper.ARG_EDIT_STATUS_ID, null);
instance = b.getString(Helper.ARG_INSTANCE, null);
token = b.getString(Helper.ARG_TOKEN, null);
@ -523,7 +526,11 @@ public class ComposeActivity extends BaseActivity implements ComposeAdapter.Mana
} 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);
if(setMentionBooster) {
mentionBooster = (Account) b.getSerializable(Helper.ARG_MENTION_BOOSTER);
} else {
mentionBooster = null;
}
accountMention = (Account) b.getSerializable(Helper.ARG_ACCOUNT_MENTION);
//Shared elements
sharedAttachments = (ArrayList<Attachment>) b.getSerializable(Helper.ARG_MEDIA_ATTACHMENTS);

View file

@ -27,6 +27,7 @@ import android.text.Html;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -37,6 +38,7 @@ import com.bumptech.glide.Glide;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.textfield.TextInputEditText;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
@ -45,10 +47,13 @@ import java.util.Objects;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.BuildConfig;
import app.fedilab.android.R;
import app.fedilab.android.databinding.AccountFeaturedHashtagItemBinding;
import app.fedilab.android.databinding.AccountFieldItemBinding;
import app.fedilab.android.databinding.ActivityEditProfileBinding;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.FeaturedTag;
import app.fedilab.android.mastodon.client.entities.api.Field;
import app.fedilab.android.mastodon.client.entities.api.Tag;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.exception.DBException;
import app.fedilab.android.mastodon.helper.Helper;
@ -62,6 +67,8 @@ public class EditProfileActivity extends BaseBarActivity {
public static final int PICK_MEDIA_HEADER = 5706;
private ActivityEditProfileBinding binding;
private AccountsVM accountsVM;
private static final int MAX_FIELDS = 4;
private static final int MAX_FEATURED_HASHTAGS = 10;
@SuppressLint("ClickableViewAccessibility")
@Override
@ -87,8 +94,9 @@ public class EditProfileActivity extends BaseBarActivity {
return false;
});
accountsVM = new ViewModelProvider(EditProfileActivity.this).get(AccountsVM.class);
new ViewModelProvider(EditProfileActivity.this).get(AccountsVM.class).getConnectedAccount(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
accountsVM.getConnectedAccount(BaseMainActivity.currentInstance, BaseMainActivity.currentToken)
.observe(EditProfileActivity.this, account -> {
if (account != null) {
Helper.setCurrentAccountMastodonAccount(EditProfileActivity.this, account);
@ -97,9 +105,10 @@ public class EditProfileActivity extends BaseBarActivity {
Helper.sendToastMessage(getApplication(), Helper.RECEIVE_TOAST_TYPE_ERROR, getString(R.string.toast_error));
}
});
}
}
@SuppressWarnings("deprecation")
private void initializeView() {
//Hydrate values
@ -113,6 +122,68 @@ public class EditProfileActivity extends BaseBarActivity {
else
bio = Html.fromHtml(Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.note).toString();
binding.bio.setText(bio);
accountsVM.getFeaturedTagsSuggestions(BaseMainActivity.currentInstance, BaseMainActivity.currentToken).observe(this, featuredTags -> {
StringBuilder text = new StringBuilder(getString(R.string.no_feature_hashtag_suggestion));
if(featuredTags != null && !featuredTags.isEmpty()) {
text = new StringBuilder();
for (Tag tag : featuredTags) {
text.append(String.format("#%s ", tag.name));
}
}
binding.featuredHashtagsSuggestions.setText(text);
});
accountsVM.getAccountFeaturedTags(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.id).observe(this, featuredTags -> {
if(featuredTags != null && !featuredTags.isEmpty()) {
for (FeaturedTag featuredTag : featuredTags) {
AccountFeaturedHashtagItemBinding featuredHashtagItemBinding = AccountFeaturedHashtagItemBinding.inflate(getLayoutInflater());
featuredHashtagItemBinding.name.setText(featuredTag.name);
featuredHashtagItemBinding.remove.setOnClickListener(v -> {
AlertDialog.Builder deleteConfirm = new MaterialAlertDialogBuilder(EditProfileActivity.this);
deleteConfirm.setTitle(getString(R.string.delete_featured_hashtag));
deleteConfirm.setMessage(getString(R.string.delete_featured_hashtag_confirm));
deleteConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
deleteConfirm.setPositiveButton(R.string.delete, (dialog, which) -> {
((ViewGroup)featuredHashtagItemBinding.getRoot().getParent()).removeView(featuredHashtagItemBinding.getRoot());
if (binding.featuredHashtagsContainer.getChildCount() >= MAX_FEATURED_HASHTAGS) {
binding.addFeaturedHashtags.setVisibility(View.GONE);
} else {
binding.addFeaturedHashtags.setVisibility(View.VISIBLE);
}
dialog.dismiss();
});
deleteConfirm.create().show();
});
binding.featuredHashtagsContainer.addView(featuredHashtagItemBinding.getRoot());
}
}
binding.addFeaturedHashtags.setOnClickListener(view -> {
AccountFeaturedHashtagItemBinding featuredHashtagItemBinding = AccountFeaturedHashtagItemBinding.inflate(getLayoutInflater());
featuredHashtagItemBinding.remove.setOnClickListener(v -> {
AlertDialog.Builder deleteConfirm = new MaterialAlertDialogBuilder(EditProfileActivity.this);
deleteConfirm.setTitle(getString(R.string.delete_featured_hashtag));
deleteConfirm.setMessage(getString(R.string.delete_featured_hashtag_confirm));
deleteConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
deleteConfirm.setPositiveButton(R.string.delete, (dialog, which) -> {
((ViewGroup)featuredHashtagItemBinding.getRoot().getParent()).removeView(featuredHashtagItemBinding.getRoot());
if (binding.featuredHashtagsContainer.getChildCount() >= MAX_FEATURED_HASHTAGS) {
binding.addFeaturedHashtags.setVisibility(View.GONE);
} else {
binding.addFeaturedHashtags.setVisibility(View.VISIBLE);
}
dialog.dismiss();
});
deleteConfirm.create().show();
});
binding.featuredHashtagsContainer.addView(featuredHashtagItemBinding.getRoot());
if (binding.featuredHashtagsContainer.getChildCount() >= MAX_FEATURED_HASHTAGS) {
binding.addFeaturedHashtags.setVisibility(View.GONE);
} else {
binding.addFeaturedHashtags.setVisibility(View.VISIBLE);
}
});
});
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) {
@ -135,7 +206,7 @@ public class EditProfileActivity extends BaseBarActivity {
binding.unlocked.setChecked(true);
}
List<Field> fields = Helper.getCurrentAccount(EditProfileActivity.this).mastodon_account.fields;
if (fields != null && fields.size() > 0) {
if (fields != null && !fields.isEmpty()) {
for (Field field : fields) {
AccountFieldItemBinding fieldItemBinding = AccountFieldItemBinding.inflate(getLayoutInflater());
fieldItemBinding.name.setText(field.name);
@ -151,11 +222,11 @@ public class EditProfileActivity extends BaseBarActivity {
deleteConfirm.setMessage(getString(R.string.delete_field_confirm));
deleteConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
deleteConfirm.setPositiveButton(R.string.delete, (dialog, which) -> {
binding.fieldsContainer.removeView(fieldItemBinding.getRoot());
if (binding.fieldsContainer.getChildCount() < 4) {
binding.fieldsContainer.setVisibility(View.VISIBLE);
((ViewGroup)fieldItemBinding.getRoot().getParent()).removeView(fieldItemBinding.getRoot());
if (binding.fieldsContainer.getChildCount() >= MAX_FIELDS) {
binding.addField.setVisibility(View.GONE);
} else {
binding.fieldsContainer.setVisibility(View.GONE);
binding.addField.setVisibility(View.VISIBLE);
}
dialog.dismiss();
});
@ -163,7 +234,11 @@ public class EditProfileActivity extends BaseBarActivity {
});
binding.fieldsContainer.addView(fieldItemBinding.getRoot());
}
if (binding.fieldsContainer.getChildCount() >= MAX_FIELDS) {
binding.addField.setVisibility(View.GONE);
} else {
binding.addField.setVisibility(View.VISIBLE);
}
}
binding.addField.setOnClickListener(view -> {
AccountFieldItemBinding fieldItemBinding = AccountFieldItemBinding.inflate(getLayoutInflater());
@ -173,25 +248,24 @@ public class EditProfileActivity extends BaseBarActivity {
deleteConfirm.setMessage(getString(R.string.delete_field_confirm));
deleteConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
deleteConfirm.setPositiveButton(R.string.delete, (dialog, which) -> {
binding.fieldsContainer.removeView(fieldItemBinding.getRoot());
if (binding.fieldsContainer.getChildCount() < 4) {
binding.fieldsContainer.setVisibility(View.VISIBLE);
((ViewGroup)fieldItemBinding.getRoot().getParent()).removeView(fieldItemBinding.getRoot());
if (binding.fieldsContainer.getChildCount() >= MAX_FIELDS) {
binding.addField.setVisibility(View.GONE);
} else {
binding.fieldsContainer.setVisibility(View.GONE);
binding.addField.setVisibility(View.VISIBLE);
}
dialog.dismiss();
});
deleteConfirm.create().show();
});
binding.fieldsContainer.addView(fieldItemBinding.getRoot());
if (binding.fieldsContainer.getChildCount() >= 4) {
if (binding.fieldsContainer.getChildCount() >= MAX_FIELDS) {
binding.addField.setVisibility(View.GONE);
} else {
binding.addField.setVisibility(View.VISIBLE);
}
});
//Actions with the activity
accountsVM = new ViewModelProvider(EditProfileActivity.this).get(AccountsVM.class);
binding.headerSelect.setOnClickListener(view -> startActivityForResult(prepareIntent(), EditProfileActivity.PICK_MEDIA_HEADER));
binding.avatarSelect.setOnClickListener(view -> startActivityForResult(prepareIntent(), EditProfileActivity.PICK_MEDIA_AVATAR));
@ -280,7 +354,7 @@ public class EditProfileActivity extends BaseBarActivity {
intent.setType("*/*");
String[] mimetypes;
long max_size = -1;
if (instanceInfo.getMimeTypeImage().size() > 0) {
if (!instanceInfo.getMimeTypeImage().isEmpty()) {
mimetypes = instanceInfo.getMimeTypeImage().toArray(new String[0]);
max_size = instanceInfo.configuration.media_attachments.image_size_limit;
} else {
@ -323,6 +397,16 @@ public class EditProfileActivity extends BaseBarActivity {
return fields;
}
List<String> getFeaturedHashtags() {
List<String> featuredHashtags = new ArrayList<>();
for (int i = 0; i < binding.featuredHashtagsContainer.getChildCount(); i++) {
String name = Objects.requireNonNull(((TextInputEditText) binding.featuredHashtagsContainer.getChildAt(i).findViewById(R.id.name)).getText()).toString().trim();
featuredHashtags.add(name);
}
return featuredHashtags;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
@ -338,7 +422,8 @@ public class EditProfileActivity extends BaseBarActivity {
getPrivacy(),
binding.sensitive.isChecked(),
null,
getFields()
getFields(),
getFeaturedHashtags()
)
.observe(EditProfileActivity.this, account -> {
if (account != null) {

View file

@ -141,6 +141,9 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
if (bundle != null) {
mediaPosition = bundle.getInt(Helper.ARG_MEDIA_POSITION, 1);
if(mediaPosition < 1 ) {
mediaPosition = 1;
}
attachments = (ArrayList<Attachment>) bundle.getSerializable(Helper.ARG_MEDIA_ARRAY);
mediaFromProfile = bundle.getBoolean(Helper.ARG_MEDIA_ARRAY_PROFILE, false);
status = (Status) bundle.getSerializable(Helper.ARG_STATUS);
@ -230,6 +233,9 @@ public class MediaActivity extends BaseBarActivity implements OnDownloadInterfac
public void onPageSelected(int position) {
mediaPosition = position;
if(mediaPosition < 1 ) {
mediaPosition = 1;
}
String description = attachments.get(position).description;
if (handler != null) {
handler.removeCallbacksAndMessages(null);

View file

@ -40,6 +40,7 @@ import android.text.method.LinkMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.text.style.UnderlineSpan;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@ -69,6 +70,7 @@ import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.request.target.CustomTarget;
import com.bumptech.glide.request.transition.Transition;
import com.google.android.material.chip.Chip;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.tabs.TabLayout;
@ -96,6 +98,7 @@ import app.fedilab.android.databinding.TabProfileCustomViewBinding;
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.FamiliarFollowers;
import app.fedilab.android.mastodon.client.entities.api.FeaturedTag;
import app.fedilab.android.mastodon.client.entities.api.Field;
import app.fedilab.android.mastodon.client.entities.api.IdentityProof;
import app.fedilab.android.mastodon.client.entities.api.MastodonList;
@ -116,6 +119,7 @@ import app.fedilab.android.mastodon.helper.SpannableHelper;
import app.fedilab.android.mastodon.helper.ThemeHelper;
import app.fedilab.android.mastodon.ui.drawer.FieldAdapter;
import app.fedilab.android.mastodon.ui.drawer.IdentityProofsAdapter;
import app.fedilab.android.mastodon.ui.drawer.StatusAdapter;
import app.fedilab.android.mastodon.ui.pageadapter.FedilabProfileTLPageAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.AccountsVM;
import app.fedilab.android.mastodon.viewmodel.mastodon.NodeInfoVM;
@ -229,7 +233,46 @@ public class ProfileActivity extends BaseActivity {
//Check if account is homeMuted
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);
//Search for featured tags
accountsVM.getAccountFeaturedTags(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, account!=null?account.id:account_id).observe(this, featuredTags -> {
if(featuredTags != null && !featuredTags.isEmpty()) {
binding.featuredHashtagsContainer.setVisibility(View.VISIBLE);
binding.featuredHashtags.removeAllViews();
for(FeaturedTag featuredTag: featuredTags) {
if(featuredTag.statuses_count > 0 ) {
Chip chip = new Chip(ProfileActivity.this);
chip.setClickable(true);
chip.setEnsureMinTouchTargetSize(false);
chip.setText(String.format("#%s", featuredTag.name));
chip.setTextColor(ThemeHelper.getAttColor(ProfileActivity.this, R.attr.colorPrimary));
chip.setOnClickListener(v -> {
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.ACCOUNT_TIMELINE);
if (account != null) {
args.putSerializable(Helper.ARG_CACHED_ACCOUNT_ID, account.id);
}
args.putString(Helper.ARG_TAGGED, featuredTag.name);
args.putBoolean(Helper.ARG_SHOW_PINNED, false);
args.putBoolean(Helper.ARG_SHOW_REPLIES, false);
args.putBoolean(Helper.ARG_SHOW_REBLOGS, false);
args.putBoolean(Helper.ARG_CHECK_REMOTELY, checkRemotely);
Intent intent = new Intent(ProfileActivity.this, TimelineActivity.class);
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);
});
});
binding.featuredHashtags.addView(chip);
}
}
} else {
binding.featuredHashtagsContainer.setVisibility(View.GONE);
}
});
}

View file

@ -57,21 +57,30 @@ public class TimelineActivity extends BaseBarActivity {
Timeline.TimeLineEnum timelineType = null;
String lemmy_post_id = null;
PinnedTimeline pinnedTimeline = null;
String tagged = null;
String timelineAccountId = null;
Status status = null;
if (bundle != null) {
timelineType = (Timeline.TimeLineEnum) bundle.get(Helper.ARG_TIMELINE_TYPE);
lemmy_post_id = bundle.getString(Helper.ARG_LEMMY_POST_ID, null);
pinnedTimeline = (PinnedTimeline) bundle.getSerializable(Helper.ARG_REMOTE_INSTANCE);
status = (Status) bundle.getSerializable(Helper.ARG_STATUS);
tagged = bundle.getString(Helper.ARG_TAGGED, null);
timelineAccountId = bundle.getString(Helper.ARG_CACHED_ACCOUNT_ID, null);
}
if (pinnedTimeline != null && pinnedTimeline.remoteInstance != null) {
setTitle(pinnedTimeline.remoteInstance.host);
}
if(tagged != null) {
setTitle(String.format("#%s",tagged));
}
FragmentMastodonTimeline fragmentMastodonTimeline = new FragmentMastodonTimeline();
Bundle args = new Bundle();
args.putSerializable(Helper.ARG_TIMELINE_TYPE, timelineType);
args.putSerializable(Helper.ARG_REMOTE_INSTANCE, pinnedTimeline);
args.putSerializable(Helper.ARG_LEMMY_POST_ID, lemmy_post_id);
args.putSerializable(Helper.ARG_TAGGED, tagged);
args.putSerializable(Helper.ARG_CACHED_ACCOUNT_ID, timelineAccountId);
if (status != null) {
args.putSerializable(Helper.ARG_STATUS, status);
}

View file

@ -33,6 +33,7 @@ import app.fedilab.android.R;
import app.fedilab.android.databinding.ActivityTrendsBinding;
import app.fedilab.android.mastodon.client.entities.app.Timeline;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonLink;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTag;
import app.fedilab.android.mastodon.ui.fragment.timeline.FragmentMastodonTimeline;
@ -56,6 +57,7 @@ public class TrendsActivity extends BaseBarActivity {
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.tags)));
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.toots)));
binding.searchTabLayout.addTab(binding.searchTabLayout.newTab().setText(getString(R.string.links)));
binding.searchTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabLayout.Tab tab) {
@ -75,6 +77,8 @@ public class TrendsActivity extends BaseBarActivity {
fragmentMastodonTimeline.scrollToTop();
} else if (fragment instanceof FragmentMastodonTag fragmentMastodonTag) {
fragmentMastodonTag.scrollToTop();
}else if (fragment instanceof FragmentMastodonLink fragmentMastodonLink) {
fragmentMastodonLink.scrollToTop();
}
}
}
@ -129,11 +133,17 @@ public class TrendsActivity extends BaseBarActivity {
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TREND_TAG);
fragmentMastodonTag.setArguments(bundle);
return fragmentMastodonTag;
} else if(position == 1) {
FragmentMastodonTimeline fragmentMastodonTimeline = new FragmentMastodonTimeline();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TREND_MESSAGE);
fragmentMastodonTimeline.setArguments(bundle);
return fragmentMastodonTimeline;
} else {
FragmentMastodonLink fragmentMastodonLink = new FragmentMastodonLink();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TREND_LINK);
fragmentMastodonLink.setArguments(bundle);
return fragmentMastodonLink;
}
FragmentMastodonTimeline fragmentMastodonTimeline = new FragmentMastodonTimeline();
bundle.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TREND_MESSAGE);
fragmentMastodonTimeline.setArguments(bundle);
return fragmentMastodonTimeline;
}
@Override
@ -142,7 +152,7 @@ public class TrendsActivity extends BaseBarActivity {
@Override
public int getCount() {
return 2;
return 3;
}
}
}

View file

@ -124,6 +124,7 @@ public interface MastodonAccountsService {
@Query("exclude_reblogs") Boolean exclude_reblogs,
@Query("only_media") Boolean only_media,
@Query("pinned") Boolean pinned,
@Query("tagged") String tagged,
@Query("limit") int limit
);

View file

@ -18,6 +18,7 @@ import java.util.List;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Conversation;
import app.fedilab.android.mastodon.client.entities.api.Link;
import app.fedilab.android.mastodon.client.entities.api.Marker;
import app.fedilab.android.mastodon.client.entities.api.MastodonList;
import app.fedilab.android.mastodon.client.entities.api.Status;
@ -80,6 +81,11 @@ public interface MastodonTimelinesService {
@Query("offset") Integer offset,
@Query("limit") Integer limit);
@GET("trends/links")
Call<List<Link>> getLinkTrends(@Header("Authorization") String token,
@Query("offset") Integer offset,
@Query("limit") Integer limit);
//Public Tags timelines
@GET("timelines/tag/{hashtag}")
Call<List<Status>> getHashTag(

View file

@ -0,0 +1,52 @@
package app.fedilab.android.mastodon.client.entities.api;
/* 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 Link implements Serializable {
@SerializedName("url")
public String url;
@SerializedName("title")
public String title;
@SerializedName("description")
public String description;
@SerializedName("type")
public String type;
@SerializedName("author_name")
public String author_name;
@SerializedName("author_url")
public String author_url;
@SerializedName("provider_name")
public String provider_name;
@SerializedName("provider_url")
public String provider_url;
@SerializedName("html")
public String html;
@SerializedName("width")
public int width;
@SerializedName("height")
public int height;
@SerializedName("image")
public String image;
@SerializedName("embed_url")
public String embed_url;
@SerializedName("blurhash")
public String blurhash;
@SerializedName("history")
public List<History> history;
}

View file

@ -16,6 +16,7 @@ package app.fedilab.android.mastodon.client.entities.api;
import android.content.Context;
import android.text.Spannable;
import android.util.Log;
import android.view.View;
import androidx.annotation.NonNull;
@ -28,6 +29,7 @@ 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 +115,7 @@ public class Status implements Serializable, Cloneable {
public List<Reaction> reactions;
public String attachedNotification = null;
public int gifPosition = 0;
public transient boolean isFetchMore = false;
public transient boolean isFetching = false;
@ -139,6 +142,8 @@ public class Status implements Serializable, Cloneable {
public boolean spoilerChecked = false;
public Filter filteredByApp;
public transient Spannable contentSpan;
public transient String[] bottomTags;
public transient Spannable contentSpoilerSpan;
public transient Spannable contentTranslateSpan;
public transient MathJaxView mathJaxView;
@ -162,6 +167,13 @@ public class Status implements Serializable, Cloneable {
return contentSpan;
}
public synchronized String[] getBottomTags() {
if(bottomTags == null) {
bottomTags = SpannableHelper.hasBottomTags(content);
}
return bottomTags;
}
public synchronized Spannable getSpanSpoiler(Context context, WeakReference<View> viewWeakReference, Callback callback) {
if (contentSpoilerSpan == null) {
contentSpoilerSpan = SpannableHelper.convert(context, spoiler_text, this, null, null, viewWeakReference, callback, true, false);

View file

@ -378,6 +378,8 @@ public class Timeline {
REMOTE("REMOTE"),
@SerializedName("TREND_TAG")
TREND_TAG("TREND_TAG"),
@SerializedName("TREND_LINK")
TREND_LINK("TREND_LINK"),
@SerializedName("TREND_MESSAGE")
TREND_MESSAGE("TREND_MESSAGE"),
@SerializedName("ACCOUNT_SUGGESTION")

View file

@ -73,10 +73,30 @@ public class CrossActionHelper {
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
new Thread(() -> {
try {
boolean confirmFav = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION_FAV), false);
boolean confirmBoost = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION), true);
List<BaseAccount> accounts = new Account(context).getCrossAccounts();
if (accounts.size() == 1) {
Handler mainHandler = new Handler(Looper.getMainLooper());
Runnable myRunnable = () -> fetchRemote(context, actionType, accounts.get(0), targetedAccount, targetedStatus);
Runnable myRunnable = () -> {
if ((actionType == TypeOfCrossAction.REBLOG_ACTION && confirmBoost) || (actionType == TypeOfCrossAction.FAVOURITE_ACTION && confirmFav)) {
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(context);
if (actionType == TypeOfCrossAction.REBLOG_ACTION) {
alt_bld.setMessage(context.getString(R.string.reblog_add));
} else {
alt_bld.setMessage(context.getString(R.string.favourite_add));
}
alt_bld.setPositiveButton(R.string.yes, (dia, id) -> {
fetchRemote(context, actionType, accounts.get(0), targetedAccount, targetedStatus);
dia.dismiss();
});
alt_bld.setNegativeButton(R.string.cancel, (dia, id) -> dia.dismiss());
AlertDialog alert = alt_bld.create();
alert.show();
} else {
fetchRemote(context, actionType, accounts.get(0), targetedAccount, targetedStatus);
}
};
mainHandler.post(myRunnable);
} else {
List<app.fedilab.android.mastodon.client.entities.api.Account> accountList = new ArrayList<>();
@ -97,8 +117,7 @@ public class CrossActionHelper {
}
builderSingle.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
builderSingle.setAdapter(accountsSearchAdapter, (dialog, which) -> {
boolean confirmFav = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION_FAV), false);
boolean confirmBoost = sharedpreferences.getBoolean(context.getString(R.string.SET_NOTIF_VALIDATION), true);
BaseAccount selectedAccount = accountArray[which];
if ((actionType == TypeOfCrossAction.REBLOG_ACTION && confirmBoost) || (actionType == TypeOfCrossAction.FAVOURITE_ACTION && confirmFav)) {
AlertDialog.Builder alt_bld = new MaterialAlertDialogBuilder(context);
@ -109,9 +128,9 @@ public class CrossActionHelper {
}
alt_bld.setPositiveButton(R.string.yes, (dia, id) -> {
fetchRemote(context, actionType, selectedAccount, targetedAccount, targetedStatus);
dialog.dismiss();
dia.dismiss();
});
alt_bld.setNegativeButton(R.string.cancel, (dia, id) -> dialog.dismiss());
alt_bld.setNegativeButton(R.string.cancel, (dia, id) -> dia.dismiss());
AlertDialog alert = alt_bld.create();
alert.show();
} else {

View file

@ -47,7 +47,7 @@ public class CustomEmoji extends ReplacementSpan {
}
public SpannableStringBuilder makeEmoji(SpannableStringBuilder content, List<Emoji> emojiList, boolean animate, Status.Callback callback) {
if (emojiList != null && emojiList.size() > 0) {
if (emojiList != null && !emojiList.isEmpty()) {
int count = 1;
for (Emoji emoji : emojiList) {
Matcher matcher = Pattern.compile(":" + emoji.shortcode + ":", Pattern.LITERAL)
@ -68,13 +68,6 @@ public class CustomEmoji extends ReplacementSpan {
@Override
public int getSize(@NonNull Paint paint, CharSequence charSequence, int i, int i1, @Nullable Paint.FontMetricsInt fontMetricsInt) {
if (fontMetricsInt != null) {
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
fontMetricsInt.top = (int) fontMetrics.top;
fontMetricsInt.ascent = (int) fontMetrics.ascent;
fontMetricsInt.descent = (int) fontMetrics.descent;
fontMetricsInt.bottom = (int) fontMetrics.bottom;
}
return (int) (paint.getTextSize() * scale);
}
@ -85,7 +78,7 @@ public class CustomEmoji extends ReplacementSpan {
int emojiSize = (int) (paint.getTextSize() * scale);
imageDrawable.setBounds(0, 0, emojiSize, emojiSize);
int transY = bottom - imageDrawable.getBounds().bottom;
transY -= paint.getFontMetrics().descent / 2;
transY -= (int) (paint.getFontMetrics().descent / 2);
canvas.translate(x, (float) transY);
imageDrawable.draw(canvas);
canvas.restore();
@ -93,19 +86,31 @@ public class CustomEmoji extends ReplacementSpan {
}
public Target<Drawable> getTarget(boolean animate, Status.Callback callback) {
return new CustomTarget<Drawable>() {
return new CustomTarget<>() {
@Override
public void onStart() {
if (imageDrawable instanceof Animatable) {
((Animatable) imageDrawable).start();
}
}
@Override
public void onStop() {
if (imageDrawable instanceof Animatable) {
((Animatable) imageDrawable).stop();
}
}
@Override
public void onResourceReady(@NonNull Drawable resource, @Nullable Transition<? super Drawable> transition) {
View view = viewWeakReference.get();
if (animate && resource instanceof Animatable) {
Drawable.Callback drawableCallBack = resource.getCallback();
resource.setCallback(new Drawable.Callback() {
@Override
public void invalidateDrawable(@NonNull Drawable drawable) {
if (drawableCallBack != null) {
drawableCallBack.invalidateDrawable(drawable);
}
if(view != null) {
view.invalidate();
}
@ -113,22 +118,18 @@ public class CustomEmoji extends ReplacementSpan {
@Override
public void scheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable, long l) {
if (drawableCallBack != null) {
drawableCallBack.scheduleDrawable(drawable, runnable, l);
}
view.postDelayed(runnable, l);
}
@Override
public void unscheduleDrawable(@NonNull Drawable drawable, @NonNull Runnable runnable) {
if (drawableCallBack != null) {
drawableCallBack.unscheduleDrawable(drawable, runnable);
}
view.removeCallbacks(runnable);
}
});
((Animatable) resource).start();
}
imageDrawable = resource;
if (view != null) {
if(view != null) {
view.invalidate();
}
if (callback != null && !callbackCalled) {
@ -139,6 +140,17 @@ public class CustomEmoji extends ReplacementSpan {
@Override
public void onLoadCleared(@Nullable Drawable placeholder) {
View view = viewWeakReference.get();
if (imageDrawable != null) {
if (imageDrawable instanceof Animatable) {
((Animatable) imageDrawable).stop();
imageDrawable.setCallback(null);
}
}
imageDrawable = null;
if(view != null) {
view.invalidate();
}
}
};
}

View file

@ -118,12 +118,7 @@ public class DividerDecoration extends RecyclerView.ItemDecoration {
c.drawLine(startPx, view.getTop() - margin, startPx, bottomPx, paint);
}
int color;
if (indentation - 1 >= colorList.size()) {
color = colorList.get(indentation - 1 - colorList.size());
} else {
color = colorList.get(indentation - 1);
}
int color = colorList.get(indentation%colorList.size()-1);
paint.setColor(ResourcesCompat.getColor(_mContext.getResources(), color, _mContext.getTheme()));
float startDp = 6 * fontScale * (indentation - 1) + 6 * fontScale;

View file

@ -127,12 +127,7 @@ public class DividerDecorationSimple extends RecyclerView.ItemDecoration {
c.drawLine(startPx, view.getTop() - margin, startPx, bottomPx, paint);
}
int color;
if (indentation - 1 >= colorList.size()) {
color = colorList.get(indentation - 1 - colorList.size());
} else {
color = colorList.get(indentation - 1);
}
int color = colorList.get(indentation%colorList.size()-1);
paint.setColor(ResourcesCompat.getColor(_mContext.getResources(), color, _mContext.getTheme()));
float startDp = 6 * fontScale * (indentation - 1) + 6 * fontScale;

View file

@ -288,6 +288,7 @@ public class Helper {
public static final String ARG_SHOW_REBLOGS = "ARG_SHOW_REBLOGS";
public static final String ARG_INITIALIZE_VIEW = "ARG_INITIALIZE_VIEW";
public static final String ARG_SHOW_PINNED = "ARG_SHOW_PINNED";
public static final String ARG_TAGGED = "ARG_TAGGED";
public static final String ARG_SHOW_MEDIA_ONY = "ARG_SHOW_MEDIA_ONY";
public static final String ARG_MENTION = "ARG_MENTION";
public static final String ARG_CHECK_REMOTELY = "ARG_CHECK_REMOTELY";
@ -1848,7 +1849,6 @@ public class Helper {
if (responseCode == HttpURLConnection.HTTP_OK) {
String fileName = "";
String disposition = httpURLConnection.getHeaderField("Content-Disposition");
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename=");
@ -1858,7 +1858,12 @@ public class Helper {
}
} else {
// extracts file name from URL
fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1);
try {
URL downLoadUrlTmp = new URL(downloadUrl);
fileName = downLoadUrlTmp.getPath().replace("/","_");
}catch (Exception exception) {
fileName = downloadUrl.substring(downloadUrl.lastIndexOf("/") + 1);
}
}
fileName = FileNameCleaner.cleanFileName(fileName);
// opens input stream from the HTTP connection

View file

@ -559,7 +559,7 @@ public class MastodonHelper {
return val;
} else {
if (instanceInfo != null) {
max_car = instanceInfo.max_toot_chars != null ? Integer.parseInt(instanceInfo.max_toot_chars) : instanceInfo.configuration.statusesConf.max_characters;
max_car = instanceInfo.max_toot_chars != null && instanceInfo.max_toot_chars.matches("\\d+") ? Integer.parseInt(instanceInfo.max_toot_chars) : instanceInfo.configuration.statusesConf.max_characters;
} else {
max_car = 500;
}

View file

@ -25,6 +25,7 @@ import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.MediaRecorder;
import android.media.MediaScannerConnection;
@ -266,6 +267,32 @@ public class MediaHelper {
);
}
public static Drawable rescaleImageIfNeeded(Activity activity, Drawable image) {
if (!(image instanceof BitmapDrawable)) {
return image;
}
int maxSize = 2000;
int width = image.getIntrinsicWidth();
int height = image.getIntrinsicHeight();
float scaleFactor;
if(width > maxSize || height > maxSize) {
if(width >= height) {
scaleFactor = (float) maxSize / width;
} else {
scaleFactor = (float) maxSize / height;
}
} else {
return image;
}
Bitmap b = ((BitmapDrawable)image).getBitmap();
int sizeX = Math.round(image.getIntrinsicWidth() * scaleFactor);
int sizeY = Math.round(image.getIntrinsicHeight() * scaleFactor);
Bitmap bitmapResized = Bitmap.createScaledBitmap(b, sizeX, sizeY, false);
image = new BitmapDrawable(activity.getResources(), bitmapResized);
return image;
}
/**
* Record media
*

View file

@ -107,6 +107,28 @@ public class SpannableHelper {
private static int linkColor;
private static boolean underlineLinks;
private static final String patternBottomTags = "\\n{2,}((#[\\w_À-ú-]+)(\\s*| *))+$";
public static String[] hasBottomTags(String text) {
if (text == null) {
return new String[]{};
}
SpannableString initialContent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
initialContent = new SpannableString(Html.fromHtml(text, Html.FROM_HTML_MODE_LEGACY));
} else {
initialContent = new SpannableString(Html.fromHtml(text));
}
final Pattern bottomTagsPattern = Pattern.compile(patternBottomTags, Pattern.CASE_INSENSITIVE);
Matcher matcherBottomTags = bottomTagsPattern.matcher(initialContent);
String[] tags = new String[]{};
while (matcherBottomTags.find()) {
String stringTags = Objects.requireNonNull(matcherBottomTags.group()).trim();
tags = stringTags.split("\\s");
}
return tags;
}
public static Spannable convert(Context context, String text,
Status status, Account account, Announcement announcement,
WeakReference<View> viewWeakReference, Status.Callback callback, boolean convertHtml, boolean convertMarkdown) {
@ -148,7 +170,8 @@ public class SpannableHelper {
if (status != null && status.mentions != null) {
mentions.addAll(status.mentions);
}
if(!convertMarkdown) {
boolean markdownSupport = sharedpreferences.getBoolean(context.getString(R.string.SET_MARKDOWN_SUPPORT), false);
if(!markdownSupport) {
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;");
@ -162,7 +185,8 @@ public class SpannableHelper {
} else {
initialContent = new SpannableString(text);
}
boolean markdownSupport = sharedpreferences.getBoolean(context.getString(R.string.SET_MARKDOWN_SUPPORT), false);
//Get all links
SpannableStringBuilder content;
if (markdownSupport && convertMarkdown) {
@ -350,9 +374,9 @@ public class SpannableHelper {
} else {
makeLinks(context, status, content, url, start, end, sameContent);
}
replaceQuoteSpans(context, content);
emails(context, content, status);
}
replaceQuoteSpans(context, content);
emails(context, content, status);
Pattern imgPattern = Pattern.compile("<img [^>]*src=\"([^\"]+)\"[^>]*>");
Matcher matcherImg = imgPattern.matcher(text);
@ -393,6 +417,20 @@ public class SpannableHelper {
}
}
}
boolean underlineBottomHashTags = sharedpreferences.getBoolean(context.getString(R.string.SET_UNDERLINE_BOTTOM_HASHTAGS), true);
if(underlineBottomHashTags) {
SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();
final Pattern bottomTagsPattern = Pattern.compile(patternBottomTags, Pattern.CASE_INSENSITIVE);
Matcher matcherBottomTags = bottomTagsPattern.matcher(content);
int length = 0;
while (matcherBottomTags.find()) {
length = Objects.requireNonNull(matcherBottomTags.group()).length();
}
spannableStringBuilder.append(content,0, content.length()-length);
return trimSpannable(spannableStringBuilder);
}
return trimSpannable(new SpannableStringBuilder(content));
}

View file

@ -76,7 +76,7 @@ public class TimelineHelper {
*/
public static List<Status> filterStatus(Context context, List<Status> statuses, Timeline.TimeLineEnum filterTimeLineType) {
//A security to make sure filters have been fetched before displaying messages
if (!BaseMainActivity.filterFetched) {
if (!BaseMainActivity.filterFetched && BaseMainActivity.filterFetchedRetry < 3) {
MastodonFiltersService mastodonFiltersService = initv2(context);
List<Filter> filterList;
Call<List<Filter>> getFiltersCall = mastodonFiltersService.getFilters(BaseMainActivity.currentToken);
@ -92,6 +92,7 @@ public class TimelineHelper {
e.printStackTrace();
}
}
BaseMainActivity.filterFetchedRetry++;
}
//If there are filters:
@ -222,7 +223,7 @@ public class TimelineHelper {
public static List<Notification> filterNotification(Context context, List<Notification> notifications) {
//A security to make sure filters have been fetched before displaying messages
List<Notification> notificationToRemove = new ArrayList<>();
if (!BaseMainActivity.filterFetched) {
if (!BaseMainActivity.filterFetched && BaseMainActivity.filterFetchedRetry < 3) {
try {
FiltersVM filtersVM = new ViewModelProvider((ViewModelStoreOwner) context).get(FiltersVM.class);
filtersVM.getFilters(BaseMainActivity.currentInstance, BaseMainActivity.currentToken).observe((LifecycleOwner) context, filters -> {
@ -232,6 +233,7 @@ public class TimelineHelper {
} catch (Exception e) {
return notifications;
}
BaseMainActivity.filterFetchedRetry++;
}
//If there are filters:
if (BaseMainActivity.mainFilters != null && !BaseMainActivity.mainFilters.isEmpty() && notifications != null && !notifications.isEmpty()) {

View file

@ -25,6 +25,7 @@ import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
@ -315,7 +316,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
*/
private void manageMentions(Context context, Status statusDraft, ComposeViewHolder holder) {
if (statusDraft.mentions != null && (statusDraft.text == null || statusDraft.text.length() == 0) && statusDraft.mentions.size() > 0) {
if (statusDraft.mentions != null && (statusDraft.text == null || statusDraft.text.isEmpty()) && !statusDraft.mentions.isEmpty()) {
//Retrieves mentioned accounts + OP and adds them at the beginin of the toot
final SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
Mention inReplyToUser;
@ -426,25 +427,25 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
String[] mimetypes = new String[0];
if (type == ComposeActivity.mediaType.PHOTO) {
if (instanceInfo != null && instanceInfo.getMimeTypeImage() != null && instanceInfo.getMimeTypeImage().size() > 0) {
if (instanceInfo != null && instanceInfo.getMimeTypeImage() != null && !instanceInfo.getMimeTypeImage().isEmpty()) {
mimetypes = instanceInfo.getMimeTypeImage().toArray(new String[0]);
} else {
mimetypes = new String[]{"image/*"};
}
} else if (type == ComposeActivity.mediaType.VIDEO) {
if (instanceInfo != null && instanceInfo.getMimeTypeVideo() != null && instanceInfo.getMimeTypeVideo().size() > 0) {
if (instanceInfo != null && instanceInfo.getMimeTypeVideo() != null && !instanceInfo.getMimeTypeVideo().isEmpty()) {
mimetypes = instanceInfo.getMimeTypeVideo().toArray(new String[0]);
} else {
mimetypes = new String[]{"video/*"};
}
} else if (type == ComposeActivity.mediaType.AUDIO) {
if (instanceInfo != null && instanceInfo.getMimeTypeAudio() != null && instanceInfo.getMimeTypeAudio().size() > 0) {
if (instanceInfo != null && instanceInfo.getMimeTypeAudio() != null && !instanceInfo.getMimeTypeAudio().isEmpty()) {
mimetypes = instanceInfo.getMimeTypeAudio().toArray(new String[0]);
} else {
mimetypes = new String[]{"audio/*"};
}
} else if (type == ComposeActivity.mediaType.ALL) {
if (instanceInfo != null && instanceInfo.getMimeTypeOther() != null && instanceInfo.getMimeTypeOther().size() > 0) {
if (instanceInfo != null && instanceInfo.getMimeTypeOther() != null && !instanceInfo.getMimeTypeOther().isEmpty()) {
mimetypes = instanceInfo.getMimeTypeOther().toArray(new String[0]);
} else {
mimetypes = new String[]{"*/*"};
@ -509,9 +510,9 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
*/
private boolean canBeRemoved(Status draft) {
return draft.poll == null
&& (draft.media_attachments == null || draft.media_attachments.size() == 0)
&& (draft.text == null || draft.text.trim().length() == 0)
&& (draft.spoiler_text == null || draft.spoiler_text.trim().length() == 0);
&& (draft.media_attachments == null || draft.media_attachments.isEmpty())
&& (draft.text == null || draft.text.trim().isEmpty())
&& (draft.spoiler_text == null || draft.spoiler_text.trim().isEmpty());
}
/**
@ -717,7 +718,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
InputStream is;
newContent[0] = "";
if (mentions.size() > 0) {
if (!mentions.isEmpty()) {
for (String mention : mentions) {
newContent[0] += mention + " ";
}
@ -734,7 +735,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
Gson gson = new Gson();
List<Quotes.Quote> quotes = gson.fromJson(json, new TypeToken<List<Quotes.Quote>>() {
}.getType());
if (quotes != null && quotes.size() > 0) {
if (quotes != null && !quotes.isEmpty()) {
final int random = new Random().nextInt(quotes.size());
Quotes.Quote quote = quotes.get(random);
newContent[0] += quote.content + "\n- " + quote.author;
@ -762,7 +763,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
if (holder.binding.content.getSelectionStart() != 0)
currentCursorPosition[0] = holder.binding.content.getSelectionStart();
if (contentString.length() == 0)
if (contentString.isEmpty())
currentCursorPosition[0] = 0;
//Only check last 15 characters before cursor position to avoid lags
//Less than 15 characters are written before the cursor position
@ -858,7 +859,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
if (currentCursorPosition >= oldContent.length())
deltaSearch = oldContent.substring(currentCursorPosition - searchLength);
}
if (!search.equals(""))
if (!search.isEmpty())
deltaSearch = deltaSearch.replace("@" + search, "");
String newContent = oldContent.substring(0, currentCursorPosition - searchLength);
newContent += deltaSearch;
@ -886,10 +887,10 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
"hashtags", false, true, false, 0,
null, null, 10).observe((LifecycleOwner) context,
results -> {
if (results == null || results.hashtags == null || results.hashtags.size() == 0) {
if (results == null || results.hashtags == null || results.hashtags.isEmpty()) {
return;
}
if (camelTags != null && camelTags.size() > 0) {
if (camelTags != null && !camelTags.isEmpty()) {
for (String camelTag : camelTags) {
Tag tag = new Tag();
tag.name = camelTag;
@ -931,7 +932,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
deltaSearch = oldContent.substring(currentCursorPosition - searchLength);
}
if (!search.equals(""))
if (!search.isEmpty())
deltaSearch = deltaSearch.replace("#" + search, "");
String newContent = oldContent.substring(0, currentCursorPosition - searchLength);
newContent += deltaSearch;
@ -954,7 +955,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
new Thread(() -> {
List<Emoji> emojisToDisplay = new ArrayList<>();
try {
if (emojisList == null || emojisList.size() == 0) {
if (emojisList == null || emojisList.isEmpty()) {
emojisList = new EmojiInstance(context).getEmojiList(BaseMainActivity.currentInstance);
}
if (emojis == null) {
@ -997,7 +998,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
deltaSearch = oldContent.substring(currentCursorPosition - searchLength);
}
if (!search.equals(""))
if (!search.isEmpty())
deltaSearch = deltaSearch.replace(":" + search, "");
String newContent = oldContent.substring(0, currentCursorPosition - searchLength);
newContent += deltaSearch;
@ -1049,9 +1050,9 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
StringBuilder contentBuilder = new StringBuilder();
if (title != null && title.trim().length() > 0) {
if (title != null && !title.trim().isEmpty()) {
contentBuilder.append(title);
} else if (subject != null && subject.trim().length() > 0) {
} else if (subject != null && !subject.trim().isEmpty()) {
contentBuilder.append(subject);
}
@ -1059,12 +1060,12 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
contentBuilder.append("\n\n");
}
if (description != null && description.trim().length() > 0) {
if (description != null && !description.trim().isEmpty()) {
if (url != null && !description.contains(url)) {
contentBuilder.append(url).append("\n\n");
}
contentBuilder.append("> ").append(description);
} else if (content != null && content.trim().length() > 0) {
} else if (content != null && !content.trim().isEmpty()) {
if (!content.contains(url)) {
contentBuilder.append(url).append("\n\n");
}
@ -1311,7 +1312,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
}
for (Status status : statusList) {
if (getItemViewType(position) == TYPE_COMPOSE) {
if (status != null && status.media_attachments != null && status.media_attachments.size() > 0) {
if (status != null && status.media_attachments != null && !status.media_attachments.isEmpty()) {
int mediaPosition = 0;
for (Attachment attachment : status.media_attachments) {
if (attachment.description == null || attachment.description.trim().isEmpty()) {
@ -1355,7 +1356,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
holder.binding.buttonAttachManual.setEnabled(false);
holder.binding.buttonPoll.setEnabled(true);
}
holder.binding.buttonPoll.setEnabled(statusDraft.media_attachments == null || statusDraft.media_attachments.size() == 0);
holder.binding.buttonPoll.setEnabled(statusDraft.media_attachments == null || statusDraft.media_attachments.isEmpty());
}
}
}
@ -1380,7 +1381,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
Status status = statusList.get(position);
StatusSimpleViewHolder holder = (StatusSimpleViewHolder) viewHolder;
if (status.media_attachments != null && status.media_attachments.size() > 0) {
if (status.media_attachments != null && !status.media_attachments.isEmpty()) {
holder.binding.simpleMedia.removeAllViews();
List<Attachment> attachmentList = statusList.get(position).media_attachments;
for (Attachment attachment : attachmentList) {
@ -1449,7 +1450,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
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) {
if (accountFromUser.fields != null && !accountFromUser.fields.isEmpty()) {
for (Field field : accountFromUser.fields) {
if (PronounsHelper.pronouns.contains(field.name.toLowerCase().trim())) {
statusList.get(position).pronouns = Helper.parseHtml(field.value);
@ -1571,17 +1572,17 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
holder.binding.contentSpoiler.setInputType(newInputTypeSpoiler);
holder.binding.buttonAttach.setOnClickListener(v -> {
if (instanceInfo.configuration.media_attachments.supported_mime_types != null) {
if (instanceInfo.getMimeTypeAudio().size() == 0) {
if (instanceInfo.configuration.media_attachments.supported_mime_types != null && instanceInfo.configuration.media_attachments.supported_mime_types.size() > 1) {
if (instanceInfo.getMimeTypeAudio().isEmpty()) {
holder.binding.buttonAttachAudio.setEnabled(false);
}
if (instanceInfo.getMimeTypeImage().size() == 0) {
if (instanceInfo.getMimeTypeImage().isEmpty()) {
holder.binding.buttonAttachImage.setEnabled(false);
}
if (instanceInfo.getMimeTypeVideo().size() == 0) {
if (instanceInfo.getMimeTypeVideo().isEmpty()) {
holder.binding.buttonAttachVideo.setEnabled(false);
}
if (instanceInfo.getMimeTypeOther().size() == 0) {
if (instanceInfo.getMimeTypeOther().isEmpty()) {
holder.binding.buttonAttachManual.setEnabled(false);
}
}
@ -1689,7 +1690,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
unlisted_changed = true;
});
if (statusDraft.spoilerChecked || statusDraft.spoiler_text != null && statusDraft.spoiler_text.trim().length() > 0) {
if (statusDraft.spoilerChecked || statusDraft.spoiler_text != null && !statusDraft.spoiler_text.trim().isEmpty()) {
holder.binding.contentSpoiler.setVisibility(View.VISIBLE);
} else {
holder.binding.contentSpoiler.setVisibility(View.GONE);
@ -1709,7 +1710,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
//Last compose drawer
buttonVisibility(holder);
if (emojis != null && emojis.size() > 0) {
if (emojis != null && !emojis.isEmpty()) {
holder.binding.buttonEmoji.setVisibility(View.VISIBLE);
} else {
holder.binding.buttonEmoji.setVisibility(View.GONE);
@ -1785,7 +1786,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
camelCaseTags.add(tag);
}
}
if (camelCaseTags.size() > 0) {
if (!camelCaseTags.isEmpty()) {
statusDraft.text += "\n\n";
int lenght = 0;
for (String tag : camelCaseTags) {
@ -1819,7 +1820,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
camelCaseTags.add(tag);
}
}
if (camelCaseTags.size() > 0) {
if (!camelCaseTags.isEmpty()) {
statusList.get(position).tagAdded = true;
int lenght = 0;
for (String tag : camelCaseTags) {
@ -1902,7 +1903,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
String[] languagesArr = new String[0];
int selection = 0;
if (storedLanguages != null && storedLanguages.size() > 0) {
if (storedLanguages != null && !storedLanguages.isEmpty()) {
int i = 0;
codesArr = new String[storedLanguages.size()];
languagesArr = new String[storedLanguages.size()];
@ -1915,7 +1916,6 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
i++;
}
} else {
List<Languages.Language> languages = Languages.get(context);
if (languages != null) {
codesArr = new String[languages.size()];
@ -1936,23 +1936,34 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(context);
builder.setTitle(context.getString(R.string.message_language));
builder.setSingleChoiceItems(languagesArr, selection, null);
String[] finalCodesArr = codesArr;
builder.setPositiveButton(R.string.validate, (dialog, which) -> {
int selectedPosition = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
editor.putString(context.getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, finalCodesArr[selectedPosition]);
editor.apply();
statusDraft.language = finalCodesArr[selectedPosition];
notifyItemChanged(holder.getLayoutPosition());
dialog.dismiss();
});
builder.setNegativeButton(R.string.reset, (dialog, which) -> {
editor.putString(context.getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, null);
editor.apply();
statusDraft.language = null;
notifyItemChanged(holder.getLayoutPosition());
dialog.dismiss();
});
if (storedLanguages == null || storedLanguages.isEmpty()) {
builder.setSingleChoiceItems(languagesArr, selection, null);
builder.setPositiveButton(R.string.validate, (dialog, which) -> {
int selectedPosition = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
editor.putString(context.getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, finalCodesArr[selectedPosition]);
editor.apply();
statusDraft.language = finalCodesArr[selectedPosition];
notifyItemChanged(holder.getLayoutPosition());
dialog.dismiss();
});
builder.setNegativeButton(R.string.reset, (dialog, which) -> {
editor.putString(context.getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, null);
editor.apply();
statusDraft.language = null;
notifyItemChanged(holder.getLayoutPosition());
dialog.dismiss();
});
} else {
builder.setSingleChoiceItems(languagesArr, selection, (dialog, which) -> {
int selectedPosition = ((AlertDialog) dialog).getListView().getCheckedItemPosition();
editor.putString(context.getString(R.string.SET_COMPOSE_LANGUAGE) + account.user_id + account.instance, finalCodesArr[selectedPosition]);
editor.apply();
statusDraft.language = finalCodesArr[selectedPosition];
notifyItemChanged(holder.getLayoutPosition());
dialog.dismiss();
});
}
builder.create().show();
});
}
@ -1988,6 +1999,7 @@ public class ComposeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder
composePollBinding.option1.textLayout.setHint(context.getString(R.string.poll_choice_s, 1));
composePollBinding.option2.text.setFilters(fArray);
composePollBinding.option2.textLayout.setHint(context.getString(R.string.poll_choice_s, 2));
composePollBinding.option2.textLayout.setHint(context.getString(R.string.poll_choice_s, 2));
composePollBinding.option1.buttonRemove.setVisibility(View.GONE);
composePollBinding.option2.buttonRemove.setVisibility(View.GONE);
int finalMax_entry = max_entry;

View file

@ -0,0 +1,181 @@
package app.fedilab.android.mastodon.ui.drawer;
/* 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.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityOptionsCompat;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.bumptech.glide.load.resource.bitmap.CenterCrop;
import com.bumptech.glide.load.resource.bitmap.CenterInside;
import com.bumptech.glide.load.resource.bitmap.RoundedCorners;
import com.bumptech.glide.request.RequestOptions;
import com.github.mikephil.charting.components.Description;
import com.github.mikephil.charting.components.YAxis;
import com.github.mikephil.charting.data.Entry;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.data.LineDataSet;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.databinding.DrawerLinkBinding;
import app.fedilab.android.mastodon.activities.MediaActivity;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.client.entities.api.History;
import app.fedilab.android.mastodon.client.entities.api.Link;
import app.fedilab.android.mastodon.client.entities.app.CachedBundle;
import app.fedilab.android.mastodon.helper.Helper;
public class LinkAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private final List<Link> linkList;
private Context context;
public LinkAdapter(List<Link> linkList) {
this.linkList = linkList;
}
public int getCount() {
return linkList.size();
}
public Link getItem(int position) {
return linkList.get(position);
}
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
context = parent.getContext();
DrawerLinkBinding itemBinding = DrawerLinkBinding.inflate(LayoutInflater.from(parent.getContext()), parent, false);
return new LinkViewHolder(itemBinding);
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int position) {
Link link = linkList.get(position);
LinkViewHolder linkViewHolder = (LinkViewHolder) viewHolder;
linkViewHolder.binding.linkTitle.setText(link.title);
linkViewHolder.binding.linkDescription.setText(link.description);
linkViewHolder.binding.linkAuthor.setText(link.provider_name);
if(link.author_url != null && link.author_url.startsWith("http")) {
linkViewHolder.binding.linkAuthor.setText(link.provider_name + " (" +link.author_name + ")");
linkViewHolder.binding.linkAuthor.setOnClickListener(v->{
Helper.openBrowser(context, link.author_url);
});
}
if(link.image != null) {
Glide.with(context).load(link.image) .apply(new RequestOptions().transform(new CenterInside(), new RoundedCorners(10))).into(linkViewHolder.binding.linkImage);
linkViewHolder.binding.linkImage.setVisibility(View.VISIBLE);
linkViewHolder.binding.linkImage.setOnClickListener(v->{
Intent intent = new Intent(context, MediaActivity.class);
Bundle args = new Bundle();
Attachment attachment = new Attachment();
attachment.preview_url = link.image;
attachment.url = link.image;
attachment.remote_url = link.image;
attachment.type = "image";
ArrayList<Attachment> attachments = new ArrayList<>();
attachments.add(attachment);
args.putSerializable(Helper.ARG_MEDIA_ARRAY, attachments);
args.putInt(Helper.ARG_MEDIA_POSITION, 1);
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intent.putExtras(bundle);
ActivityOptionsCompat options = ActivityOptionsCompat
.makeSceneTransitionAnimation(((Activity)context), linkViewHolder.binding.linkImage, attachment.url);
// start the new activity
context.startActivity(intent, options.toBundle());
});
});
} else {
linkViewHolder.binding.linkImage.setVisibility(View.GONE);
}
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
if (sharedpreferences.getBoolean(context.getString(R.string.SET_CARDVIEW), false)) {
linkViewHolder.binding.cardviewContainer.setCardElevation(Helper.convertDpToPixel(5, context));
linkViewHolder.binding.dividerCard.setVisibility(View.GONE);
}
List<Entry> trendsEntry = new ArrayList<>();
List<History> historyList = link.history;
if (historyList != null) {
for (History history : historyList) {
trendsEntry.add(0, new Entry(Float.parseFloat(history.day), Float.parseFloat(history.uses)));
}
}
LineDataSet dataTrending = new LineDataSet(trendsEntry, context.getString(R.string.trending));
dataTrending.setDrawValues(false);
dataTrending.setDrawFilled(true);
dataTrending.setDrawCircles(false);
dataTrending.setDrawCircleHole(false);
linkViewHolder.binding.chart.getAxis(YAxis.AxisDependency.LEFT).setEnabled(false);
linkViewHolder.binding.chart.getAxis(YAxis.AxisDependency.RIGHT).setEnabled(false);
linkViewHolder.binding.chart.getXAxis().setEnabled(false);
linkViewHolder.binding.chart.getLegend().setEnabled(false);
linkViewHolder.binding.chart.setTouchEnabled(false);
dataTrending.setMode(LineDataSet.Mode.CUBIC_BEZIER);
Description description = linkViewHolder.binding.chart.getDescription();
description.setEnabled(false);
List<ILineDataSet> dataSets = new ArrayList<>();
dataSets.add(dataTrending);
LineData data = new LineData(dataSets);
linkViewHolder.binding.chart.setData(data);
linkViewHolder.binding.chart.invalidate();
linkViewHolder.binding.getRoot().setOnClickListener(v -> Helper.openBrowser(context, link.url));
}
@Override
public int getItemCount() {
return linkList.size();
}
public static class LinkViewHolder extends RecyclerView.ViewHolder {
DrawerLinkBinding binding;
LinkViewHolder(DrawerLinkBinding itemView) {
super(itemView.getRoot());
binding = itemView;
}
}
}

View file

@ -108,6 +108,7 @@ 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.material.chip.Chip;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.smarteist.autoimageslider.SliderAnimations;
import com.smarteist.autoimageslider.SliderView;
@ -143,6 +144,7 @@ import app.fedilab.android.databinding.LayoutPollItemBinding;
import app.fedilab.android.mastodon.activities.ComposeActivity;
import app.fedilab.android.mastodon.activities.ContextActivity;
import app.fedilab.android.mastodon.activities.CustomSharingActivity;
import app.fedilab.android.mastodon.activities.HashTagActivity;
import app.fedilab.android.mastodon.activities.MediaActivity;
import app.fedilab.android.mastodon.activities.ProfileActivity;
import app.fedilab.android.mastodon.activities.ReportActivity;
@ -508,6 +510,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 pst = (LinearLayoutCompat.MarginLayoutParams) holder.binding.statusHashtags.getLayoutParams();
pst.setMarginStart((int) Helper.convertDpToPixel(6, context));
holder.binding.statusHashtags.setLayoutParams(pst);
LinearLayoutCompat.MarginLayoutParams psq = (LinearLayoutCompat.MarginLayoutParams) holder.binding.quotedMessage.cardviewContainer.getLayoutParams();
psq.setMarginStart((int) Helper.convertDpToPixel(6, context));
holder.binding.quotedMessage.cardviewContainer.setLayoutParams(psq);
@ -547,7 +552,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
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) {
if (statusToDeal.pronouns == null && statusToDeal.account != 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);
@ -1510,6 +1515,37 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
recyclerView.post(() -> adapter.notifyItemChanged(holder.getBindingAdapterPosition()));
}),
TextView.BufferType.SPANNABLE);
boolean underlineBottomHashTags = sharedpreferences.getBoolean(context.getString(R.string.SET_UNDERLINE_BOTTOM_HASHTAGS), true);
if(underlineBottomHashTags) {
if (statusToDeal.getBottomTags().length > 0) {
holder.binding.statusHashtags.setVisibility(View.VISIBLE);
holder.binding.statusHashtags.removeAllViews();
for (String tag : statusToDeal.getBottomTags()) {
Chip chip = new Chip(context);
chip.setClickable(true);
chip.setEnsureMinTouchTargetSize(false);
chip.setText(tag);
chip.setTextColor(ThemeHelper.getAttColor(context, R.attr.colorPrimary));
chip.setOnClickListener(v -> {
Intent intentTag = new Intent(context, HashTagActivity.class);
Bundle args = new Bundle();
args.putString(Helper.ARG_SEARCH_KEYWORD, tag.replace("#", ""));
new CachedBundle(context).insertBundle(args, Helper.getCurrentAccount(context), bundleId -> {
Bundle bundle = new Bundle();
bundle.putLong(Helper.ARG_INTENT_ID, bundleId);
intentTag.putExtras(bundle);
intentTag.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentTag);
});
});
holder.binding.statusHashtags.addView(chip);
}
} else {
holder.binding.statusHashtags.setVisibility(View.GONE);
}
} else {
holder.binding.statusHashtags.setVisibility(View.GONE);
}
if (truncate_toots_size > 0) {
holder.binding.statusContent.setMaxLines(truncate_toots_size);
holder.binding.statusContent.setEllipsize(TextUtils.TruncateAt.END);
@ -1576,6 +1612,15 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
});
}
LayoutInflater inflater = ((Activity) context).getLayoutInflater();
//Release players if they already exist
if(holder.binding.mediaContainer.getChildCount() > 0 ) {
for(int i = 0 ; i < holder.binding.mediaContainer.getChildCount() ; i++ ) {
PlayerView video = holder.binding.mediaContainer.getChildAt(i).findViewById(R.id.media_video);
if (video != null && video.getPlayer() != null) {
video.getPlayer().release();
}
}
}
holder.binding.mediaContainer.removeAllViews();
PlayerView video = holder.binding.media.media1Container.findViewById(R.id.media_video);
if (video != null && video.getPlayer() != null) {
@ -1615,7 +1660,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
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);
boolean autoplaygif = sharedpreferences.getBoolean(context.getString(R.string.SET_AUTO_PLAY_GIG_MEDIA), false);
if (!fullAttachement || statusToDeal.sensitive) {
int defaultHeight = (int) Helper.convertDpToPixel(300, context);
int orientation = context.getResources().getConfiguration().orientation;
@ -2107,7 +2152,11 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
adapter.notifyItemChanged(holder.getBindingAdapterPosition());
}
}));
holder.binding.poll.pollContainer.setVisibility(View.VISIBLE);
if (statusToDeal.spoiler_text == null || statusToDeal.spoiler_text.trim().isEmpty() || statusToDeal.isExpended) {
holder.binding.poll.pollContainer.setVisibility(View.VISIBLE);
} else {
holder.binding.poll.pollContainer.setVisibility(View.GONE);
}
String pollInfo = context.getResources().getQuantityString(R.plurals.number_of_voters, normalize, normalize);
if (statusToDeal.poll.expired) {
pollInfo += " - " + context.getString(R.string.poll_finish_at, MastodonHelper.dateToStringPoll(statusToDeal.poll.expires_at));
@ -3580,10 +3629,23 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
public void onViewRecycled(@NonNull RecyclerView.ViewHolder viewHolder) {
super.onViewRecycled(viewHolder);
if (viewHolder instanceof StatusViewHolder holder) {
if (holder.binding != null) {
PlayerView doubleTapPlayerView = holder.binding.media.getRoot().findViewById(R.id.media_video);
if (doubleTapPlayerView != null && doubleTapPlayerView.getPlayer() != null) {
doubleTapPlayerView.getPlayer().release();
//Release players
if (holder.binding != null) { //Cropped views
if(holder.binding.media.getRoot().getChildCount() > 0) {
for(int i = 0 ; i < holder.binding.media.getRoot().getChildCount() ; i++ ) {
PlayerView doubleTapPlayerView = holder.binding.media.getRoot().getChildAt(i).findViewById(R.id.media_video);
if (doubleTapPlayerView != null && doubleTapPlayerView.getPlayer() != null) {
doubleTapPlayerView.getPlayer().release();
}
}
}
if (holder.binding.mediaContainer.getChildCount() > 0) { //Not cropped views
for(int i = 0 ; i < holder.binding.mediaContainer.getChildCount() ; i++ ) {
PlayerView doubleTapPlayerView = holder.binding.mediaContainer.getChildAt(i).findViewById(R.id.media_video);
if (doubleTapPlayerView != null && doubleTapPlayerView.getPlayer() != null) {
doubleTapPlayerView.getPlayer().release();
}
}
}
}
}

View file

@ -605,7 +605,7 @@ public class StatusDirectMessageAdapter extends RecyclerView.Adapter<RecyclerVie
video.getPlayer().release();
}
holder.binding.media.media4Container.removeAllViews();
boolean autoplaygif = sharedpreferences.getBoolean(context.getString(R.string.SET_AUTO_PLAY_GIG_MEDIA), true);
boolean autoplaygif = sharedpreferences.getBoolean(context.getString(R.string.SET_AUTO_PLAY_GIG_MEDIA), false);
for (Attachment attachment : status.media_attachments) {
LayoutMediaBinding layoutMediaBinding = LayoutMediaBinding.inflate(LayoutInflater.from(context));
layoutMediaBinding.mediaRoot.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT));

View file

@ -45,6 +45,7 @@ import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.databinding.DrawerStatusScheduledBinding;
import app.fedilab.android.mastodon.activities.ComposeActivity;
import app.fedilab.android.mastodon.activities.ContextActivity;
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;
@ -61,9 +62,6 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
private final List<ScheduledBoost> scheduledBoosts;
public ScheduledActions scheduledActions;
private Context context;
private ScheduledStatus scheduledStatus;
private StatusDraft statusDraft;
private ScheduledBoost scheduledBoost;
public StatusScheduledAdapter(List<ScheduledStatus> scheduledStatuses, List<StatusDraft> statusDraftList, List<ScheduledBoost> scheduledBoosts) {
this.scheduledStatuses = scheduledStatuses;
@ -82,32 +80,27 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
@Override
public void onBindViewHolder(@NonNull StatusScheduledHolder holder, int position) {
scheduledStatus = null;
statusDraft = null;
String scheduledDate = null;
String statusContent = null;
if (scheduledStatuses != null) {
scheduledStatus = scheduledStatuses.get(position);
scheduledDate = Helper.dateToString(scheduledStatus.scheduled_at);
statusContent = scheduledStatus.params.text;
if (scheduledStatus.params.in_reply_to_id != null) {
if (scheduledStatuses != null && scheduledStatuses.size() > position) {
scheduledDate = Helper.dateToString(scheduledStatuses.get(position).scheduled_at);
statusContent = scheduledStatuses.get(position).params.text;
if (scheduledStatuses.get(position).params.in_reply_to_id != null) {
holder.binding.reply.setVisibility(View.VISIBLE);
} else {
holder.binding.reply.setVisibility(View.GONE);
}
} else if (statusDraftList != null) {
statusDraft = statusDraftList.get(position);
scheduledDate = Helper.dateToString(statusDraft.scheduled_at);
statusContent = statusDraft.statusDraftList.get(0).text;
if (statusDraft.statusDraftList.get(0).in_reply_to_id != null) {
} else if (statusDraftList != null && statusDraftList.size() > position) {
scheduledDate = Helper.dateToString(statusDraftList.get(position).scheduled_at);
statusContent = statusDraftList.get(position).statusDraftList.get(0).text;
if (statusDraftList.get(position).statusDraftList.get(0).in_reply_to_id != null) {
holder.binding.reply.setVisibility(View.VISIBLE);
} else {
holder.binding.reply.setVisibility(View.GONE);
}
} else if (scheduledBoosts != null) {
scheduledBoost = scheduledBoosts.get(position);
scheduledDate = Helper.dateToString(scheduledBoost.scheduledAt);
if (scheduledBoost.status.in_reply_to_id != null) {
} else if (scheduledBoosts != null && scheduledBoosts.size() > position) {
scheduledDate = Helper.dateToString(scheduledBoosts.get(position).scheduledAt);
if (scheduledBoosts.get(position).status.in_reply_to_id != null) {
holder.binding.reply.setVisibility(View.VISIBLE);
} else {
holder.binding.reply.setVisibility(View.GONE);
@ -116,10 +109,10 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
holder.binding.date.setText(scheduledDate);
if (scheduledBoost != null) {
if (scheduledBoosts != null && scheduledBoosts.size() > position) {
SpannableString statusContentSpan;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
statusContentSpan = new SpannableString(Html.fromHtml(scheduledBoost.status.content, FROM_HTML_MODE_LEGACY));
statusContentSpan = new SpannableString(Html.fromHtml(scheduledBoosts.get(position).status.content, FROM_HTML_MODE_LEGACY));
else
statusContentSpan = new SpannableString(Html.fromHtml(statusContent));
holder.binding.statusContent.setText(statusContentSpan, TextView.BufferType.SPANNABLE);
@ -142,6 +135,17 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
intent.putExtras(bundle);
context.startActivity(intent);
});
} else if(scheduledBoosts != null) {
Intent intentContext = new Intent(context, ContextActivity.class);
Bundle args2 = new Bundle();
args2.putSerializable(Helper.ARG_STATUS, scheduledBoosts.get(position).status);
new CachedBundle(context).insertBundle(args2, Helper.getCurrentAccount(context), bundleId2 -> {
Bundle bundleCached = new Bundle();
bundleCached.putLong(Helper.ARG_INTENT_ID, bundleId2);
intentContext.putExtras(bundleCached);
intentContext.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intentContext);
});
}
});
holder.binding.delete.setOnClickListener(v -> {
@ -149,43 +153,37 @@ public class StatusScheduledAdapter extends RecyclerView.Adapter<StatusScheduled
unfollowConfirm.setMessage(context.getString(R.string.remove_scheduled));
unfollowConfirm.setNegativeButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
unfollowConfirm.setPositiveButton(R.string.delete, (dialog, which) -> {
if (scheduledStatus != null) {
if (scheduledStatuses != null && scheduledStatuses.size() > position) {
StatusesVM statusesVM = new ViewModelProvider((ViewModelStoreOwner) context).get(StatusesVM.class);
statusesVM.deleteScheduledStatus(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, scheduledStatus.id)
statusesVM.deleteScheduledStatus(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, scheduledStatuses.get(position).id)
.observe((LifecycleOwner) context, unused -> {
if (scheduledStatuses != null) {
scheduledStatuses.remove(scheduledStatus);
if (scheduledStatuses.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);
scheduledStatuses.remove(scheduledStatuses.get(position));
if (scheduledStatuses.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);
});
} else if (statusDraft != null) {
} else if (statusDraftList != null && statusDraftList.size() > position) {
try {
new StatusDraft(context).removeScheduled(statusDraft);
WorkManager.getInstance(context).cancelWorkById(statusDraft.workerUuid);
if (statusDraftList != null) {
statusDraftList.remove(statusDraft);
if (statusDraftList.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);
new StatusDraft(context).removeScheduled(statusDraftList.get(position));
WorkManager.getInstance(context).cancelWorkById(statusDraftList.get(position).workerUuid);
statusDraftList.remove(statusDraftList.get(position));
if (statusDraftList.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);
} catch (DBException e) {
e.printStackTrace();
}
} else if (scheduledBoost != null) {
} else if (scheduledBoosts != null && position < scheduledBoosts.size()) {
try {
new ScheduledBoost(context).removeScheduled(scheduledBoost);
WorkManager.getInstance(context).cancelWorkById(scheduledBoost.workerUuid);
if (scheduledBoosts != null) {
scheduledBoosts.remove(scheduledBoost);
if (scheduledBoosts.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);
new ScheduledBoost(context).removeScheduled(scheduledBoosts.get(position));
WorkManager.getInstance(context).cancelWorkById(scheduledBoosts.get(position).workerUuid);
scheduledBoosts.remove(scheduledBoosts.get(position));
if (scheduledBoosts.isEmpty()) {
scheduledActions.onAllDeleted();
}
notifyItemRemoved(position);
} catch (DBException e) {
e.printStackTrace();
}

View file

@ -15,6 +15,7 @@ package app.fedilab.android.mastodon.ui.fragment.media;
* see <http://www.gnu.org/licenses>. */
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
@ -58,6 +59,7 @@ import app.fedilab.android.mastodon.activities.MediaActivity;
import app.fedilab.android.mastodon.client.entities.api.Attachment;
import app.fedilab.android.mastodon.helper.CacheDataSourceFactory;
import app.fedilab.android.mastodon.helper.Helper;
import app.fedilab.android.mastodon.helper.MediaHelper;
import app.fedilab.android.mastodon.viewmodel.mastodon.TimelinesVM;
import es.dmoral.toasty.Toasty;
@ -167,7 +169,9 @@ public class FragmentMedia extends Fragment {
return;
}
binding.mediaPicture.setZoomable(true);
binding.mediaPicture.setImageDrawable(resource);
Drawable scaledRessource = MediaHelper.rescaleImageIfNeeded(requireActivity(), resource);
binding.mediaPicture.setImageDrawable(scaledRessource);
if (attachment.type.equalsIgnoreCase("image") && !attachment.url.toLowerCase().endsWith(".gif")) {
binding.mediaPicture.setVisibility(View.VISIBLE);
@ -185,7 +189,8 @@ public class FragmentMedia extends Fragment {
return;
}
binding.loader.setVisibility(View.GONE);
binding.mediaPicture.setImageDrawable(resource);
Drawable scaledRessource = MediaHelper.rescaleImageIfNeeded(requireActivity(), resource);
binding.mediaPicture.setImageDrawable(scaledRessource);
binding.mediaPicture.setZoomable(true);
}

View file

@ -128,7 +128,7 @@ public class FragmentMediaProfile extends Fragment {
public void federatedAccount(Account account) {
if (account != null && isAdded() && !requireActivity().isFinishing()) {
accountId = account.id;
accountsVM.getAccountStatuses(tempInstance, null, accountId, null, null, null, null, null, true, false, MastodonHelper.statusesPerCall(requireActivity()))
accountsVM.getAccountStatuses(tempInstance, null, accountId, null, null, null, null, null, true, false, null, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), statuses -> initializeStatusesCommonView(statuses));
} else {
if (isAdded() && !requireActivity().isFinishing()) {
@ -141,7 +141,7 @@ public class FragmentMediaProfile extends Fragment {
tempToken = BaseMainActivity.currentToken;
tempInstance = BaseMainActivity.currentInstance;
accountId = accountTimeline.id;
accountsVM.getAccountStatuses(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountTimeline.id, null, null, null, null, null, true, false, MastodonHelper.statusesPerCall(requireActivity()))
accountsVM.getAccountStatuses(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountTimeline.id, null, null, null, null, null, true, false, null, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
}
}
@ -208,7 +208,7 @@ public class FragmentMediaProfile extends Fragment {
if (!flagLoading) {
flagLoading = true;
binding.loadingNextElements.setVisibility(View.VISIBLE);
accountsVM.getAccountStatuses(tempInstance, tempToken, accountId, max_id, null, null, null, null, true, false, MastodonHelper.statusesPerCall(requireActivity()))
accountsVM.getAccountStatuses(tempInstance, tempToken, accountId, max_id, null, null, null, null, true, false, null, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), newStatuses -> dealWithPagination(newStatuses));
}
} else {

View file

@ -23,6 +23,7 @@ import androidx.preference.ListPreference;
import androidx.preference.MultiSelectListPreference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceManager;
import androidx.preference.SwitchPreferenceCompat;
import java.util.List;
import java.util.Objects;
@ -59,6 +60,12 @@ public class FragmentComposeSettings extends PreferenceFragmentCompat implements
SET_WATERMARK_TEXT.setText(val);
}
SwitchPreferenceCompat SET_MENTION_BOOSTER = findPreference(getString(R.string.SET_MENTION_BOOSTER));
if (SET_MENTION_BOOSTER != null) {
boolean val = sharedPreferences.getBoolean(getString(R.string.SET_MENTION_BOOSTER) + BaseMainActivity.currentUserID + BaseMainActivity.currentInstance, sharedPreferences.getBoolean(getString(R.string.SET_MENTION_BOOSTER), false));
SET_MENTION_BOOSTER.setChecked(val);
}
MultiSelectListPreference SET_SELECTED_LANGUAGE = findPreference(getString(R.string.SET_SELECTED_LANGUAGE));
if (SET_SELECTED_LANGUAGE != null) {
@ -66,7 +73,7 @@ public class FragmentComposeSettings extends PreferenceFragmentCompat implements
Set<String> storedLanguages = sharedPreferences.getStringSet(getString(R.string.SET_SELECTED_LANGUAGE), null);
String[] selectedValue = new String[0];
if (storedLanguages != null && storedLanguages.size() > 0) {
if (storedLanguages != null && !storedLanguages.isEmpty()) {
if (storedLanguages.size() == 1 && storedLanguages.toArray()[0] == null) {
sharedPreferences.edit().remove(getString(R.string.SET_SELECTED_LANGUAGE)).commit();
} else {
@ -102,6 +109,11 @@ public class FragmentComposeSettings extends PreferenceFragmentCompat implements
editor.putString(getString(R.string.SET_WATERMARK_TEXT) + BaseMainActivity.currentUserID + BaseMainActivity.currentInstance, sharedPreferences.getString(getString(R.string.SET_WATERMARK_TEXT), null));
editor.apply();
}
if (Objects.requireNonNull(key).equalsIgnoreCase(getString(R.string.SET_MENTION_BOOSTER))) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(getString(R.string.SET_MENTION_BOOSTER) + BaseMainActivity.currentUserID + BaseMainActivity.currentInstance, sharedPreferences.getBoolean(getString(R.string.SET_MENTION_BOOSTER), false));
editor.apply();
}
}
@Override

View file

@ -0,0 +1,178 @@
package app.fedilab.android.mastodon.ui.fragment.timeline;
/* 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.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.preference.PreferenceManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.databinding.FragmentPaginationBinding;
import app.fedilab.android.mastodon.activities.SearchResultTabActivity;
import app.fedilab.android.mastodon.client.entities.api.Link;
import app.fedilab.android.mastodon.helper.MastodonHelper;
import app.fedilab.android.mastodon.ui.drawer.LinkAdapter;
import app.fedilab.android.mastodon.viewmodel.mastodon.TimelinesVM;
public class FragmentMastodonLink extends Fragment {
private FragmentPaginationBinding binding;
private LinkAdapter linkAdapter;
private Integer offset;
private boolean flagLoading;
private List<Link> linkList;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
binding = FragmentPaginationBinding.inflate(inflater, container, false);
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(requireActivity());
boolean displayScrollBar = sharedpreferences.getBoolean(getString(R.string.SET_TIMELINE_SCROLLBAR), false);
binding.recyclerView.setVerticalScrollBarEnabled(displayScrollBar);
return binding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
binding.loader.setVisibility(View.VISIBLE);
binding.recyclerView.setVisibility(View.GONE);
offset = 0;
flagLoading = false;
binding.swipeContainer.setRefreshing(false);
binding.swipeContainer.setEnabled(false);
router();
}
/**
* Router for timelines
*/
private void router() {
TimelinesVM timelinesVM = new ViewModelProvider(FragmentMastodonLink.this).get(TimelinesVM.class);
timelinesVM.getLinksTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, offset, MastodonHelper.SEARCH_PER_CALL)
.observe(getViewLifecycleOwner(), links -> {
if (links != null && offset == 0) {
initializeLinkCommonView(links);
} else if (links != null) {
dealWithPaginationTag(links);
}
});
}
public void scrollToTop() {
binding.recyclerView.setAdapter(linkAdapter);
}
private void dealWithPaginationTag(final List<Link> links) {
if (binding == null || !isAdded() || getActivity() == null) {
return;
}
if (links == null || links.isEmpty()) {
flagLoading = true;
binding.loadingNextElements.setVisibility(View.GONE);
return;
}
offset += MastodonHelper.SEARCH_PER_CALL;
binding.swipeContainer.setRefreshing(false);
binding.loadingNextElements.setVisibility(View.GONE);
flagLoading = false;
int start = linkList.size();
linkList.addAll(links);
linkAdapter.notifyItemRangeInserted(start, links.size());
}
/**
* Initialize the view for links
*
* @param links List of {@link Link}
*/
private void initializeLinkCommonView(final List<Link> links) {
if (binding == null || !isAdded() || getActivity() == null) {
return;
}
linkList = new ArrayList<>();
binding.loader.setVisibility(View.GONE);
binding.noAction.setVisibility(View.GONE);
binding.swipeContainer.setRefreshing(false);
binding.swipeContainer.setOnRefreshListener(() -> {
binding.swipeContainer.setRefreshing(true);
router();
});
if (links == null || links.isEmpty()) {
if (requireActivity() instanceof SearchResultTabActivity) {
((SearchResultTabActivity) requireActivity()).tagEmpty = true;
if (((SearchResultTabActivity) requireActivity()).accountEmpty != null) {
if (((SearchResultTabActivity) requireActivity()).accountEmpty) {
((SearchResultTabActivity) requireActivity()).moveToMessage();
} else {
((SearchResultTabActivity) requireActivity()).moveToAccount();
}
}
}
binding.recyclerView.setVisibility(View.GONE);
binding.noAction.setVisibility(View.VISIBLE);
binding.noActionText.setText(R.string.no_tags);
return;
}
offset += MastodonHelper.SEARCH_PER_CALL;
binding.recyclerView.setVisibility(View.VISIBLE);
binding.noAction.setVisibility(View.GONE);
linkList.addAll(links);
linkAdapter = new LinkAdapter(linkList);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(requireActivity());
binding.recyclerView.setLayoutManager(mLayoutManager);
binding.recyclerView.setAdapter(linkAdapter);
binding.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();
if (dy > 0) {
int visibleItemCount = mLayoutManager.getChildCount();
int totalItemCount = mLayoutManager.getItemCount();
if (firstVisibleItem + visibleItemCount == totalItemCount) {
if (!flagLoading) {
flagLoading = true;
binding.loadingNextElements.setVisibility(View.VISIBLE);
router();
}
} else {
binding.loadingNextElements.setVisibility(View.GONE);
}
}
}
});
}
}

View file

@ -17,6 +17,7 @@ package app.fedilab.android.mastodon.ui.fragment.timeline;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.networkAvailable;
import static app.fedilab.android.mastodon.helper.Helper.TAG;
import android.content.BroadcastReceiver;
import android.content.Context;
@ -26,6 +27,7 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -89,6 +91,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
private Integer offset;
private StatusAdapter statusAdapter;
private Timeline.TimeLineEnum timelineType;
private String tagged;
private List<Status> timelineStatuses;
//Handle actions that can be done in other fragments
private final BroadcastReceiver receive_action = new BroadcastReceiver() {
@ -416,6 +419,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
lemmy_post_id = bundle.getString(Helper.ARG_LEMMY_POST_ID, null);
list_id = bundle.getString(Helper.ARG_LIST_ID, null);
search = bundle.getString(Helper.ARG_SEARCH_KEYWORD, null);
tagged = bundle.getString(Helper.ARG_TAGGED, null);
searchCache = bundle.getString(Helper.ARG_SEARCH_KEYWORD_CACHE, null);
pinnedTimeline = (PinnedTimeline) bundle.getSerializable(Helper.ARG_REMOTE_INSTANCE);
canBeFederated = true;
@ -571,9 +575,13 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
insertedStatus = updateStatusListWith(fetched_statuses.statuses);
} else { //Trends cannot be ordered by id
insertedStatus = fetched_statuses.statuses.size();
int fromPosition = timelineStatuses.size();
timelineStatuses.addAll(fetched_statuses.statuses);
statusAdapter.notifyItemRangeInserted(fromPosition, insertedStatus);
for(Status statusReceived: fetched_statuses.statuses) {
if (!timelineStatuses.contains(statusReceived)) {
timelineStatuses.add(statusReceived);
statusAdapter.notifyItemInserted(timelineStatuses.size() - 1);
insertedStatus++;
}
}
}
//For these directions, the app will display counters for new messages
if (insertedStatus >= 0 && update != null && direction != DIRECTION.FETCH_NEW && !fetchingMissing) {
@ -631,7 +639,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
binding.loader.setVisibility(View.GONE);
binding.noAction.setVisibility(View.GONE);
binding.swipeContainer.setRefreshing(false);
if (searchCache == null && timelineType != Timeline.TimeLineEnum.TREND_MESSAGE) {
if (searchCache == null ) {
binding.swipeContainer.setOnRefreshListener(() -> {
binding.swipeContainer.setRefreshing(true);
flagLoading = false;
@ -722,7 +730,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
binding.recyclerView.addOnScrollListener(preloader);
binding.recyclerView.setItemViewCacheSize(0);
if (timelineType != Timeline.TimeLineEnum.TREND_MESSAGE) {
binding.recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
@ -759,7 +767,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
if (slug != null /*&& slug.compareTo(Helper.getSlugOfFirstFragment(requireActivity(), currentUserID, currentInstance)) == 0*/ && rememberPosition) {
route(DIRECTION.FETCH_NEW, true);
}
}
}
@ -1132,7 +1140,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
}
});
}
} else if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.PIXELFED) {
}
else if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.PIXELFED) {
if (direction == null) {
timelinesVM.getPixelfedDiscoverTrending(remoteInstance)
.observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
@ -1164,8 +1173,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
public void federatedAccount(Account account) {
if (account != null && isAdded() && !requireActivity().isFinishing()) {
accountIDInRemoteInstance = account.id;
accountsVM.getAccountStatuses(tempInstance[0], null, accountIDInRemoteInstance, null, null, null, null, null, false, true, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), pinnedStatuses -> accountsVM.getAccountStatuses(tempInstance[0], null, accountIDInRemoteInstance, null, null, null, exclude_replies, exclude_reblogs, media_only, false, MastodonHelper.statusesPerCall(requireActivity()))
accountsVM.getAccountStatuses(tempInstance[0], null, accountIDInRemoteInstance, null, null, null, null, null, false, true, tagged, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), pinnedStatuses -> accountsVM.getAccountStatuses(tempInstance[0], null, accountIDInRemoteInstance, null, null, null, exclude_replies, exclude_reblogs, media_only, false, tagged, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), otherStatuses -> {
if (otherStatuses != null && otherStatuses.statuses != null) {
if (pinnedStatuses != null && pinnedStatuses.statuses != null) {
@ -1197,9 +1206,9 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
accountId[0] = accountTimeline.id;
}
displayStatuses(direction, accountId[0], tempInstance[0], tempToken[0], fetchStatus);
} else if (search != null) {
}
else if (search != null) {
SearchVM searchVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, SearchVM.class);
if (direction == null) {
searchVM.search(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, search.trim(), null, null, false, true, false, 0, null, null, MastodonHelper.SEARCH_PER_CALL)
.observe(getViewLifecycleOwner(), results -> {
@ -1225,7 +1234,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
} else {
flagLoading = false;
}
} else if (searchCache != null) {
}
else if (searchCache != null) {
SearchVM searchVM = new ViewModelProvider(FragmentMastodonTimeline.this).get(viewModelKey, SearchVM.class);
searchVM.searchCache(BaseMainActivity.currentInstance, BaseMainActivity.currentUserID, searchCache.trim())
.observe(getViewLifecycleOwner(), results -> {
@ -1238,7 +1248,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
Toasty.error(requireActivity(), getString(R.string.toast_error), Toasty.LENGTH_LONG).show();
}
});
} else if (timelineType == Timeline.TimeLineEnum.FAVOURITE_TIMELINE) {
}
else if (timelineType == Timeline.TimeLineEnum.FAVOURITE_TIMELINE) {
if (direction == null) {
accountsVM.getFavourites(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, String.valueOf(MastodonHelper.statusesPerCall(requireActivity())), null, null)
.observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
@ -1248,7 +1259,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
} else {
flagLoading = false;
}
} else if (timelineType == Timeline.TimeLineEnum.BOOKMARK_TIMELINE) {
}
else if (timelineType == Timeline.TimeLineEnum.BOOKMARK_TIMELINE) {
if (direction == null) {
accountsVM.getBookmarks(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, String.valueOf(MastodonHelper.statusesPerCall(requireActivity())), null, null, null)
.observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
@ -1258,17 +1270,28 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
} else {
flagLoading = false;
}
} else if (timelineType == Timeline.TimeLineEnum.TREND_MESSAGE) {
}
else if (timelineType == Timeline.TimeLineEnum.TREND_MESSAGE) {
if (direction == null) {
timelinesVM.getStatusTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, null, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
} else if (direction == DIRECTION.BOTTOM) {
timelinesVM.getStatusTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, max_id, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
} else {
}else if (direction == DIRECTION.TOP) {
flagLoading = false;
} else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP || direction == DIRECTION.FETCH_NEW) {
timelinesVM.getStatusTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, null, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), statusesRefresh -> {
if (statusAdapter != null) {
dealWithPagination(statusesRefresh, direction, true, true, fetchStatus);
} else {
initializeStatusesCommonView(statusesRefresh);
}
});
}
} else if (timelineType == Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC) {
}
else if (timelineType == Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC) {
if (direction == null) {
timelinesVM.getStatusTrends(null, publicTrendsDomain, null, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
@ -1294,8 +1317,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
if (direction == null && !checkRemotely) {
if (show_pinned) {
//Fetch pinned statuses to display them at the top
accountsVM.getAccountStatuses(currentInstance, MainActivity.currentToken, accountId, null, null, null, null, null, false, true, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), pinnedStatuses -> accountsVM.getAccountStatuses(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountId, null, null, null, exclude_replies, exclude_reblogs, media_only, false, MastodonHelper.statusesPerCall(requireActivity()))
accountsVM.getAccountStatuses(currentInstance, MainActivity.currentToken, accountId, null, null, null, null, null, false, true, tagged, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), pinnedStatuses -> accountsVM.getAccountStatuses(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, accountId, null, null, null, exclude_replies, exclude_reblogs, media_only, false, tagged, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), otherStatuses -> {
if (otherStatuses != null && otherStatuses.statuses != null && pinnedStatuses != null && pinnedStatuses.statuses != null) {
for (Status status : pinnedStatuses.statuses) {
@ -1306,11 +1329,11 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
}
}));
} else {
accountsVM.getAccountStatuses(tempInstance, tempToken, accountId, null, null, null, exclude_replies, exclude_reblogs, media_only, false, MastodonHelper.statusesPerCall(requireActivity()))
accountsVM.getAccountStatuses(tempInstance, tempToken, accountId, null, null, null, exclude_replies, exclude_reblogs, media_only, false, tagged, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
}
} else if (direction == DIRECTION.BOTTOM) {
accountsVM.getAccountStatuses(tempInstance, tempToken, accountId, max_id, null, null, exclude_replies, exclude_reblogs, media_only, false, MastodonHelper.statusesPerCall(requireActivity()))
accountsVM.getAccountStatuses(tempInstance, tempToken, accountId, max_id, null, null, exclude_replies, exclude_reblogs, media_only, false, tagged, MastodonHelper.statusesPerCall(requireActivity()))
.observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
} else {
flagLoading = false;

View file

@ -20,12 +20,14 @@ import android.net.Uri;
import android.os.Handler;
import android.os.Looper;
import androidx.annotation.NonNull;
import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import java.net.IDN;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
@ -251,6 +253,7 @@ public class AccountsVM extends AndroidViewModel {
* @param sensitive Whether to mark authored statuses as sensitive by default.
* @param language Default language to use for authored statuses. (ISO 6391)
* @param fields Profile metadata name (By default, max 4 fields and 255 characters per property/value)
* @param featuredHashtags Featured hashtags that will be displayed on the profile
* @return {@link LiveData} containing an {@link Account}
*/
public LiveData<Account> updateCredentials(@NonNull String instance, String token,
@ -262,10 +265,15 @@ public class AccountsVM extends AndroidViewModel {
String privacy,
Boolean sensitive,
String language,
LinkedHashMap<Integer, Field.FieldParams> fields
LinkedHashMap<Integer, Field.FieldParams> fields,
List<String> featuredHashtags
) {
MastodonAccountsService mastodonAccountsService = init(instance);
accountMutableLiveData = new MutableLiveData<>();
if(featuredHashtags == null) {
featuredHashtags = new ArrayList<>();
}
List<String> finalFeaturedHashtags = featuredHashtags;
new Thread(() -> {
Account account = null;
Account.AccountParams accountParams = new Account.AccountParams();
@ -291,6 +299,46 @@ public class AccountsVM extends AndroidViewModel {
e.printStackTrace();
}
}
Call<List<FeaturedTag>> featuredTagsCall = mastodonAccountsService.getFeaturedTags(token);
try {
Response<List<FeaturedTag>> featuredTagsResponse = featuredTagsCall.execute();
if (featuredTagsResponse.isSuccessful()) {
List<FeaturedTag> currentFeaturedTags = featuredTagsResponse.body();
if(currentFeaturedTags == null) {
currentFeaturedTags = new ArrayList<>();
}
List<String> currentTags = new ArrayList<>();
for(FeaturedTag featuredTag: currentFeaturedTags) {
currentTags.add(featuredTag.name);
}
List<String> toRemove = new ArrayList<>();
List<String> toAdd = new ArrayList<>();
for(String value: currentTags) {
if(!finalFeaturedHashtags.contains(value)){
toRemove.add(value);
}
}
for(String value: finalFeaturedHashtags) {
if(!currentTags.contains(value)){
toAdd.add(value);
}
}
for(String remove: toRemove) {
for(FeaturedTag featuredTag: currentFeaturedTags) {
if(featuredTag.name.trim().equalsIgnoreCase(remove.trim())) {
mastodonAccountsService.removeFeaturedTag(token, featuredTag.id).execute();
break;
}
}
}
for(String add: toAdd) {
mastodonAccountsService.addFeaturedTag(token, add).execute();
}
}
} catch (Exception e) {
e.printStackTrace();
}
Handler mainHandler = new Handler(Looper.getMainLooper());
Account finalAccount = account;
Runnable myRunnable = () -> accountMutableLiveData.setValue(finalAccount);
@ -372,6 +420,7 @@ public class AccountsVM extends AndroidViewModel {
Boolean excludeReblogs,
Boolean only_media,
Boolean pinned,
String tagged,
int count) {
statusesMutableLiveData = new MutableLiveData<>();
MastodonAccountsService mastodonAccountsService = init(instance);
@ -379,7 +428,7 @@ public class AccountsVM extends AndroidViewModel {
List<Status> statusList = null;
Pagination pagination = null;
Call<List<Status>> accountStatusesCall = mastodonAccountsService.getAccountStatuses(
token, id, maxId, sinceId, minId, excludeReplies, excludeReblogs, only_media, pinned, count);
token, id, maxId, sinceId, minId, excludeReplies, excludeReblogs, only_media, pinned, tagged, count);
if (accountStatusesCall != null) {
try {
Response<List<Status>> accountStatusesResponse = accountStatusesCall.execute();

View file

@ -49,6 +49,7 @@ import app.fedilab.android.mastodon.client.endpoints.MastodonTimelinesService;
import app.fedilab.android.mastodon.client.entities.api.Account;
import app.fedilab.android.mastodon.client.entities.api.Conversation;
import app.fedilab.android.mastodon.client.entities.api.Conversations;
import app.fedilab.android.mastodon.client.entities.api.Link;
import app.fedilab.android.mastodon.client.entities.api.Marker;
import app.fedilab.android.mastodon.client.entities.api.MastodonList;
import app.fedilab.android.mastodon.client.entities.api.Pagination;
@ -95,6 +96,7 @@ public class TimelinesVM extends AndroidViewModel {
private MutableLiveData<Marker> markerMutableLiveData;
private MutableLiveData<List<Status>> statusListMutableLiveData;
private MutableLiveData<List<Tag>> tagListMutableLiveData;
private MutableLiveData<List<Link>> linkListMutableLiveData;
public TimelinesVM(@NonNull Application application) {
super(application);
@ -244,6 +246,30 @@ public class TimelinesVM extends AndroidViewModel {
return tagListMutableLiveData;
}
public LiveData<List<Link>> getLinksTrends(String token, @NonNull String instance, Integer offset, Integer limit) {
MastodonTimelinesService mastodonTimelinesService = init(instance);
linkListMutableLiveData = new MutableLiveData<>();
new Thread(() -> {
Call<List<Link>> publicTlCall = mastodonTimelinesService.getLinkTrends(token, offset, limit);
List<Link> linkList = null;
if (publicTlCall != null) {
try {
Response<List<Link>> publicTlResponse = publicTlCall.execute();
if (publicTlResponse.isSuccessful()) {
linkList = publicTlResponse.body();
}
} catch (Exception e) {
e.printStackTrace();
}
}
Handler mainHandler = new Handler(Looper.getMainLooper());
List<Link> finalLinkList = linkList;
Runnable myRunnable = () -> linkListMutableLiveData.setValue(finalLinkList);
mainHandler.post(myRunnable);
}).start();
return linkListMutableLiveData;
}
/**
* Public timeline for Nitter
*

View file

@ -22,13 +22,12 @@ import android.content.Context;
import android.os.Build;
import android.text.Html;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.google.android.material.chip.Chip;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
@ -39,7 +38,6 @@ import java.util.List;
import app.fedilab.android.R;
import app.fedilab.android.databinding.DrawerInstancePeertubeBinding;
import app.fedilab.android.peertube.client.data.InstanceData.Instance;
import app.fedilab.android.peertube.helper.RoundedBackgroundSpan;
public class InstanceAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@ -95,28 +93,22 @@ public class InstanceAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
holder.binding.name.setText(instance.getName());
holder.binding.host.setText(instance.getHost());
SpannableStringBuilder stringBuilder = new SpannableStringBuilder();
String between = "";
holder.binding.chips.removeAllViews();
if (peertubeInformation != null && peertubeInformation.getCategories() != null) {
LinkedHashMap<Integer, String> info_cat = new LinkedHashMap<>(peertubeInformation.getCategories());
if (instance.getCategories() != null && instance.getCategories().size() > 0 && instance.getSpannableStringBuilder() == null) {
for (int category : instance.getCategories()) {
String cat = info_cat.get(category);
stringBuilder.append(between);
if (cat != null && cat.trim().toLowerCase().compareTo("null") != 0) {
if (between.length() == 0) between = " ";
String tag = " " + cat + " ";
stringBuilder.append(tag);
stringBuilder.setSpan(new RoundedBackgroundSpan(context), stringBuilder.length() - tag.length(), stringBuilder.length() - tag.length() + tag.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
Chip chip = new Chip(context);
chip.setClickable(false);
chip.setEnsureMinTouchTargetSize(false);
chip.setText(cat);
holder.binding.chips.addView(chip);
}
}
instance.setSpannableStringBuilder(stringBuilder);
}
}
if (instance.getSpannableStringBuilder() != null) {
holder.binding.tags.setText(instance.getSpannableStringBuilder());
}
if (peertubeInformation != null && peertubeInformation.getLanguages() != null) {
LinkedHashMap<String, String> info_lang = new LinkedHashMap<>(peertubeInformation.getLanguages());

View file

@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?><!--
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>
-->
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipChildren="false"
android:clipToPadding="false"
android:layout_marginTop="6dp"
app:cardElevation="0dp"
app:strokeWidth="0dp">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center_vertical"
tools:text="@tools:sample/first_names" />
<com.google.android.material.button.MaterialButton
android:id="@+id/remove"
android:layout_marginStart="5dp"
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
android:layout_width="36dp"
android:layout_height="36dp"
android:contentDescription="@string/delete_field"
android:insetTop="0dp"
android:insetBottom="0dp"
android:padding="0dp"
android:textColor="?colorError"
app:icon="@drawable/ic_compose_attachment_remove"
app:iconGravity="textStart"
app:iconPadding="0dp"
app:iconTint="?colorError"
app:layout_constraintStart_toStartOf="@id/banner_pp"
app:layout_constraintTop_toTopOf="@id/banner_pp"
app:strokeColor="?colorError" />
</androidx.appcompat.widget.LinearLayoutCompat>
</com.google.android.material.card.MaterialCardView>

View file

@ -55,6 +55,7 @@
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.button.MaterialButton
android:layout_marginStart="5dp"
android:id="@+id/remove"
style="@style/Widget.Material3.Button.OutlinedButton.Icon"
android:layout_width="36dp"

View file

@ -161,32 +161,160 @@
app:layout_constraintTop_toBottomOf="@id/acct"
tools:text="@tools:sample/lorem/random" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/fields"
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/fields_main_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:layout_marginTop="12dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/bio">
android:layout_marginStart="16dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toBottomOf="@id/bio"
>
<View
android:id="@+id/fields_border_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:paddingBottom="10dp"
android:background="@drawable/translation_border"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/fields_border_top" />
<androidx.constraintlayout.widget.Placeholder
android:id="@+id/fields_border_top"
android:layout_width="wrap_content"
android:layout_height="1dp"
app:layout_constraintBottom_toBottomOf="@id/fields_label"
app:layout_constraintEnd_toEndOf="@id/fields_label"
app:layout_constraintTop_toTopOf="@id/fields_label" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/fields_label"
android:layout_width="wrap_content"
android:background="?colorSurface"
android:elevation="2dp"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:layout_marginTop="12dp"
android:text="@string/fields_title"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/fields_container"
android:id="@+id/fields"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
android:layout_marginHorizontal="12dp"
android:padding="5dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/fields_label">
<com.google.android.material.button.MaterialButton
android:id="@+id/add_field"
style="@style/Widget.Material3.Button.OutlinedButton"
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/fields_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<com.google.android.material.button.MaterialButton
android:id="@+id/add_field"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginVertical="6dp"
android:text="@string/add_field"
app:icon="@drawable/ic_baseline_add_24" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/featured_hashtags_main_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="10dp"
android:layout_marginEnd="16dp"
app:layout_constraintTop_toBottomOf="@id/fields_main_container"
>
<View
android:id="@+id/featured_hashtags_border_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:paddingBottom="10dp"
android:background="@drawable/translation_border"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/featured_hashtags_border_top" />
<androidx.constraintlayout.widget.Placeholder
android:id="@+id/featured_hashtags_border_top"
android:layout_width="wrap_content"
android:layout_height="1dp"
app:layout_constraintBottom_toBottomOf="@id/featured_hashtags_label"
app:layout_constraintEnd_toEndOf="@id/featured_hashtags_label"
app:layout_constraintTop_toTopOf="@id/featured_hashtags_label" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/featured_hashtags_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginVertical="6dp"
android:text="@string/add_field"
app:icon="@drawable/ic_baseline_add_24" />
android:background="?colorSurface"
android:elevation="2dp"
android:paddingStart="2dp"
android:paddingEnd="2dp"
android:layout_marginHorizontal="12dp"
android:layout_marginTop="12dp"
android:text="@string/featured_hashtags_title"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/featured_hashtags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="12dp"
android:padding="5dp"
android:orientation="vertical"
app:layout_constraintTop_toBottomOf="@id/featured_hashtags_label">
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<com.google.android.material.textview.MaterialTextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/Suggestions"/>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/featured_hashtags_suggestions"
android:layout_marginStart="10dp"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="@string/Suggestions"/>
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_marginTop="5dp"
android:id="@+id/featured_hashtags_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<com.google.android.material.button.MaterialButton
android:id="@+id/add_featured_hashtags"
style="@style/Widget.Material3.Button.OutlinedButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginVertical="6dp"
android:text="@string/add_featured_hashtag"
app:icon="@drawable/ic_baseline_add_24" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/visibility_label"
@ -196,7 +324,7 @@
android:layout_marginTop="12dp"
android:text="@string/toots_visibility_title"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
app:layout_constraintTop_toBottomOf="@id/fields" />
app:layout_constraintTop_toBottomOf="@id/featured_hashtags_main_container" />
<com.google.android.material.button.MaterialButtonToggleGroup
android:id="@+id/visibility_group"

View file

@ -20,7 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:fitsSystemWindows="true"
android:fitsSystemWindows="false"
android:background="@android:color/transparent">
@ -35,6 +35,7 @@
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/description_container"
android:fitsSystemWindows="true"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:background="#AA000000"

View file

@ -375,6 +375,27 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/info" />
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/featured_hashtags_container"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible"
android:gravity="center"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fields_container">
<com.google.android.material.chip.ChipGroup
android:id="@+id/featured_hashtags"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:chipSpacingHorizontal="6dp"
app:chipSpacingVertical="6dp"
/>
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
@ -388,7 +409,7 @@
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/fields_container"
app:layout_constraintTop_toBottomOf="@+id/featured_hashtags_container"
tools:visibility="visible">
<androidx.appcompat.widget.AppCompatTextView

View file

@ -11,8 +11,9 @@
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_weight="1"
android:gravity="center"
android:gravity="end|center_vertical"
android:minHeight="20dp"
android:layout_marginEnd="5dp"
android:padding="5dp"
android:paddingTop="10dp"
android:paddingBottom="10dp" />
@ -20,17 +21,19 @@
<androidx.appcompat.widget.LinearLayoutCompat
android:id="@+id/valueBG"
android:layout_width="0dp"
android:layout_marginStart="5dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/value"
android:layout_width="match_parent"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="center"
android:gravity="center"
android:layout_gravity="start|center_vertical"
android:gravity="start|center_vertical"
android:paddingTop="10dp"
android:drawablePadding="5dp"
android:paddingBottom="10dp"
android:textIsSelectable="true" />
</androidx.appcompat.widget.LinearLayoutCompat>

View file

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="utf-8"?><!--
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>.
-->
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/cardview_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/card_margin"
android:layout_marginTop="@dimen/card_margin"
android:clipChildren="false"
android:clipToPadding="false"
app:cardElevation="0dp"
app:strokeWidth="0dp">
<View
android:id="@+id/divider_card"
android:layout_width="match_parent"
android:layout_height="1px"
android:background="?colorOutline" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="@dimen/fab_margin"
android:paddingTop="5dp"
android:paddingEnd="@dimen/fab_margin">
<TextView
android:id="@+id/link_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textSize="20sp" />
<TextView
android:layout_marginTop="10dp"
android:id="@+id/link_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
<TextView
android:id="@+id/count"
android:layout_width="40dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:textSize="25sp" />
<ImageView
android:id="@+id/link_image"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:contentDescription="@string/link_image" />
<androidx.appcompat.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/link_author"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical" />
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/chart"
android:layout_width="200dp"
android:layout_height="50dp" />
</androidx.appcompat.widget.LinearLayoutCompat>
</androidx.appcompat.widget.LinearLayoutCompat>
</com.google.android.material.card.MaterialCardView>

View file

@ -281,6 +281,18 @@
tools:maxLines="10"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.chip.ChipGroup
android:id="@+id/status_hashtags"
android:visibility="gone"
tools:visibility="visible"
android:layout_marginStart="48dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:chipSpacingHorizontal="6dp"
app:chipSpacingVertical="6dp"
app:layout_constraintTop_toBottomOf="@id/description"/>
<androidx.core.widget.NestedScrollView
android:id="@+id/status_content_maths"
android:layout_width="match_parent"
@ -725,6 +737,7 @@
android:layout_width="0dp"
android:layout_height="48dp"
android:contentDescription="@string/action_quote"
android:visibility="gone"
app:icon="@drawable/ic_baseline_format_quote_24"
app:iconGravity="textStart"
app:iconSize="28dp"
@ -851,6 +864,7 @@
app:layout_constraintWidth_max="48dp" />
<androidx.constraintlayout.helper.widget.Flow
android:id="@+id/action_buttons_flow"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:constraint_referenced_ids="action_button_reply_container,action_button_boost_container,action_button_quote,action_button_favorite_container,action_button_bookmark,action_button_translate,action_button_maths,status_add_custom_emoji,status_emoji,action_button_more"

View file

@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.AppCompatImageView
<com.google.android.material.imageview.ShapeableImageView
android:id="@+id/media"
android:adjustViewBounds="true"
android:layout_height="match_parent"
@ -16,6 +16,9 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Fedilab.DrawerMedia"
app:strokeColor="?colorOutline"
app:strokeWidth="1dp"
tools:ignore="ContentDescription" />
<androidx.media3.ui.PlayerView

View file

@ -14,91 +14,108 @@
You should have received a copy of the GNU General Public License along with Fedilab; if not,
see <http://www.gnu.org/licenses>.
-->
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.material.card.MaterialCardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/main_container"
style="@style/Widget.Material3.CardView.Outlined"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:divider="?android:dividerHorizontal"
android:gravity="bottom"
android:orientation="vertical"
android:showDividers="end">
android:layout_marginVertical="6dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:orientation="vertical">
<androidx.appcompat.widget.AppCompatTextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textStyle="bold"
android:textAppearance="@style/TextAppearance.Material3.BodyLarge"
app:layout_constraintBottom_toTopOf="@id/host"
app:layout_constraintEnd_toStartOf="@id/pickup"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
tools:text="@tools:sample/cities" />
<androidx.appcompat.widget.AppCompatTextView
<com.google.android.material.textview.MaterialTextView
android:id="@+id/host"
android:layout_width="wrap_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
app:layout_constraintStart_toEndOf="@+id/name"
app:layout_constraintTop_toTopOf="parent" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:textAppearance="@style/TextAppearance.Material3.BodySmall"
app:layout_constraintBottom_toTopOf="@id/barrier_1"
app:layout_constraintEnd_toStartOf="@id/pickup"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/name" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/description" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/followers_instance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:drawablePadding="10dp"
app:drawableStartCompat="@drawable/ic_baseline_group_24"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tags" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/languages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:drawablePadding="10dp"
app:drawableStartCompat="@drawable/ic_baseline_forum_24"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/followers_instance" />
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/sensitive_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/languages" />
app:layout_constraintTop_toBottomOf="@id/name"
tools:text="@tools:sample/cities" />
<com.google.android.material.button.MaterialButton
android:id="@+id/pickup"
style="@style/Widget.Material3.Button.ElevatedButton"
style="@style/Widget.Material3.Button.TonalButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="@string/pickup_instance"
app:icon="@drawable/ic_navigate_next"
app:iconGravity="end"
app:layout_constraintBottom_toTopOf="@id/barrier_1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sensitive_content" />
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier_1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:barrierDirection="bottom"
app:constraint_referenced_ids="host,pickup" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:textAppearance="@style/TextAppearance.Material3.BodyMedium"
app:layout_constraintTop_toBottomOf="@id/barrier_1"
tools:maxLines="4"
tools:text="@tools:sample/lorem/random" />
<com.google.android.material.chip.ChipGroup
android:id="@+id/chips"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
app:chipSpacingHorizontal="6dp"
app:chipSpacingVertical="6dp"
app:layout_constraintTop_toBottomOf="@id/description">
</com.google.android.material.chip.ChipGroup>
<com.google.android.material.textview.MaterialTextView
android:id="@+id/followers_instance"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:drawablePadding="12dp"
app:drawableStartCompat="@drawable/ic_baseline_group_24"
app:layout_constraintTop_toBottomOf="@id/chips" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/languages"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:drawablePadding="12dp"
app:drawableStartCompat="@drawable/ic_baseline_forum_24"
app:layout_constraintTop_toBottomOf="@id/followers_instance" />
<com.google.android.material.textview.MaterialTextView
android:id="@+id/sensitive_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
app:layout_constraintTop_toBottomOf="@id/languages" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.appcompat.widget.LinearLayoutCompat>
</com.google.android.material.card.MaterialCardView>

View file

@ -68,7 +68,7 @@
<string name="favourite_remove">هل تود إزالة هذه الرسالة من مفضلاتك؟</string>
<string name="reblog_add">هل تود إعادة مشاركة هذه الرسالة؟</string>
<string name="reblog_remove">هل تود إلغاء إعادة مشاركة هذه الرسالة؟</string>
<string name="more_action_1">كتم</string>
<string name="more_action_1">الكتم</string>
<string name="more_action_2">حظر</string>
<string name="more_action_3">الإبلاغ عنه</string>
<string name="more_action_4">حذف</string>
@ -179,7 +179,7 @@
<string name="notif_status">أنشأ رسالة جديدة</string>
<string name="notif_reblog">رقى تبويقك</string>
<string name="notif_favourite">أُعجِب بتبويقك</string>
<string name="notif_follow">يتابعك</string>
<string name="notif_follow">يُتابعك</string>
<string name="notif_follow_request">طلب متابَعتك</string>
<string name="delete_notification_ask_all">هل تود حذف كافة الإشعارات؟</string>
<string name="delete_notification_all">تم حذف جميع الإشعارات بنجاح!</string>
@ -241,7 +241,7 @@
</string-array>
<string name="action_follow">متابعة</string>
<string name="action_unblock">إلغاء الحظر</string>
<string name="action_mute">كتم</string>
<string name="action_mute">كتم الصوت</string>
<string name="action_unmute">إلغاء الكتم</string>
<string name="request_sent">تم إرسال الطلب</string>
<string name="followed_by">يتابعك</string>
@ -605,7 +605,7 @@
<string name="replace_instagram">انستغرام</string>
<string name="replace_twitter_description">استخدام واجهة أمامية بديلة لتويتر</string>
<string name="replace_instagram_description">استخدام واجهة أمامية بديلة لـ Instagram</string>
<string name="hide_content">إخفاء المحتوى &lt;</string>
<string name="hide_content"><![CDATA[إخفاء المحتوى <]]></string>
<string name="set_accounts_page">عدد الحسابات لكل تحميل</string>
<string name="replace_youtube_host">نطاق الواجهة الأمامية لـ YouTube</string>
<string name="replace_reddit">ريديت</string>
@ -619,7 +619,7 @@
<string name="data_export_settings_success">تم تصدير الإعدادات بنجاح</string>
<string name="data_import_settings_success">تم استيراد الإعدادات بنجاح</string>
<string name="followers_only">المتابِعون فقط</string>
<string name="show_content">إظهار المحتوى&gt;</string>
<string name="show_content">إظهار المحتوى &gt;</string>
<string name="stop_recording">إيقاف التسجيل</string>
<string name="replace_instagram_host">نطاق الواجهة الأمامية لـ Instagram</string>
<string name="toots_visibility_title">مدى رؤية الرسائل بشكل افتراضي:</string>
@ -680,7 +680,7 @@
<string name="account_unsuspended">الحساب غير معلّق</string>
<string name="account_suspended">تم تعليق الحساب</string>
<string name="account_disabled">تم تعطيل الحساب</string>
<string name="state">الحالة</string>
<string name="state">الحَالة</string>
<string name="restart_the_app">إعادة تشغيل التطبيق؟</string>
<string name="restart_the_app_theme">تحتاج إلى إعادة تشغيل التطبيق لتفعيل التغييرات.</string>
<string name="set_language_picker_title">اللغات في المُنتَقي</string>
@ -860,7 +860,7 @@
<string name="set_autoplay_gif">تشغيل الوسائط المتحركة آليا</string>
<string name="thumbnail">الصورة المصغرة</string>
<string name="set_alt_text_mandatory_warn">تنبيه فقط</string>
<string name="permission_missing">لم يتم منح الإذن</string>
<string name="permission_missing">لم يتم منح الإذن!</string>
<string name="about_mastodon">\"ماستدون ليس موقعا شبكيا واحدا مثل تويتر أو فيسبوك، بل هو شبكة من آلاف المجتمعات المحلية التي تديرها مختلف المنظمات والأفراد الذين يقدمون تجربة إعلامية اجتماعية مميزة.\"</string>
<string name="push_distributors">موزع الإشعارات</string>
<string name="report_indication_title_status">أخبرنا ما الخَطب مع هذا المنشور</string>
@ -913,4 +913,208 @@
<string name="display_remote_conversation">إظهار المحادثة البُعدية</string>
<string name="add_keyword">إضافة كلمة مفتاحية</string>
<string name="silenced">تم كتمه</string>
<string name="twitter_tags">وسوم تويتر (عبر Nitter)</string>
<string name="report_1_block">لن ترى منشوراتهم. لن يتمكنوا من رؤية منشوراتك أو متابعتك. سيتمكنون من معرفة أنهم محظورون.</string>
<string name="delete_cache_message">هل أنت متأكد أنك تريد حذف الذاكرة المؤقتة؟ إذا كانت لديك مسودات تحتوي على وسائط، فستفقد الوسائط المرفقة.</string>
<string name="messages_stored_in_drafts">الرسائل المخزنة في المسودات</string>
<string name="set_single_topbar">عند التمكين، سيكون للتطبيق شريط واحد فقط للخطوط الزمنية</string>
<string name="set_display_relative_date">عرض التاريخ النسبي للرسائل</string>
<string name="set_use_cache_indication">سيتم تخزين الخطوط الزمنية مؤقتًا حتى يكون التطبيق أسرع.</string>
<string name="set_display_counters_description">سيعرض عداد فقاعات في علامات تبويب الخطوط الزمنية للرسائل الجديدة</string>
<string name="unblock_domain_confirm">هل أنت متأكد من إلغاء حظر %1$s؟</string>
<string name="action_pinned_delete">حذف الخطوط الزمنية المثبتة؟</string>
<string name="thread_long_message_message">سيتم تقسيم الرسالة إلى عدة ردود لتتوافق مع الحد الأقصى لعدد الأحرف في خادمك.</string>
<string name="set_cardview">بطاقات مرتفعة</string>
<string name="toast_on_your_instance">بدأت المحادثة على خادمك!</string>
<string name="set_remove_left_margin">إزالة الهامش الأيسر في الخطوط الزمنية لجعل الرسائل أكثر إحكامًا</string>
<string name="exclude_visibility">استبعاد مستوى الرؤية</string>
<string name="self">ذاتي</string>
<string name="hide_single_media_with_card">إخفاء الوسائط المفردة عند وجود معاينة رابط</string>
<string name="set_mention_at_top">الإشارات في الأعلى</string>
<string name="number_of_replies">عدد الردود</string>
<string name="update_date">تاريخ التحديث</string>
<string name="tags_renamed">تم تغيير الوسم!</string>
<string name="tags_deleted">تمت إزالة الوسم!</string>
<string name="underline_links">تسطير العناصر القابلة للنقر</string>
<string name="chart_home_cache_logs">سجلات الذاكرة المؤقتة للرئيسية</string>
<string name="local_only">محلي فقط</string>
<string name="instance_health_indication">الإصدار: %s \n %s مستخدم - %s حالة</string>
<string name="qr_code_generator">مولد رمز الاستجابة السريعة</string>
<string name="approved">موافق عليه</string>
<string name="icons_extra_features_visibility_summary">إذا كان خادمك لا يقبل بعض الميزات الإضافية، يمكنك إخفاء هذه الأيقونات</string>
<string name="account_silenced">تم إسكات الحساب</string>
<string name="report">إبلاغ</string>
<string name="notif_signed_up">تم التسجيل</string>
<string name="set_customize_dark_indication">يسمح بتخصيص بعض العناصر في الرسائل للسمة الداكنة.</string>
<string name="auto_fetch_missing">جلب الرسائل المفقودة تلقائيًا</string>
<string name="more_options">خيارات إضافية</string>
<string name="action_favourite">إضافة للمفضلة</string>
<string name="warn_boost_no_media_description">تحذير إذا لم يكن للرسالة وصف وسائط قبل إعادة النشر</string>
<string name="add_content_warning">إضافة تحذير محتوى</string>
<string name="set_language">تعيين اللغة</string>
<string name="attach_files">إرفاق ملفات</string>
<string name="add_poll">إضافة استطلاع</string>
<string name="toast_error_internet">لا يوجد اتصال بالإنترنت!</string>
<string name="toast_error_token_empty">لا يمكن أن يكون الرمز فارغًا!</string>
<string name="favourited_by">أُعجب به بواسطة</string>
<string name="otp_message">رمز مصادقة ثنائية</string>
<string name="add_all_users_home_muted">إضافة جميع المستخدمين إلى قائمة الكتم في الرئيسية</string>
<string name="filter_action_explanations">اختر الإجراء الذي سيتم تنفيذه عندما يتطابق منشور مع المُرشح</string>
<string name="messages_in_cache_for_other_timelines">الرسائل المخزنة مؤقتًا للخطوط الزمنية الأخرى</string>
<string name="mute_tag">هل أنت متأكد من كتم الوسم %1$s؟</string>
<string name="toast_error_fetch_message">لم يتمكن التطبيق من العثور على الرسالة عن بعد.</string>
<string name="set_fetch_home">جلب رسائل الرئيسية تلقائيًا</string>
<string name="set_custom_accent_value_light_description">اللون الذي سيتم تطبيقه على السمة الفاتحة</string>
<string name="instance_information">معلومات الخادم</string>
<string name="network">الشبكة</string>
<string name="delete_notification_all_warning">هل أنت متأكد أنك تريد حذف جميع الإشعارات؟ لا يمكن التراجع عن هذا الإجراء.</string>
<string name="toast_fetch_error">لا يمكن للتطبيق العثور على البيانات عن بعد!</string>
<string name="translate_in">ترجمة إلى</string>
<string name="chart_home_cache">سجلات الذاكرة المؤقتة للرئيسية لكل ساعة</string>
<string name="set_notif_update">إشعار للتحديثات</string>
<string name="create_domain_block">إنشاء حظر نطاق</string>
<string name="type_default_theme_light">سمة فاتحة افتراضية</string>
<string name="translator_domain">نطاق المترجم</string>
<string name="card_picture">صورة البطاقة</string>
<string name="set_disable_topbar_scrolling_title">تعطيل تمرير الشريط العلوي</string>
<string name="set_audo_hide_compose_summary">إخفاء زر الإنشاء تلقائيًا عند التمرير لأعلى في الخط الزمني</string>
<string name="fail_count">%d فشل</string>
<string name="inserted_count">%d رسائل جديدة</string>
<string name="set_disable_release_notes_indication">عند نشر إصدار جديد، لن يتم تنبيهك داخل التطبيق.</string>
<string name="fetch_home_every">جلب الرئيسية كل</string>
<string name="reply_visibility">مستوى رؤية الرد</string>
<string name="hide_with_warning">إخفاء مع تحذير</string>
<string name="set_audo_hide_compose_title">إخفاء زر الإنشاء تلقائيًا</string>
<string name="remember_position">تذكر الموضع في الخطوط الزمنية</string>
<string name="set_live_translate">فرض الترجمة إلى لغة معينة. اختر القيمة الأولى لإعادة التعيين إلى إعدادات الجهاز</string>
<string name="icons_extra_features">أيقونات للميزات الإضافية</string>
<string name="set_display_local_only">عرض زر محلي فقط</string>
<string name="also_followed_by">متابع أيضًا بواسطة:</string>
<string name="action_change_subscribed_language">تغيير اللغات المشترك بها</string>
<string name="type_of_home_delay_title">وقت جلب الرئيسية</string>
<string name="set_mention_booster">الإشارة إلى مُعيد النشر</string>
<string name="set_mention_booster_indication">عند الرد على إعادة نشر، سيتم الإشارة إلى الشخص الذي أعاد النشر في الرد</string>
<string name="set_alt_text_mandatory_description_warn">إذا كانت هناك وسائط مفقودة، فسيتم عرض مربع حوار مع إمكانية إرسال الرسالة بدون وصف وسائط</string>
<string name="fails">فشل</string>
<string name="frequency_minutes">التكرار (بالدقائق)</string>
<string name="fetched_count">%d رسائل مجلوبة</string>
<string name="frequency_count_minutes">%d تكرار (بالدقائق)</string>
<string name="set_custom_accent">لون تمييز مخصص</string>
<string name="toast_try_later">من فضلك، حاول مرة أخرى لاحقًا.</string>
<string name="formula">صيغة</string>
<string name="maths_format">تنسيق الرياضيات</string>
<string name="no_cached_messages">لا توجد رسائل مخزنة مؤقتًا في الرئيسية!</string>
<string name="check_home_cache">التحقق من الذاكرة المؤقتة للرئيسية</string>
<string name="set_custom_accent_dark_value">لون تمييز داكن</string>
<string name="set_custom_accent_value_dark_description">اللون الذي سيتم تطبيقه على السمة الداكنة</string>
<string name="clipboard_version">تم نسخ المعلومات إلى الحافظة</string>
<string name="tag_already_followed">أنت تتابع هذا الوسم بالفعل!</string>
<string name="show_self_boosts">عرض معيدات النشر الخاصة بي</string>
<string name="show_self_replies">عرض ردودي الخاصة</string>
<string name="set_push_notifications_delay">تعيين التأخير بين كل عملية جلب جديدة</string>
<string name="notif_reported">أرسل تقريرًا</string>
<string name="set_pixelfed_full_media">وسائط بملء الشاشة</string>
<string name="set_pixelfed_full_media_indication">ستأخذ الوسائط عرض الشاشة بالكامل وسيتم احترام نسبة العرض إلى الارتفاع.</string>
<string name="copy_version">نسخ المعلومات</string>
<string name="is_up">يعمل!</string>
<string name="use_token">استخدام رمز</string>
<string name="toast_fail_authenticate">فشل التطبيق في مصادقة الحساب!</string>
<string name="set_unlisted_replies_indication">يتعلق هذا فقط بالردود العامة. عند التمكين، ستكون ردودك تلقائيًا ذات مستوى رؤية غير مدرج بدلاً من عام</string>
<string name="mark_unresolved">تمييز كغير محلول</string>
<string name="mark_resolved">تمييز كمحلول</string>
<string name="account_undisabled">تم إلغاء تعطيل الحساب</string>
<string name="not_interested">غير مهتم</string>
<string name="pref_custom_theme_new_summary">السماح بإنشاء سمتك المخصصة</string>
<string name="instance_token">الرمز الخاص بك</string>
<string name="action_reblog">إعادة نشر</string>
<string name="action_quote">اقتباس</string>
<string name="remove_content_warning">إزالة تحذير المحتوى</string>
<string name="change_visibility">تغيير مستوى الرؤية</string>
<string name="action_publish">نشر</string>
<string name="open_new_attachment_panel">فتح لوحة مرفقات جديدة</string>
<string name="close_new_attachment_panel">إغلاق لوحة المرفقات الجديدة</string>
<string name="attach_images">إرفاق صور</string>
<string name="attach_audio">إرفاق صوت</string>
<string name="attach_videos">إرفاق فيديوهات</string>
<string name="pronouns_support">دعم الضمائر</string>
<string name="is_down">متوقف!</string>
<string name="instance_health_uptime">وقت التشغيل: %,.2f %%</string>
<string name="report_1_mute">لن ترى منشوراتهم. لا يزال بإمكانهم متابعتك ورؤية منشوراتك ولن يعرفوا أنهم مكتومون.</string>
<string name="report_2_title">هل هناك أي منشورات تدعم هذا التقرير؟</string>
<string name="aggregate_notifications_summary">عند التشغيل، سيقوم التطبيق بدمج الإشعارات ذات الصلة</string>
<string name="display_media_notification_summary">سيتم عرض الوسائط في إشعارات معيدات النشر والمفضلة</string>
<string name="write_the_tag_to_follow">اكتب الوسم للمتابعة</string>
<string name="not_valid_tag_name">اسم الوسم غير صالح!</string>
<string name="max_indentation_thread">أقصى مسافة بادئة في السلاسل</string>
<string name="account_unsilenced">تم إلغاء إسكات الحساب</string>
<string name="set_language_picker">السماح بتقليل قائمة اللغات في المنتقي عند إنشاء رسالة.</string>
<string name="hide_completely">إخفاء بالكامل</string>
<string name="hide_with_warning_description">إخفاء المحتوى المُرشح خلف تحذير يذكر عنوان المُرشح</string>
<string name="hide_completely_description">إخفاء المحتوى المُرشح بالكامل، كما لو لم يكن موجودًا</string>
<string name="context_home_list">الرئيسية والقوائم</string>
<string name="keyword_or_phrase">كلمة مفتاحية أو عبارة</string>
<string name="display_remote_profile">عرض الملف الشخصي عن بعد</string>
<string name="notif_submitted_report">تم إرسال تقرير</string>
<string name="unpin_timeline">إزالة الخط الزمني المثبت؟</string>
<string name="unpin_timeline_description">هل أنت متأكد من إلغاء تثبيت هذا الخط الزمني؟</string>
<string name="order_lists">ترتيب القوائم</string>
<string name="admin_domainblock_domain">لن يمنع حظر النطاق إنشاء إدخالات حساب في قاعدة البيانات، ولكنه سيطبق تلقائيًا وبأثر رجعي طرق إشراف محددة على تلك الحسابات.</string>
<string name="admin_domainblock_reject_media">تجاهل جميع التقارير الواردة من هذا النطاق. غير ذي صلة بالتعليقات</string>
<string name="set_customize_light">تخصيص السمة الفاتحة</string>
<string name="set_customize_light_indication">يسمح بتخصيص بعض العناصر في الرسائل للسمة الفاتحة.</string>
<string name="set_customize_dark">تخصيص السمة الداكنة</string>
<string name="set_extand_extra_features">بتمكين هذا الخيار، سيعرض التطبيق ميزات إضافية. هذه الميزة مخصصة لبرامج التواصل الاجتماعي مثل Pleroma أو Akkoma أو Glitch Social</string>
<string name="icons_visibility">رؤية الأيقونات</string>
<string name="set_remote_profile">سيعرض التطبيق الملفات الشخصية بشكل عام للحصول على جميع الرسائل. ستحتاج التفاعلات إلى خطوة إضافية لتوحيد الرسائل.</string>
<string name="set_remote_conversation">سيعرض التطبيق المحادثات بشكل عام للحصول على جميع الرسائل. ستحتاج التفاعلات إلى خطوة إضافية لتوحيد الرسائل.</string>
<string name="set_display_compact_buttons">أزرار إجراءات مدمجة</string>
<string name="boost_original_date">عرض التاريخ الأصلي لمعيدات النشر</string>
<string name="set_disable_release_notes">تعطيل ملاحظات الإصدار</string>
<string name="home_cache">الذاكرة المؤقتة للرئيسية</string>
<string name="number_of_media">عدد الوسائط</string>
<string name="total_fetched">إجمالي الرسائل المجلبة</string>
<string name="set_custom_accent_indication">تحديد لون سمة لكل حساب</string>
<string name="admin_domainblock_reject_obfuscate">إخفاء اسم النطاق جزئيًا في القائمة إذا تم تمكين الإعلان عن قائمة قيود النطاق</string>
<string name="admin_domainblock_private_comment">تعليق حول هذا القيد على النطاق للاستخدام الداخلي من قبل المشرفين.</string>
<string name="admin_domainblock_public_comment">تعليق حول هذا القيد على النطاق للجمهور العام، إذا تم تمكين الإعلان عن قائمة قيود النطاق.</string>
<string name="saved_changes">تم حفظ التغييرات!</string>
<string name="type_of_theme">اختر وضعًا للسمة</string>
<string name="pref_customize_summary">السماح بتعيين ألوانك المخصصة للسمات.</string>
<string name="set_cardview_indication">عند التمكين، سيكون للعناصر في الخطوط الزمنية ظل وارتفاع.</string>
<string name="about_peertube">PeerTube هو أداة لمشاركة مقاطع الفيديو عبر الإنترنت طورته Framasoft، وهي منظمة فرنسية غير ربحية.… يسمح PeerTube بربط المنصات ببعضها البعض، مما يخلق شبكة كبيرة من المنصات المستقلة والمترابطة في نفس الوقت</string>
<string name="messages_in_cache_for_home">الرسائل المخزنة مؤقتًا للرئيسية</string>
<string name="set_your_max_char_count">تعيين الحد الأقصى لعدد الأحرف الخاص بك</string>
<string name="set_timelines_in_a_list">عند التمكين، سيتم عرض جميع الخطوط الزمنية المثبتة في قائمة منسدلة</string>
<string name="toast_feature_not_supported">لا يبدو أن خادمك يدعم هذه الميزة!</string>
<string name="watch_trends_for_instance">مشاهدة الاتجاهات لهذا الخادم</string>
<string name="admin_domainblock_severity">الإسكات سيجعل منشورات الحساب غير مرئية لأي شخص لا يتابعهم. التعليق سيزيل جميع محتويات الحساب والوسائط وبيانات الملف الشخصي. استخدم لا شيء إذا كنت ترغب فقط في رفض ملفات الوسائط.</string>
<string name="admin_domainblock_reject_reports">تجاهل جميع التقارير الواردة من هذا النطاق. غير ذي صلة بالتعليقات</string>
<string name="set_dynamic_color_indication">محاذاة لونية مع نظام ألوان خلفية شاشتك الشخصية.</string>
<string name="set_custom_colors">تعيين ألوان مخصصة</string>
<string name="light_custom_colors">فاتح - ألوان مخصصة</string>
<string name="cark_custom_colors">داكن - ألوان مخصصة</string>
<string name="group_reblogs">تجميع معيدات النشر في الخط الزمني الرئيسي</string>
<string name="icons_visibility_summary">يمكنك إخفاء هذه الأيقونات السفلية بأمان للحصول على مساحة أكبر. توجد أيضًا في القائمة الفرعية.</string>
<string name="set_display_reaction_indication">عرض أزرار ردود الفعل</string>
<string name="set_remote_profile_title">الملفات الشخصية عن بعد</string>
<string name="set_remote_conversation_title">المحادثات عن بعد</string>
<string name="set_pixelfed_presentation">عرض وسائط Pixelfed</string>
<string name="set_display_compact_buttons_description">لن تأخذ الأزرار في أسفل الرسائل العرض الكامل</string>
<string name="timeline_scrollbar">عرض شريط تمرير للخطوط الزمنية</string>
<string name="set_display_quote_indication">عرض زر اقتباس</string>
<string name="markdown_support">دعم ماركداون</string>
<string name="set_maths_support">كتابة صيغة</string>
<string name="filter_languages">تصفية اللغات</string>
<string name="toast_error_peertube_not_supported">خادم Peertube الخاص بك قديم جدًا ولا يمكن للتطبيق دعمه.</string>
<string name="fetch_home_messages">جلب رسائل الرئيسية</string>
<string name="set_mention_at_top_indication">عند الرد، ستتم إضافة جميع الإشارات إلى بداية الرسالة</string>
<string name="tags_stored">تم تخزين الوسم!</string>
<string name="more_media">%1$s وسائط إضافية</string>
<string name="set_alt_text_mandatory_description">لن يتم إرسال الرسالة إذا كان هناك وصف مفقود مع الوسائط</string>
<string name="truncate_links">قص الروابط</string>
<string name="truncate_links_max">الحد الأقصى للأحرف في الروابط</string>
<string name="messages">%1$d رسائل مخزنة مؤقتًا</string>
<string name="updated_count">%d رسائل محدثة</string>
<string name="track_selection_title">اختيار المسارات</string>
<string name="set_custom_accent_light_value">لون تمييز فاتح</string>
</resources>

File diff suppressed because it is too large Load diff

View file

@ -1096,4 +1096,24 @@
<string name="set_pixelfed_full_media">Média přes celý displej</string>
<string name="set_pixelfed_full_media_indication">Média se budou zobrazovat přes celou šířku displeje a u výšky se bude respektovat poměr stran.</string>
<string name="twitter_tags">Tagy Twitteru (přes Nitter)</string>
<string name="more_options">Více voleb</string>
<string name="action_favourite">Oblíbené</string>
<string name="action_reblog">Boostnout</string>
<string name="action_quote">Citovat</string>
<string name="add_content_warning">Přidat varování o obsahu</string>
<string name="remove_content_warning">Odstranit varování o obsahu</string>
<string name="change_visibility">Změnit viditelnost</string>
<string name="set_language">Nastavit jazyk</string>
<string name="action_publish">Publikovat</string>
<string name="open_new_attachment_panel">Otevřít panel pro novou přílohu</string>
<string name="close_new_attachment_panel">Zavřít panel pro novou přílohu</string>
<string name="attach_images">Připojit obrázky</string>
<string name="attach_audio">Připojit zvuk</string>
<string name="attach_videos">Připojit videa</string>
<string name="attach_files">Připojit soubory</string>
<string name="add_poll">Přidat anketu</string>
<string name="instance_information">Informace o instanci</string>
<string name="network">Síť</string>
<string name="set_audo_hide_compose_title">Automaticky skrývat tlačítko pro vytvoření</string>
<string name="set_audo_hide_compose_summary">Automaticky skrývat tlačítko pro vytvoření během posouvání nahoru po časové ose</string>
</resources>

View file

@ -61,7 +61,7 @@
<string name="disclaimer_full">Gall y wybodaeth isod roi adlewyrchiad anghyflawn o broffil y defnyddiwr.</string>
<string name="insert_emoji">Mewnosod emoji</string>
<string name="no_emoji">Ni gasglwyd emoji dethol gan yr ap am y tro.</string>
<string name="logout_account_confirmation">Are you sure you want to logout @%1$s@%2$s?</string>
<string name="logout_account_confirmation">Dych chi\'n siwr i chi eisiau allgofnodi @%1$s@%2$s?</string>
<!-- Status -->
<string name="no_status">Dim neges i\'w dangos</string>
<string name="favourite_add">Ychwanegu\'r neges hon at eich ffefrynnau\?</string>
@ -76,7 +76,7 @@
<string name="more_action_6">Rhannu</string>
<string name="more_action_7">Crybwyll</string>
<string name="more_action_8">Tawelu am gyfnod</string>
<string name="more_action_9">Delete &amp; re-draft</string>
<string name="more_action_9">Dileu &amp; ailwampio</string>
<string-array name="more_action_confirm">
<item>Tawelu\'r cyfrif hwn?</item>
<item>Blocio\'r cyfrif hwn?</item>
@ -105,11 +105,11 @@
<string name="date_day">%d d</string>
<plurals name="date_seconds_polls">
<item quantity="zero">%d seconds</item>
<item quantity="one">%d second</item>
<item quantity="two">%d seconds</item>
<item quantity="few">%d seconds</item>
<item quantity="many">%d seconds</item>
<item quantity="other">%d seconds</item>
<item quantity="one">%d eiliad</item>
<item quantity="two">eiliad</item>
<item quantity="few">%d eiliadau</item>
<item quantity="many">%d eiliadau</item>
<item quantity="other"></item>
</plurals>
<plurals name="date_minutes_polls">
<item quantity="zero">%d minutes</item>
@ -120,20 +120,20 @@
<item quantity="other">%d minutes</item>
</plurals>
<plurals name="date_hours_polls">
<item quantity="zero">%d hours</item>
<item quantity="one">%d hour</item>
<item quantity="two">%d hours</item>
<item quantity="few">%d hours</item>
<item quantity="many">%d hours</item>
<item quantity="other">%d hours</item>
<item quantity="zero">%d awr</item>
<item quantity="one">%d awr</item>
<item quantity="two">%d awr</item>
<item quantity="few">%d oriau</item>
<item quantity="many">%d oriau</item>
<item quantity="other"></item>
</plurals>
<plurals name="date_day_polls">
<item quantity="zero">%d days</item>
<item quantity="one">%d day</item>
<item quantity="two">%d days</item>
<item quantity="few">%d days</item>
<item quantity="many">%d days</item>
<item quantity="other">%d days</item>
<item quantity="one">%d dydd</item>
<item quantity="two">%d dydd</item>
<item quantity="few">%d dyddiau</item>
<item quantity="many">%d dyddiau</item>
<item quantity="other"></item>
</plurals>
<!-- TOOT -->
<string name="toot_select_image_error">Roedd gwall!</string>
@ -176,11 +176,11 @@
<!-- Notifications -->
<string name="no_notifications">Dim hysbysiad i\'w arddangos</string>
<string name="notif_mention">wedi\'ch crybwyll</string>
<string name="notif_status">wrote a new message</string>
<string name="notif_status">wedi ysgrifennu neges newydd</string>
<string name="notif_reblog">wedi hybu\'ch tŵt</string>
<string name="notif_favourite">wedi nodi\'ch tŵt yn ffefryn</string>
<string name="notif_follow">wedi\'ch dilyn chi</string>
<string name="notif_follow_request">asked to follow you</string>
<string name="notif_follow_request">ymofyn i ganlyn chi</string>
<string name="delete_notification_ask_all">Dileu pob hysbysiad?</string>
<string name="delete_notification_all">Mae pob hysbysiad wedi ei ddileu!</string>
<!-- HEADER -->
@ -318,10 +318,10 @@
<string name="channel_notif_follow">New follow</string>
<string name="channel_notif_boost">Hybiad newydd</string>
<string name="channel_notif_fav">Ffefryn newydd</string>
<string name="channel_notif_mention">New Mention</string>
<string name="channel_notif_mention">Crybwylliad newydd</string>
<string name="channel_notif_poll">Poll Ended</string>
<string name="channel_notif_backup">Negeseuon wrth gefn</string>
<string name="channel_notif_status">New posts</string>
<string name="channel_notif_status">Postiau newydd</string>
<string name="channel_notif_media">Lawrlwytho Cyfryngau</string>
<string name="select_sound">Dewis tôn</string>
<string name="set_enable_time_slot">Caniatau slot amser</string>
@ -398,34 +398,34 @@
<string name="no_tags">Dim tagiau</string>
<string name="set_retrieve_metadata_share_from_extras">Attach an image when sharing a URL</string>
<!-- end languages -->
<string name="create_poll">Create a poll</string>
<string name="poll_choice_s">Choice %d</string>
<string name="create_poll">Creu pôl</string>
<string name="poll_choice_s">Dewis %d</string>
<string name="poll_invalid_choices">You need two choices at least for the poll!</string>
<string name="done">Done</string>
<string name="done">Wedi gorffen</string>
<string name="poll_finish_at">end at %s</string>
<string name="vote">Vote</string>
<string name="notif_poll">A poll you have voted in has ended</string>
<string name="notif_poll_self">Mae arolwg barn a gyhoeddwyd gennych wedi dod i ben</string>
<string name="settings_category_notif_categories">Categories</string>
<string name="settings_category_notif_categories">Categorïau</string>
<string name="move_timeline">Move timeline</string>
<string name="hide_timeline">Hide timeline</string>
<string name="reorder_timelines">Rheoli ffrydiau</string>
<string name="reorder_list_deleted">List permanently deleted</string>
<string name="reorder_list_deleted">Rhestr wedi dileu\'n barhaol</string>
<string name="reorder_instance_removed">Followed instance removed</string>
<string name="reorder_tag_removed">Pinned tag removed</string>
<string name="undo">Undo</string>
<string name="undo">Dadwneud</string>
<string name="warning_main_timeline">Main timelines can only be hidden!</string>
<string name="set_sensitive_content">Always mark media as sensitive</string>
<string name="gnu_instance">GNU instance</string>
<string name="gnu_instance">Enghraifft GNU</string>
<string name="set_forward_tags">Forward tags in replies</string>
<string name="set_long_press_media">Long press to store media</string>
<string name="add_tags">Manage tags</string>
<string name="add_tags">Rheoli tagiau</string>
<string name="display_name">Display name</string>
<string name="label_emoji">Emoji</string>
<string name="label_text">Text</string>
<string name="label_filter">Filter</string>
<string name="label_brush">Brush</string>
<string name="discard">Discard</string>
<string name="label_brush">Brws</string>
<string name="discard">Gwaredu</string>
<string name="saving">Saving…</string>
<string name="image_saved">Image Saved Successfully!</string>
<string name="save_image_failed">Failed to save Image</string>
@ -435,30 +435,30 @@
<string name="toast_unmute_conversation">The conversation is no longer muted!</string>
<string name="toast_mute_conversation">The conversation is muted</string>
<string name="category_general">General</string>
<string name="category_regional">Regional</string>
<string name="category_art">Art</string>
<string name="category_regional">Rhanbarthol</string>
<string name="category_art">Celf</string>
<string name="category_activism">Activism</string>
<string name="category_games">Gaming</string>
<string name="category_games">Gêmau</string>
<string name="category_tech">Technology</string>
<string name="category_furry">Furry</string>
<string name="category_food">Food</string>
<string name="instance_logo">Logo of the instance</string>
<string name="join_mastodon">Join Mastodon</string>
<string name="category_furry">Blewog</string>
<string name="category_food">Bwyd</string>
<string name="instance_logo">Logo enghraifft</string>
<string name="join_mastodon">Ymuno â Mastodon</string>
<string name="pickup_instance_category">Choose an instance by picking up a category, then tap on a check button.</string>
<string name="users">%1$s users</string>
<string name="users">%1$s defnyddwyr</string>
<string name="password_confirm">Confirm password</string>
<string name="agreement_check">I agree to %1$s and %2$s</string>
<string name="server_rules">server rules</string>
<string name="agreement_check">Dw i\'n cytuno â %1$s a %2$s</string>
<string name="server_rules">rheolau gweinydd</string>
<string name="tos">terms of service</string>
<string name="sign_up">Cofrestru</string>
<string name="validation_needed">This instance works with invitations. Your account will need to be manually approved by an administrator before being usable.</string>
<string name="password_error">Passwords don\'t match!</string>
<string name="password_error">Dydy\'r cyfrinair ddim yn cyd-fynd!</string>
<string name="email_error">The email doesn\'t seem to be valid!</string>
<string name="email_indicator">You will be sent a confirmation e-mail</string>
<string name="password_indicator">Use at least 8 characters</string>
<string name="password_too_short">Password should contain at least 8 characters</string>
<string name="username_error">Username should only contain letters, numbers and underscores</string>
<string name="account_created">Account created!</string>
<string name="account_created">Cyfrif wedi creu!</string>
<string name="account_created_message"> Your account has been created!\n\n
Think to validate your email within the 48 next hours.\n\n
You can now connect your account by writing <b>%1$s</b> in the first field and tap on <b>Connect</b>.\n\n
@ -467,43 +467,43 @@
<string name="save_draft">Save the message in drafts?</string>
<string name="administration">Administration</string>
<string name="reports">Reports</string>
<string name="unresolved">Unresolved</string>
<string name="remote">Remote</string>
<string name="unresolved">Ddim wedi penderfynu</string>
<string name="remote">Bell</string>
<string name="active">Active</string>
<string name="pending">Pending</string>
<string name="disabled">Disabled</string>
<string name="suspended">Suspended</string>
<string name="permissions">Permissions</string>
<string name="disable">Disable</string>
<string name="silence">Silence</string>
<string name="pending">Hyd</string>
<string name="disabled">Anabl</string>
<string name="suspended">Ar grog</string>
<string name="permissions">Caniatâd</string>
<string name="disable">Anablu</string>
<string name="silence">Distawrwydd</string>
<string name="account">Account</string>
<string name="unsilence">Undo silence</string>
<string name="undisable">Undo disable</string>
<string name="suspend">Suspend</string>
<string name="unsuspend">Undo suspend</string>
<string name="unsilence">Dadwneud distawrwydd</string>
<string name="undisable">Dadwneud anablu</string>
<string name="suspend">Gwahardd</string>
<string name="unsuspend">Dadwneud gwahardd</string>
<string name="audio">The application needs to access audio recording</string>
<string name="voice_message">Voice message</string>
<string name="voice_message">Neges llais</string>
<string name="set_enable_time_slot_indication">During the time slot, the app will send notifications. You can reverse (ie: silent) this time slot with the right spinner.</string>
<string name="set_fit_preview_indication">Previews will not be cropped in timelines</string>
<string name="set_capitalize_indication">Automatically insert a line break after the mention to capitalize the first letter</string>
<string name="settings_title_custom_sharing_indication">Allow content creators to share statuses to their RSS feeds</string>
<string name="compose">Compose</string>
<string name="select">Select</string>
<string name="add_instances">Add an instance</string>
<string name="compose">Cyfansoddi</string>
<string name="select">Dewis</string>
<string name="add_instances">Adio enghraifft</string>
<string name="set_enable_crash_report">Enable crash reports</string>
<string name="set_enable_crash_report_indication">If enabled, a crash report will be created locally and then you will be able to share it.</string>
<string name="crash_title">Mae Fedilab wedi stopio :(</string>
<string name="crash_message">Mae modd i chi anfon adroddiad crash ata\'i drwy ebost. Bydd yn help i\'w ddatrys. :)\n\nMae modd i chi ychwanegu cynnwys ychwanegol! Diolch!</string>
<string name="visibility">Visibility</string>
<string name="visibility">Gwelededd</string>
<string name="set_disable_animated_emoji">Disable custom animated emojis</string>
<string name="report_account">Report account</string>
<plurals name="number_of_voters">
<item quantity="zero">%d voters</item>
<item quantity="one">%d voter</item>
<item quantity="two">%d voters</item>
<item quantity="few">%d voters</item>
<item quantity="many">%d voters</item>
<item quantity="other">%d voters</item>
<item quantity="zero">%d pleidleisiwr</item>
<item quantity="one">%d pleidleisiwr</item>
<item quantity="two">%d pleidleisiwr</item>
<item quantity="few">%d pleidleisiwyr</item>
<item quantity="many">%d pleidleisiwyr</item>
<item quantity="other"></item>
</plurals>
<string-array name="poll_choice_type">
<item>Single choice</item>
@ -531,7 +531,7 @@
<string name="note_for_account">Notes for the account</string>
<string name="set_resize_picture_indication">Allow to compress large photos into smaller sized photos with very less or negligible loss in quality of the image.</string>
<string name="set_resize_video_indication">Allow compressing videos while maintaining their quality.</string>
<string name="order_by">Order by</string>
<string name="order_by">Trefnu erbyn</string>
<string name="link_color_title">Links</string>
<string name="link_color">Change the color of links (URLs, mentions, tags, etc.) in messages</string>
<string name="boost_header_color_title">Reblogs header</string>
@ -540,19 +540,19 @@
<string name="boost_header_color">Change the color of the header for reblogs</string>
<string name="background_status_title">Posts</string>
<string name="background_status">Background color of posts in timelines</string>
<string name="reset_color">Reset colors</string>
<string name="reset_color">Ailosod lliwiau</string>
<string name="clik_reset">Tap here to reset all your custom colors</string>
<string name="reset">Reset</string>
<string name="icons_color_title">Icons</string>
<string name="icons_color">Color of bottom icons in timelines</string>
<string name="logo_of_the_instance">Logo of the instance</string>
<string name="edit_profile">Edit profile</string>
<string name="make_an_action">Make an action</string>
<string name="translation">Translation</string>
<string name="logo_of_the_instance">Logo enghraifft</string>
<string name="edit_profile">Golygu proffeil</string>
<string name="make_an_action">Gwneud gweithred</string>
<string name="translation">Cyfieithiad</string>
<string name="text_color_title">Text color</string>
<string name="text_color">Change the text color in messages</string>
<string name="pref_custom_theme">Use a custom theme</string>
<string name="theming">Theming</string>
<string name="theming">Themâu</string>
<string name="data_export_theme">The theme was exported</string>
<string name="data_export_theme_success">The theme has been successfully exported in CSV</string>
<string name="import_theme">Import a theme</string>
@ -560,33 +560,33 @@
<string name="export_theme">Export the theme</string>
<string name="export_theme_title">Tap here to export the current theme</string>
<string name="theme_file_error">An error occurred when selecting the theme file</string>
<string name="user_count">User count</string>
<string name="status_count">Status count</string>
<string name="instance_count">Instance count</string>
<string name="user_count">Cyfrifiad defnyddwyr</string>
<string name="status_count">Cyfrifiad safleoedd</string>
<string name="instance_count">Cyfrifiad enghraifft</string>
<string name="poll_finish_in">End in %s</string>
<string name="no_instance_reccord">This instance is not available on https://instances.social</string>
<string name="no_instance_reccord">Dydy\'r enghraifft\'na ddim ar gael yn https://instances.social</string>
<string name="display_full_link">Display full link</string>
<string name="share_link">Share link</string>
<string name="open_other_app">Open with another app</string>
<string name="check_redirect">Check redirect</string>
<string name="no_redirect">This URL does not redirect</string>
<string name="redirect_detected">%1$s \n\nredirects to\n\n %2$s</string>
<string name="redirect_detected">%1$s \n\nyn ailgyfeirio i\n\n %2$s</string>
<string name="set_utm_parameters">Remove UTM parameters</string>
<string name="set_utm_parameters_indication">The app will automatically remove UTM parameters from URLs before visiting a link.</string>
<string name="talking_about">%d people talking</string>
<string name="twitter_accounts">Twitter accounts (via Nitter)</string>
<string name="talking_about">%d pobl yn sôn</string>
<string name="twitter_accounts">Cyfrifon Twitter (trwy Nitter)</string>
<string name="list_of_twitter_accounts">Twitter usernames space separated</string>
<string name="identity_proofs">Identity proofs</string>
<string name="verified_user">Verified identity</string>
<string name="verified_by">Verified by %1$s (%2$s)</string>
<string name="verified_by">Wedi gwirio erbyn %1$s (%2$s)</string>
<string name="action_disabled">Action disabled</string>
<string name="action_unfollow">Unfollow</string>
<string name="error_destination_path">Something went wrong, please check your download directory in settings.</string>
<string name="action_announcements">Announcements</string>
<string name="action_announcements">Cyhoeddiadau</string>
<string name="no_announcements">No announcements!</string>
<string name="add_reaction">Add a reaction</string>
<string name="set_video_cache">Video cache in MB, zero means no cache.</string>
<string name="set_watermark">Watermarks</string>
<string name="set_watermark">Dyfrnodau</string>
<string name="set_watermark_indication">Automatically add a watermark at the bottom of pictures. The text can be customized for each account.</string>
<string name="no_distributors_found">No distributors found!</string>
<string name="no_distributors_explanation">You need a distributor for receiving push notifications.\nYou will find more details at %1$s.\n\nYou can also disable push notifications in settings for ignoring that message.</string>
@ -625,4 +625,4 @@
<string name="set_accounts_page">Nifer y cyfrifon fesul llwyth</string>
<string name="proxy_protocol_http">HTTP</string>
<string name="proxy_protocol_socks">SOCKS</string>
</resources>
</resources>

View file

@ -584,13 +584,13 @@
<string name="keepon">Fortfahren</string>
<string name="instance_not_valid">Diese Instanz scheint nicht gültig zu sein!</string>
<string name="boosted_by">Geteilt von</string>
<string name="favourited_by">Favoritisiert von</string>
<string name="favourited_by">Favorisiert von</string>
<string name="followers_only">Nur Follower</string>
<string name="eg_sensitive_content">Z. B.: Sensibler Inhalt</string>
<string name="add_status">Status hinzufügen</string>
<string name="remove_status">Status entfernen</string>
<string name="instance_health_checkedat">Überprüft am: %s</string>
<string name="show_content">Inhalt anzeigen &gt;</string>
<string name="show_content"><![CDATA[Inhalt anzeigen >]]></string>
<string name="stop_recording">Aufnahme anhalten</string>
<string name="report_val1">Ich mag es nicht</string>
<string name="report_val2">Es ist Spam</string>
@ -660,7 +660,7 @@
<string name="bottom_menu">Unteres Menü</string>
<string name="top_menu">Oberes Menü</string>
<string name="report_1_title_more">Einstellungen zur Kontrolle dessen, was Du auf Mastodon siehst:</string>
<string name="hide_content">Inhalt verbergen &lt;</string>
<string name="hide_content"><![CDATA[Inhalt verbergen <]]></string>
<string name="category_custom">Benutzerdefiniert</string>
<string name="post_message_text">Sende Nachricht %d/%d</string>
<string name="is_up">Ist erreichbar!</string>
@ -894,8 +894,8 @@
<string name="admin_domainblock_domain">Das Blockieren der Domäne verhindert nicht die Erstellung von Konto-Einträgen in der Datenbank, sondern wendet rückwirkend und automatisch bestimmte Moderations-Methoden auf diese Konten an.</string>
<string name="admin_domainblock_reject_reports">Ignoriere alle Meldungen die von dieser Domäne kommen. Für Suspendierungen irrelevant</string>
<string name="admin_domainblock_severity">Stummschaltung macht die Beiträge des Kontos für alle unsichtbar, die ihm nicht folgen. Suspendierung entfernt alle Inhalte, Medien und Profildaten des Kontos. Verwende Keine, wenn Du nur die Mediendateien ablehnen möchtest.</string>
<string name="admin_domainblock_reject_obfuscate">Verschleiere teilweise den Domänennamen in der Liste, wenn die Verteilung der Liste der Domänen-Beschränkunden aktiviert ist</string>
<string name="admin_domainblock_public_comment">Kommentiere die Domainbeschränkung für die Öffentlichkeit, wenn die Verteilung der Liste der Domainbeschränkunden aktiviert ist.</string>
<string name="admin_domainblock_reject_obfuscate">Verschleiere teilweise den Domänennamen in der Liste, wenn die Verteilung der Liste der Domänen-Beschränkungen aktiviert ist</string>
<string name="admin_domainblock_public_comment">Kommentiere die Domainbeschränkung für die Öffentlichkeit, wenn die Verteilung der Liste der Domainbeschränkungen aktiviert ist.</string>
<string name="order_lists">Listen sortieren</string>
<string name="notif_reported">Bericht senden</string>
<string name="mute_tag">Den Hashtag %1$s wirklich stummschalten\?</string>
@ -1078,4 +1078,25 @@
<string name="Pronouns">Pronomen</string>
<string name="pronouns_support">Unterstützung von Pronomen</string>
<string name="qr_code_generator">QR Code Generator</string>
<string name="instance_token">Dein Token</string>
<string name="more_options">Mehr Optionen</string>
<string name="action_favourite">Favorisieren</string>
<string name="action_quote">Zitieren</string>
<string name="add_content_warning">Content Warnung (CW) hinzufügen</string>
<string name="remove_content_warning">Content Warnung (CW) entfernen</string>
<string name="action_publish">Veröffentlichen</string>
<string name="change_visibility">Sichtbarkeit anpassen</string>
<string name="set_language">Sprache ändern</string>
<string name="network">Netzwerk</string>
<string name="set_audo_hide_compose_title">Verstecke Verfassen-Knopf automatisch</string>
<string name="set_audo_hide_compose_summary">Versteckt den Verfassen-Knopf automatisch beim Scrollen durch eine Timeline</string>
<string name="attach_images">Bilder anhängen</string>
<string name="attach_audio">Audio angehängen</string>
<string name="attach_videos">Videos anhängen</string>
<string name="open_new_attachment_panel">Anhangsbereich öffnen</string>
<string name="close_new_attachment_panel">Neuen Anhangsbereich schließen</string>
<string name="attach_files">Dateien anhängen</string>
<string name="add_poll">Umfrage anhängen</string>
<string name="links">Links</string>
<string name="toast_error_internet">Es gibt keine Verbindung zum Internet!</string>
</resources>

View file

@ -448,13 +448,7 @@
<string name="password_too_short">La contraseña debe tener al menos 8 caracteres</string>
<string name="username_error">Los nombres de usuario solo pueden contener letras, números y guiones bajos</string>
<string name="account_created">¡Cuenta creada!</string>
<string name="account_created_message"> ¡Tu cuenta ha sido creada!
\n
\n \u0020Valida tu correo electrónico dentro de las próximas 48 horas.
\n
\n \u0020Ahora puedes conectar tu cuenta escribiendo <b>%1$s</b> en el primer campo y pulsando en <b>Conectar</b>.
\n
\n \u0020<b>Importante</b>: Si tu instancia requiere validación, recibirás un correo electrónico cuando se haya completado. \u0020</string>
<string name="account_created_message">¡Tu cuenta ha sido creada! \n \n \u0020Valida tu correo electrónico dentro de las próximas 48 horas. \n \n \u0020Ahora puedes conectar tu cuenta escribiendo <b>%1$s</b> en el primer campo y pulsando en <b>Conectar</b>. \n \n \u0020<b>Importante</b>: Si tu instancia requiere validación, recibirás un correo electrónico cuando se haya completado.</string>
<string name="save_draft">¿Guardar el mensaje en borradores?</string>
<string name="administration">Administración</string>
<string name="reports">Informes</string>
@ -1064,7 +1058,7 @@
<string name="data_import_settings_success">Los ajustes se importaron con éxito</string>
<string name="messages_stored_in_drafts">Mensajes guardados en borradores</string>
<string name="watch_trends_for_instance">Mira los temas relevantes en esta instancia</string>
<string name="hide_content">Ocultar contenido &lt;</string>
<string name="hide_content"><![CDATA[Ocultar contenido <]]></string>
<string name="set_fetch_home">Obtener automáticamente los mensajes de inicio</string>
<string name="home_cache">Caché de Inicio</string>
<string name="type_of_home_delay_title">Intervalo de actualización de la página de inicio</string>

File diff suppressed because it is too large Load diff

View file

@ -956,7 +956,7 @@
<string name="set_remove_left_margin">Suppression de la marge de gauche dans les lignes de temps pour rendre les messages plus compacts</string>
<string name="version">Version</string>
<string name="post_format">Format de publication</string>
<string name="set_pixelfed_presentation">Présentation façon Pixelfed pour les médias</string>
<string name="set_pixelfed_presentation">Présentation de Pixelfed pour les médias</string>
<string name="set_display_quote_indication">Afficher le bouton « Citer »</string>
<string name="set_display_reaction_indication">Afficher les boutons \"Réactions\"</string>
<string name="set_post_format">Format du message</string>
@ -1075,7 +1075,7 @@
<string name="copy_version">Copier l\'information</string>
<string name="qr_code_generator">Générateur de QR Code</string>
<string name="set_disable_topbar_scrolling_title">Désactiver le défilement de la barre supérieure</string>
<string name="thread_long_message_message">Le message sera divisé en plusieurs réponses en respectant la limite des caractères max de votre instance.</string>
<string name="thread_long_message_message">Le message sera divisé en plusieurs réponses afin de respecter le nombre maximum de caractères de votre instance.</string>
<string name="card_picture">Image de la carte</string>
<string name="set_display_relative_date">Afficher la date relative des messages</string>
<string name="pronouns_support">Prise en charge des pronoms</string>
@ -1086,4 +1086,22 @@
<string name="toast_fail_authenticate">L\'application n\'a réussi à authentifier le compte!</string>
<string name="toast_error_internet">Pas de connexion internet!</string>
<string name="set_pixelfed_full_media">Médias en plein écran</string>
<string name="more_options">Plus d\'options</string>
<string name="action_favourite">Favorit</string>
<string name="action_quote">Citer</string>
<string name="add_content_warning">Ajouter avertissement de contenu</string>
<string name="action_publish">Publier</string>
<string name="open_new_attachment_panel">Ouvrir nouveau panneau de pièces jointes</string>
<string name="close_new_attachment_panel">Fermer nouveau panneau de pièces jointes</string>
<string name="attach_videos">Joindre vidéos</string>
<string name="attach_files">Joindre fichiers</string>
<string name="network">Réseau</string>
<string name="instance_information">Information de l\'instance</string>
<string name="add_poll">Ajouter un sondage</string>
<string name="remove_content_warning">Supprimer avertissement de contenu</string>
<string name="change_visibility">Changer la visibilité</string>
<string name="set_language">Définir la langue</string>
<string name="attach_audio">Joindre audio</string>
<string name="attach_images">Joindre images</string>
<string name="set_pixelfed_full_media_indication">Les fichiers multimédia ocuperont toute la largeur de l\'écran et le format de la hauteur de l\'image sera respecté.</string>
</resources>

View file

@ -1090,4 +1090,13 @@
<string name="more_options">Máis opcións</string>
<string name="action_quote">Citar</string>
<string name="remove_content_warning">Retirar aviso sobre o contido</string>
<string name="instance_information">Información da instancia</string>
<string name="set_audo_hide_compose_title">Oculta o botón para redactar</string>
<string name="network">Rede</string>
<string name="set_audo_hide_compose_summary">Oculta automáticamente o botón para redactar cando te desprazas nunha cronoloxía</string>
<string name="set_mention_booster">Mencionar a quen promoveu</string>
<string name="set_mention_booster_indication">Ao responder a unha promoción, a persoa que promoveu será mencionada na resposta</string>
<string name="links">Ligazóns</string>
<string name="link_image">Imaxe anexa á ligazón</string>
<string name="underline_bottom_hashtags">Destacar cancelos da parte inferior</string>
</resources>

View file

@ -602,7 +602,7 @@
<string name="channel_notif_signup">Nuova iscrizione</string>
<string name="channel_notif_report">Nuova segnalazione</string>
<string name="notif_update_push">Un messaggio che hai condiviso è stato modificato</string>
<string name="show_content">Mostra contenuto &gt;</string>
<string name="show_content"><![CDATA[Mostra contenuto >]]></string>
<string name="stop_recording">Ferma registrazione</string>
<string name="report_val4">Si tratta di altro</string>
<string name="report_1_unfollow">Stai seguendo questo account. Per non vedere più i suoi post sul tuo home feed, smetti di seguirlo.</string>
@ -660,7 +660,7 @@
<string name="post_message_text">Inviando messaggio %d/%d</string>
<string name="is_up">É online!</string>
<string name="notif_display_favourites">Preferiti</string>
<string name="hide_content">Nascondi contenuto&lt;</string>
<string name="hide_content"><![CDATA[Nascondi contenuto >]]></string>
<string name="report_1_mute_title">Muta %1$s</string>
<string name="report_more_additional">Commenti aggiuntivi</string>
<string name="dont_have_an_account">Non hai un account\?</string>
@ -1069,4 +1069,38 @@
<string name="fail_count">%d fallimenti</string>
<string name="group_reblogs">Raggruppa i riblog nella linea temporale iniziale</string>
<string name="fails">Fallisce</string>
<string name="Pronouns">Pronomi</string>
<string name="underline_links">Sottolinea gli elementi cliccabili</string>
<string name="instance_token">Il tuo token</string>
<string name="more_options">Altre opzioni</string>
<string name="action_quote">Cita</string>
<string name="action_favourite">Preferito</string>
<string name="remove_content_warning">Rimuovi l\'avviso sul contenuto</string>
<string name="add_content_warning">Aggiungi un avviso sul contenuto</string>
<string name="change_visibility">Cambia la visibilità</string>
<string name="set_language">Seleziona la lingua</string>
<string name="action_publish">Pubblica</string>
<string name="open_new_attachment_panel">Apri un pannello per nuovi allegati</string>
<string name="close_new_attachment_panel">Chiudi il pannello per nuovi allegati</string>
<string name="attach_images">Allega immagini</string>
<string name="attach_audio">Allega audio</string>
<string name="attach_videos">Allega video</string>
<string name="attach_files">Allega file</string>
<string name="add_poll">Aggiungi sondaggio</string>
<string name="toast_error_token_empty">Il token non può essere vuoto!</string>
<string name="instance_information">Informazioni sull\'istanza</string>
<string name="copy_version">Copia informazioni</string>
<string name="qr_code_generator">Generatore di QR</string>
<string name="twitter_tags">Tag Twitter (via Nitter)</string>
<string name="pronouns_support">Supporto dei pronomi</string>
<string name="toast_fail_authenticate">L\'app non è riuscita ad autenticare l\'account!</string>
<string name="tag_already_followed">Già segui questo tag!</string>
<string name="toast_error_internet">Non c\'è connessione internet!</string>
<string name="clipboard_version">Le informazioni sono state copiate negli appunti</string>
<string name="network">Rete</string>
<string name="set_mention_booster_indication">Quando si risponde ad un boost, la persone che è stata boostata sarà citata nella replica</string>
<string name="set_pixelfed_full_media">Media a schermo intero</string>
<string name="use_token">Usa un token</string>
<string name="set_display_relative_date">Mostra la data relativa per i messaggi</string>
<string name="timeline_scrollbar">Mostra la barra di scorrimento per le linee temporali</string>
</resources>

View file

@ -45,7 +45,7 @@
<string name="mention">Ibdaren</string>
<string name="reblog">Izuzar</string>
<string name="show_boosts">Sken-d izuzar</string>
<string name="show_replies">Ssekned tiririt</string>
<string name="show_replies">Sken-d tiririyin</string>
<string name="action_open_in_web">Ldi deg iminig</string>
<string name="translate">Suqel</string>
<!--- Menu -->
@ -63,12 +63,12 @@
<string name="no_emoji">The app did not collect custom emojis for the moment.</string>
<string name="logout_account_confirmation">Are you sure you want to logout @%1$s@%2$s?</string>
<!-- Status -->
<string name="no_status">Ulac ituten ara d-nesken</string>
<string name="no_status">Ulac iznan ara d-nesken</string>
<string name="favourite_add">Add this toot to your favourites?</string>
<string name="favourite_remove">Remove this toot from your favourites?</string>
<string name="reblog_add">Boost this toot?</string>
<string name="reblog_remove">Unboost this toot?</string>
<string name="more_action_1">Susem</string>
<string name="more_action_1">Sgugem</string>
<string name="more_action_2">Seḥbes</string>
<string name="more_action_3">Cetki</string>
<string name="more_action_4">Kkes</string>
@ -225,7 +225,7 @@
</string-array>
<string name="action_follow">Ḍfeṛ</string>
<string name="action_unblock">Serreḥ</string>
<string name="action_mute">Susem</string>
<string name="action_mute">Sgugem</string>
<string name="action_unmute">Unmute</string>
<string name="request_sent">Request sent</string>
<string name="followed_by">Yeṭafar-ik id</string>
@ -243,9 +243,9 @@
<string name="keywords_hint_custom_sharing">Awalen n tsaruţ…</string>
<!-- ACTIVITY CACHE -->
<string name="v_public">Azayez</string>
<string name="v_unlisted">Unlisted</string>
<string name="v_unlisted">War abdar</string>
<string name="v_private">Uslig</string>
<string name="v_direct">Direct</string>
<string name="v_direct">Srid</string>
<!-- PRIVACY -->
<string name="filter_regex">Filter out by regular expressions</string>
<string name="search">Nadi</string>
@ -324,7 +324,7 @@
<string name="display_toot_truncate">Sken ddeqs</string>
<string name="hide_toot_truncate">Sken kra kan</string>
<string name="tags_already_stored">The tag already exists!</string>
<string name="schedule_boost">Schedule boost</string>
<string name="schedule_boost">Sɣiwes azuzer</string>
<string name="boost_scheduled">The boost is scheduled!</string>
<string name="no_scheduled_boosts">No scheduled boost to display!</string>
<string name="open_menu">Ldi umuɣ</string>
@ -466,7 +466,7 @@
<string name="suspend">Suspend</string>
<string name="unsuspend">Undo suspend</string>
<string name="audio">The application needs to access audio recording</string>
<string name="voice_message">Voice message</string>
<string name="voice_message">Izen s taɣect</string>
<string name="set_enable_time_slot_indication">During the time slot, the app will send notifications. You can reverse (ie: silent) this time slot with the right spinner.</string>
<string name="set_fit_preview_indication">Previews will not be cropped in timelines</string>
<string name="set_capitalize_indication">Automatically insert a line break after the mention to capitalize the first letter</string>
@ -643,4 +643,9 @@
<string name="import_settings">Iɣewwaṛen n uketer</string>
<string name="load_settings">Ɛebbi iɣewwaṛen yettwasifḍen</string>
<string name="import_data">Kter isefka</string>
<string name="instance_information">Talɣut ɣef uqeddac</string>
<string name="interactions">Timyigawin</string>
<string name="Directory">Akaram</string>
<string name="my_instance">Aqeddac-iw</string>
<string name="followers_only">Imeḍfaṛen kan</string>
</resources>

View file

@ -97,4 +97,77 @@
<string name="set_custom_accent_light_value">Šviesi akcento spalva</string>
<string name="thumbnail">Miniatiūra</string>
<string name="set_custom_accent_dark_value">Tamsi akcento spalva</string>
<string name="favourite">Mėgstami</string>
<string name="follow">Nauji sekėjai</string>
<string name="mention">Paminėjimai</string>
<string name="reblog">Pasidalinimai</string>
<string name="show_boosts">Rodyti pasidalinimus</string>
<string name="show_replies">Rodyti atsakymus</string>
<string name="show_self_boosts">Rodyti savo pasidalinimus</string>
<string name="show_self_replies">Rodyti savo atsakymus</string>
<string name="show_my_messages">Rodyti mano įrašus</string>
<string name="show_privates">Rodyti tiesiogines žinutes</string>
<string name="action_open_in_web">Atverti naršyklėje</string>
<string name="translate">Versti</string>
<string name="home_menu">Pagrindinis</string>
<string name="context_home">Pagrindinė laiko juosta</string>
<string name="settings_category_label_interface">Sąsaja</string>
<string name="done">Atlikta</string>
<string name="display_name">Rodomas vardas</string>
<string name="label_emoji">Jaustukai</string>
<string name="more_options">Daugiau parinkčių</string>
<string name="muted_menu">Nutildyti naudotojai</string>
<string name="muted_menu_home">Pagrindinio nutildyti naudotojai</string>
<string name="send_email">Siųsti el. laišką</string>
<string name="disclaimer_full">Žemiau esanti informacija gali nevisiškai atitikti naudotojo profilį.</string>
<string name="insert_emoji">Įterpti jaustuką</string>
<string name="no_emoji">Šiuo metu programėlė nerinko pasirinktinių jaustukų.</string>
<string name="action_favourite">Pamėgti</string>
<string name="action_reblog">Pasidalinti</string>
<string name="action_quote">Cituoti</string>
<string name="poll_choice_s">%d pasirinkimas</string>
<string name="poll_invalid_choices">Reikia bent dviejų pasirinkimų apklausai.</string>
<string name="gnu_instance">GNU serveris</string>
<string name="label_text">Tekstas</string>
<string name="label_filter">Filtras</string>
<string name="profile_picture">Profilio nuotrauka</string>
<string name="blocked_menu">Užblokuoti naudotojai</string>
<string name="report_1_unfollow">Sekate šią paskyrą. Kad nebematytumėte jų įrašų savo pagrindiniame sraute, nebesekite jų.</string>
<string name="context_home_list">Pagrindinė ir sąrašai</string>
<string name="logout_account_confirmation">Ar tikrai norite atsijungti @%1$s@%2$s?</string>
<string name="messages_in_cache_for_home">Įrašai podėlyje skalei Pagrindinė</string>
<string name="mute_home">Nutildyti skalei pagrindinė</string>
<string name="check_home_cache">Tikrinti pagrindinio podėlį</string>
<string name="chart_home_cache_logs">Pagrindinio podėlio žurnalai</string>
<string name="chart_home_cache">Pagrindinio podėlio įrašai per valandą</string>
<string name="follows_you">Seka jus</string>
<string name="fails">Failai</string>
<string name="set_custom_accent_value_dark_description">Spalva, kuri bus taikoma tamsiai temai</string>
<string name="set_custom_accent_value_light_description">Spalva, kuri bus taikoma šviesiai temai</string>
<string name="fetch_home_every">Gauti pagrindinę kas</string>
<string name="type_of_home_delay_title">Pagrindinės gavimo laikas</string>
<string name="set_fetch_home">Automatiškai gauti pagrindinius įrašus</string>
<string name="set_live_translate">Priverstinai išverskite į konkrečią kalbą. Pasirinkite pirmąją reikšmę, kad atkurtumėte įrenginio nustatymus.</string>
<string name="home_cache">Pagrindinio podėlis</string>
<string name="fetch_home_messages">Gauti pagrindinius įrašus</string>
<string name="clipboard">Įrašo turinys nukopijuotas į iškarpinę</string>
<string name="clipboard_url">Įrašo URL nukopijuotas į iškarpinę</string>
<string name="clipboard_version">Informacija nukopijuota į iškarpinę</string>
<string name="media">Medija</string>
<string name="validate">Patikrinti</string>
<string name="share_with">Bendrinti su</string>
<string name="shared_via">Bendrinta per „Fedilab“</string>
<string name="replies">Atsakymai</string>
<string name="username">Naudotojo vardas</string>
<string name="drafts">Juodraščiai</string>
<string name="notifications">Pranešimai</string>
<string name="follow_request">Sekimo prašymai</string>
<string name="favourite_add">Pridėti šį įrašą prie savo mėgstamų?</string>
<string name="favourite_remove">Pašalinti šį įrašą iš savo mėgstamų?</string>
<string name="reblog_add">Pasidalinti šiuo įrašu?</string>
<string name="warn_boost_no_media_description">Įspėti, jei prieš pasidalinat įrašą nėra medijos aprašo</string>
<string name="no_status">Nėra įrašo parodyti.</string>
<string name="languages">Kalbos</string>
<string name="administration">Administravimas</string>
<string name="reports">Ataskaitos</string>
</resources>

View file

@ -276,7 +276,7 @@
<string name="poxy_port">Порт</string>
<string name="poxy_login">Имя пользователя</string>
<string name="poxy_password">Пароль</string>
<string name="set_share_details">Добавлять детали сообщения при перепосте</string>
<string name="set_share_details">Добавлять детали сообщения при перепубликации</string>
<string name="support_the_app_on_liberapay">Поддержать приложение на Liberapay</string>
<string name="alert_regex">В регулярном выражении есть ошибка!</string>
<string name="toast_instance_unavailable">На этом инстансе лент не найдено!</string>
@ -682,7 +682,7 @@
<string name="followed_tags">Отслеживаемые теги</string>
<string name="follow_tag">Подписаться на тег</string>
<string name="report_val4">Другое</string>
<string name="show_content">Показать содержимое &gt;</string>
<string name="show_content"><![CDATA[Показать содержимое>]]></string>
<string name="join_the_fediverse">Присоединяйтесь к fediverse</string>
<string name="invite_join_the_fediverse">Привет! Приглашаем Вас присоединиться к Fediverse.</string>
<string name="report_val_more4">Проблема не подпадает под другие категории</string>
@ -1030,4 +1030,13 @@
<string name="unmute_home">Не игнорировать для домашней</string>
<string name="mute_them_all">Игнорировать их все</string>
<string name="manage_accounts">Управление профилями</string>
<string name="toast_fetch_error">Приложение не может найти удаленные данные!</string>
<string name="set_notif_admin_report">Новый отчёт (модераторы)</string>
<string name="open_with_account">Открыть из другой учётной записи</string>
<string name="set_audo_hide_compose_title">Припрятывать кнопку Составить</string>
<string name="create_domain_block">Добавить блокировку домена</string>
<string name="admin_reject_obfuscate">Обфусцировать доменное имя</string>
<string name="admin_domainblock_reject_media">Игнорироать все жалобы, поступающие от этого домена. Не имеет значения для приостановок</string>
<string name="admin_reject_reports">Отклонять жалобы</string>
<string name="admin_domainblock_reject_reports">Игнорироать все жалобы, поступающие от этого домена. Не имеет значения для приостановок</string>
</resources>

View file

@ -372,32 +372,32 @@
<string name="change_tag_column">Змінити назву стовпця</string>
<string name="misskey_instance">Екземпляр Misskey</string>
<string name="trending">В тренді</string>
<string name="local">Local</string>
<string name="local">Місцевий</string>
<string name="category">Категорія</string>
<string name="description">Description</string>
<string name="description">Опис</string>
<string name="share">Поділіться</string>
<string name="toots_server">Повідомлення (сервер)</string>
<string name="toots_client">Повідомлення (пристрій)</string>
<string name="settings_category_label_timelines">Часові рамки</string>
<string name="settings_category_label_interface">Interface</string>
<string name="contact">Contacts</string>
<string name="settings_category_label_interface">Інтерфейс</string>
<string name="contact">Контакти</string>
<string name="toot_select_file_error">Під час вибору файлу резервної копії сталася помилка!</string>
<string name="action_logout_account">Вийти з облікового запису</string>
<string name="all">Все</string>
<string name="copy_link">Копіювати посилання</string>
<string name="calls_blocked">http-дзвінки, заблоковані програмою</string>
<string name="list_of_blocked_domains">Список заблокованих дзвінків</string>
<string name="submit">Submit</string>
<string name="submit">Надіслати</string>
<string name="filter_timeline_with_a_tag">Фільтрувати шкалу часу з тегами</string>
<string name="no_tags">No tags</string>
<string name="no_tags">Без тегів</string>
<string name="set_retrieve_metadata_share_from_extras">Додайте зображення, коли надсилаєте URL-адресу</string>
<!-- end languages -->
<string name="create_poll">Створіть опитування</string>
<string name="poll_choice_s">Вибір %d</string>
<string name="poll_invalid_choices">Вам потрібно принаймні два варіанти для опитування!</string>
<string name="done">Готово</string>
<string name="poll_finish_at">end at %s</string>
<string name="vote">Vote</string>
<string name="poll_finish_at">кінець о %s</string>
<string name="vote">Голосувати</string>
<string name="notif_poll">Опитування, у якому ви проголосували, завершено</string>
<string name="notif_poll_self">Опубліковане вами опитування закінчилося</string>
<string name="settings_category_notif_categories">Категорії</string>
@ -415,9 +415,9 @@
<string name="set_long_press_media">Натисніть і утримуйте, щоб зберегти медіа</string>
<string name="add_tags">Керуйте тегами</string>
<string name="display_name">Відображуване ім\'я</string>
<string name="label_emoji">Emoji</string>
<string name="label_text">Text</string>
<string name="label_filter">Filter</string>
<string name="label_emoji">Е-пошта</string>
<string name="label_text">Текст</string>
<string name="label_filter">Фільтр</string>
<string name="label_brush">Кисть</string>
<string name="discard">Відкинути</string>
<string name="saving">Збереження…</string>
@ -428,12 +428,12 @@
<string name="unmute_conversation">Увімкнути бесіду</string>
<string name="toast_unmute_conversation">Розмова більше не ігнорується!</string>
<string name="toast_mute_conversation">Розмова вимкнено</string>
<string name="category_general">General</string>
<string name="category_general">Загальне</string>
<string name="category_regional">Регіональний</string>
<string name="category_art">Арт</string>
<string name="category_activism">Активізм</string>
<string name="category_games">Геймінг</string>
<string name="category_tech">Technology</string>
<string name="category_tech">Технології</string>
<string name="category_furry">Пухнастий</string>
<string name="category_food">Їжа</string>
<string name="instance_logo">Логотип інстанції</string>
@ -453,24 +453,20 @@
<string name="password_too_short">Пароль має містити не менше 8 символів</string>
<string name="username_error">Ім\'я користувача має містити лише літери, цифри та підкреслення</string>
<string name="account_created">Обліковий запис створено!</string>
<string name="account_created_message"> Your account has been created!\n\n
Think to validate your email within the 48 next hours.\n\n
You can now connect your account by writing <b>%1$s</b> in the first field and click on <b>Connect</b>.\n\n
<b>Important</b>: If your instance required validation, you will receive an email once it is validated!
</string>
<string name="account_created_message">Ваш обліковий запис створено!\n\nПодумайте про підтвердження вашої електронної пошти протягом наступних 48 годин.\n\n Тепер ви можете підключити свій обліковий запис, ввівши <b>%1$s</b> у перше поле та натиснувши <b>Підключитися</b>.\n\n<b>Важливо</b>: Якщо ваш екземпляр потребував перевірки, ви отримаєте електронний лист після її завершення!</string>
<string name="save_draft">Зберегти повідомлення в чернетках?</string>
<string name="administration">Administration</string>
<string name="administration">Адміністрація</string>
<string name="reports">Reports</string>
<string name="unresolved">Невирішено</string>
<string name="remote">Дистанційний</string>
<string name="active">Active</string>
<string name="active">Активний</string>
<string name="pending">В очікуванні</string>
<string name="disabled">Вимкнено</string>
<string name="suspended">Підвішено</string>
<string name="permissions">Дозволи</string>
<string name="disable">Вимкнути</string>
<string name="silence">Тиша</string>
<string name="account">Account</string>
<string name="account">Обліковий запис</string>
<string name="unsilence">Відмінити тишу</string>
<string name="undisable">Відмінити вимкнення</string>
<string name="suspend">Призупинити</string>
@ -517,10 +513,10 @@
<string name="set_unfollow_validation">Показати діалогове вікно підтвердження, перш ніж скасувати підписку</string>
<string name="replace_medium">Replace Medium links</string>
<string name="replace_medium_description">Використовуйте альтернативний фронтенд для Medium</string>
<string name="replace_medium_host">Default: scribe.rip</string>
<string name="replace_medium_host">Середній фронтенд-домен</string>
<string name="set_push_notifications">Використовуйте систему push-повідомлень для отримання сповіщень у режимі реального часу.</string>
<string name="action_add_notes">Add notes</string>
<string name="note_for_account">Notes for the account</string>
<string name="action_add_notes">Додати нотатки</string>
<string name="note_for_account">Примітки до облікового запису</string>
<string name="set_resize_picture_indication">Дозволяє стискати великі фотографії у фотографії меншого розміру з дуже незначною втратою якості зображення.</string>
<string name="set_resize_video_indication">Дозволяє стискати відео, зберігаючи їх якість.</string>
<string name="order_by">Замовити за</string>
@ -530,32 +526,32 @@
<string name="displayname_title">Змініть колір відображуваного імені у верхній частині повідомлень</string>
<string name="username_title">Змініть колір імені користувача у верхній частині повідомлень</string>
<string name="boost_header_color">Змініть колір заголовка для реблогів</string>
<string name="background_status_title">Posts</string>
<string name="background_status_title">Дописи</string>
<string name="background_status">Колір фону публікацій у часових шкалах</string>
<string name="reset_color">Скинути кольори</string>
<string name="clik_reset">Торкніться тут, щоб скинути всі власні кольори</string>
<string name="reset">Скинути</string>
<string name="icons_color_title">Icons</string>
<string name="icons_color_title">Іконки</string>
<string name="icons_color">Колір нижніх значків на шкалі часу</string>
<string name="logo_of_the_instance">Логотип інстанції</string>
<string name="edit_profile">Редагувати профіль</string>
<string name="make_an_action">Зробіть дію</string>
<string name="translation">Переклад</string>
<string name="text_color_title">Text color</string>
<string name="text_color_title">Колір тексту</string>
<string name="text_color">Змінити колір тексту в повідомленнях</string>
<string name="pref_custom_theme">Використовуйте спеціальну тему</string>
<string name="theming">Тематизація</string>
<string name="data_export_theme">Тему було експортовано</string>
<string name="data_export_theme_success">Тему успішно експортовано у CSV</string>
<string name="import_theme">Import a theme</string>
<string name="import_theme">Імпорт теми</string>
<string name="import_theme_title">Торкніться тут, щоб імпортувати тему з попереднього експорту</string>
<string name="export_theme">Export the theme</string>
<string name="export_theme">Експорт теми</string>
<string name="export_theme_title">Торкніться тут, щоб експортувати поточну тему</string>
<string name="theme_file_error">Під час вибору файлу теми сталася помилка</string>
<string name="user_count">Кількість користувачів</string>
<string name="status_count">Кількість статусів</string>
<string name="instance_count">Кількість примірників</string>
<string name="poll_finish_in">End in %s</string>
<string name="poll_finish_in">Закінчиться через %s</string>
<string name="no_instance_reccord">Цей екземпляр недоступний на https://instances.social</string>
<string name="display_full_link">Показати повне посилання</string>
<string name="share_link">Поділитися посиланням</string>
@ -652,7 +648,7 @@
<string name="hide_content"><![CDATA[Hide content <]]></string>
<string name="report_val1">Мені це не подобається</string>
<string name="report_val4">Це щось інше</string>
<string name="stop_recording">ЗУпинити запис</string>
<string name="stop_recording">Зупинити запис</string>
<string name="report_1_title">Не хочеш це бачити?</string>
<string name="report_1_unfollow_title">Відписатись від %1$s</string>
<string name="instance_health_uptime">Час роботи: %,.2f %%</string>
@ -1106,4 +1102,11 @@
<string name="action_favourite">Улюблений</string>
<string name="network">Мережа</string>
<string name="instance_information">Інформація про примірник</string>
<string name="set_audo_hide_compose_title">Автоматично приховати кнопку створення</string>
<string name="set_audo_hide_compose_summary">Автоматично приховувати кнопку створення під час прокручування вгору на часовій шкалі</string>
<string name="set_mention_booster_indication">Під час відповіді на посилення особа, яка здійснила посилення, буде згадана у відповіді</string>
<string name="set_mention_booster">Згадайте бустер</string>
<string name="underline_bottom_hashtags">Виділіть нижні хештеги</string>
<string name="links">Посилання</string>
<string name="link_image">Зображення додано до посилання</string>
</resources>

View file

@ -1094,4 +1094,11 @@
<string name="instance_information">实例信息</string>
<string name="attach_files">附加文件</string>
<string name="network">网络</string>
<string name="set_audo_hide_compose_summary">向上滚动时间轴时自动隐藏编辑按钮</string>
<string name="set_audo_hide_compose_title">自动隐藏编辑按钮</string>
<string name="set_mention_booster_indication">回复转嘟时,会在回复中提及转发嘟文的人</string>
<string name="set_mention_booster">提及转发嘟文者</string>
<string name="links">链接</string>
<string name="underline_bottom_hashtags">突出显示底部话题标签</string>
<string name="link_image">附加到链接的图像</string>
</resources>

View file

@ -19,6 +19,7 @@
<string name="email">Email</string>
<string name="accounts">Accounts</string>
<string name="toots">Messages</string>
<string name="links">Links</string>
<string name="tags">Tags</string>
<string name="save">Save</string>
<string name="instance">Instance</string>
@ -731,13 +732,19 @@
<string name="interactions">Interactions</string>
<string name="add_filter">Add filter</string>
<string name="add_field">Add Field</string>
<string name="add_featured_hashtag">Add Featured Hashtag</string>
<string name="no_feature_hashtag_suggestion">No suggestions for featured hashtags!</string>
<string name="unlocked">Unlocked</string>
<string name="locked">Locked</string>
<string name="save_changes">Save changes</string>
<string name="set_bot_content">Bot account</string>
<string name="fields_title">Add or remove fields</string>
<string name="featured_hashtags_title">Add or remove featured hashtags</string>
<string name="set_discoverable_content">Account discoverable</string>
<string name="delete_field">Delete field</string>
<string name="delete_featured_hashtag">Delete featured hashtag</string>
<string name="delete_field_confirm">Are you sure you want to delete that field?</string>
<string name="delete_featured_hashtag_confirm">Are you sure you want to delete that featured hashtag?</string>
<string name="profiled_updated">Profile has been updated!</string>
<string name="not_valid_list_name">List name is not valid!</string>
<string name="no_account_in_list">No accounts found for this list!</string>
@ -1148,7 +1155,7 @@
<string name="SET_DISABLE_ANIMATED_EMOJI" translatable="false">SET_DISABLE_ANIMATED_EMOJI</string>
<string name="SET_CAPITALIZE" translatable="false">SET_CAPITALIZE</string>
<string name="SET_MENTIONS_AT_TOP" translatable="false">SET_MENTIONS_AT_TOP</string>
<string name="SET_MENTION_BOOSTER" translatable="false">SET_MENTION_BOOSTER</string>
<string name="SET_THREAD_MESSAGE" translatable="false">SET_THREAD_MESSAGE</string>
<string name="SET_THEME_BASE" translatable="false">SET_THEME_BASE</string>
<string name="SET_DYNAMICCOLOR" translatable="false">SET_DYNAMICCOLOR</string>
@ -1265,6 +1272,7 @@
<string name="SET_TIMELINE_SCROLLBAR" translatable="false">SET_TIMELINE_SCROLLBAR</string>
<string name="SET_MARKDOWN_SUPPORT" translatable="false">SET_MARKDOWN_SUPPORT</string>
<string name="SET_TRUNCATE_LINKS" translatable="false">SET_TRUNCATE_LINKS</string>
<string name="SET_UNDERLINE_BOTTOM_HASHTAGS" translatable="false">SET_UNDERLINE_BOTTOM_HASHTAGS</string>
<string name="SET_UNDERLINE_CLICKABLE" translatable="false">SET_UNDERLINE_CLICKABLE</string>
<string name="SET_PRONOUNS_SUPPORT" translatable="false">SET_PRONOUNS_SUPPORT</string>
<string name="SET_TRUNCATE_LINKS_MAX" translatable="false">SET_TRUNCATE_LINKS_MAX</string>
@ -1382,6 +1390,7 @@
<string name="set_push_notifications_delay">Set the delay between each new fetch</string>
<string name="refresh_every">Fetch notifications every:</string>
<string name="type_of_notifications_delay_title">Notifications fetch time</string>
<string name="link_image">Image attached to the link</string>
<string-array name="photo_editor_emoji" translatable="false">
<!-- Smiles -->
<item>u+1f604</item>
@ -2060,6 +2069,8 @@
<string name="set_mention_at_top">Mentions at the top</string>
<string name="set_mention_at_top_indication">When replying mentions will all be added to the beginning of the message</string>
<string name="set_mention_booster">Mention the booster</string>
<string name="set_mention_booster_indication">When replying to a boost, the person who boosted will be mentioned in the reply</string>
<string name="number_of_media">Number of media</string>
<string name="number_of_replies">Number of replies</string>
@ -2079,6 +2090,7 @@
<string name="toot_error_no_media_description">There are missing media descriptions</string>
<string name="truncate_links">Truncate links</string>
<string name="underline_bottom_hashtags">Highlight bottom hashtags</string>
<string name="underline_links">Underline clickable elements</string>
<string name="truncate_links_max">Max chars in links</string>

View file

@ -273,5 +273,8 @@
<item name="android:insetBottom">0dp</item>
</style>
<style name="ShapeAppearanceOverlay.Fedilab.DrawerMedia" parent="">
<item name="cornerSize">6dp</item>
</style>
</resources>

View file

@ -32,6 +32,15 @@
app:singleLineTitle="false"
app:summary="@string/set_mention_at_top_indication"
app:title="@string/set_mention_at_top" />
<SwitchPreferenceCompat
app:defaultValue="false"
app:iconSpaceReserved="false"
app:key="@string/SET_MENTION_BOOSTER"
app:singleLineTitle="false"
app:summary="@string/set_mention_booster_indication"
app:title="@string/set_mention_booster" />
<!--
<SwitchPreferenceCompat
app:defaultValue="false"

View file

@ -72,6 +72,14 @@
app:singleLineTitle="false"
app:title="@string/truncate_links" />
<SwitchPreferenceCompat
android:defaultValue="true"
app:iconSpaceReserved="false"
app:key="@string/SET_UNDERLINE_BOTTOM_HASHTAGS"
app:singleLineTitle="false"
app:title="@string/underline_bottom_hashtags" />
<SwitchPreferenceCompat
android:defaultValue="false"
app:iconSpaceReserved="false"
@ -256,7 +264,7 @@
app:title="@string/set_fit_preview" />
<SwitchPreferenceCompat
android:defaultValue="true"
android:defaultValue="false"
app:iconSpaceReserved="false"
app:key="@string/SET_AUTO_PLAY_GIG_MEDIA"
app:singleLineTitle="false"

View file

@ -373,8 +373,11 @@ public class Translate {
//Retrieves the translated content
String content;
try {
content = URLDecoder.decode(translationJson.getString("translation"), "utf-8");
} catch (UnsupportedEncodingException e) {
String data = translationJson.getString("translation");
data = data.replaceAll("%(?![0-9a-fA-F]{2})", "%25");
data = data.replaceAll("\\+", "%2B");
content = URLDecoder.decode(data, "utf-8");
} catch (Exception e) {
content = translationJson.getString("translation");
}
translate.setTranslatedContent(content);

View file

@ -0,0 +1,14 @@
تم إضافة:
- ثلاثة أيقونات تطبيق جديدة (برايد، وردي، وقرصان)
- الحفاظ على الموضع في المحادثات عن بعد
تم إصلاح:
- ماركداون: إيقاف تحليل الوسوم ودعم النص المشطوب
- جعل المؤشر أكثر وضوحاً عند الكتابة
- عدم عمل الحد الأقصى لطول الأحرف في النسخ المخصصة
- مشكلة علامات التبويب في الملفات الشخصية
- عدم إمكانية النقر على الوسوم في بعض اللغات
- خطأ يتعلق بالحسابات التي لديها عدد كبير جداً من المتابعين
- مشكلة الانهيار عند وجود عدة صور متحركة (GIF) في نفس الرسالة
- - الحد الأقصى لأحرف الاستطلاع
- بعض الأعطال

View file

@ -0,0 +1,8 @@
تمت إضافة:
- دعم أندرويد 14
- تقسيم الرسائل الطويلة تلقائيًا في سلاسل المحادثات (الافتراضي: اسأل)
- الروابط والوسائط قابلة للنقر عند الإنشاء
تم إصلاح:
- تجنب الخطأ 429 مع NTFY
- تم إصلاح العديد من الأعطال

View file

@ -0,0 +1,8 @@
تمت إضافة:
- دعم أندرويد 14
- تقسيم الرسائل الطويلة تلقائيًا في سلاسل المحادثات (الافتراضي: اسأل)
- الروابط والوسائط قابلة للنقر عند الإنشاء
تم إصلاح:
- تجنب الخطأ 429 مع NTFY
- تم إصلاح العديد من الأعطال

View file

@ -0,0 +1,14 @@
تمت الإضافة:
- السماح بوضع خط تحت العناصر القابلة للنقر (الإعدادات > الجداول الزمنية - الافتراضي: معطل)
- السماح بتعطيل التاريخ النسبي في الرسائل
تم التغيير:
- العدادات قريبة من أزرار الإجراءات
- إخفاء منتقي الرموز التعبيرية إذا لم يكن لدى المثيل رموز تعبيرية
- ترتيب الوسوم التي تتابعها
- منتقي الحساب عند الفتح بحساب آخر
تم الإصلاح:
- إصلاح عطل عند الإنشاء
- إصلاح مشكلة زر الرجوع
- إصلاح مشكلة عرض الوسوم التي تتابعها

View file

@ -0,0 +1,9 @@
**تمت الإضافة:**
- إضافة شريط تمرير للمخططات الزمنية (معطل افتراضيًا)
- إضافة شريط بحث للرموز التعبيرية المخصصة
**تم الإصلاح:**
- إصلاح ظهور المطالبة بالتقسيم عدة مرات عند الرفض
- إصلاح الأعطال المتعلقة بالملفات الشخصية
- إصلاح مشكلة تتعلق بالاستطلاعات وPleroma
- إصلاح عدم ظهور الرموز التعبيرية في أداة الاختيار

View file

@ -0,0 +1,25 @@
تمت إضافة:
- دعم أندرويد 14
- تقسيم الرسائل الطويلة تلقائيًا في سلاسل المحادثات (الافتراضي: اسأل)
- الروابط والوسائط قابلة للنقر عند الإنشاء
- السماح بوضع خط تحت العناصر القابلة للنقر (الإعدادات > الجداول الزمنية - الافتراضي: معطل)
- السماح بتعطيل التاريخ النسبي في الرسائل
- إضافة شريط تمرير للجداول الزمنية (الافتراضي: معطل)
- إضافة شريط بحث للرموز التعبيرية المخصصة
- الروابط قابلة للنقر في أوصاف الوسائط
تم تغيير:
- العدادات قريبة من أزرار الإجراءات
- إخفاء منتقي الرموز التعبيرية إذا لم يكن لدى المثيل أي رموز تعبيرية
- ترتيب الوسوم المتابعة
- منتقي الحساب عند الفتح بحساب آخر
تم إصلاح:
- تجنب الخطأ 429 مع NTFY
- إصلاح الألوان المخصصة (أندرويد 14)
- إصلاح عطل عند الإنشاء
- مشكلة عرض مع الوسوم المتابعة
- أعطال مع الملفات الشخصية
- إصلاح مشكلة مع الاستطلاع و Pleroma
- الرموز التعبيرية لا تظهر في المنتقي
- تم إصلاح العديد من الأعطال

View file

@ -0,0 +1 @@
يُفترض أن يُصلح هذا الإصدار الأعطال (TransactionTooLargeException). إذا واجهت أعطالاً، تراجع عن الإصدار عبر FDdroid.

View file

@ -0,0 +1,2 @@
- مشكلة في الإنشاء
- من المفترض أن يصلح هذا الإصدار الأعطال (TransactionTooLargeException). إذا واجهت أعطالاً، فعد إلى الإصدارات السابقة عبر FDdroid.

View file

@ -0,0 +1 @@
- إصلاح موضع التذكر

View file

@ -0,0 +1,6 @@
تمت إضافة:
- شريط علوي ثابت (افتراضي: معطل)
- تكرار استخدام الوسوم عند التأليف
تم إصلاح:
- بعض الأعطال

View file

@ -0,0 +1,11 @@
تمت إضافة:
- شريط علوي ثابت (معطل افتراضياً)
- تكرار استخدام الوسوم عند كتابة منشور
تم تغيير:
- تعطيل دعم Markdown افتراضياً
تم إصلاح:
- إصلاح الأعطال التي تحدث أثناء التفاعلات أو عند فتح شاشة جديدة
- إصلاح لون مربعات الحوار في الإعدادات
- إصلاح بعض الأعطال الطفيفة

View file

@ -0,0 +1,9 @@
تمت إضافة:
- النقر على لافتات الحسابات لعرضها كوسائط
تم إصلاح:
- فقدان الموضع عند التبديل بين الحسابات
- ظهور ملفات شخصية خاطئة عند تمكين المحادثات عن بعد
- الجدول الزمني المحلي لـ Peertube
- البحث عن مثيلات Peertube
- أعطال الإصدار السابق

View file

@ -0,0 +1,8 @@
تم إضافة:
- دعم الضمائر (الجدول الزمني / الإنشاء / الإكمال التلقائي)
تم تغيير:
- استخدام مكتبة Media3
تم إصلاح:
- مشاكل التعطل من الإصدار السابق

View file

@ -0,0 +1,10 @@
**أضيف:**
* دعم الضمائر (الجدول الزمني/الإنشاء/الإكمال التلقائي)
**تم تغيير:**
* استخدام مكتبة Media3
**تم إصلاح:**
* مدة كتم الصوت المؤقت طويلة جداً
* مشاركة مقاطع الفيديو تقوم بتنزيلها فقط
* أعطال من الإصدار السابق

View file

@ -0,0 +1,9 @@
تمت إضافة:
- السماح بتعطيل دعم الضمائر (افتراضي: ممكّن)
- إضافة المزيد من الدعم للضمائر (الترجمة إلى لغات مختلفة)
تم إصلاح:
- إصلاح انهيار عند الإبلاغ عن الرسائل
- إصلاح انهيار عند متابعة الوسوم
- إصلاح بعض مشاكل العرض
- عدة إصلاحات من الإصدار الأخير (3.28.0)

View file

@ -10,3 +10,16 @@
- إجراءات ما بين الحسابات بواسطة الضغط المطوّل
- ميزة الترجمة
- خطوط زمنية فنية
- خيارات متعددة للتحديثات التلقائية
- إشعارات الدفع عبر UnifiedPush (بما في ذلك ntfy على FDroid)
- البقاء متصلاً لتلقي الإشعارات المباشرة
- إشعارات مؤجلة (الاتصال كل 30 ثانية)
- استبدال روابط يوتيوب وتويتر بروابط إلى نسخ invidious و nitter
- سمات مخصصة، استيراد وتصدير، وتحديد
- استيراد وتصدير قاعدة بيانات التطبيق
- منتقي رموز تعبيرية (إيموجي) مع رموز مخصصة
- أيقونات تشغيل متعددة
- تصفية متقدمة للمنشورات (toots)
- جدول زمني فني خاص لوسم mastoart
- تصدير المنشورات (toots)
- تخصيص مشاركة الروابط لمشاركة الروابط مباشرة إلى خدمات أخرى

View file

@ -0,0 +1,14 @@
S'ha afegit:
- Tres noves icones d'app (Orgull, Rosa i Pirata)
- Mantenir la posició amb converses remotes
Reparacions:
- Markdown: atura l'anàlisi d'etiquetes i admet text tatxat
- Cursor més visible en redactar
- Corregeix la longitud màxima del caràcter personalitzat d'instància que no funciona
- Pestanyes als perfils
- Reparació d'etiquetes no clicables per a alguns idiomes
- Error amb comptes amb una gran quantitat de seguidores
- Fallides quan un bran tenia diversos gifs
- Màxim de carpacters en enquesta
- Algunes fallides

View file

@ -0,0 +1,8 @@
S'ha afegit:
- Suport per a Android 14
- Divideix automàticament els missatges llargs en els fils (per defecte: ASK)
- Els enllaços i els mèdia són clicables mentre es redacta
Reparacions:
- Evita l'error 429 amb NTFY
- S'han corregit diverses fallides

View file

@ -0,0 +1,8 @@
S'ha afegit:
- Suport per a Android 14
- Divideix automàticament els missatges llargs en els fils (per defecte: ASK)
- Els enllaços i els mèdia són clicables mentre es redacta
Reparacions:
- Evita l'error 429 amb NTFY
- S'han corregit diverses fallides

View file

@ -0,0 +1,14 @@
S'ha afegit:
- Permet subratllar els elements clicables (Configuració > Pissarres - per defecte: deshabilitat)
- Permet deshabilitar la data relativa en els brams
Canvis:
- Comptadors a tocar dels botons d'acció
- Oculta el selector d'emoticones si la instància no té emoticones
- S'ordenen les etiquetes en seguiment
- Selector de comptes en obrir amb un altre compte
Reparacions:
- Correcció d'una fallida en redactar
- Correcció d'un problema amb el botó d'enrere
- Problema de visualització amb les etiquetes en seguiment

View file

@ -0,0 +1,9 @@
S'ha afegit:
- Una barra rodoladora per a pissarres (per defecte: desactivada)
- Una barra de cerca per a les emoticones a mida
Reparacions:
- Reparat que l'indicador preguntés diverses vegades quan es rebutjava la divisió
- Fallides amb perfils
- Reparat un problema entre l'enquesta i Pleroma
- Emoticona que no sortia al selector

View file

@ -0,0 +1,25 @@
S'ha afegit:
- Suport per a Android 14
- Divisió automàtica dels brams llargs en els fils (per defecte: ASK)
- Enllaços i mèdia clicables en redactar
- Permetre de subratllar els elements clicables (Configuració > Pissarres - per defecte: deshabilitat)
- Permetre deshabilitar la data relativa en els brams
- Una barra de ròdol per a les pissarres (per defecte: deshabilitat)
- Una barra de cerca per emoticones a mida
- Enllaços clicables en les descripcions de mèdia
Canvis:
- Comptadors a tocar dels botons d'acció
- Ocultar el selector d'emoticones si la instància no té emoticones
- Ordenació de les etiquetes en seguiment
- Selector de comptes en obrir amb un altre compte
Reparacions:
- Evitar error 429 amb NTFY
- Correcció de colors a mida (Android 14)
- Correcció d'una fallida en redactar
- Problema de visualització d'etiquetes en seguiment
- Fallides amb perfils
- Correcció d'un problema entre l'enquesta i Pleroma
- Emoticona que no es mostra al selector
- Correcció de fallides diverses

View file

@ -0,0 +1 @@
Aquest llançament hauria de corregir les fallides (TransactionTooLargeException). Si teniu fallides, torneu a la versió anterior amb l'ajut d'FDdroid.

View file

@ -0,0 +1,2 @@
- Problema de redacció
- Aquesta versió hauria de corregir les fallides (TransactionTooLargeException). Si teniu fallides, torneu a la versió anterior amb l'ajut d'FDdroid.

View file

@ -0,0 +1 @@
- Reparat el record de posició

View file

@ -0,0 +1,6 @@
S'ha afegit:
- Reparació de barra superior (per defecte: deshabilitada)
- Freqüència d'ús d'etiquetes en redactar
Reparacions:
- Algunes fallides

View file

@ -0,0 +1,11 @@
S'ha afegit:
- Reparació de barra superior (per defecte: deshabilitada)
- Freqüència d'ús d'etiquetes en redactar
Canvis:
- El suport de Markdown està deshabilitat per defecte
Reparacions:
- Reparació de fallides en interaccions o en obrir una pantalla nova
- Reparat el color dels diàlegs a Configuració
- Algunes fallides menors

View file

@ -0,0 +1,9 @@
S'ha afegit:
- Tocar els bàners de comptes per mostrar-los com a mèdia
Reparacions:
- Pèrdua de posició en canviar entre comptes
- Perfils erronis en habilitar converses remotes
- Pissarra local de Peertube
- Cerca d'instàncies de Peertube
- Fallides de la versió anterior

View file

@ -0,0 +1,8 @@
S'ha afegit:
- Implementació de pronoms (Pissarra/Redactar/Autocompletar)
Canvis:
- Us de la biblioteca Media3
Reparacions:
- Fallides de la versió anterior

View file

@ -0,0 +1,10 @@
S'ha afegit:
- Implementació de pronoms (Pissarra/Redactar/Autocompletar)
Canvis:
- Us de la biblioteca Media3
Reparacions:
- Durada excessiva del silenciat temporal
- Compartició de vídeos només els descarregava
- Fallides de la versió anterior

View file

@ -0,0 +1,9 @@
S'ha afegit:
- Permet deshabilitar la compatibilitat amb els pronoms (per defecte: habilitat)
- Més suport per als pronoms (localització en diferents idiomes)
Reparacions:
- Reparada una fallida en denunciar brams
- Reparada una fallida en seguir etiquetes
- Reparats alguns problemes de visualització
- Diverses correccions de l'última versió (3.28.0)

View file

@ -0,0 +1,6 @@
S'ha afegit:
- Mostrar un codi QR als perfils
Reparacions:
- Reparació del toc de brams en les converses
- Els pronoms que ocupaven massa lloc

View file

@ -0,0 +1,11 @@
S'ha afegit:
- Permetre editar brams programats de la banda del servidor
Canvis:
- Ordenar alfabèticament el nom de la llista en els perfils
Reparacions:
- Notificacions fugaces
- Selector d'instàncies del Peertube
- Edició de fils programats (local)
- Cerca instantània de resultats repetits de Hashtag

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