Compare commits

..

307 Commits

Author SHA1 Message Date
sk
99f0817bdb generalize filtering logic 2023-05-26 02:07:50 +02:00
sk
220cd35d82 fix context not checked for warnings
closes sk22#518
2023-05-25 21:25:09 +02:00
sk
07f4ef1697 remove unused imports 2023-05-25 21:22:27 +02:00
sk
f20732ddc2 Merge remote-tracking branch 'upstream/master' 2023-05-25 20:27:23 +02:00
sk
b1e0dc5843 show compose button when switching tab
closes sk22#506
2023-05-25 20:26:59 +02:00
Gregory K
285eb25706 Merge pull request #584 from sk22/fix-restored-tab-selection
Fix wrong tab being selected on restore
2023-05-25 21:00:12 +03:00
sk
ec556511e6 Merge branch 'fix-restored-tab-selection' 2023-05-25 19:57:34 +02:00
sk
85c3d9f65f fix wrong tab being selected on restore 2023-05-25 19:51:45 +02:00
sk
a7ebadf269 increase read timeout
re: sk22#392
2023-05-25 15:11:40 +02:00
sk
94c09d46c2 fix contentType being a required field
re: sk22#516
2023-05-25 14:53:26 +02:00
sk
f6f08d176c change user-agent string 2023-05-23 10:26:48 +02:00
sk
66cdd63496 use fedinuke block list
closes sk22#511
2023-05-22 18:04:37 +02:00
Jacoco
8b502b605c Alternative content types (#516)
* Akkoma content types

* Default content type preference

* per-account content types, compatible with glitch

* disable content types by default, change icon

* persist content type to state

* update string

* fall back to plain text if formatting enabled

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-05-22 17:56:50 +02:00
FineFindus
2c0ec28803 Panic responder (#512)
* feat: add panic responder

* refactor: logOut before removing session

* fix(panic): close app after logOut to avoid crash

* build: reset gradle.properties
2023-05-20 13:20:25 +02:00
Jacoco
a9ab9cb249 Fix crashes on Calckey and GoToSocial (#515)
* Fix crashes on calckey and gts

* Use url if previewUrl is null
2023-05-14 23:26:03 +02:00
sk
961c69b525 Merge remote-tracking branch 'upstream/master' 2023-05-13 15:15:00 +02:00
sk
c70f393559 account card layout adjustments 2023-05-13 15:13:43 +02:00
sk
9abdc174f4 guarantee space for display name in header
closes sk22#513
2023-05-13 14:07:44 +02:00
LucasGGamerM
2e5bfa1d9c fix: NPE when instance is null and attempts to get new notifications
For some weird reason, someone saw a pixelfed instance return null as the instance, causing a crash on the updateNotificationsBadge method. This reminds me of why java is such a shit language
2023-05-13 13:37:19 +02:00
Grishka
33cbd85e19 Bump version 2023-05-11 05:42:40 +03:00
Grishka
8cb1f3f387 Merge branch 'l10n_master' 2023-05-11 05:40:54 +03:00
Eugen Rochko
3f0c6fcec5 New translations strings.xml (Icelandic) 2023-05-10 13:59:12 +02:00
Eugen Rochko
797cf893da New translations strings.xml (Italian) 2023-05-08 15:58:22 +02:00
Eugen Rochko
a3564b70e1 New translations strings.xml (Ukrainian) 2023-05-08 07:52:51 +02:00
Eugen Rochko
43004307b8 New translations strings.xml (Ukrainian) 2023-05-08 06:34:46 +02:00
Eugen Rochko
acd1e4ced3 New translations full_description.txt (Scottish Gaelic) 2023-05-06 07:17:18 +02:00
Eugen Rochko
6717070f93 New translations strings.xml (Scottish Gaelic) 2023-05-06 07:17:17 +02:00
Eugen Rochko
387499ae49 New translations strings.xml (Vietnamese) 2023-05-05 08:49:53 +02:00
Eugen Rochko
8ab140c55d New translations strings.xml (Japanese) 2023-05-04 22:50:38 +02:00
Eugen Rochko
914abb95dd New translations strings.xml (Japanese) 2023-05-04 21:34:45 +02:00
Eugen Rochko
5360c0f0f7 New translations strings.xml (Greek) 2023-05-04 01:44:50 +02:00
Eugen Rochko
243d803b51 New translations strings.xml (Turkish) 2023-05-03 23:31:14 +02:00
Eugen Rochko
b343fe3835 New translations strings.xml (Turkish) 2023-05-03 22:27:36 +02:00
Eugen Rochko
3c42c1120f New translations strings.xml (Japanese) 2023-05-03 17:42:48 +02:00
Eugen Rochko
ad840dcef6 New translations strings.xml (Japanese) 2023-05-03 16:47:22 +02:00
Eugen Rochko
f73072d95e New translations strings.xml (Spanish) 2023-05-03 01:08:32 +02:00
Eugen Rochko
95cb9b5079 New translations strings.xml (Thai) 2023-05-02 21:12:14 +02:00
Eugen Rochko
c6684d3c9b New translations strings.xml (Thai) 2023-05-02 19:41:48 +02:00
Eugen Rochko
5c5989d8c0 New translations strings.xml (Chinese Traditional) 2023-05-02 18:13:38 +02:00
Eugen Rochko
60e92d30b0 New translations strings.xml (Italian) 2023-05-02 14:58:27 +02:00
Eugen Rochko
8bf8e3f86b New translations strings.xml (Slovenian) 2023-05-02 00:17:51 +02:00
Eugen Rochko
891ee2d06b New translations strings.xml (Indonesian) 2023-05-01 21:04:03 +02:00
Eugen Rochko
b450bc7ae8 New translations strings.xml (Icelandic) 2023-05-01 21:04:02 +02:00
Eugen Rochko
4ca1e0d5db New translations strings.xml (Vietnamese) 2023-05-01 21:04:01 +02:00
Eugen Rochko
859213dd9e New translations strings.xml (Chinese Simplified) 2023-05-01 21:04:01 +02:00
Eugen Rochko
ad2857791d New translations strings.xml (Turkish) 2023-05-01 21:03:59 +02:00
Eugen Rochko
497827f2e2 New translations strings.xml (Slovenian) 2023-05-01 21:03:57 +02:00
Eugen Rochko
967e333022 New translations strings.xml (Japanese) 2023-05-01 21:03:54 +02:00
Eugen Rochko
8df1406006 New translations strings.xml (Dutch) 2023-05-01 21:03:46 +02:00
Eugen Rochko
4af42fafdc New translations strings.xml (Russian) 2023-05-01 21:03:45 +02:00
Eugen Rochko
a9e6a452c1 New translations strings.xml (Galician) 2023-05-01 21:03:43 +02:00
Eugen Rochko
a4a4632397 New translations strings.xml (Chinese Traditional) 2023-05-01 21:03:42 +02:00
Eugen Rochko
421f39e414 New translations strings.xml (Italian) 2023-05-01 21:03:41 +02:00
Eugen Rochko
f8121e2dc4 New translations strings.xml (German) 2023-05-01 21:03:41 +02:00
Eugen Rochko
b1784fc51c New translations strings.xml (Danish) 2023-05-01 21:03:40 +02:00
Eugen Rochko
96db0d7de7 New translations strings.xml (Greek) 2023-05-01 21:03:39 +02:00
Eugen Rochko
3837ed9cb1 New translations strings.xml (Thai) 2023-05-01 21:03:38 +02:00
Eugen Rochko
2be789a43c New translations strings.xml (Spanish) 2023-05-01 21:03:37 +02:00
Grishka
fd8d96169a Update string 2023-05-01 21:38:16 +03:00
Eugen Rochko
1562dc32c1 New translations strings.xml (Dutch) 2023-05-01 13:44:56 +02:00
Eugen Rochko
38f377ca09 New translations full_description.txt (Armenian) 2023-04-28 20:21:00 +02:00
Eugen Rochko
cc28bba884 New translations strings.xml (Armenian) 2023-04-28 20:20:59 +02:00
Eugen Rochko
beb3081918 New translations strings.xml (Armenian) 2023-04-28 19:06:20 +02:00
Eugen Rochko
1b3c9106b5 New translations strings.xml (Russian) 2023-04-28 09:05:19 +02:00
Eugen Rochko
385b91761b New translations strings.xml (Portuguese, Brazilian) 2023-04-28 02:45:25 +02:00
Luna!
d7b76ed70a Fixed a typo in a comment in blocks.tsv (#509) 2023-04-27 17:49:15 +02:00
Eugen Rochko
43600756c0 New translations strings.xml (Chinese Traditional) 2023-04-25 18:41:49 +02:00
Eugen Rochko
3c3e0633ad New translations strings.xml (Danish) 2023-04-25 12:23:29 +02:00
Eugen Rochko
f819ad6917 New translations strings.xml (Danish) 2023-04-25 11:26:19 +02:00
sk
2e84faa505 update languages 2023-04-23 17:08:51 +02:00
sk
e7e8d13d9e fix auto hide fab in profile fragment 2023-04-22 22:33:20 +02:00
sk
a683c2cb11 hide fab in notifications 2023-04-22 22:20:40 +02:00
sk
addf7de316 single fab for home tabs
closes sk22#415
2023-04-22 21:25:02 +02:00
sk
44d4eada51 fix "load missing more" being hidden
closes sk22#482
2023-04-22 20:14:07 +02:00
sk
40bfdea5b1 fix pleroma emoji reaction notifications 2023-04-22 19:52:46 +02:00
sk
55138c1e86 fix wrong true black badge border color
closes sk22#485
2023-04-22 19:17:12 +02:00
Eugen Rochko
e7ad396fc6 New translations strings.xml (Italian) 2023-04-22 19:15:42 +02:00
sk
0aef680572 Merge remote-tracking branch 'weblate/main' 2023-04-22 19:06:03 +02:00
sk22
6dc37d6bde Translated using Weblate (German)
Currently translated at 100.0% (275 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-04-22 17:05:32 +00:00
sk
60ea7cedf6 support glitch react notification 2023-04-22 19:05:14 +02:00
Espasant3
c986b10e14 Translated using Weblate (Galician)
Currently translated at 99.6% (272 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-04-22 17:00:55 +00:00
Choukajohn
d52174bd9e Translated using Weblate (French)
Currently translated at 100.0% (273 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-04-22 17:00:55 +00:00
sk22
c65d138911 Translated using Weblate (German)
Currently translated at 100.0% (273 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-04-22 17:00:55 +00:00
sk
ad9bb8ad58 support glitch react notification 2023-04-22 19:00:37 +02:00
sk
63e536c66c fix hidden no alt/alt badge remaining clickable
closes sk22#498
2023-04-22 18:20:05 +02:00
Jacoco
b5a08b1b98 Pleroma emoji reaction notifications (#499) 2023-04-22 17:39:41 +02:00
r3g_5z
226e2a7cdc Minor maintenance things (#501)
* validate gradle wrapper jar file

this is extremely important. see the following:

https://blog.gradle.org/wrapper-attack-report
https://github.com/gradle/wrapper-validation-action#the-gradle-wrapper-problem-in-open-source

Signed-off-by: r3g_5z <june@girlboss.ceo>

* update gradle wrapper to 8.1.1

it is necessary to run the gradlew update command twice to actually
update the jar file properly, e.g.:

./gradlew wrapper --gradle-version=8.1.1 --gradle-distribution-sha256-sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
./gradlew wrapper --gradle-version=8.1.1 --gradle-distribution-sha256-sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f

Signed-off-by: r3g_5z <june@girlboss.ceo>

* use Gradle toolchain

this allows for better build reproducibility and avoid mix and matching
JDKs from other projects

https://docs.gradle.org/current/userguide/toolchains.html

Signed-off-by: r3g_5z <june@girlboss.ceo>

* update dependencies and fix build errors

Signed-off-by: r3g_5z <june@girlboss.ceo>

---------

Signed-off-by: r3g_5z <june@girlboss.ceo>
Co-authored-by: sk22 <sk22@mailbox.org>
2023-04-22 17:28:16 +02:00
sk
4d7c4aed4c enable nonTransitiveRClass 2023-04-22 16:51:44 +02:00
sk
c9bcd000c3 update gradle 2023-04-22 16:49:42 +02:00
Eugen Rochko
b1cb4d4257 New translations strings.xml (German) 2023-04-22 16:44:30 +02:00
sk22
de42145f30 Translated using Weblate (German)
Currently translated at 100.0% (273 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-04-22 14:38:25 +00:00
sk
7bcdd6070a boost instead of reblog 2023-04-22 16:38:16 +02:00
sk
8a215e90d0 Merge remote-tracking branch 'weblate/main' 2023-04-22 16:34:11 +02:00
sk
b736fa18bb remove empty french metadata 2023-04-22 16:32:00 +02:00
ihor_ck
43c19e4942 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-04-22 14:30:34 +00:00
Eryk Michalak
ffc18029bb Translated using Weblate (Polish)
Currently translated at 100.0% (273 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-04-22 14:30:34 +00:00
Linerly
b88b3d15f8 Translated using Weblate (Indonesian)
Currently translated at 100.0% (273 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-04-22 14:30:34 +00:00
Choukajohn
c817886a2d Translated using Weblate (French)
Currently translated at 100.0% (273 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-04-22 14:30:34 +00:00
gallegonovato
aae239494e Translated using Weblate (Spanish)
Currently translated at 100.0% (273 of 273 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-04-22 14:30:34 +00:00
a_mento
b0b2daa5d5 Translated using Weblate (Basque)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2023-04-22 14:30:34 +00:00
Espasant3
eea2e38f1b Translated using Weblate (Galician)
Currently translated at 100.0% (17 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/gl/
2023-04-22 14:30:34 +00:00
AiOO
f894ecd25b Translated using Weblate (Korean)
Currently translated at 100.0% (17 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2023-04-22 14:30:34 +00:00
AiOO
e0b6ed7103 Translated using Weblate (Korean)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-04-22 14:30:34 +00:00
Espasant3
a78e75747a Translated using Weblate (Galician)
Currently translated at 100.0% (17 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/gl/
2023-04-22 14:30:34 +00:00
ihor_ck
3b25e367bb Translated using Weblate (Ukrainian)
Currently translated at 100.0% (17 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-04-22 14:30:34 +00:00
gallegonovato
08b29dff3d Translated using Weblate (Spanish)
Currently translated at 100.0% (17 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2023-04-22 14:30:34 +00:00
Choukajohn
2f2e053d26 Translated using Weblate (French)
Currently translated at 17.6% (3 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2023-04-22 14:30:34 +00:00
Pegasus89
191d582c30 Translated using Weblate (Croatian)
Currently translated at 12.5% (2 of 16 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/hr/
2023-04-22 14:30:34 +00:00
Pegasus89
8d3380ff6e Translated using Weblate (Croatian)
Currently translated at 97.4% (265 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/hr/
2023-04-22 14:30:34 +00:00
AiOO
ba85d18574 Translated using Weblate (Korean)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2023-04-22 14:30:34 +00:00
sk22
0f53b17515 Translated using Weblate (Spanish)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-04-22 14:30:34 +00:00
Anonymous
cb9c869712 Translated using Weblate (Russian)
Currently translated at 92.2% (251 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-04-22 14:30:34 +00:00
poesty
aa3d9e7b8f Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-04-22 14:30:34 +00:00
sk
b3a9b5824d fix non-positional subtitution in string 2023-04-22 16:29:41 +02:00
sk
b6186a349f update gradle 2023-04-20 16:03:57 +02:00
Eugen Rochko
100bd4b062 New translations strings.xml (Galician) 2023-04-19 07:36:52 +02:00
Eugen Rochko
7da09d9b37 New translations strings.xml (Spanish) 2023-04-19 07:36:51 +02:00
Eugen Rochko
f46eb07228 New translations strings.xml (Galician) 2023-04-19 06:04:49 +02:00
Eugen Rochko
7627b5eb25 New translations strings.xml (Greek) 2023-04-17 15:01:08 +02:00
Eugen Rochko
c710448c6b New translations strings.xml (Greek) 2023-04-17 13:59:43 +02:00
Eugen Rochko
1ad270b1d6 New translations strings.xml (Chinese Simplified) 2023-04-16 18:13:11 +02:00
Eugen Rochko
099e253b2b New translations strings.xml (Chinese Simplified) 2023-04-16 17:11:48 +02:00
Eugen Rochko
66de4a5b91 New translations strings.xml (Thai) 2023-04-16 09:19:23 +02:00
Eugen Rochko
41437d91d5 New translations strings.xml (Icelandic) 2023-04-15 11:54:07 +02:00
Eugen Rochko
d33d5a6efa New translations strings.xml (Icelandic) 2023-04-15 10:45:31 +02:00
Eugen Rochko
4f9248d040 New translations strings.xml (Vietnamese) 2023-04-15 05:15:40 +02:00
Eugen Rochko
f40c0e41f3 New translations strings.xml (Japanese) 2023-04-14 20:26:49 +02:00
sk
15fcb0e25d fix alt badge padding and margin 2023-04-13 23:17:46 +02:00
sk
2dae662333 fix username displacement in compose 2023-04-13 23:03:07 +02:00
sk
3ad46926f1 Merge remote-tracking branch 'upstream/master' 2023-04-13 21:46:45 +02:00
sk
2385d102ae fix header username displacement 2023-04-13 21:42:43 +02:00
Eugen Rochko
deeb03ff2b New translations strings.xml (Indonesian) 2023-04-13 21:36:15 +02:00
Eugen Rochko
5c2a09e243 New translations strings.xml (Indonesian) 2023-04-13 20:38:20 +02:00
Eugen Rochko
2473c999db New translations strings.xml (German) 2023-04-13 14:38:33 +02:00
Eugen Rochko
ea2cc265e3 New translations strings.xml (Turkish) 2023-04-13 05:12:38 +02:00
Eugen Rochko
a0cd2d42cf New translations strings.xml (Turkish) 2023-04-13 04:16:05 +02:00
Grishka
0a17ceb984 Merge branch 'l10n_master' 2023-04-12 19:20:42 +03:00
Grishka
4ef18f1f4a Add touch interaction for the SplashFragment art 2023-04-12 19:20:23 +03:00
Grishka
0de227ab9c Use fixed colors for SplashFragment
fixes #561
2023-04-12 18:47:02 +03:00
Eugen Rochko
19cb8703a6 New translations strings.xml (Kabyle) 2023-04-12 17:37:10 +02:00
Eugen Rochko
e18567dd82 New translations strings.xml (Filipino) 2023-04-12 17:37:06 +02:00
Eugen Rochko
bfb3bcdbfb New translations strings.xml (Portuguese, Brazilian) 2023-04-12 17:37:02 +02:00
Eugen Rochko
565cd14d88 New translations strings.xml (Galician) 2023-04-12 17:37:00 +02:00
Eugen Rochko
ebc37eac75 New translations strings.xml (Vietnamese) 2023-04-12 17:36:59 +02:00
Eugen Rochko
c3702db577 New translations strings.xml (Chinese Traditional) 2023-04-12 17:36:59 +02:00
Eugen Rochko
e15c4fa342 New translations strings.xml (Chinese Simplified) 2023-04-12 17:36:58 +02:00
Eugen Rochko
8330b9f1c5 New translations strings.xml (Turkish) 2023-04-12 17:36:57 +02:00
Eugen Rochko
f759150982 New translations strings.xml (Swedish) 2023-04-12 17:36:56 +02:00
Eugen Rochko
6af177b596 New translations strings.xml (Slovenian) 2023-04-12 17:36:55 +02:00
Eugen Rochko
657bb94975 New translations strings.xml (Russian) 2023-04-12 17:36:54 +02:00
Eugen Rochko
3c946212b1 New translations strings.xml (Polish) 2023-04-12 17:36:52 +02:00
Eugen Rochko
b4e80f7fca New translations strings.xml (Norwegian) 2023-04-12 17:36:51 +02:00
Eugen Rochko
c9efc2cb2b New translations strings.xml (Korean) 2023-04-12 17:36:50 +02:00
Eugen Rochko
0d62e33dc7 New translations strings.xml (Japanese) 2023-04-12 17:36:49 +02:00
Eugen Rochko
ac88b9e19c New translations strings.xml (Italian) 2023-04-12 17:36:48 +02:00
Eugen Rochko
871dfda79e New translations strings.xml (Hungarian) 2023-04-12 17:36:47 +02:00
Eugen Rochko
e0c2c208ae New translations strings.xml (Basque) 2023-04-12 17:36:44 +02:00
Eugen Rochko
22ac112bdb New translations strings.xml (German) 2023-04-12 17:36:43 +02:00
Eugen Rochko
afd0cca176 New translations strings.xml (Danish) 2023-04-12 17:36:42 +02:00
Eugen Rochko
c083c8bce5 New translations strings.xml (Arabic) 2023-04-12 17:36:41 +02:00
Eugen Rochko
63bde032b3 New translations strings.xml (French) 2023-04-12 17:36:40 +02:00
Eugen Rochko
49492c0788 New translations strings.xml (Belarusian) 2023-04-12 17:36:38 +02:00
Eugen Rochko
b439c64add New translations strings.xml (Greek) 2023-04-12 17:36:37 +02:00
Eugen Rochko
1868bfe8e3 New translations strings.xml (Thai) 2023-04-12 17:36:36 +02:00
Eugen Rochko
f240a3d996 New translations strings.xml (Indonesian) 2023-04-12 17:36:35 +02:00
Eugen Rochko
788e5bd12e New translations strings.xml (Icelandic) 2023-04-12 17:36:34 +02:00
Eugen Rochko
a55fed4502 New translations strings.xml (Ukrainian) 2023-04-12 17:36:33 +02:00
Eugen Rochko
a8fdaf1a47 New translations strings.xml (Dutch) 2023-04-12 17:36:32 +02:00
Eugen Rochko
4a758bd488 New translations strings.xml (Czech) 2023-04-12 17:36:31 +02:00
Eugen Rochko
2c9731ec2a New translations strings.xml (Spanish) 2023-04-12 17:36:30 +02:00
Grishka
eef33266fc Remove unused code and strings 2023-04-12 18:34:28 +03:00
Eugen Rochko
58d2c3e5a6 New translations strings.xml (Indonesian) 2023-04-11 17:28:22 +02:00
Eugen Rochko
9e6a355db0 New translations strings.xml (Slovenian) 2023-04-10 00:54:45 +02:00
Eugen Rochko
0d10e09fd6 New translations strings.xml (Slovenian) 2023-04-09 23:47:00 +02:00
Eugen Rochko
f85bb995ba New translations strings.xml (Greek) 2023-04-09 17:56:44 +02:00
Eugen Rochko
268e5639f6 New translations strings.xml (Greek) 2023-04-09 16:26:19 +02:00
Eugen Rochko
51809df8ca New translations strings.xml (Thai) 2023-04-09 07:25:51 +02:00
Eugen Rochko
94fb676b0c New translations strings.xml (Chinese Traditional) 2023-04-09 04:29:35 +02:00
Eugen Rochko
a47106594b New translations strings.xml (Chinese Traditional) 2023-04-09 03:10:02 +02:00
Grishka
d93d66f702 Prepare new release 2023-04-09 01:59:13 +03:00
Eugen Rochko
b2f9f7ae54 New translations strings.xml (Italian) 2023-04-09 00:51:05 +02:00
Grishka
de7b908c78 Merge branch 'l10n_master' 2023-04-09 01:50:55 +03:00
Eugen Rochko
75d3c2fdce New translations strings.xml (Italian) 2023-04-08 23:55:36 +02:00
Eugen Rochko
ea1b6c5835 New translations strings.xml (Greek) 2023-04-08 22:51:05 +02:00
Eugen Rochko
cb7887da41 New translations strings.xml (Greek) 2023-04-08 21:38:06 +02:00
Eugen Rochko
a80313ee6b New translations strings.xml (Thai) 2023-04-07 23:53:35 +02:00
Eugen Rochko
e1a821bc43 New translations strings.xml (Thai) 2023-04-07 22:56:50 +02:00
Grishka
924ea2d03a Fix #557 2023-04-07 22:58:04 +03:00
Grishka
55270fe654 Fix 2023-04-07 22:55:29 +03:00
Eugen Rochko
a125fab57b New translations strings.xml (Kabyle) 2023-04-07 21:48:05 +02:00
Eugen Rochko
395ee0aa99 New translations strings.xml (Scottish Gaelic) 2023-04-07 21:48:03 +02:00
Eugen Rochko
0f50fa6ba1 New translations strings.xml (Bosnian) 2023-04-07 21:48:01 +02:00
Eugen Rochko
adb7df3c71 New translations strings.xml (Filipino) 2023-04-07 21:48:00 +02:00
Eugen Rochko
5d7bcb629b New translations strings.xml (Burmese) 2023-04-07 21:47:59 +02:00
Eugen Rochko
a00f1417d2 New translations strings.xml (Hindi) 2023-04-07 21:47:59 +02:00
Eugen Rochko
8efd7e8ebf New translations strings.xml (Croatian) 2023-04-07 21:47:58 +02:00
Eugen Rochko
b016d277e0 New translations strings.xml (Bengali) 2023-04-07 21:47:57 +02:00
Eugen Rochko
fdb39617d1 New translations strings.xml (Persian) 2023-04-07 21:47:56 +02:00
Eugen Rochko
89f83fbf62 New translations strings.xml (Portuguese, Brazilian) 2023-04-07 21:47:55 +02:00
Eugen Rochko
ecee9e01a6 New translations strings.xml (Galician) 2023-04-07 21:47:54 +02:00
Eugen Rochko
20dc9bb8b9 New translations strings.xml (Vietnamese) 2023-04-07 21:47:53 +02:00
Eugen Rochko
2c47d0e9ed New translations strings.xml (Chinese Traditional) 2023-04-07 21:47:52 +02:00
Eugen Rochko
8e13d52e51 New translations strings.xml (Chinese Simplified) 2023-04-07 21:47:51 +02:00
Eugen Rochko
cc40198c9e New translations strings.xml (Turkish) 2023-04-07 21:47:50 +02:00
Eugen Rochko
290897ea41 New translations strings.xml (Swedish) 2023-04-07 21:47:49 +02:00
Eugen Rochko
b9e1c84304 New translations strings.xml (Slovenian) 2023-04-07 21:47:48 +02:00
Eugen Rochko
3c44c80e2e New translations strings.xml (Russian) 2023-04-07 21:47:47 +02:00
Eugen Rochko
dffa4e4594 New translations strings.xml (Portuguese) 2023-04-07 21:47:46 +02:00
Eugen Rochko
fa2d9fec58 New translations strings.xml (Polish) 2023-04-07 21:47:45 +02:00
Eugen Rochko
09c1a2cfa0 New translations strings.xml (Norwegian) 2023-04-07 21:47:44 +02:00
Eugen Rochko
d1f90eb231 New translations strings.xml (Korean) 2023-04-07 21:47:42 +02:00
Eugen Rochko
1f7d97134b New translations strings.xml (Japanese) 2023-04-07 21:47:42 +02:00
Eugen Rochko
79be91784d New translations strings.xml (Italian) 2023-04-07 21:47:41 +02:00
Eugen Rochko
de2654def3 New translations strings.xml (Hungarian) 2023-04-07 21:47:39 +02:00
Eugen Rochko
56343dacff New translations strings.xml (Hebrew) 2023-04-07 21:47:38 +02:00
Eugen Rochko
0e677f8ce7 New translations strings.xml (Basque) 2023-04-07 21:47:36 +02:00
Eugen Rochko
aa911896d6 New translations strings.xml (German) 2023-04-07 21:47:35 +02:00
Eugen Rochko
c62a8635b9 New translations strings.xml (Danish) 2023-04-07 21:47:34 +02:00
Eugen Rochko
4e900247c5 New translations strings.xml (Catalan) 2023-04-07 21:47:33 +02:00
Eugen Rochko
b3bd62bc6c New translations strings.xml (Arabic) 2023-04-07 21:47:32 +02:00
Eugen Rochko
8e5fd48ecd New translations strings.xml (French) 2023-04-07 21:47:31 +02:00
Eugen Rochko
b2bca9dd2c New translations strings.xml (Romanian) 2023-04-07 21:47:30 +02:00
Eugen Rochko
b8c0dc3181 New translations strings.xml (Belarusian) 2023-04-07 21:47:29 +02:00
Eugen Rochko
cccdc5292e New translations strings.xml (Greek) 2023-04-07 21:47:28 +02:00
Eugen Rochko
76d77a0e7a New translations strings.xml (Thai) 2023-04-07 21:47:27 +02:00
Eugen Rochko
e737f4bf9a New translations strings.xml (Indonesian) 2023-04-07 21:47:26 +02:00
Eugen Rochko
391db2f1c9 New translations strings.xml (Icelandic) 2023-04-07 21:47:25 +02:00
Eugen Rochko
359d61183c New translations strings.xml (Ukrainian) 2023-04-07 21:47:24 +02:00
Eugen Rochko
46fd05d88e New translations strings.xml (Dutch) 2023-04-07 21:47:23 +02:00
Eugen Rochko
cde22a0945 New translations strings.xml (Czech) 2023-04-07 21:47:22 +02:00
Eugen Rochko
111b7e25c5 New translations strings.xml (Spanish) 2023-04-07 21:47:21 +02:00
Grishka
4f8d8f0c8d Welcome fragment redesign again
# Conflicts:
#	mastodon/src/main/res/values/strings.xml
#	mastodon/src/main/res/values/styles.xml
2023-04-07 22:44:28 +03:00
Grishka
915b0603d0 Reblog -> boost 2023-04-07 22:42:16 +03:00
sk
6ec43a6f86 slightly smaller collapsed height
closes sk22#480
2023-04-07 18:45:11 +02:00
sk
df93a1a845 increase max height 2023-04-07 18:42:18 +02:00
sk
41a70a353c distinct default languages
closes sk22#487
2023-04-07 18:21:23 +02:00
sk
8d69bcfd4b new profile counters for account card
closes sk22#483
2023-04-07 18:08:57 +02:00
sk
0ef30f82a7 fix disappearing no-alt indicator
closes sk22#484
2023-04-07 17:16:45 +02:00
sk
be60e78ea6 improve external share behavior 2023-04-07 16:58:02 +02:00
sk
5434325fa8 fix header alignments… again 2023-04-07 16:30:49 +02:00
sk
0a04c9357c Revert "display reblog popup by default"
This reverts commit 21c4cef397.

okay, so, i think i'll keep reblog as a default. i fear that exposing everyone
to an overwhelming menu (you literally have to *decide* for a visibility!)
when just pressing reblog might not be a good idea. i'll just have "confirm
before reblogging" as an option in the settings instead
https://floss.social/@megalodon/110157968813469351
2023-04-07 16:20:29 +02:00
Eugen Rochko
075aab8074 New translations strings.xml (Greek) 2023-04-07 16:16:35 +02:00
sk
21c4cef397 display reblog popup by default 2023-04-07 16:04:35 +02:00
sk
4b2fcd760a add option to confirm before reblog
closes sk22#456
2023-04-07 15:29:43 +02:00
Eugen Rochko
6ebe4c86af New translations strings.xml (Greek) 2023-04-07 15:16:19 +02:00
Eugen Rochko
0925c8c582 New translations strings.xml (Spanish) 2023-04-06 21:52:50 +02:00
sk
9824b5fb56 allow boosting with every visibility
closes sk22#486
2023-04-06 20:24:40 +02:00
sk
78fcf31e34 remove unused crowdin.yml 2023-04-06 20:16:33 +02:00
sk
eadb62d3a8 fix wrong rel=me link on website 2023-04-06 20:16:26 +02:00
sk
f6279fcc0c Merge branch 'l10n_fr' of codeberg.org:butterflyoffire/megalodon 2023-04-06 20:08:46 +02:00
Eugen Rochko
a683fdce62 New translations strings.xml (Greek) 2023-04-06 18:46:34 +02:00
Eugen Rochko
b958299446 New translations strings.xml (Greek) 2023-04-06 17:45:19 +02:00
Eugen Rochko
3f80be8377 New translations strings.xml (Greek) 2023-04-05 16:29:26 +02:00
Eugen Rochko
ced0accde5 New translations strings.xml (Belarusian) 2023-04-05 12:06:47 +02:00
Eugen Rochko
b454ff5ec7 New translations strings.xml (Belarusian) 2023-04-05 11:07:06 +02:00
Eugen Rochko
45af198f32 New translations strings.xml (Greek) 2023-04-05 02:04:08 +02:00
Eugen Rochko
ff374f8899 New translations strings.xml (Greek) 2023-04-05 00:46:17 +02:00
Eugen Rochko
faecb3bc4b New translations strings.xml (Greek) 2023-04-04 20:21:01 +02:00
Eugen Rochko
6b893fadef New translations short_description.txt (Greek) 2023-04-04 17:47:01 +02:00
Eugen Rochko
c328467a41 New translations strings.xml (Greek) 2023-04-04 17:47:00 +02:00
Eugen Rochko
182325470b New translations full_description.txt (Greek) 2023-04-04 17:46:59 +02:00
Eugen Rochko
f330ad71ac New translations full_description.txt (Greek) 2023-04-04 16:06:32 +02:00
Eugen Rochko
ba0c064f36 New translations full_description.txt (Chinese Traditional) 2023-04-03 16:47:01 +02:00
Eugen Rochko
8d7aaee5b9 New translations strings.xml (Dutch) 2023-04-01 15:16:39 +02:00
Eugen Rochko
68cba2de63 New translations strings.xml (Icelandic) 2023-03-29 00:29:42 +02:00
Eugen Rochko
5a914f9c0e New translations strings.xml (Thai) 2023-03-28 21:06:33 +02:00
Eugen Rochko
b0e6805a20 New translations strings.xml (Czech) 2023-03-28 16:34:35 +02:00
Eugen Rochko
21e7e44c01 New translations strings.xml (Czech) 2023-03-28 15:36:30 +02:00
Eugen Rochko
f7df4abdae New translations strings.xml (Spanish) 2023-03-26 17:05:29 +02:00
Eugen Rochko
7674ceefe9 New translations strings.xml (Ukrainian) 2023-03-25 20:42:18 +01:00
Eugen Rochko
4be575c534 New translations strings.xml (Ukrainian) 2023-03-25 19:25:16 +01:00
Eugen Rochko
dd0f0a7d5a New translations strings.xml (Indonesian) 2023-03-25 04:22:02 +01:00
Eugen Rochko
759b44c224 New translations strings.xml (Indonesian) 2023-03-25 03:16:02 +01:00
sk
ebdd1a0b03 rename version 2023-03-24 20:05:42 +01:00
sk
6c44575f7a bump version 2023-03-24 20:04:35 +01:00
sk
8be832239a Merge remote-tracking branch 'upstream/l10n_master' 2023-03-24 20:03:31 +01:00
sk
c7be202430 Merge remote-tracking branch 'weblate/main' 2023-03-24 20:03:21 +01:00
poesty
6bbb9a638e Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-03-24 18:40:14 +00:00
Espasant3
44041b136a Translated using Weblate (Galician)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-03-24 18:40:14 +00:00
ihor_ck
7e17c30ce2 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-03-24 18:40:14 +00:00
McKris
c4d3d1b409 Translated using Weblate (Polish)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-03-24 18:40:14 +00:00
Linerly
03de63754b Translated using Weblate (Indonesian)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-03-24 18:40:14 +00:00
Choukajohn
0e506f0b1a Translated using Weblate (French)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-03-24 18:40:14 +00:00
gallegonovato
a2ab752870 Translated using Weblate (Spanish)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-03-24 18:40:14 +00:00
sk22
eaa032828a Translated using Weblate (German)
Currently translated at 100.0% (272 of 272 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-03-24 18:40:14 +00:00
Eugen Rochko
920384b26c New translations strings.xml (Dutch) 2023-03-24 16:26:08 +01:00
Eugen Rochko
193a2c4f70 New translations strings.xml (German) 2023-03-23 13:42:28 +01:00
Eugen Rochko
793dec98b2 New translations strings.xml (Vietnamese) 2023-03-23 07:36:02 +01:00
Eugen Rochko
11ddf8015d New translations strings.xml (Galician) 2023-03-23 05:17:18 +01:00
Eugen Rochko
1753bdbd8b New translations strings.xml (Thai) 2023-03-22 17:21:08 +01:00
Eugen Rochko
cc8c818e13 New translations strings.xml (Slovenian) 2023-03-21 11:52:06 +01:00
Eugen Rochko
2e1f273d78 New translations strings.xml (Chinese Traditional) 2023-03-21 06:38:54 +01:00
Eugen Rochko
35d6800877 New translations strings.xml (Chinese Traditional) 2023-03-21 05:17:21 +01:00
Eugen Rochko
91e154bbee New translations strings.xml (Italian) 2023-03-20 20:01:49 +01:00
Eugen Rochko
0c02b0cb68 New translations strings.xml (Dutch) 2023-03-20 18:49:16 +01:00
Weblate Admin
c97a7e5158 Translated using Weblate (French)
Currently translated at 98.8% (351 of 355 strings)

Co-authored-by: Weblate Admin <butterflyoffire@todz.ynh.fr>
Translate-URL: https://rosette.todz.ynh.fr/projects/megalodon-app/app-strings/fr/
Translation: Megalodon app/Megalodon app
2022-12-06 09:19:24 +01:00
Weblate Admin
32e2d24b15 Translated using Weblate (Arabic (Algeria))
Currently translated at 94.0% (334 of 355 strings)

Translated using Weblate (French)

Currently translated at 96.9% (344 of 355 strings)

Co-authored-by: Weblate Admin <butterflyoffire@todz.ynh.fr>
Translate-URL: https://rosette.todz.ynh.fr/projects/megalodon-app/app-strings/ar_DZ/
Translate-URL: https://rosette.todz.ynh.fr/projects/megalodon-app/app-strings/fr/
Translation: Megalodon app/Megalodon app
2022-12-04 07:10:53 +01:00
Weblate Admin
c102aae819 Translated using Weblate (French)
Currently translated at 95.4% (339 of 355 strings)

Co-authored-by: Weblate Admin <butterflyoffire@todz.ynh.fr>
Translate-URL: https://rosette.todz.ynh.fr/projects/megalodon-app/app-strings/fr/
Translation: Megalodon app/Megalodon app
2022-12-03 18:22:49 +01:00
Weblate
bed72cb5ed Added translation using Weblate (Occitan)
Co-authored-by: Weblate <noreply@weblate.org>
2022-12-03 04:15:12 +01:00
Weblate
f0c1046fe9 Added translation using Weblate (Kabyle)
Co-authored-by: Weblate <noreply@weblate.org>
2022-12-03 04:15:08 +01:00
Weblate
d88104d105 Added translation using Weblate (French)
Added translation using Weblate (Arabic (Algeria))

Co-authored-by: Weblate <noreply@weblate.org>
2022-12-03 04:15:03 +01:00
Weblate
f3e21e5a82 Added translation using Weblate (Occitan)
Co-authored-by: Weblate <noreply@weblate.org>
2022-12-03 04:14:56 +01:00
Weblate
a77bee8664 Added translation using Weblate (Kabyle)
Co-authored-by: Weblate <noreply@weblate.org>
2022-12-03 04:14:51 +01:00
Weblate
b5d0aed59e Added translation using Weblate (French)
Added translation using Weblate (Arabic (Algeria))

Co-authored-by: Weblate <noreply@weblate.org>
2022-12-03 04:14:47 +01:00
Weblate Admin
2440cc6af5 Translated using Weblate (Arabic (Algeria))
Currently translated at 91.2% (324 of 355 strings)

Co-authored-by: Weblate Admin <butterflyoffire@todz.ynh.fr>
Translate-URL: https://rosette.todz.ynh.fr/projects/megalodon-app/app-strings/ar_DZ/
Translation: Megalodon app/Megalodon app
2022-12-02 22:40:00 +01:00
butterflyoffire
90114dfbe0 Supprimer 'mastodon/src/main/res/values-ar-DZ/strings.xml' 2022-12-02 21:34:54 +00:00
Weblate Admin
64b8cdf7dc Translated using Weblate (Arabic (Algeria))
Currently translated at 89.8% (319 of 355 strings)

Translated using Weblate (Arabic (Algeria))

Currently translated at 0.2% (1 of 355 strings)

Added translation using Weblate (Arabic (Algeria))

Added translation using Weblate (Arabic (Algeria))

Co-authored-by: Weblate Admin <butterflyoffire@todz.ynh.fr>
Translate-URL: https://rosette.todz.ynh.fr/projects/megalodon-app/app-strings/ar_DZ/
Translation: Megalodon app/Megalodon app
2022-12-02 19:14:49 +01:00
172 changed files with 4186 additions and 1409 deletions

View File

@@ -0,0 +1,11 @@
name: Validate Gradle Wrapper
on: [pull_request, push]
jobs:
validation:
name: Validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: gradle/wrapper-validation-action@v1

View File

@@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Megalodon</title>
<link rel="icon" href="mastodon/src/main/res/mipmap-mdpi/ic_launcher_round.png">
<link rel="me" href="https://floss.social/@mastodon">
<link rel="me" href="https://floss.social/@megalodon">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.1.0/github-markdown.min.css">
</head>
<body class="markdown-body">

View File

@@ -5,7 +5,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.1'
classpath 'com.android.tools.build:gradle:8.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}

View File

@@ -1,5 +0,0 @@
files:
- source: /mastodon/src/main/res/values/strings.xml
translation: /mastodon/src/main/res/values-%android_code%/strings.xml
- source: /fastlane/metadata/android/en-US/*.txt
translation: /fastlane/metadata/android/%locale%/%original_file_name%

View File

@@ -16,4 +16,7 @@ org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
# https://developer.android.com/topic/libraries/support-library/androidx-rn
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=false
android.enableJetifier=false
android.defaults.buildfeatures.buildconfig=true
android.nonTransitiveRClass=true
android.nonFinalResIds=false

Binary file not shown.

View File

@@ -1,6 +1,7 @@
#Thu Jan 13 11:33:43 MSK 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
distributionSha256Sum=e111cb9948407e26351227dabce49822fb88c37ee72f1d1582a69c68af2e702f
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

288
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,98 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +118,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +129,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +137,109 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

15
gradlew.bat vendored
View File

@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@@ -2,6 +2,12 @@ plugins {
id 'com.android.application'
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
android {
compileSdk 33
defaultConfig {
@@ -9,11 +15,11 @@ android {
applicationId "org.joinmastodon.android.sk"
minSdk 23
targetSdk 33
versionCode 82
versionName "1.2.0+fork.82"
versionCode 83
versionName "1.2.3+fork.83"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "da-rDK", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fa-rIR", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "ig-rNG", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "my-rMM", "nl-rNL", "no-rNO", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
}
resourceConfigurations += ['ar-rSA', 'ar-rDZ', 'be-rBY', 'bn-rBD', 'bs-rBA', 'ca-rES', 'cs-rCZ', 'da-rDK', 'de-rDE', 'el-rGR', 'es-rES', 'eu-rES', 'fa-rIR', 'fi-rFI', 'fil-rPH', 'fr-rFR', 'ga-rIE', 'gd-rGB', 'gl-rES', 'hi-rIN', 'hr-rHR', 'hu-rHU', 'hy-rAM', 'ig-rNG', 'in-rID', 'is-rIS', 'it-rIT', 'iw-rIL', 'ja-rJP', 'kab', 'ko-rKR', 'my-rMM', 'nl-rNL', 'no-rNO', 'oc-rFR', 'pl-rPL', 'pt-rBR', 'pt-rPT', 'ro-rRO', 'ru-rRU', 'si-rLK', 'sl-rSI', 'sv-rSE', 'th-rTH', 'tr-rTR', 'uk-rUA', 'ur-rIN', 'vi-rVN', 'zh-rCN', 'zh-rTW']
}
buildTypes {
release {
@@ -49,14 +55,19 @@ android {
setRoot "src/github"
}
}
lintOptions{
checkReleaseBuilds false
namespace 'org.joinmastodon.android'
lint {
abortOnError false
checkReleaseBuilds false
}
buildFeatures {
buildConfig true
}
}
dependencies {
api 'androidx.annotation:annotation:1.3.0'
api 'androidx.annotation:annotation:1.6.0'
implementation 'com.squareup.okhttp3:okhttp:3.14.9'
implementation 'me.grishka.litex:recyclerview:1.2.1.1'
implementation 'me.grishka.litex:swiperefreshlayout:1.1.0.1'
@@ -65,7 +76,7 @@ dependencies {
implementation 'me.grishka.litex:viewpager:1.0.0'
implementation 'me.grishka.litex:viewpager2:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.7'
implementation 'com.google.code.gson:gson:2.8.9'
implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8'
implementation 'de.psdev:async-otto:1.0.3'

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.joinmastodon.android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.joinmastodon.android">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
@@ -39,6 +38,22 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".PanicResponderActivity"
android:exported="true"
android:launchMode="singleInstance"
android:noHistory="true"
android:theme="@android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="info.guardianproject.panic.action.TRIGGER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity
android:name=".ExitActivity"
android:exported="false"
android:theme="@android:style/Theme.NoDisplay" />
<activity android:name=".OAuthActivity" android:exported="true" android:configChanges="orientation|screenSize" android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>

View File

@@ -1,89 +0,0 @@
# lists.d Mastodon Blocklist (c) 2022 Greyhat Academy LICENSED UNDER: CC-BY-NC-SA 4.0
# https://raw.githubusercontent.com/greyhat-academy/lists.d/main/mastodon.domains.block.list.tsv
# This list contains domains of toxic mastodon instances
# Last-Modified: 1672044500
# gab - a neonazi social network
gab.ai
gab.com
gab.protohype.net
# consequence-free speech
social.unzensiert.to
freeatlantis.com
# reactionary bigotry and hatespeech against magrinalized groups
poa.st
freespeechextremist.com
rdrama.cc
outpoa.st
anime.website
gameliberty.club
social.byoblu.com
yggdrasil.social
smuglo.li
dogeposting.social
unsafe.space
freezepeach.xyz
# + CSAM
rojogato.com
# antivaxxer shitposting & fearmongering
shadowsocial.org
# Kiwifarms
kiwifarms.net
kiwifarms.cc
kiwifarms.is
kiwifarms.pleroma.net
# https://mastodon.art/@Curator/109649354849593592
poa.st antisemitic racist homophobic
nicecrew.digital antisemitic
beefyboys.win antisemitic racist homophobic harassment
cawfee.club antisemitic racist homophobic
comfyboy.club antisemitic racist homophobic
freespeechextremist.com racist homophobic
cum.salon racist misogynist
bae.st racist
natehiggers.online racist
rapemeat.solutions misogynist
rapist.town misogynist
rapefeminists.network misogynist
kiwifarms.cc harassment
noagendasocial.com noagenda
posting.lolicon.rocks underage
urchan.org harassment homophobic racist
ryona.agency harassment
yggdrasil.social antisemitic homophobic racist
genderheretics.xyz transphobic
baraag.net underage
lolison.top underage
shota.house underage
shota.social underage
aethy.com underage
taullo.social underage
childpawn.shop underage
posting.lolicon.rocks underage
loli.best underage
gothloli.club underage
smuglo.li underage
youjo.love underage
pedo.school underage
lolison.network underage
freak.university underage
mirr0r.city underage
xhais.love underage
refusal.biz underage
refusal.llc underage
mirr0r.city underage
nnia.space underage
ignorelist.com malicious
repl.co malicious
# custom
pawoo.net csam
1 # lists.d Mastodon Blocklist (c) 2022 Greyhat Academy LICENSED UNDER: CC-BY-NC-SA 4.0
2 # https://raw.githubusercontent.com/greyhat-academy/lists.d/main/mastodon.domains.block.list.tsv
3 # This list contains domains of toxic mastodon instances
4 # Last-Modified: 1672044500
5 # gab - a neonazi social network
6 gab.ai
7 gab.com
8 gab.protohype.net
9 # consequence-free speech
10 social.unzensiert.to
11 freeatlantis.com
12 # reactionary bigotry and hatespeech against magrinalized groups
13 poa.st
14 freespeechextremist.com
15 rdrama.cc
16 outpoa.st
17 anime.website
18 gameliberty.club
19 social.byoblu.com
20 yggdrasil.social
21 smuglo.li
22 dogeposting.social
23 unsafe.space
24 freezepeach.xyz
25 # + CSAM
26 rojogato.com
27 # antivaxxer shitposting & fearmongering
28 shadowsocial.org
29 # Kiwifarms
30 kiwifarms.net
31 kiwifarms.cc
32 kiwifarms.is
33 kiwifarms.pleroma.net
34 # https://mastodon.art/@Curator/109649354849593592
35 poa.st antisemitic racist homophobic
36 nicecrew.digital antisemitic
37 beefyboys.win antisemitic racist homophobic harassment
38 cawfee.club antisemitic racist homophobic
39 comfyboy.club antisemitic racist homophobic
40 freespeechextremist.com racist homophobic
41 cum.salon racist misogynist
42 bae.st racist
43 natehiggers.online racist
44 rapemeat.solutions misogynist
45 rapist.town misogynist
46 rapefeminists.network misogynist
47 kiwifarms.cc harassment
48 noagendasocial.com noagenda
49 posting.lolicon.rocks underage
50 urchan.org harassment homophobic racist
51 ryona.agency harassment
52 yggdrasil.social antisemitic homophobic racist
53 genderheretics.xyz transphobic
54 baraag.net underage
55 lolison.top underage
56 shota.house underage
57 shota.social underage
58 aethy.com underage
59 taullo.social underage
60 childpawn.shop underage
61 posting.lolicon.rocks underage
62 loli.best underage
63 gothloli.club underage
64 smuglo.li underage
65 youjo.love underage
66 pedo.school underage
67 lolison.network underage
68 freak.university underage
69 mirr0r.city underage
70 xhais.love underage
71 refusal.biz underage
72 refusal.llc underage
73 mirr0r.city underage
74 nnia.space underage
75 ignorelist.com malicious
76 repl.co malicious
77 # custom
78 pawoo.net csam

View File

@@ -0,0 +1,171 @@
13bells.com
4aem.com
aethy.com
anime.website
annihilation.social
anon-kenkai.com
asbestos.cafe
bae.st
bajax.us
banepo.st
baraag.net
beefyboys.win
beepboop.ga
berserker.town
bikeshed.party
boks.moe
brainsoap.net
breastmilk.club
brighteon.social
cawfee.club
clew.lol
clubcyberia.co
collapsitarian.io
comfyboy.club
contrapointsfan.club
cum.camp
cum.salon
cybercriminal.eu
darknight-coffee.org
dembased.xyz
desupost.soy
detroitriotcity.com
eatthebugs.social
eientei.org
elementality.org
eveningzoo.club
firedragonstudios.com
firefaithfellowship.com
fluf.club
foxfam.club
freak.university
freeatlantis.com
freecumextremist.com
freedomstrike.org
freesoftwareextremist.com
freespeech.group
freespeechextremist.com
freetalklive.com
froth.zone
fulltermprivacy.com
gameliberty.club
gearlandia.haus
genderheretics.xyz
geofront.rocks
gleasonator.com
glee.li
glindr.org
goyim.app
goyslop.cafe
haeder.net
handholding.io
hidamari.apartments
hitchhiker.social
hunk.city
iddqd.social
intkos.link
justicewarrior.social
kawa-kun.com
kitsunemimi.club
kiwifarms.cc
kompost.cz
kurosawa.moe
leafposter.club
leftychan.net
lewdieheaven.com
liberdon.com
ligma.pro
lizards.live
lolicon.rocks
lolison.top
lovingexpressions.net
lucasvl.nl
mahodou.moe
makemysarcophagus.com
maladaptive.art
masochi.st
mastinator.com
merovingian.club
midwaytrades.com
mirr0r.city
moa.st
mouse.services
mugicha.club
narrativerry.xyz
natehiggers.online
neckbeard.xyz
needs.vodka
neenster.org
nicecrew.digital
nnia.space
noagendasocial.com
noagendasocial.nl
noagendatube.com
nobodyhasthe.biz
nukem.biz
obo.sh
onionfarms.org
outpoa.st
pawlicker.com
pawoo.net
pedo.school
piazza.today
pibvt.net
pieville.net
pisskey.io
plagu.ee
pmth.us
poa.st
poast.org
poast.tv
poster.place
prospeech.space
quodverum.com
rakket.app
rapemeat.solutions
rdrama.cc
rebelbase.site
retardedniggers.forsale
rojogato.com
ryona.agency
schwartzwelt.xyz
seal.cafe
shigusegubu.club
shitpost.cloud
shitposter.club
shota.house
silliness.observer
skinheads.eu
skinheads.io
skinheads.social
skinheads.uk
skippers-bin.com
skyshanty.xyz
slash.cl
sleepy.cafe
smuglo.li
sneed.social
sonichu.com
spinster.xyz
springbo.cc
starnix.network
stereophonic.space
strelizia.net
syspxl.xyz
tastingtraffic.net
teci.world
theapex.social
thepostearthdestination.com
tkammer.de
trumpislovetrumpis.life
truthsocial.co.in
urchan.org
varishangout.net
whinge.house
whinge.town
wideboys.org
wolfgirl.bar
xn--p1abe3d.xn--80asehdb
yggdrasil.social
youjo.love
zztails.gay

View File

@@ -0,0 +1,24 @@
package org.joinmastodon.android;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class ExitActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
finishAndRemoveTask();
}
public static void exit(Context context) {
Intent intent = new Intent(context, ExitActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent);
}
}

View File

@@ -13,6 +13,7 @@ import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.jsoup.internal.StringUtil;
import java.util.ArrayList;
import java.util.Collections;
@@ -51,9 +52,15 @@ public class ExternalShareActivity extends FragmentStackActivity{
String subject = "";
if (intent.hasExtra(Intent.EXTRA_SUBJECT)) {
subject = intent.getStringExtra(Intent.EXTRA_SUBJECT);
if (!subject.isBlank()) builder.append(subject).append("\n\n");
if (!StringUtil.isBlank(subject)) builder.append(subject).append("\n\n");
}
if (intent.hasExtra(Intent.EXTRA_TEXT)) {
String extra = intent.getStringExtra(Intent.EXTRA_TEXT);
if (!StringUtil.isBlank(extra)) {
if (extra.startsWith(subject)) extra = extra.substring(subject.length()).trim();
builder.append(extra).append("\n\n");
}
}
if (intent.hasExtra(Intent.EXTRA_TEXT)) builder.append(intent.getStringExtra(Intent.EXTRA_TEXT)).append("\n");
String text=builder.toString();
List<Uri> mediaUris;
if(Intent.ACTION_SEND.equals(intent.getAction())){
@@ -80,8 +87,7 @@ public class ExternalShareActivity extends FragmentStackActivity{
args.putString("account", accountID);
if(!TextUtils.isEmpty(text))
args.putString("prefilledText", text);
if(!subject.isBlank())
args.putInt("selectionEnd", subject.length());
args.putInt("selectionStart", StringUtil.isBlank(subject) ? 0 : subject.length());
if(mediaUris!=null && !mediaUris.isEmpty())
args.putParcelableArrayList("mediaAttachments", toArrayList(mediaUris));
Fragment fragment=new ComposeFragment();

View File

@@ -8,6 +8,7 @@ import android.content.SharedPreferences;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.TimelineDefinition;
import java.lang.reflect.Type;
@@ -46,16 +47,20 @@ public class GlobalUserPreferences{
public static boolean autoHideFab;
public static boolean replyLineAboveHeader;
public static boolean compactReblogReplyLine;
public static boolean confirmBeforeReblog;
public static String publishButtonText;
public static ThemePreference theme;
public static ColorPreference color;
private final static Type recentLanguagesType = new TypeToken<Map<String, List<String>>>() {}.getType();
private final static Type pinnedTimelinesType = new TypeToken<Map<String, List<TimelineDefinition>>>() {}.getType();
private final static Type accountsDefaultContentTypesType = new TypeToken<Map<String, ContentType>>() {}.getType();
public static Map<String, List<String>> recentLanguages;
public static Map<String, List<TimelineDefinition>> pinnedTimelines;
public static Set<String> accountsWithLocalOnlySupport;
public static Set<String> accountsInGlitchMode;
public static Set<String> accountsWithContentTypesEnabled;
public static Map<String, ContentType> accountsDefaultContentTypes;
/**
* Pleroma
@@ -102,6 +107,7 @@ public class GlobalUserPreferences{
autoHideFab=prefs.getBoolean("autoHideFab", true);
replyLineAboveHeader=prefs.getBoolean("replyLineAboveHeader", true);
compactReblogReplyLine=prefs.getBoolean("compactReblogReplyLine", true);
confirmBeforeReblog=prefs.getBoolean("confirmBeforeReblog", false);
publishButtonText=prefs.getString("publishButtonText", "");
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
recentLanguages=fromJson(prefs.getString("recentLanguages", null), recentLanguagesType, new HashMap<>());
@@ -109,6 +115,8 @@ public class GlobalUserPreferences{
accountsWithLocalOnlySupport=prefs.getStringSet("accountsWithLocalOnlySupport", new HashSet<>());
accountsInGlitchMode=prefs.getStringSet("accountsInGlitchMode", new HashSet<>());
replyVisibility=prefs.getString("replyVisibility", null);
accountsWithContentTypesEnabled=prefs.getStringSet("accountsWithContentTypesEnabled", new HashSet<>());
accountsDefaultContentTypes=fromJson(prefs.getString("accountsDefaultContentTypes", null), accountsDefaultContentTypesType, new HashMap<>());
try {
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.PINK.name()));
@@ -148,6 +156,7 @@ public class GlobalUserPreferences{
.putString("publishButtonText", publishButtonText)
.putBoolean("bottomEncoding", bottomEncoding)
.putBoolean("replyLineAboveHeader", replyLineAboveHeader)
.putBoolean("confirmBeforeReblog", confirmBeforeReblog)
.putInt("theme", theme.ordinal())
.putString("color", color.name())
.putString("recentLanguages", gson.toJson(recentLanguages))
@@ -155,6 +164,8 @@ public class GlobalUserPreferences{
.putStringSet("accountsWithLocalOnlySupport", accountsWithLocalOnlySupport)
.putStringSet("accountsInGlitchMode", accountsInGlitchMode)
.putString("replyVisibility", replyVisibility)
.putStringSet("accountsWithContentTypesEnabled", accountsWithContentTypesEnabled)
.putString("accountsDefaultContentTypes", gson.toJson(accountsDefaultContentTypes))
.apply();
}

View File

@@ -0,0 +1,49 @@
package org.joinmastodon.android;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
public class PanicResponderActivity extends Activity {
public static final String PANIC_TRIGGER_ACTION = "info.guardianproject.panic.action.TRIGGER";
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Intent intent = getIntent();
if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) {
AccountSessionManager.getInstance().getLoggedInAccounts().forEach(accountSession -> logOut(accountSession.getID()));
ExitActivity.exit(this);
}
finishAndRemoveTask();
}
private void logOut(String accountID){
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
new RevokeOauthToken(session.app.clientId, session.app.clientSecret, session.token.accessToken)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Object result){
onLoggedOut(accountID);
}
@Override
public void onError(ErrorResponse error){
onLoggedOut(accountID);
}
})
.exec(accountID);
}
private void onLoggedOut(String accountID){
AccountSessionManager.getInstance().removeAccount(accountID);
}
}

View File

@@ -74,10 +74,8 @@ public class CacheController{
int flags=cursor.getInt(1);
status.hasGapAfter=((flags & POST_FLAG_GAP_AFTER)!=0);
newMaxID=status.id;
for(Filter filter:filters){
if(filter.matches(status))
continue outer;
}
if (!new StatusFilterPredicate(filters, Filter.FilterContext.HOME).test(status))
continue outer;
result.add(status);
}while(cursor.moveToNext());
String _newMaxID=newMaxID;
@@ -92,7 +90,7 @@ public class CacheController{
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<Status> result){
callback.onSuccess(new CacheablePaginatedResponse<>(result.stream().filter(new StatusFilterPredicate(filters)).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id, false));
callback.onSuccess(new CacheablePaginatedResponse<>(result.stream().filter(new StatusFilterPredicate(filters, Filter.FilterContext.HOME)).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id, false));
putHomeTimeline(result, maxID==null);
}
@@ -148,10 +146,8 @@ public class CacheController{
ntf.postprocess();
newMaxID=ntf.id;
if(ntf.status!=null){
for(Filter filter:filters){
if(filter.matches(ntf.status))
continue outer;
}
if (!new StatusFilterPredicate(filters, Filter.FilterContext.NOTIFICATIONS).test(ntf.status))
continue outer;
}
result.add(ntf);
}while(cursor.moveToNext());
@@ -170,11 +166,7 @@ public class CacheController{
public void onSuccess(List<Notification> result){
callback.onSuccess(new CacheablePaginatedResponse<>(result.stream().filter(ntf->{
if(ntf.status!=null){
for(Filter filter:filters){
if(filter.matches(ntf.status)){
return false;
}
}
return new StatusFilterPredicate(filters, Filter.FilterContext.NOTIFICATIONS).test(ntf.status);
}
return true;
}).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id, false));

View File

@@ -28,6 +28,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -51,7 +52,9 @@ public class MastodonAPIController{
.registerTypeAdapter(Status.class, new Status.StatusDeserializer())
.create();
private static WorkerThread thread=new WorkerThread("MastodonAPIController");
private static OkHttpClient httpClient=new OkHttpClient.Builder().build();
private static OkHttpClient httpClient=new OkHttpClient.Builder()
.readTimeout(5, TimeUnit.MINUTES)
.build();
private AccountSession session;
private static List<String> badDomains = new ArrayList<>();
@@ -60,7 +63,7 @@ public class MastodonAPIController{
thread.start();
try {
final BufferedReader reader = new BufferedReader(new InputStreamReader(
MastodonApp.context.getAssets().open("blocks.tsv")
MastodonApp.context.getAssets().open("blocks.txt")
));
String line;
while ((line = reader.readLine()) != null) {
@@ -91,7 +94,7 @@ public class MastodonAPIController{
Request.Builder builder=new Request.Builder()
.url(req.getURL().toString())
.method(req.getMethod(), req.getRequestBody())
.header("User-Agent", "MastodonAndroid/"+BuildConfig.VERSION_NAME);
.header("User-Agent", "MegalodonAndroid/"+BuildConfig.VERSION_NAME);
String token=null;
if(session!=null)

View File

@@ -5,8 +5,6 @@ import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import org.joinmastodon.android.R;
import me.grishka.appkit.api.ErrorResponse;
public class MastodonErrorResponse extends ErrorResponse{
@@ -22,7 +20,7 @@ public class MastodonErrorResponse extends ErrorResponse{
@Override
public void bindErrorView(View view){
TextView text=view.findViewById(R.id.error_text);
TextView text=view.findViewById(me.grishka.appkit.R.id.error_text);
text.setText(error);
}

View File

@@ -1,6 +1,7 @@
package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.ScheduledStatus;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.StatusPrivacy;
@@ -46,6 +47,7 @@ public class CreateStatus extends MastodonAPIRequest<Status>{
public String language;
public String quoteId;
public ContentType contentType;
public static class Poll{
public ArrayList<String> options=new ArrayList<>();

View File

@@ -2,17 +2,22 @@ package org.joinmastodon.android.api.requests.statuses;
import org.joinmastodon.android.api.AllFieldsAreRequired;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.RequiredField;
import org.joinmastodon.android.model.BaseModel;
import org.joinmastodon.android.model.ContentType;
public class GetStatusSourceText extends MastodonAPIRequest<GetStatusSourceText.Response>{
public GetStatusSourceText(String id){
super(HttpMethod.GET, "/statuses/"+id+"/source", Response.class);
}
@AllFieldsAreRequired
public static class Response extends BaseModel{
@RequiredField
public String id;
@RequiredField
public String text;
@RequiredField
public String spoilerText;
public ContentType contentType;
}
}

View File

@@ -3,10 +3,6 @@ package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.animation.TranslateAnimation;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
@@ -64,7 +60,12 @@ public class AccountTimelineFragment extends StatusListFragment{
@Override
public void onSuccess(List<Status> result){
if(getActivity()==null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.ACCOUNT)).collect(Collectors.toList());
AccountSessionManager asm = AccountSessionManager.getInstance();
result=result.stream().filter(status -> {
// don't hide own posts in own profile
if (asm.isSelf(accountID, user) && asm.isSelf(accountID, status.account)) return true;
else return new StatusFilterPredicate(accountID, getFilterContext()).test(status);
}).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
}
})
@@ -122,4 +123,10 @@ public class AccountTimelineFragment extends StatusListFragment{
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
// no-op
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.ACCOUNT;
}
}

View File

@@ -45,7 +45,6 @@ import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
import org.joinmastodon.android.ui.photoviewer.PhotoViewerHost;
import org.joinmastodon.android.ui.utils.MediaAttachmentViewController;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.MediaGridLayout;
import org.joinmastodon.android.utils.TypedObjectPool;
import java.util.ArrayList;
@@ -69,7 +68,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends RecyclerFragment<T> implements PhotoViewerHost, ScrollableToTop{
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends RecyclerFragment<T> implements PhotoViewerHost, ScrollableToTop, HasFab{
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
protected DisplayItemsAdapter adapter;
protected String accountID;
@@ -83,16 +82,17 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
public BaseStatusListFragment(){
super(20);
if (withComposeButton()) setListLayoutId(R.layout.recycler_fragment_with_fab);
if (wantsComposeButton()) setListLayoutId(R.layout.recycler_fragment_with_fab);
}
protected boolean withComposeButton() {
protected boolean wantsComposeButton() {
return false;
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
UiUtils.loadMaxWidth(getContext());
if(GlobalUserPreferences.disableMarquee){
setTitleMarqueeEnabled(false);
setSubtitleMarqueeEnabled(false);
@@ -101,8 +101,6 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
setRetainInstance(true);
}
@Override
protected RecyclerView.Adapter getAdapter(){
return adapter=new DisplayItemsAdapter();
@@ -270,37 +268,59 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
});
}
@Override
public @Nullable View getFab() {
if (getParentFragment() instanceof HasFab l) return l.getFab();
else return fab;
}
@Override
public void showFab() {
View fab = getFab();
if (fab == null || fab.getVisibility() == View.VISIBLE) return;
fab.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
fab.getHeight() * 2,
0);
animate.setDuration(300);
fab.startAnimation(animate);
}
@Override
public void hideFab() {
View fab = getFab();
if (fab == null || fab.getVisibility() != View.VISIBLE) return;
TranslateAnimation animate = new TranslateAnimation(
0,
0,
0,
fab.getHeight() * 2);
animate.setDuration(300);
fab.startAnimation(animate);
fab.setVisibility(View.INVISIBLE);
scrollDiff = 0;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
fab=view.findViewById(R.id.fab);
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
if(currentPhotoViewer!=null)
currentPhotoViewer.offsetView(-dx, -dy);
View fab = getFab();
if (fab!=null && GlobalUserPreferences.autoHideFab) {
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
TranslateAnimation animate = new TranslateAnimation(
0,
0,
0,
fab.getHeight() * 2);
animate.setDuration(300);
fab.startAnimation(animate);
fab.setVisibility(View.INVISIBLE);
scrollDiff = 0;
hideFab();
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
if (list.getChildAt(0).getTop() == 0 || scrollDiff > 400) {
fab.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
fab.getHeight() * 2,
0);
animate.setDuration(300);
fab.startAnimation(animate);
showFab();
scrollDiff = 0;
} else {
scrollDiff += Math.abs(dy);
@@ -343,10 +363,12 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
((UsableRecyclerView) list).setIncludeMarginsInItemHitbox(true);
updateToolbar();
if (withComposeButton()) {
if (wantsComposeButton() && !getArguments().getBoolean("__disable_fab", false)) {
fab.setVisibility(View.VISIBLE);
fab.setOnClickListener(this::onFabClick);
fab.setOnLongClickListener(this::onFabLongClick);
} else if (fab != null) {
fab.setVisibility(View.GONE);
}
}
@@ -655,13 +677,13 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
currentPhotoViewer.onPause();
}
protected void onFabClick(View v){
public void onFabClick(View v){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.go(getActivity(), ComposeFragment.class, args);
}
protected boolean onFabLongClick(View v) {
public boolean onFabLongClick(View v) {
return UiUtils.pickAccountForCompose(getActivity(), accountID);
}
@@ -758,7 +780,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
if(!imgHolder.getItem().status.spoilerRevealed){
if(TextUtils.isEmpty(imgHolder.getItem().status.spoilerText)){
int listWidth=getListWidthForMediaLayout();
int width=Math.min(listWidth, V.dp(MediaGridLayout.MAX_WIDTH));
int width=Math.min(listWidth, UiUtils.MAX_WIDTH);
if(currentMediaHiddenLayoutsWidth!=width)
rebuildMediaHiddenLayouts(width-V.dp(32));
c.save();

View File

@@ -4,6 +4,7 @@ import android.app.Activity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetBookmarkedStatuses;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Status;
@@ -35,4 +36,9 @@ public class BookmarkedStatusListFragment extends StatusListFragment{
})
.exec(accountID);
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.ACCOUNT;
}
}

View File

@@ -91,6 +91,7 @@ import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusUpdatedEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.EmojiCategory;
import org.joinmastodon.android.model.Instance;
@@ -179,8 +180,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private int charCount, charLimit, trimmedCharCount;
private Button publishButton, languageButton, scheduleTimeBtn, draftsBtn;
private PopupMenu languagePopup, visibilityPopup, draftOptionsPopup;
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn, scheduleDraftDismiss;
private PopupMenu languagePopup, contentTypePopup, visibilityPopup, draftOptionsPopup;
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn, scheduleDraftDismiss, contentTypeBtn;
private ImageView sensitiveIcon;
private ComposeMediaLayout attachmentsView;
private TextView replyText;
@@ -234,6 +235,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private Runnable updateUploadEtaRunnable;
private String language, encoding;
private ContentType contentType;
private MastodonLanguage.LanguageResolver languageResolver;
@Override
@@ -242,6 +244,12 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
setRetainInstance(true);
accountID=getArguments().getString("account");
contentType = GlobalUserPreferences.accountsDefaultContentTypes.get(accountID);
if (contentType == null && GlobalUserPreferences.accountsWithContentTypesEnabled.contains(accountID)) {
// if formatting is enabled, use plain to avoid confusing unspecified default setting
contentType = ContentType.PLAIN;
}
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
self=session.self;
instanceDomain=session.domain;
@@ -330,6 +338,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
emojiBtn=view.findViewById(R.id.btn_emoji);
spoilerBtn=view.findViewById(R.id.btn_spoiler);
visibilityBtn=view.findViewById(R.id.btn_visibility);
contentTypeBtn=view.findViewById(R.id.btn_content_type);
scheduleDraftView=view.findViewById(R.id.schedule_draft_view);
scheduleDraftText=view.findViewById(R.id.schedule_draft_text);
scheduleDraftDismiss=view.findViewById(R.id.schedule_draft_dismiss);
@@ -364,6 +373,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
visibilityBtn.setOnClickListener(v->visibilityPopup.show());
visibilityBtn.setOnTouchListener(visibilityPopup.getDragToOpenListener());
buildContentTypePopup(contentTypeBtn);
contentTypeBtn.setOnClickListener(v->contentTypePopup.show());
contentTypeBtn.setOnTouchListener(contentTypePopup.getDragToOpenListener());
scheduleDraftDismiss.setOnClickListener(v->updateScheduledAt(null));
scheduleTimeBtn.setOnClickListener(v->pickScheduledDateTime());
@@ -466,8 +479,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
}
if(editingStatus!=null && editingStatus.visibility!=null) {
statusVisibility=editingStatus.visibility;
if (savedInstanceState != null) {
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
} else if (editingStatus != null && editingStatus.visibility != null) {
statusVisibility = editingStatus.visibility;
} else {
loadDefaultStatusVisibility(savedInstanceState);
}
@@ -482,6 +497,20 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}).setChecked(true);
visibilityPopup.getMenu().findItem(R.id.local_only).setChecked(localOnly);
if (savedInstanceState != null && savedInstanceState.containsKey("contentType")) {
contentType = (ContentType) savedInstanceState.getSerializable("contentType");
} else if (getArguments().containsKey("sourceContentType")) {
try {
String val = getArguments().getString("sourceContentType");
contentType = val == null ? null : ContentType.valueOf(val);
} catch (IllegalArgumentException ignored) {}
}
int contentTypeId = ContentType.getContentTypeRes(contentType);
contentTypePopup.getMenu().findItem(contentTypeId).setChecked(true);
contentTypeBtn.setSelected(contentTypeId != R.id.content_type_null && contentTypeId != R.id.content_type_plain);
autocompleteViewController=new ComposeAutocompleteViewController(getActivity(), accountID);
autocompleteViewController.setCompletionSelectedListener(this::onAutocompleteOptionSelected);
View autocompleteView=autocompleteViewController.getView();
@@ -518,6 +547,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
outState.putParcelableArrayList("attachments", serializedAttachments);
}
outState.putSerializable("visibility", statusVisibility);
outState.putSerializable("contentType", contentType);
if (scheduledAt != null) outState.putSerializable("scheduledAt", scheduledAt);
if (scheduledStatus != null) outState.putParcelable("scheduledStatus", Parcels.wrap(scheduledStatus));
}
@@ -907,6 +937,17 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
});
}
private int getContentTypeName(String id) {
return switch (id) {
case "text/plain" -> R.string.sk_content_type_plain;
case "text/html" -> R.string.sk_content_type_html;
case "text/markdown" -> R.string.sk_content_type_markdown;
case "text/bbcode" -> R.string.sk_content_type_bbcode;
case "text/x.misskeymarkdown" -> R.string.sk_content_type_mfm;
default -> throw new IllegalArgumentException("Invalid content type");
};
}
private void addBottomLanguage(Menu menu) {
if (menu.findItem(allLanguages.size()) == null) {
menu.add(0, allLanguages.size(), Menu.NONE, "bottom (\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48)");
@@ -1053,6 +1094,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
req.visibility=localOnly && instance.pleroma != null ? StatusPrivacy.LOCAL : statusVisibility;
req.sensitive=sensitive;
req.language=language;
req.contentType=contentType;
req.scheduledAt = scheduledAt;
if(!attachments.isEmpty()){
req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList());
@@ -1547,7 +1589,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
if(att.isUploadingOrProcessing())
att.cancelUpload();
attachments.remove(att);
uploadNextQueuedAttachment();
if(!areThereAnyUploadingAttachments())
uploadNextQueuedAttachment();
attachmentsView.removeView(att.view);
if(getMediaAttachmentsCount()==0)
attachmentsView.setVisibility(View.GONE);
@@ -1894,14 +1937,36 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
});
}
@SuppressLint("ClickableViewAccessibility")
private void buildContentTypePopup(View btn) {
contentTypePopup=new PopupMenu(getActivity(), btn);
contentTypePopup.inflate(R.menu.compose_content_type);
Menu m = contentTypePopup.getMenu();
ContentType.adaptMenuToInstance(m, instance);
if (contentType != null) m.findItem(R.id.content_type_null).setVisible(false);
contentTypePopup.setOnMenuItemClickListener(i->{
int id=i.getItemId();
if (id == R.id.content_type_null) contentType = null;
else if (id == R.id.content_type_plain) contentType = ContentType.PLAIN;
else if (id == R.id.content_type_html) contentType = ContentType.HTML;
else if (id == R.id.content_type_markdown) contentType = ContentType.MARKDOWN;
else if (id == R.id.content_type_bbcode) contentType = ContentType.BBCODE;
else if (id == R.id.content_type_misskey_markdown) contentType = ContentType.MISSKEY_MARKDOWN;
else return false;
btn.setSelected(id != R.id.content_type_null && id != R.id.content_type_plain);
i.setChecked(true);
return true;
});
if (!GlobalUserPreferences.accountsWithContentTypesEnabled.contains(accountID)) {
btn.setVisibility(View.GONE);
}
}
private void loadDefaultStatusVisibility(Bundle savedInstanceState) {
if(replyTo != null) statusVisibility = replyTo.visibility;
// A saved privacy setting from a previous compose session wins over the reply visibility
if(savedInstanceState !=null){
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
}
AccountSessionManager asm = AccountSessionManager.getInstance();
Preferences prefs = asm.getAccount(accountID).preferences;
if (prefs != null) {

View File

@@ -4,6 +4,7 @@ import android.app.Activity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetFavoritedStatuses;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Status;
@@ -35,4 +36,9 @@ public class FavoritedStatusListFragment extends StatusListFragment{
})
.exec(accountID);
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.ACCOUNT;
}
}

View File

@@ -0,0 +1,9 @@
package org.joinmastodon.android.fragments;
import android.view.View;
public interface HasFab {
View getFab();
void showFab();
void hideFab();
}

View File

@@ -39,7 +39,7 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
private MenuItem followButton;
@Override
protected boolean withComposeButton() {
protected boolean wantsComposeButton() {
return true;
}
@@ -123,7 +123,7 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
@Override
public void onSuccess(List<Status> result){
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
}
})
@@ -138,12 +138,12 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
}
@Override
protected boolean onFabLongClick(View v) {
public boolean onFabLongClick(View v) {
return UiUtils.pickAccountForCompose(getActivity(), accountID, '#'+hashtag+' ');
}
@Override
protected void onFabClick(View v){
public void onFabClick(View v){
Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("prefilledText", '#'+hashtag+' ');
@@ -154,4 +154,9 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment {
protected void onSetFabBottomInset(int inset){
((ViewGroup.MarginLayoutParams) fab.getLayoutParams()).bottomMargin=V.dp(24)+inset;
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.PUBLIC;
}
}

View File

@@ -104,7 +104,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
content.setOrientation(LinearLayout.VERTICAL);
FrameLayout fragmentContainer=new FrameLayout(getActivity());
fragmentContainer.setId(R.id.fragment_wrap);
fragmentContainer.setId(me.grishka.appkit.R.id.fragment_wrap);
content.addView(fragmentContainer, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 0, 1f));
inflater.inflate(R.layout.tab_bar, content);
@@ -128,10 +128,10 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
if(savedInstanceState==null){
getChildFragmentManager().beginTransaction()
.add(R.id.fragment_wrap, homeTabFragment)
.add(R.id.fragment_wrap, searchFragment).hide(searchFragment)
.add(R.id.fragment_wrap, notificationsFragment).hide(notificationsFragment)
.add(R.id.fragment_wrap, profileFragment).hide(profileFragment)
.add(me.grishka.appkit.R.id.fragment_wrap, homeTabFragment)
.add(me.grishka.appkit.R.id.fragment_wrap, searchFragment).hide(searchFragment)
.add(me.grishka.appkit.R.id.fragment_wrap, notificationsFragment).hide(notificationsFragment)
.add(me.grishka.appkit.R.id.fragment_wrap, profileFragment).hide(profileFragment)
.commit();
String defaultTab=getArguments().getString("tab");
@@ -160,6 +160,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
notificationsFragment=(NotificationsFragment) getChildFragmentManager().getFragment(savedInstanceState, "notificationsFragment");
profileFragment=(ProfileFragment) getChildFragmentManager().getFragment(savedInstanceState, "profileFragment");
currentTab=savedInstanceState.getInt("selectedTab");
tabBar.selectTab(currentTab);
Fragment current=fragmentForTab(currentTab);
getChildFragmentManager().beginTransaction()
.hide(homeTabFragment)
@@ -227,6 +228,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
}
getChildFragmentManager().beginTransaction().hide(fragmentForTab(currentTab)).show(newFragment).commit();
maybeTriggerLoading(newFragment);
if (newFragment instanceof HasFab fabulous) fabulous.showFab();
currentTab=tab;
((FragmentStackActivity)getActivity()).invalidateSystemBarColors(this);
}
@@ -291,7 +293,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
if (instance == null) return;
new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance.pleroma != null)
new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance != null && instance.pleroma != null)
.setCallback(new Callback<>() {
@Override
public void onSuccess(List<Notification> notifications) {

View File

@@ -24,6 +24,7 @@ import android.view.ViewParent;
import android.view.ViewTreeObserver;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.PopupMenu;
import android.widget.TextView;
@@ -70,7 +71,7 @@ import me.grishka.appkit.fragments.OnBackPressedListener;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V;
public class HomeTabFragment extends MastodonToolbarFragment implements ScrollableToTop, OnBackPressedListener {
public class HomeTabFragment extends MastodonToolbarFragment implements ScrollableToTop, OnBackPressedListener, HasFab {
private static final int ANNOUNCEMENTS_RESULT = 654;
private String accountID;
@@ -98,6 +99,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
private PopupMenu overflowPopup;
private View overflowActionView = null;
private boolean announcementsBadged, settingsBadged;
private ImageButton fab;
@Override
public void onCreate(Bundle savedInstanceState) {
@@ -122,6 +124,10 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
@Override
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle bundle) {
FrameLayout view = new FrameLayout(getContext());
inflater.inflate(R.layout.compose_fab, view);
fab = view.findViewById(R.id.fab);
fab.setOnClickListener(this::onFabClick);
fab.setOnLongClickListener(this::onFabLongClick);
pager = new ViewPager2(getContext());
toolbarFrame = (FrameLayout) LayoutInflater.from(getContext()).inflate(R.layout.home_toolbar, getToolbar(), false);
@@ -129,6 +135,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
Bundle args = new Bundle();
args.putString("account", accountID);
args.putBoolean("__is_tab", true);
args.putBoolean("__disable_fab", true);
args.putBoolean("onlyPosts", true);
for (int i = 0; i < timelineDefinitions.size(); i++) {
@@ -280,6 +287,20 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
}).exec(accountID);
}
private void onFabClick(View v){
if (fragments[pager.getCurrentItem()] instanceof BaseStatusListFragment<?> l) {
l.onFabClick(v);
}
}
private boolean onFabLongClick(View v) {
if (fragments[pager.getCurrentItem()] instanceof BaseStatusListFragment<?> l) {
return l.onFabLongClick(v);
} else {
return false;
}
}
private void addListsToOverflowMenu() {
Context ctx = getContext();
listsMenu.clear();
@@ -427,9 +448,20 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
updateSwitcherIcon(i);
}
@Override
public void showFab() {
if (fragments[pager.getCurrentItem()] instanceof BaseStatusListFragment<?> l) l.showFab();
}
@Override
public void hideFab() {
if (fragments[pager.getCurrentItem()] instanceof BaseStatusListFragment<?> l) l.hideFab();
}
private void updateSwitcherIcon(int i) {
timelineIcon.setImageResource(timelines[i].getIcon().iconRes);
timelineTitle.setText(timelines[i].getTitle(getContext()));
showFab();
}
@Override
@@ -657,6 +689,10 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
return hashtagsItems.values();
}
public ImageButton getFab() {
return fab;
}
private class HomePagerAdapter extends RecyclerView.Adapter<SimpleViewHolder> {
@NonNull
@Override

View File

@@ -8,8 +8,6 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
import org.joinmastodon.android.api.session.AccountSessionManager;
@@ -38,7 +36,7 @@ public class HomeTimelineFragment extends StatusListFragment {
private String lastSavedMarkerID;
@Override
protected boolean withComposeButton() {
protected boolean wantsComposeButton() {
return true;
}
@@ -150,7 +148,7 @@ public class HomeTimelineFragment extends StatusListFragment {
result.get(result.size()-1).hasGapAfter=true;
toAdd=result;
}
StatusFilterPredicate filterPredicate=new StatusFilterPredicate(accountID, Filter.FilterContext.HOME);
StatusFilterPredicate filterPredicate=new StatusFilterPredicate(accountID, getFilterContext());
toAdd=toAdd.stream().filter(filterPredicate).collect(Collectors.toList());
if(!toAdd.isEmpty()){
prependItems(toAdd, true);
@@ -229,7 +227,7 @@ public class HomeTimelineFragment extends StatusListFragment {
List<StatusDisplayItem> targetList=displayItems.subList(gapPos, gapPos+1);
targetList.clear();
List<Status> insertedPosts=data.subList(gapPostIndex+1, gapPostIndex+1);
StatusFilterPredicate filterPredicate=new StatusFilterPredicate(accountID, Filter.FilterContext.HOME);
StatusFilterPredicate filterPredicate=new StatusFilterPredicate(accountID, getFilterContext());
for(Status s:result){
if(idsBelowGap.contains(s.id))
break;
@@ -282,4 +280,9 @@ public class HomeTimelineFragment extends StatusListFragment {
protected boolean shouldRemoveAccountPostsWhenUnfollowing(){
return true;
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.HOME;
}
}

View File

@@ -44,7 +44,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
private ListTimeline.RepliesPolicy repliesPolicy;
@Override
protected boolean withComposeButton() {
protected boolean wantsComposeButton() {
return true;
}
@@ -137,7 +137,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
@Override
public void onSuccess(List<Status> result) {
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.HOME)).collect(Collectors.toList());
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
}
})
@@ -152,7 +152,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
}
@Override
protected void onFabClick(View v){
public void onFabClick(View v){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.go(getActivity(), ComposeFragment.class, args);
@@ -162,4 +162,10 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
protected void onSetFabBottomInset(int inset) {
((ViewGroup.MarginLayoutParams) fab.getLayoutParams()).bottomMargin=V.dp(24)+inset;
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.HOME;
}
}

View File

@@ -16,14 +16,15 @@ import org.joinmastodon.android.events.PollUpdatedEvent;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.TextStatusDisplayItem;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
import org.joinmastodon.android.ui.utils.InsetStatusItemDecoration;
import org.joinmastodon.android.ui.utils.UiUtils;
@@ -48,8 +49,8 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
private final DiscoverInfoBannerHelper bannerHelper = new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.POST_NOTIFICATIONS);
@Override
protected boolean withComposeButton() {
return true;
protected boolean wantsComposeButton() {
return false;
}
@Override
@@ -83,6 +84,13 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
protected List<StatusDisplayItem> buildDisplayItems(Notification n){
Account reportTarget = n.report == null ? null : n.report.targetAccount == null ? null :
n.report.targetAccount;
Emoji emoji = new Emoji();
if(n.emojiUrl!=null){
emoji.shortcode=n.emoji.substring(1,n.emoji.length()-1);
emoji.url=n.emojiUrl;
emoji.staticUrl=n.emojiUrl;
emoji.visibleInPicker=false;
}
String extraText=switch(n.type){
case FOLLOW -> getString(R.string.user_followed_you);
case FOLLOW_REQUEST -> getString(R.string.user_sent_follow_request);
@@ -93,8 +101,10 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
case UPDATE -> getString(R.string.sk_post_edited);
case SIGN_UP -> getString(R.string.sk_signed_up);
case REPORT -> getString(R.string.sk_reported);
case REACTION, PLEROMA_EMOJI_REACTION ->
n.emoji != null ? getString(R.string.sk_reacted_with, n.emoji) : getString(R.string.sk_reacted);
};
HeaderStatusDisplayItem titleItem=extraText!=null ? new HeaderStatusDisplayItem(n.id, n.account, n.createdAt, this, accountID, n.status, extraText, n, null) : null;
HeaderStatusDisplayItem titleItem=extraText!=null ? new HeaderStatusDisplayItem(n.id, n.account, n.createdAt, this, accountID, n.status, n.emojiUrl!=null ? HtmlParser.parseCustomEmoji(extraText, Collections.singletonList(emoji)) : extraText, n, null) : null;
if(n.status!=null){
ArrayList<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, n.status, accountID, n, knownAccounts, titleItem!=null, titleItem==null, n, false, Filter.FilterContext.NOTIFICATIONS);
if(titleItem!=null)
@@ -144,8 +154,9 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
if(offset==0 && !result.items.isEmpty() && !result.isFromCache()){
E.post(new AllNotificationsSeenEvent());
new SaveMarkers(null, result.items.get(0).id).exec(accountID);
AccountSessionManager.getInstance().getAccount(accountID).markers
.notifications.lastReadId = result.items.get(0).id;
if (AccountSessionManager.getInstance().getAccount(accountID).markers != null)
AccountSessionManager.getInstance().getAccount(accountID).markers
.notifications.lastReadId = result.items.get(0).id;
AccountSessionManager.getInstance().writeAccountsFile();
}
}
@@ -196,7 +207,6 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
list.addItemDecoration(new InsetStatusItemDecoration(this));
if (getParentFragment() instanceof NotificationsFragment) fab.setVisibility(View.GONE);
if (onlyPosts) bannerHelper.maybeAddBanner(contentWrap);
}

View File

@@ -337,7 +337,7 @@ public class ProfileAboutFragment extends Fragment implements WindowInsetsAwareF
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState){
super.onSelectedChanged(viewHolder, actionState);
if(actionState==ItemTouchHelper.ACTION_STATE_DRAG){
viewHolder.itemView.setTag(R.id.item_touch_helper_previous_elevation, viewHolder.itemView.getElevation()); // prevents the default behavior of changing elevation in onDraw()
viewHolder.itemView.setTag(me.grishka.appkit.R.id.item_touch_helper_previous_elevation, viewHolder.itemView.getElevation()); // prevents the default behavior of changing elevation in onDraw()
viewHolder.itemView.animate().translationZ(V.dp(1)).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
draggedViewHolder=viewHolder;
}

View File

@@ -19,13 +19,11 @@ import android.os.Bundle;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
@@ -112,7 +110,7 @@ import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class ProfileFragment extends LoaderFragment implements OnBackPressedListener, ScrollableToTop{
public class ProfileFragment extends LoaderFragment implements OnBackPressedListener, ScrollableToTop, HasFab{
private static final int AVATAR_RESULT=722;
private static final int COVER_RESULT=343;
@@ -152,7 +150,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private WindowInsets childInsets;
private PhotoViewer currentPhotoViewer;
private boolean editModeLoading;
protected int scrollDiff = 0;
private static final int MAX_FIELDS=4;
@@ -761,6 +758,16 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
return fab;
}
@Override
public void showFab() {
if (getFragmentForPage(pager.getCurrentItem()) instanceof HasFab fabulous) fabulous.showFab();
}
@Override
public void hideFab() {
if (getFragmentForPage(pager.getCurrentItem()) instanceof HasFab fabulous) fabulous.hideFab();
}
private void onScrollChanged(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY){
int topBarsH=getToolbar().getHeight()+statusBarHeight;
if(scrollY>avatarBorder.getTop()-topBarsH){
@@ -791,35 +798,6 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
if(currentPhotoViewer!=null){
currentPhotoViewer.offsetView(0, oldScrollY-scrollY);
}
if (GlobalUserPreferences.autoHideFab) {
int dy = scrollY - oldScrollY;
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
TranslateAnimation animate = new TranslateAnimation(
0,
0,
0,
fab.getHeight() * 2);
animate.setDuration(300);
fab.startAnimation(animate);
fab.setVisibility(View.INVISIBLE);
scrollDiff = 0;
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
if (v.getScrollY() == 0 || scrollDiff > 400) {
fab.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
fab.getHeight() * 2,
0);
animate.setDuration(300);
fab.startAnimation(animate);
scrollDiff = 0;
} else {
scrollDiff += Math.abs(dy);
}
}
}
}
private Fragment getFragmentForPage(int page){
@@ -1375,7 +1353,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
public void onSelectedChanged(@Nullable RecyclerView.ViewHolder viewHolder, int actionState){
super.onSelectedChanged(viewHolder, actionState);
if(actionState==ItemTouchHelper.ACTION_STATE_DRAG){
viewHolder.itemView.setTag(R.id.item_touch_helper_previous_elevation, viewHolder.itemView.getElevation()); // prevents the default behavior of changing elevation in onDraw()
viewHolder.itemView.setTag(me.grishka.appkit.R.id.item_touch_helper_previous_elevation, viewHolder.itemView.getElevation()); // prevents the default behavior of changing elevation in onDraw()
viewHolder.itemView.animate().translationZ(V.dp(1)).setDuration(200).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
draggedViewHolder=viewHolder;
}

View File

@@ -31,7 +31,7 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
private static final int SCHEDULED_STATUS_LIST_OPENED = 161;
@Override
protected boolean withComposeButton() {
protected boolean wantsComposeButton() {
return true;
}
@@ -56,7 +56,7 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
}
@Override
protected void onFabClick(View v) {
public void onFabClick(View v) {
Bundle args=new Bundle();
args.putString("account", accountID);
args.putSerializable("scheduledAt", CreateStatus.getDraftInstant());
@@ -64,7 +64,7 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
}
@Override
protected boolean onFabLongClick(View v) {
public boolean onFabLongClick(View v) {
Bundle args=new Bundle();
args.putString("account", accountID);
args.putSerializable("scheduledAt", CreateStatus.getDraftInstant());
@@ -79,7 +79,7 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
@Override
protected List<StatusDisplayItem> buildDisplayItems(ScheduledStatus s) {
return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, false, false, null, true);
return StatusDisplayItem.buildItems(this, s.toStatus(), accountID, s, knownAccounts, false, false, null, true, null);
}
@Override
@@ -96,6 +96,8 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
args.putString("sourceText", status.text);
args.putString("sourceSpoiler", status.spoilerText);
args.putBoolean("redraftStatus", true);
args.putString("sourceContentType", scheduledStatus.params.contentType != null ?
scheduledStatus.params.contentType.name() : null);
setResult(true, null);
// closing this scheduled status list if another status list is opened from compose fragment

View File

@@ -14,6 +14,7 @@ import android.util.LruCache;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -48,6 +49,7 @@ import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
import org.joinmastodon.android.model.PushNotification;
@@ -64,6 +66,7 @@ import java.util.function.Consumer;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -80,7 +83,8 @@ public class SettingsFragment extends MastodonToolbarFragment{
private ArrayList<Item> items=new ArrayList<>();
private ThemeItem themeItem;
private NotificationPolicyItem notificationPolicyItem;
private SwitchItem showNewPostsButtonItem, glitchModeItem, compactReblogReplyLineItem;
private SwitchItem showNewPostsItem, glitchModeItem, compactReblogReplyLineItem;
private ButtonItem defaultContentTypeButtonItem;
private String accountID;
private boolean needUpdateNotificationSettings;
private boolean needAppRestart;
@@ -89,7 +93,9 @@ public class SettingsFragment extends MastodonToolbarFragment{
private ImageView themeTransitionWindowView;
private TextItem checkForUpdateItem, clearImageCacheItem;
private ImageCache imageCache;
private Menu contentTypeMenu;
@SuppressLint("ClickableViewAccessibility")
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
@@ -207,6 +213,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
GlobalUserPreferences.prefixRepliesWithRe=i.checked;
GlobalUserPreferences.save();
}));
items.add(new SwitchItem(R.string.sk_settings_confirm_before_reblog, R.drawable.ic_fluent_checkmark_circle_24_regular, GlobalUserPreferences.confirmBeforeReblog, i->{
GlobalUserPreferences.confirmBeforeReblog=i.checked;
GlobalUserPreferences.save();
}));
items.add(new HeaderItem(R.string.sk_timelines));
items.add(new SwitchItem(R.string.sk_settings_show_replies, R.drawable.ic_fluent_chat_multiple_24_regular, GlobalUserPreferences.showReplies, i->{
@@ -235,15 +245,15 @@ public class SettingsFragment extends MastodonToolbarFragment{
}));
items.add(new SwitchItem(R.string.sk_settings_load_new_posts, R.drawable.ic_fluent_arrow_sync_24_regular, GlobalUserPreferences.loadNewPosts, i->{
GlobalUserPreferences.loadNewPosts=i.checked;
showNewPostsButtonItem.enabled = i.checked;
showNewPostsItem.enabled = i.checked;
if (!i.checked) {
GlobalUserPreferences.showNewPostsButton = false;
showNewPostsButtonItem.checked = false;
showNewPostsItem.checked = false;
}
if (list.findViewHolderForAdapterPosition(items.indexOf(showNewPostsButtonItem)) instanceof SwitchViewHolder svh) svh.rebind();
if (list.findViewHolderForAdapterPosition(items.indexOf(showNewPostsItem)) instanceof SwitchViewHolder svh) svh.rebind();
GlobalUserPreferences.save();
}));
items.add(showNewPostsButtonItem = new SwitchItem(R.string.sk_settings_see_new_posts_button, R.drawable.ic_fluent_arrow_up_24_regular, GlobalUserPreferences.showNewPostsButton, i->{
items.add(showNewPostsItem = new SwitchItem(R.string.sk_settings_see_new_posts_button, R.drawable.ic_fluent_arrow_up_24_regular, GlobalUserPreferences.showNewPostsButton, i->{
GlobalUserPreferences.showNewPostsButton=i.checked;
GlobalUserPreferences.save();
}));
@@ -326,6 +336,36 @@ public class SettingsFragment extends MastodonToolbarFragment{
if (!TextUtils.isEmpty(instance.version)) items.add(new SmallTextItem(getString(R.string.sk_settings_server_version, instance.version)));
items.add(new HeaderItem(R.string.sk_instance_features));
items.add(new SwitchItem(R.string.sk_settings_content_types, 0, GlobalUserPreferences.accountsWithContentTypesEnabled.contains(accountID), (i)->{
if (i.checked) {
GlobalUserPreferences.accountsWithContentTypesEnabled.add(accountID);
if (GlobalUserPreferences.accountsDefaultContentTypes.get(accountID) == null) {
GlobalUserPreferences.accountsDefaultContentTypes.put(accountID, ContentType.PLAIN);
}
} else {
GlobalUserPreferences.accountsWithContentTypesEnabled.remove(accountID);
GlobalUserPreferences.accountsDefaultContentTypes.remove(accountID);
}
if (list.findViewHolderForAdapterPosition(items.indexOf(defaultContentTypeButtonItem))
instanceof ButtonViewHolder bvh) bvh.rebind();
GlobalUserPreferences.save();
}));
items.add(new SmallTextItem(getString(R.string.sk_settings_content_types_explanation)));
items.add(defaultContentTypeButtonItem = new ButtonItem(R.string.sk_settings_default_content_type, 0, b->{
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
popupMenu.inflate(R.menu.compose_content_type);
popupMenu.setOnMenuItemClickListener(item -> this.onContentTypeChanged(item, b));
b.setOnTouchListener(popupMenu.getDragToOpenListener());
b.setOnClickListener(v->popupMenu.show());
ContentType contentType = GlobalUserPreferences.accountsDefaultContentTypes.get(accountID);
b.setText(getContentTypeString(contentType));
contentTypeMenu = popupMenu.getMenu();
contentTypeMenu.findItem(ContentType.getContentTypeRes(contentType)).setChecked(true);
ContentType.adaptMenuToInstance(contentTypeMenu, instance);
contentTypeMenu.findItem(R.id.content_type_null).setVisible(
!GlobalUserPreferences.accountsWithContentTypesEnabled.contains(accountID));
}));
items.add(new SmallTextItem(getString(R.string.sk_settings_default_content_type_explanation)));
items.add(new SwitchItem(R.string.sk_settings_support_local_only, 0, GlobalUserPreferences.accountsWithLocalOnlySupport.contains(accountID), i->{
glitchModeItem.enabled = i.checked;
if (i.checked) {
@@ -496,6 +536,34 @@ public class SettingsFragment extends MastodonToolbarFragment{
}
}
private @StringRes int getContentTypeString(@Nullable ContentType contentType) {
if (contentType == null) return R.string.sk_content_type_unspecified;
return switch (contentType) {
case PLAIN -> R.string.sk_content_type_plain;
case HTML -> R.string.sk_content_type_html;
case MARKDOWN -> R.string.sk_content_type_markdown;
case BBCODE -> R.string.sk_content_type_bbcode;
case MISSKEY_MARKDOWN -> R.string.sk_content_type_mfm;
};
}
private boolean onContentTypeChanged(MenuItem item, Button btn){
int id = item.getItemId();
ContentType contentType = switch (id) {
case R.id.content_type_plain -> ContentType.PLAIN;
case R.id.content_type_html -> ContentType.HTML;
case R.id.content_type_markdown -> ContentType.MARKDOWN;
case R.id.content_type_bbcode -> ContentType.BBCODE;
case R.id.content_type_misskey_markdown -> ContentType.MISSKEY_MARKDOWN;
default -> null;
};
GlobalUserPreferences.accountsDefaultContentTypes.put(accountID, contentType);
GlobalUserPreferences.save();
btn.setText(getContentTypeString(contentType));
item.setChecked(true);
return true;
}
private boolean onReplyVisibilityChanged(MenuItem item, Button btn){
String pref = null;
int id = item.getItemId();
@@ -1003,7 +1071,11 @@ public class SettingsFragment extends MastodonToolbarFragment{
@Override
public void onBind(ButtonItem item){
text.setText(item.text);
icon.setImageResource(item.icon);
if (item.icon == 0) {
icon.setVisibility(View.GONE);
} else {
icon.setImageResource(item.icon);
}
item.buttonConsumer.accept(button);
}
}

View File

@@ -1,43 +1,47 @@
package org.joinmastodon.android.fragments;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.style.ReplacementSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Button;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.instance.GetInstance;
import org.joinmastodon.android.fragments.onboarding.InstanceCatalogSignupFragment;
import org.joinmastodon.android.fragments.onboarding.InstanceChooserLoginFragment;
import org.joinmastodon.android.fragments.onboarding.InstanceRulesFragment;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.ui.InterpolatingMotionEffect;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.SizeListenerFrameLayout;
import org.parceler.Parcels;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager2.widget.ViewPager2;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.fragments.AppKitFragment;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.BottomSheet;
public class SplashFragment extends AppKitFragment{
private static final String DEFAULT_SERVER="mastodon.social";
private SizeListenerFrameLayout contentView;
private View artContainer, blueFill, greenFill;
private ViewPager2 pager;
private ViewGroup pagerDots;
private InterpolatingMotionEffect motionEffect;
private View artClouds, artPlaneElephant, artRightHill, artLeftHill, artCenterHill;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
}
@Nullable
@@ -46,44 +50,26 @@ public class SplashFragment extends AppKitFragment{
contentView=(SizeListenerFrameLayout) inflater.inflate(R.layout.fragment_splash, container, false);
contentView.findViewById(R.id.btn_get_started).setOnClickListener(this::onButtonClick);
contentView.findViewById(R.id.btn_log_in).setOnClickListener(this::onButtonClick);
Button joinDefault=contentView.findViewById(R.id.btn_join_default_server);
joinDefault.setText(getString(R.string.join_default_server, DEFAULT_SERVER));
joinDefault.setOnClickListener(this::onJoinDefaultServerClick);
contentView.findViewById(R.id.btn_learn_more).setOnClickListener(this::onLearnMoreClick);
artClouds=contentView.findViewById(R.id.art_clouds);
artPlaneElephant=contentView.findViewById(R.id.art_plane_elephant);
artRightHill=contentView.findViewById(R.id.art_right_hill);
artLeftHill=contentView.findViewById(R.id.art_left_hill);
artCenterHill=contentView.findViewById(R.id.art_center_hill);
pager=contentView.findViewById(R.id.pager);
pagerDots=contentView.findViewById(R.id.pager_dots);
pager.setAdapter(new PagerAdapter());
pager.setOffscreenPageLimit(3);
pager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback(){
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels){
for(int i=0;i<pagerDots.getChildCount();i++){
float alpha;
if(i==position){
alpha=0.3f+0.7f*(1f-positionOffset);
}else if(i==position+1){
alpha=0.3f+0.7f*positionOffset;
}else{
alpha=0.3f;
}
pagerDots.getChildAt(i).setAlpha(alpha);
}
float parallaxProgress=(position+positionOffset)/2f;
artClouds.setTranslationX(V.dp(-27)*(position>=1 ? 1f : positionOffset));
artPlaneElephant.setTranslationX(V.dp(101.55f)*parallaxProgress);
artLeftHill.setTranslationX(V.dp(-88)*parallaxProgress);
artLeftHill.setTranslationY(V.dp(24)*parallaxProgress);
artRightHill.setTranslationX(V.dp(-88)*parallaxProgress);
artRightHill.setTranslationY(V.dp(-24)*parallaxProgress);
artCenterHill.setTranslationX(V.dp(-40)*parallaxProgress);
}
});
artContainer=contentView.findViewById(R.id.art_container);
blueFill=contentView.findViewById(R.id.blue_fill);
greenFill=contentView.findViewById(R.id.green_fill);
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artClouds, V.dp(-5), V.dp(5), V.dp(-5), V.dp(5)));
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artRightHill, V.dp(-15), V.dp(25), V.dp(-10), V.dp(10)));
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artLeftHill, V.dp(-25), V.dp(15), V.dp(-15), V.dp(15)));
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artCenterHill, V.dp(-14), V.dp(14), V.dp(-5), V.dp(25)));
motionEffect.addViewEffect(new InterpolatingMotionEffect.ViewEffect(artPlaneElephant, V.dp(-20), V.dp(12), V.dp(-20), V.dp(12)));
artContainer.setOnTouchListener(motionEffect);
contentView.setSizeListener(new SizeListenerFrameLayout.OnSizeChangedListener(){
@Override
@@ -109,6 +95,38 @@ public class SplashFragment extends AppKitFragment{
Nav.go(getActivity(), isSignup ? InstanceCatalogSignupFragment.class : InstanceChooserLoginFragment.class, extras);
}
private void onJoinDefaultServerClick(View v){
new GetInstance()
.setCallback(new Callback<>(){
@Override
public void onSuccess(Instance result){
if(getActivity()==null)
return;
Bundle args=new Bundle();
args.putParcelable("instance", Parcels.wrap(result));
Nav.go(getActivity(), InstanceRulesFragment.class, args);
}
@Override
public void onError(ErrorResponse error){
if(getActivity()==null)
return;
error.showToast(getActivity());
}
})
.wrapProgress(getActivity(), R.string.loading_instance, true)
.execNoAuth(DEFAULT_SERVER);
}
private void onLearnMoreClick(View v){
View sheetView=getActivity().getLayoutInflater().inflate(R.layout.intro_bottom_sheet, null);
BottomSheet sheet=new BottomSheet(getActivity());
sheet.setContentView(sheetView);
sheet.setNavigationBarBackground(new ColorDrawable(UiUtils.alphaBlendColors(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Surface),
UiUtils.getThemeColor(getActivity(), R.attr.colorM3Primary), 0.05f)), !UiUtils.isDarkTheme());
sheet.show();
}
private void updateArtSize(int w, int h){
float scale=w/(float)V.dp(360);
artContainer.setScaleX(scale);
@@ -139,60 +157,15 @@ public class SplashFragment extends AppKitFragment{
return true;
}
private class PagerAdapter extends RecyclerView.Adapter<PagerViewHolder>{
@NonNull
@Override
public PagerViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
return new PagerViewHolder(viewType);
}
@Override
public void onBindViewHolder(@NonNull PagerViewHolder holder, int position){}
@Override
public int getItemCount(){
return 3;
}
@Override
public int getItemViewType(int position){
return position;
}
@Override
protected void onShown(){
super.onShown();
motionEffect.activate();
}
private class PagerViewHolder extends RecyclerView.ViewHolder{
public PagerViewHolder(int page){
super(new LinearLayout(getActivity()));
LinearLayout ll=(LinearLayout) itemView;
ll.setOrientation(LinearLayout.VERTICAL);
int pad=V.dp(16);
ll.setPadding(pad, pad, pad, pad);
ll.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
TextView title=new TextView(getActivity());
title.setTextAppearance(R.style.m3_headline_medium);
title.setText(switch(page){
case 0 -> getString(R.string.welcome_page1_title);
case 1 -> getString(R.string.welcome_page2_title);
case 2 -> getString(R.string.welcome_page3_title);
default -> throw new IllegalStateException("Unexpected value: "+page);
});
title.setTextColor(0xFF17063B);
LinearLayout.LayoutParams lp=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, V.dp(page==0 ? 46 : 36));
lp.bottomMargin=V.dp(page==0 ? 4 : 14);
ll.addView(title, lp);
TextView text=new TextView(getActivity());
text.setTextAppearance(R.style.m3_body_medium);
text.setText(switch(page){
case 0 -> R.string.welcome_page1_text;
case 1 -> R.string.welcome_page2_text;
case 2 -> R.string.welcome_page3_text;
default -> throw new IllegalStateException("Unexpected value: "+page);
});
text.setTextColor(0xFF17063B);
ll.addView(text, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
}
@Override
protected void onHidden(){
super.onHidden();
motionEffect.deactivate();
}
}

View File

@@ -6,6 +6,7 @@ import android.view.View;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetStatusEditHistory;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.ReblogOrReplyLineStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
@@ -55,7 +56,7 @@ public class StatusEditHistoryFragment extends StatusListFragment{
@Override
protected List<StatusDisplayItem> buildDisplayItems(Status s){
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null);
List<StatusDisplayItem> items=StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, true, false, null, null);
int idx=data.indexOf(s);
if(idx>=0){
String date=UiUtils.DATE_TIME_FORMATTER.format(s.createdAt.atZone(ZoneId.systemDefault()));
@@ -156,4 +157,9 @@ public class StatusEditHistoryFragment extends StatusListFragment{
public boolean isItemEnabled(String id){
return false;
}
@Override
protected Filter.FilterContext getFilterContext() {
return null;
}
}

View File

@@ -34,9 +34,11 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
protected List<StatusDisplayItem> buildDisplayItems(Status s){
boolean addFooter = !GlobalUserPreferences.spectatorMode ||
(this instanceof ThreadFragment t && s.id.equals(t.mainStatus.id));
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, false, addFooter, null, Filter.FilterContext.HOME);
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, false, addFooter, null, getFilterContext());
}
protected abstract Filter.FilterContext getFilterContext();
@Override
protected void addAccountToKnown(Status s){
if(!knownAccounts.containsKey(s.account.id))

View File

@@ -137,7 +137,7 @@ public class ThreadFragment extends StatusListFragment{
}
private List<Status> filterStatuses(List<Status> statuses){
StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,Filter.FilterContext.THREAD);
StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,getFilterContext());
return statuses.stream()
.filter(statusFilterPredicate)
.collect(Collectors.toList());
@@ -181,4 +181,10 @@ public class ThreadFragment extends StatusListFragment{
public boolean wantsLightNavigationBar(){
return !UiUtils.isDarkTheme();
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.THREAD;
}
}

View File

@@ -26,7 +26,7 @@ public class DiscoverPostsFragment extends StatusListFragment implements IsOnTop
@Override
public void onSuccess(List<Status> result){
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
}
}).exec(accountID);
@@ -42,4 +42,10 @@ public class DiscoverPostsFragment extends StatusListFragment implements IsOnTop
public boolean isOnTop() {
return isRecyclerViewOnTop(list);
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.PUBLIC;
}
}

View File

@@ -21,7 +21,7 @@ public class FederatedTimelineFragment extends StatusListFragment {
private String maxID;
@Override
protected boolean withComposeButton() {
protected boolean wantsComposeButton() {
return true;
}
@@ -35,7 +35,7 @@ public class FederatedTimelineFragment extends StatusListFragment {
if(!result.isEmpty())
maxID=result.get(result.size()-1).id;
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
}
})
@@ -47,4 +47,9 @@ public class FederatedTimelineFragment extends StatusListFragment {
super.onViewCreated(view, savedInstanceState);
bannerHelper.maybeAddBanner(contentWrap);
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.PUBLIC;
}
}

View File

@@ -20,7 +20,7 @@ public class LocalTimelineFragment extends StatusListFragment {
private String maxID;
@Override
protected boolean withComposeButton() {
protected boolean wantsComposeButton() {
return true;
}
@@ -34,7 +34,7 @@ public class LocalTimelineFragment extends StatusListFragment {
if(!result.isEmpty())
maxID=result.get(result.size()-1).id;
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, Filter.FilterContext.PUBLIC)).collect(Collectors.toList());
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
}
})
@@ -46,4 +46,9 @@ public class LocalTimelineFragment extends StatusListFragment {
super.onViewCreated(view, savedInstanceState);
bannerHelper.maybeAddBanner(contentWrap);
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.PUBLIC;
}
}

View File

@@ -15,6 +15,7 @@ import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.SearchResult;
import org.joinmastodon.android.model.SearchResults;
@@ -80,7 +81,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult> impleme
return switch(s.type){
case ACCOUNT -> Collections.singletonList(new AccountStatusDisplayItem(s.id, this, s.account));
case HASHTAG -> Collections.singletonList(new HashtagStatusDisplayItem(s.id, this, s.hashtag));
case STATUS -> StatusDisplayItem.buildItems(this, s.status, accountID, s, knownAccounts, false, true, null);
case STATUS -> StatusDisplayItem.buildItems(this, s.status, accountID, s, knownAccounts, false, true, null, Filter.FilterContext.PUBLIC);
};
}

View File

@@ -21,6 +21,7 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.events.FinishReportFragmentsEvent;
import org.joinmastodon.android.fragments.StatusListFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.AudioStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
@@ -261,4 +262,9 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
protected boolean wantsOverlaySystemNavigation(){
return false;
}
@Override
protected Filter.FilterContext getFilterContext() {
return null;
}
}

View File

@@ -0,0 +1,40 @@
package org.joinmastodon.android.model;
import android.view.Menu;
import androidx.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
import org.joinmastodon.android.R;
public enum ContentType {
@SerializedName("text/plain")
PLAIN,
@SerializedName("text/html")
HTML,
@SerializedName("text/markdown")
MARKDOWN,
@SerializedName("text/bbcode")
BBCODE, // akkoma
@SerializedName("text/x.misskeymarkdown")
MISSKEY_MARKDOWN; // akkoma/*key
public static int getContentTypeRes(@Nullable ContentType contentType) {
return contentType == null ? R.id.content_type_null : switch(contentType) {
case PLAIN -> R.id.content_type_plain;
case HTML -> R.id.content_type_html;
case MARKDOWN -> R.id.content_type_markdown;
case BBCODE -> R.id.content_type_bbcode;
case MISSKEY_MARKDOWN -> R.id.content_type_misskey_markdown;
};
}
public static void adaptMenuToInstance(Menu m, Instance i) {
if (i.pleroma == null) {
// memo: change this if glitch or another mastodon fork supports bbcode or mfm
m.findItem(R.id.content_type_bbcode).setVisible(false);
m.findItem(R.id.content_type_misskey_markdown).setVisible(false);
}
}
}

View File

@@ -2,22 +2,22 @@ package org.joinmastodon.android.model;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;
import java.time.Instant;
import java.util.EnumSet;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@Parcel
public class Filter extends BaseModel{
@RequiredField
public String id;
@RequiredField
public String phrase;
public String title;
public transient EnumSet<FilterContext> context=EnumSet.noneOf(FilterContext.class);

View File

@@ -1,8 +1,15 @@
package org.joinmastodon.android.model;
import org.joinmastodon.android.api.ObjectValidationException;
import org.parceler.Parcel;
@Parcel
public class FilterResult extends BaseModel {
public Filter filter;
@Override
public void postprocess() throws ObjectValidationException {
super.postprocess();
if (filter != null) filter.postprocess();
}
}

View File

@@ -20,6 +20,8 @@ public class Notification extends BaseModel implements DisplayItemsParent{
public Account account;
public Status status;
public Report report;
public String emoji;
public String emojiUrl;
@Override
public void postprocess() throws ObjectValidationException{
@@ -51,6 +53,10 @@ public class Notification extends BaseModel implements DisplayItemsParent{
STATUS,
@SerializedName("update")
UPDATE,
@SerializedName("reaction")
REACTION,
@SerializedName("pleroma:emoji_reaction")
PLEROMA_EMOJI_REACTION,
@SerializedName("admin.sign_up")
SIGN_UP,
@SerializedName("admin.report")

View File

@@ -39,6 +39,7 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
public String idempotency;
public String applicationId;
public List<String> mediaIds;
public ContentType contentType;
}
@Parcel

View File

@@ -101,6 +101,9 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
card.postprocess();
if(reblog!=null)
reblog.postprocess();
if(filtered!=null)
for(FilterResult fr : filtered)
fr.postprocess();
spoilerRevealed=GlobalUserPreferences.alwaysExpandContentWarnings || !sensitive;
if (visibility.equals(StatusPrivacy.LOCAL)) localOnly = true;

View File

@@ -1,17 +1,25 @@
package org.joinmastodon.android.ui;
import android.annotation.SuppressLint;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.PathInterpolator;
import java.util.ArrayList;
public class InterpolatingMotionEffect implements SensorEventListener{
import androidx.dynamicanimation.animation.DynamicAnimation;
import androidx.dynamicanimation.animation.FloatValueHolder;
import androidx.dynamicanimation.animation.SpringAnimation;
import androidx.dynamicanimation.animation.SpringForce;
public class InterpolatingMotionEffect implements SensorEventListener, View.OnTouchListener{
private SensorManager sm;
private WindowManager wm;
@@ -20,6 +28,34 @@ public class InterpolatingMotionEffect implements SensorEventListener{
private Sensor accelerometer;
private boolean accelerometerEnabled;
private ArrayList<ViewEffect> views=new ArrayList<>();
private float pitch, roll;
private float touchDownX, touchDownY, touchAddX, touchAddY, touchAddLastAnimX, touchAddLastAnimY;
private PathInterpolator touchInterpolator=new PathInterpolator(0.5f, 1f, 0.89f, 1f);
private SpringAnimation touchSpringX, touchSpringY;
private FloatValueHolder touchSpringXHolder=new FloatValueHolder(){
@Override
public float getValue(){
return touchAddX;
}
@Override
public void setValue(float value){
touchAddX=value;
updateEffects();
}
};
private FloatValueHolder touchSpringYHolder=new FloatValueHolder(){
@Override
public float getValue(){
return touchAddY;
}
@Override
public void setValue(float value){
touchAddY=value;
updateEffects();
}
};
public InterpolatingMotionEffect(Context context){
sm=context.getSystemService(SensorManager.class);
@@ -50,8 +86,8 @@ public class InterpolatingMotionEffect implements SensorEventListener{
float z=event.values[2]/SensorManager.GRAVITY_EARTH;
float pitch=(float) (Math.atan2(x, Math.sqrt(y*y+z*z))/Math.PI*2.0);
float roll=(float) (Math.atan2(y, Math.sqrt(x*x+z*z))/Math.PI*2.0);
pitch=(float) (Math.atan2(x, Math.sqrt(y*y+z*z))/Math.PI*2.0);
roll=(float) (Math.atan2(y, Math.sqrt(x*x+z*z))/Math.PI*2.0);
switch(rotation){
case Surface.ROTATION_0:
@@ -88,9 +124,7 @@ public class InterpolatingMotionEffect implements SensorEventListener{
}else if(roll<-1f){
roll=-2f-roll;
}
for(ViewEffect view:views){
view.update(pitch, roll);
}
updateEffects();
}
@Override
@@ -110,6 +144,62 @@ public class InterpolatingMotionEffect implements SensorEventListener{
views.clear();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent ev){
switch(ev.getAction()){
case MotionEvent.ACTION_DOWN -> {
if(touchSpringX!=null){
touchAddLastAnimX=touchAddX;
touchSpringX.cancel();
touchSpringX=null;
}else{
touchAddLastAnimX=0;
}
if(touchSpringY!=null){
touchAddLastAnimY=touchAddY;
touchSpringY.cancel();
touchSpringY=null;
}else{
touchAddLastAnimY=0;
}
touchDownX=ev.getX();
touchDownY=ev.getY();
}
case MotionEvent.ACTION_MOVE -> {
touchAddX=touchInterpolator.getInterpolation(Math.min(1f, Math.abs((ev.getX()-touchDownX)/(v.getWidth()/2f))));
touchAddY=touchInterpolator.getInterpolation(Math.min(1f, Math.abs((ev.getY()-touchDownY)/(v.getHeight()/2f))));
if(ev.getX()>touchDownX)
touchAddX=-touchAddX;
if(ev.getY()<touchDownY)
touchAddY=-touchAddY;
touchAddX+=touchAddLastAnimX;
touchAddY+=touchAddLastAnimY;
updateEffects();
}
case MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {
touchSpringX=new SpringAnimation(touchSpringXHolder, 0f);
touchSpringX.setMinimumVisibleChange(0.01f);
touchSpringX.getSpring().setStiffness(SpringForce.STIFFNESS_LOW).setDampingRatio(0.85f);
touchSpringX.addEndListener((animation, canceled, value, velocity)->touchSpringX=null);
touchSpringX.start();
touchSpringY=new SpringAnimation(touchSpringYHolder, 0f);
touchSpringY.setMinimumVisibleChange(0.01f);
touchSpringY.getSpring().setStiffness(SpringForce.STIFFNESS_LOW).setDampingRatio(0.85f);
touchSpringY.addEndListener((animation, canceled, value, velocity)->touchSpringY=null);
touchSpringY.start();
updateEffects();
}
}
return true;
}
private void updateEffects(){
for(ViewEffect view:views){
view.update(Math.min(1f, Math.max(-1f, pitch+touchAddX)), Math.min(1f, Math.max(-1f, roll+touchAddY)));
}
}
public static class ViewEffect{
private View view;
private float minX, maxX, minY, maxY;

View File

@@ -200,6 +200,11 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private void onBoostClick(View v){
if (GlobalUserPreferences.confirmBeforeReblog) {
v.startAnimation(opacityIn);
onBoostLongClick(v);
return;
}
boost.setSelected(!item.status.reblogged);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, null, r->boostConsumer(v, r));
}
@@ -235,9 +240,9 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
reblogHeader.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
reblogAs.setVisibility(AccountSessionManager.getInstance().getLoggedInAccounts().size() > 1 ? View.VISIBLE : View.GONE);
itemPublic.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.PUBLIC) ? View.GONE : View.VISIBLE);
itemUnlisted.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) ? View.GONE : View.VISIBLE);
itemFollowers.setVisibility(item.status.reblogged || item.status.visibility.isLessVisibleThan(StatusPrivacy.PRIVATE) ? View.GONE : View.VISIBLE);
itemPublic.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
itemUnlisted.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
itemFollowers.setVisibility(item.status.reblogged ? View.GONE : View.VISIBLE);
Drawable checkMark = ctx.getDrawable(R.drawable.ic_fluent_checkmark_circle_20_regular);
Drawable publicDrawable = ctx.getDrawable(R.drawable.ic_fluent_earth_24_regular);
@@ -245,16 +250,6 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
Drawable followersDrawable = ctx.getDrawable(R.drawable.ic_fluent_lock_closed_24_regular);
StatusPrivacy defaultVisibility = session.preferences != null ? session.preferences.postingDefaultVisibility : null;
// e.g. post visibility is unlisted, but default is public
// in this case, we want to display the check mark on the most visible visibility
if (defaultVisibility != null && item.status.visibility.isLessVisibleThan(defaultVisibility)) {
for (StatusPrivacy vis : StatusPrivacy.values()) {
if (vis.equals(item.status.visibility)) {
defaultVisibility = vis;
break;
}
}
}
itemPublic.setCompoundDrawablesWithIntrinsicBounds(publicDrawable, null, StatusPrivacy.PUBLIC.equals(defaultVisibility) ? checkMark : null, null);
itemUnlisted.setCompoundDrawablesWithIntrinsicBounds(unlistedDrawable, null, StatusPrivacy.UNLISTED.equals(defaultVisibility) ? checkMark : null, null);
itemFollowers.setCompoundDrawablesWithIntrinsicBounds(followersDrawable, null, StatusPrivacy.PRIVATE.equals(defaultVisibility) ? checkMark : null, null);

View File

@@ -44,6 +44,7 @@ import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Announcement;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.ScheduledStatus;
@@ -83,13 +84,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
public final Status status;
private boolean hasVisibilityToggle;
boolean needBottomPadding;
private String extraText;
private CharSequence extraText;
private Notification notification;
private ScheduledStatus scheduledStatus;
private Announcement announcement;
private Consumer<String> consumeReadAnnouncement;
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID, Status status, String extraText, Notification notification, ScheduledStatus scheduledStatus){
public HeaderStatusDisplayItem(String parentID, Account user, Instant createdAt, BaseStatusListFragment parentFragment, String accountID, Status status, CharSequence extraText, Notification notification, ScheduledStatus scheduledStatus){
super(parentID, parentFragment);
user=scheduledStatus != null ? AccountSessionManager.getInstance().getAccount(accountID).self : user;
this.user=user;
@@ -114,6 +115,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
}
}
this.extraText=extraText;
emojiHelper.addText(extraText);
}
public static HeaderStatusDisplayItem fromAnnouncement(Announcement a, Status fakeStatus, Account instanceUser, BaseStatusListFragment parentFragment, String accountID, Consumer<String> consumeReadID) {
@@ -216,6 +218,9 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
public void onSuccess(GetStatusSourceText.Response result){
args.putString("sourceText", result.text);
args.putString("sourceSpoiler", result.spoilerText);
if (result.contentType != null) {
args.putString("sourceContentType", result.contentType.name());
}
if (redraft) {
UiUtils.confirmDeletePost(item.parentFragment.getActivity(), item.parentFragment.getAccountID(), item.status, s->{
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);

View File

@@ -1,6 +1,6 @@
package org.joinmastodon.android.ui.displayitems;
import static org.joinmastodon.android.ui.utils.MediaAttachmentViewController.altWrapPadding;
import static org.joinmastodon.android.GlobalUserPreferences.*;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -55,7 +55,7 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
for(Attachment att:attachments){
requests.add(new UrlImageLoaderRequest(switch(att.type){
case IMAGE -> att.url;
case VIDEO, GIFV -> att.previewUrl;
case VIDEO, GIFV -> att.previewUrl != null ? att.previewUrl : att.url;
default -> throw new IllegalStateException("Unexpected value: "+att.type);
}, 1000, 1000));
}
@@ -183,10 +183,11 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
altTextIndex=index;
Attachment att=item.attachments.get(index);
boolean hasAltText = !TextUtils.isEmpty(att.description);
altTextButton.setVisibility(hasAltText && GlobalUserPreferences.showAltIndicator ? View.VISIBLE : View.GONE);
noAltTextButton.setVisibility(!hasAltText && GlobalUserPreferences.showNoAltIndicator ? View.VISIBLE : View.GONE);
altText.setVisibility(hasAltText && GlobalUserPreferences.showAltIndicator ? View.VISIBLE : View.GONE);
noAltText.setVisibility(!hasAltText && GlobalUserPreferences.showNoAltIndicator ? View.VISIBLE : View.GONE);
if ((hasAltText && !showAltIndicator) || (!hasAltText && !showNoAltIndicator)) return;
altTextButton.setVisibility(hasAltText && showAltIndicator ? View.VISIBLE : View.GONE);
noAltTextButton.setVisibility(!hasAltText && showNoAltIndicator ? View.VISIBLE : View.GONE);
altText.setVisibility(hasAltText && showAltIndicator ? View.VISIBLE : View.GONE);
noAltText.setVisibility(!hasAltText && showNoAltIndicator ? View.VISIBLE : View.GONE);
altText.setText(att.description);
altTextWrapper.setVisibility(View.VISIBLE);
altTextWrapper.setBackgroundResource(hasAltText ? R.drawable.bg_image_alt_overlay : R.drawable.bg_image_no_alt_overlay);
@@ -202,15 +203,16 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
btnL-=loc[0];
btnT-=loc[1];
ViewGroup.MarginLayoutParams margins = (ViewGroup.MarginLayoutParams) altTextWrapper.getLayoutParams();
ArrayList<Animator> anims=new ArrayList<>();
anims.add(ObjectAnimator.ofFloat(altTextButton, View.ALPHA, 1, 0));
anims.add(ObjectAnimator.ofFloat(noAltTextButton, View.ALPHA, 1, 0));
anims.add(ObjectAnimator.ofFloat(altTextScroller, View.ALPHA, 0, 1));
anims.add(ObjectAnimator.ofFloat(altTextClose, View.ALPHA, 0, 1));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "left", btnL+altWrapPadding[0], altTextWrapper.getLeft()));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "top", btnT+altWrapPadding[1], altTextWrapper.getTop()));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "right", btnL+v.getWidth()-altWrapPadding[2], altTextWrapper.getRight()));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "bottom", btnT+v.getHeight()-altWrapPadding[3], altTextWrapper.getBottom()));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "left", btnL+margins.leftMargin, altTextWrapper.getLeft()));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "top", btnT+margins.topMargin, altTextWrapper.getTop()));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "right", btnL+v.getWidth()-margins.rightMargin, altTextWrapper.getRight()));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "bottom", btnT+v.getHeight()-margins.bottomMargin, altTextWrapper.getBottom()));
for(Animator a:anims)
a.setDuration(300);
@@ -249,8 +251,11 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
View btn=controllers.get(altTextIndex).btnsWrap;
int i=0;
for(MediaAttachmentViewController c:controllers){
if(c.btnsWrap!=null && c.btnsWrap!=btn && !TextUtils.isEmpty(item.attachments.get(i).description))
c.btnsWrap.setVisibility(View.VISIBLE);
boolean hasAltText = !TextUtils.isEmpty(item.attachments.get(i).description);
if(c.btnsWrap!=null
&& c.btnsWrap!=btn
&& ((hasAltText && showAltIndicator) || (!hasAltText && showNoAltIndicator))
) c.btnsWrap.setVisibility(View.VISIBLE);
i++;
}
@@ -261,15 +266,16 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
btnL-=loc[0];
btnT-=loc[1];
ViewGroup.MarginLayoutParams margins = (ViewGroup.MarginLayoutParams) altTextWrapper.getLayoutParams();
ArrayList<Animator> anims=new ArrayList<>();
anims.add(ObjectAnimator.ofFloat(altTextButton, View.ALPHA, 1));
anims.add(ObjectAnimator.ofFloat(noAltTextButton, View.ALPHA, 1));
anims.add(ObjectAnimator.ofFloat(altTextScroller, View.ALPHA, 0));
anims.add(ObjectAnimator.ofFloat(altTextClose, View.ALPHA, 0));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "left", btnL+altWrapPadding[0]));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "top", btnT+altWrapPadding[1]));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "right", btnL+btn.getWidth()-altWrapPadding[2]));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "bottom", btnT+btn.getHeight()-altWrapPadding[3]));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "left", btnL+margins.leftMargin));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "top", btnT+margins.topMargin));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "right", btnL+btn.getWidth()-margins.rightMargin));
anims.add(ObjectAnimator.ofInt(altTextWrapper, "bottom", btnT+btn.getHeight()-margins.bottomMargin));
for(Animator a:anims)
a.setDuration(300);

View File

@@ -81,18 +81,10 @@ public abstract class StatusDisplayItem{
};
}
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification){
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, false, Filter.FilterContext.HOME);
}
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, Filter.FilterContext filterContext){
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, false, filterContext);
}
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate){
return buildItems(fragment, status, accountID, parentObject, knownAccounts, inset, addFooter, notification, disableTranslate, Filter.FilterContext.HOME);
}
public static ArrayList<StatusDisplayItem> buildItems(BaseStatusListFragment<?> fragment, Status status, String accountID, DisplayItemsParent parentObject, Map<String, Account> knownAccounts, boolean inset, boolean addFooter, Notification notification, boolean disableTranslate, Filter.FilterContext filterContext){
String parentID=parentObject.getID();
ArrayList<StatusDisplayItem> items=new ArrayList<>();
@@ -102,12 +94,8 @@ public abstract class StatusDisplayItem{
args.putString("account", accountID);
ScheduledStatus scheduledStatus = parentObject instanceof ScheduledStatus ? (ScheduledStatus) parentObject : null;
List<Filter> filters = AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream()
.filter(f -> f.context.contains(filterContext)).collect(Collectors.toList());
StatusFilterPredicate filterPredicate = new StatusFilterPredicate(filters);
if(!statusForContent.filterRevealed){
statusForContent.filterRevealed = filterPredicate.testWithWarning(status);
if (!statusForContent.filterRevealed) {
statusForContent.filterRevealed = new StatusFilterPredicate(accountID, filterContext, Filter.FilterAction.WARN).test(status);
}
ReblogOrReplyLineStatusDisplayItem replyLine = null;
@@ -201,8 +189,6 @@ public abstract class StatusDisplayItem{
}
if(addFooter){
items.add(new FooterStatusDisplayItem(parentID, fragment, statusForContent, accountID));
if(status.hasGapAfter && !(fragment instanceof ThreadFragment))
items.add(new GapStatusDisplayItem(parentID, fragment));
}
int i=1;
for(StatusDisplayItem item:items){
@@ -210,13 +196,16 @@ public abstract class StatusDisplayItem{
item.index=i++;
}
if (!statusForContent.filterRevealed) {
return new ArrayList<>(List.of(
new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items)
));
ArrayList<StatusDisplayItem> result = statusForContent.filterRevealed ? items :
new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items)));
if (addFooter && status.hasGapAfter && !(fragment instanceof ThreadFragment)) {
StatusDisplayItem gap = new GapStatusDisplayItem(parentID, fragment);
gap.index = i++;
result.add(gap);
}
return items;
return result;
}
public static void buildPollItems(String parentID, BaseStatusListFragment fragment, Poll poll, List<StatusDisplayItem> items){

View File

@@ -29,6 +29,16 @@ public class CustomEmojiHelper{
}
}
public void addText(CharSequence text) {
if(!(text instanceof Spanned))
return;
CustomEmojiSpan[] spans=((Spanned) text).getSpans(0, text.length(), CustomEmojiSpan.class);
for(List<CustomEmojiSpan> group:Arrays.stream(spans).collect(Collectors.groupingBy(s->s.emoji)).values()){
this.spans.add(group);
requests.add(group.get(0).createImageLoaderRequest());
}
}
public int getImageCount(){
return requests.size();
}

View File

@@ -19,7 +19,6 @@ public class MediaAttachmentViewController{
public final MediaGridStatusDisplayItem.GridItemType type;
public final ImageView photo;
public final View altButton, noAltButton, btnsWrap;
public static int[] altWrapPadding = null;
private BlurhashCrossfadeDrawable crossfadeDrawable=new BlurhashCrossfadeDrawable();
private final Context context;
private boolean didClear;
@@ -37,9 +36,6 @@ public class MediaAttachmentViewController{
btnsWrap=view.findViewById(R.id.alt_badges);
this.type=type;
this.context=context;
if (altWrapPadding == null) {
altWrapPadding = new int[] { btnsWrap.getPaddingLeft(), btnsWrap.getPaddingTop(), btnsWrap.getPaddingRight(), btnsWrap.getPaddingBottom() };
}
}
public void bind(Attachment attachment, Status status){

View File

@@ -137,10 +137,15 @@ public class UiUtils {
private static Handler mainHandler = new Handler(Looper.getMainLooper());
private static final DateTimeFormatter DATE_FORMATTER_SHORT_WITH_YEAR = DateTimeFormatter.ofPattern("d MMM uuuu"), DATE_FORMATTER_SHORT = DateTimeFormatter.ofPattern("d MMM");
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG, FormatStyle.SHORT);
public static int MAX_WIDTH;
private UiUtils() {
}
public static void loadMaxWidth(Context ctx) {
if (MAX_WIDTH == 0) MAX_WIDTH = (int) ctx.getResources().getDimension(R.dimen.layout_max_width);
}
public static void launchWebBrowser(Context context, String url) {
try {
if (GlobalUserPreferences.useCustomTabs) {

View File

@@ -3,13 +3,13 @@ package org.joinmastodon.android.ui.views;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import org.joinmastodon.android.ui.utils.UiUtils;
import me.grishka.appkit.utils.V;
public class ComposeMediaLayout extends ViewGroup{
private static final int MAX_WIDTH_DP=400;
private static final int GAP_DP=8;
private static final float ASPECT_RATIO=0.5625f;
@@ -23,6 +23,7 @@ public class ComposeMediaLayout extends ViewGroup{
public ComposeMediaLayout(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
UiUtils.loadMaxWidth(context);
}
@Override
@@ -30,7 +31,7 @@ public class ComposeMediaLayout extends ViewGroup{
int mode=MeasureSpec.getMode(widthMeasureSpec);
@SuppressLint("SwitchIntDef")
int width=switch(mode){
case MeasureSpec.AT_MOST -> Math.min(V.dp(MAX_WIDTH_DP), MeasureSpec.getSize(widthMeasureSpec));
case MeasureSpec.AT_MOST -> Math.min(UiUtils.MAX_WIDTH, MeasureSpec.getSize(widthMeasureSpec));
case MeasureSpec.EXACTLY -> MeasureSpec.getSize(widthMeasureSpec);
default -> throw new IllegalArgumentException("unsupported measure mode");
};

View File

@@ -6,6 +6,8 @@ import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import me.grishka.appkit.utils.V;
/**
* A LinearLayout for TextViews. First child TextView will get truncated if it doesn't fit, remaining will always wrap content.
*/
@@ -36,7 +38,8 @@ public class HeaderSubtitleLinearLayout extends LinearLayout{
}
View first=getChildAt(0);
if(first instanceof TextView){
((TextView) first).setMaxWidth(remainingWidth);
// guaranteeing at least 64dp of width for the display name
((TextView) first).setMaxWidth(Math.max(remainingWidth, V.dp(64)));
}
}else{
View first=getChildAt(0);

View File

@@ -6,13 +6,13 @@ import android.view.View;
import android.view.ViewGroup;
import org.joinmastodon.android.ui.PhotoLayoutHelper;
import org.joinmastodon.android.ui.utils.UiUtils;
import me.grishka.appkit.utils.V;
public class MediaGridLayout extends ViewGroup{
private static final String TAG="MediaGridLayout";
public static final int MAX_WIDTH=400; // dp
private static final int GAP=1; // dp
private PhotoLayoutHelper.TiledLayoutResult tiledLayout;
private int[] columnStarts=new int[10], columnEnds=new int[10], rowStarts=new int[10], rowEnds=new int[10];
@@ -27,7 +27,7 @@ public class MediaGridLayout extends ViewGroup{
public MediaGridLayout(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
UiUtils.loadMaxWidth(context);
}
@Override
@@ -36,7 +36,7 @@ public class MediaGridLayout extends ViewGroup{
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), 0);
return;
}
int width=Math.min(V.dp(MAX_WIDTH), MeasureSpec.getSize(widthMeasureSpec));
int width=Math.min(UiUtils.MAX_WIDTH, MeasureSpec.getSize(widthMeasureSpec));
int height=Math.round(width*(tiledLayout.height/(float)PhotoLayoutHelper.MAX_WIDTH));
int offset=0;
@@ -74,10 +74,9 @@ public class MediaGridLayout extends ViewGroup{
if(tiledLayout==null)
return;
int maxWidth=V.dp(MAX_WIDTH);
int xOffset=0;
if(r-l>maxWidth){
xOffset=(r-l)/2-maxWidth/2;
if(r-l>UiUtils.MAX_WIDTH){
xOffset=(r-l)/2-UiUtils.MAX_WIDTH/2;
}
for(int i=0;i<getChildCount();i++){

File diff suppressed because one or more lines are too long

View File

@@ -8,52 +8,53 @@ import java.time.Instant;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class StatusFilterPredicate implements Predicate<Status>{
private final List<Filter> filters;
private final Filter.FilterContext context;
private final Filter.FilterAction action;
public StatusFilterPredicate(List<Filter> filters){
public StatusFilterPredicate(List<Filter> filters, Filter.FilterContext context){
this.filters=filters;
this.context = context;
this.action = Filter.FilterAction.HIDE;
}
/**
* @param context null makes the predicate pass automatically
*/
public StatusFilterPredicate(String accountID, Filter.FilterContext context){
this(accountID, context, Filter.FilterAction.HIDE);
}
/**
* @param context null makes the predicate pass automatically
* @param action defines what the predicate should check:
* should not be hidden or should not display with warning
*/
public StatusFilterPredicate(String accountID, Filter.FilterContext context, Filter.FilterAction action){
filters=AccountSessionManager.getInstance().getAccount(accountID).wordFilters.stream().filter(f->f.context.contains(context)).collect(Collectors.toList());
this.context = context;
this.action = action;
}
@Override
public boolean test(Status status){
if(status.filtered!=null){
if (status.filtered.isEmpty()){
return true;
}
boolean matches=status.filtered.stream()
.map(filterResult->filterResult.filter)
.filter(filter->filter.expiresAt==null||filter.expiresAt.isAfter(Instant.now()))
.anyMatch(filter->filter.filterAction==Filter.FilterAction.HIDE);
return !matches;
}
for(Filter filter:filters){
if(filter.matches(status))
return false;
}
return true;
}
if (context == null) return true;
public boolean testWithWarning(Status status) {
if(status.filtered!=null){
if (status.filtered.isEmpty()){
return true;
}
boolean matches=status.filtered.stream()
.map(filterResult->filterResult.filter)
.filter(filter->filter.expiresAt==null||filter.expiresAt.isAfter(Instant.now()))
.anyMatch(filter->filter.filterAction==Filter.FilterAction.WARN);
return !matches;
}
for(Filter filter:filters){
if(filter.matches(status))
return false;
}
return true;
Stream<Filter> stream = status.filtered != null
// use server-provided per-status info (status.filtered) if available
? status.filtered.stream().map(f -> f.filter)
// or fall back to cached filters
: filters.stream().filter(filter -> filter.matches(status));
return stream
// discard expired filters
.filter(filter -> filter.expiresAt == null || filter.expiresAt.isAfter(Instant.now()))
// only apply filters for given context
.filter(filter -> filter.context.contains(context))
// treating filterAction = null (from filters list) as FilterAction.HIDE
.noneMatch(filter -> filter.filterAction == null ? action == Filter.FilterAction.HIDE : filter.filterAction == action);
}
}

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorM3OnSurface" android:alpha="0.12"/>
</selector>

View File

@@ -2,8 +2,14 @@
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="?colorWindowBackground"/>
<corners android:topLeftRadius="12dp" android:topRightRadius="12dp"/>
<solid android:color="?colorM3Surface"/>
<corners android:topLeftRadius="28dp" android:topRightRadius="28dp"/>
</shape>
</item>
<item>
<shape android:tint="?colorM3Primary">
<solid android:color="#0D000000"/>
<corners android:topLeftRadius="28dp" android:topRightRadius="28dp"/>
</shape>
</item>
</layer-list>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="center" android:width="36dp" android:height="4dp">
<shape>
<solid android:color="?android:textColorSecondary"/>
<item android:gravity="center" android:width="32dp" android:height="4dp">
<shape android:tint="?colorM3Outline">
<solid android:color="#66000000"/>
<corners android:radius="2dp"/>
</shape>
</item>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple android:color="@color/m3_primary_overlay" xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<selector>
<item android:state_enabled="true">
<shape>
<stroke android:color="?colorM3Outline" android:width="1dp"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item>
<shape>
<stroke android:color="@color/m3_on_surface_overlay" android:width="1dp"/>
<corners android:radius="20dp"/>
</shape>
</item>
</selector>
</item>
<item android:id="@android:id/mask">
<shape>
<solid android:color="#000"/>
<corners android:radius="20dp"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple android:color="#1effffff" xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<selector>
<item android:state_enabled="true">
<shape>
<stroke android:color="?colorM3Outline" android:width="1dp"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item>
<shape>
<stroke android:color="@color/m3_on_surface_overlay" android:width="1dp"/>
<corners android:radius="20dp"/>
</shape>
</item>
</selector>
</item>
<item android:id="@android:id/mask">
<shape>
<solid android:color="#000"/>
<corners android:radius="20dp"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple android:color="#1effffff" xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@android:id/mask">
<shape>
<solid android:color="#000"/>
<corners android:radius="20dp"/>
</shape>
</item>
</ripple>

View File

@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M20.063 8.445c1.256 1.258 1.255 3.295-0.002 4.551l-7.114 7.102c-0.271 0.272-0.608 0.469-0.978 0.573l-4.613 1.303c-0.57 0.162-1.094-0.373-0.92-0.94l1.387-4.543c0.107-0.354 0.3-0.675 0.562-0.936l7.124-7.112c1.258-1.256 3.297-1.255 4.554 0.002zM8.15 2.37L8.2 2.475l3.253 8.249-1.157 1.155L9.556 10H5.443l-0.995 2.52c-0.14 0.354-0.518 0.542-0.876 0.454l-0.098-0.031c-0.353-0.14-0.54-0.518-0.452-0.876l0.03-0.098 3.754-9.495C7.042 1.88 7.85 1.844 8.151 2.37zM7.503 4.792L6.036 8.5h2.928L7.503 4.792z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M20.063 8.445c1.256 1.258 1.255 3.295-0.002 4.551l-7.123 7.112c-0.263 0.262-0.587 0.455-0.943 0.562l-4.293 1.29c-0.529 0.159-1.086-0.141-1.245-0.67-0.058-0.194-0.056-0.402 0.006-0.594l1.361-4.228c0.11-0.34 0.3-0.65 0.552-0.903l7.133-7.121c1.258-1.256 3.297-1.255 4.554 0.002zm-3.494 1.06l-7.133 7.12c-0.084 0.085-0.147 0.188-0.184 0.301l-1.07 3.323 3.382-1.015c0.119-0.036 0.227-0.1 0.314-0.188L19 11.936c0.672-0.671 0.672-1.76 0.002-2.43-0.672-0.672-1.76-0.673-2.433-0.002zM8.15 2.37L8.2 2.475l3.253 8.249-1.157 1.155L9.556 10H5.443l-0.995 2.52c-0.14 0.354-0.518 0.542-0.876 0.454l-0.098-0.031c-0.353-0.14-0.54-0.518-0.452-0.876l0.03-0.098 3.754-9.495C7.042 1.88 7.85 1.844 8.151 2.37zM7.503 4.792L6.036 8.5h2.928L7.503 4.792z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<!--~ Copyright (c) 2023. ~ Microsoft Corporation. All rights reserved.-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_fluent_text_edit_style_24_filled" android:state_activated="true"/>
<item android:drawable="@drawable/ic_fluent_text_edit_style_24_filled" android:state_checked="true"/>
<item android:drawable="@drawable/ic_fluent_text_edit_style_24_filled" android:state_selected="true"/>
<item android:drawable="@drawable/ic_fluent_text_edit_style_24_regular"/>
</selector>

View File

@@ -0,0 +1,27 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:width="134dp"
android:height="34dp"
android:viewportWidth="313"
android:viewportHeight="81">
<path
android:pathData="M72.95,18.45C71.82,9.95 64.5,3.24 55.85,1.95C54.38,1.73 48.85,0.93 36.02,0.93H35.92C23.09,0.93 20.34,1.73 18.87,1.95C10.44,3.22 2.76,9.23 0.88,17.84C-0,22.08 -0.1,26.78 0.07,31.09C0.31,37.27 0.36,43.43 0.91,49.6C1.29,53.69 1.95,57.74 2.9,61.73C4.68,69.11 11.86,75.25 18.9,77.75C26.43,80.35 34.53,80.79 42.29,79C43.14,78.79 43.98,78.56 44.82,78.29C46.71,77.68 48.92,77 50.55,75.81C50.57,75.8 50.59,75.77 50.6,75.75C50.61,75.72 50.62,75.7 50.62,75.66V69.7C50.62,69.7 50.62,69.65 50.6,69.62C50.6,69.6 50.57,69.58 50.55,69.56C50.53,69.55 50.5,69.54 50.48,69.53C50.45,69.53 50.43,69.53 50.41,69.53C45.43,70.73 40.33,71.34 35.23,71.33C26.43,71.33 24.06,67.09 23.39,65.34C22.85,63.82 22.5,62.22 22.36,60.61C22.36,60.59 22.36,60.57 22.37,60.54C22.37,60.52 22.39,60.49 22.42,60.48C22.44,60.47 22.46,60.46 22.49,60.44H22.57C27.46,61.64 32.48,62.25 37.51,62.25C38.72,62.25 39.92,62.25 41.14,62.21C46.19,62.06 51.52,61.81 56.51,60.82C56.63,60.8 56.76,60.77 56.87,60.75C64.72,59.21 72.19,54.42 72.95,42.27C72.97,41.79 73.04,37.25 73.04,36.76C73.04,35.07 73.58,24.79 72.96,18.48L72.95,18.45Z">
<aapt:attr name="android:fillColor">
<gradient
android:startX="36.62"
android:startY="0.93"
android:endX="36.62"
android:endY="80.07"
android:type="linear">
<item android:offset="0" android:color="#FF6364FF"/>
<item android:offset="1" android:color="#FF563ACC"/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData="M14.81,23.2C14.81,20.72 16.77,18.72 19.2,18.72C21.62,18.72 23.58,20.73 23.58,23.2C23.58,25.67 21.62,27.68 19.2,27.68C16.77,27.68 14.81,25.67 14.81,23.2Z"
android:fillColor="#fff"/>
<path
android:pathData="M80.02,27.06V47.66H72.03V27.67C72.03,23.45 70.3,21.32 66.83,21.32C63,21.32 61.07,23.87 61.07,28.87V39.82H53.14V28.87C53.14,23.84 51.24,21.32 47.38,21.32C43.92,21.32 42.18,23.45 42.18,27.67V47.65H34.21V27.06C34.21,22.86 35.25,19.51 37.35,17.03C39.53,14.54 42.37,13.29 45.89,13.29C49.97,13.29 53.07,14.9 55.11,18.11L57.11,21.52L59.1,18.11C61.14,14.91 64.23,13.29 68.32,13.29C71.84,13.29 74.69,14.55 76.86,17.03C78.96,19.51 80.01,22.83 80.01,27.06H80.02ZM107.49,37.3C109.15,35.51 109.93,33.29 109.93,30.59C109.93,27.89 109.14,25.65 107.49,23.94C105.91,22.15 103.89,21.3 101.45,21.3C99.02,21.3 97.01,22.15 95.41,23.94C93.83,25.65 93.04,27.89 93.04,30.59C93.04,33.29 93.83,35.53 95.41,37.3C97,39 99.02,39.87 101.45,39.87C103.89,39.87 105.9,39.02 107.49,37.3ZM109.93,14.12H117.8V47.06H109.93V43.18C107.55,46.41 104.26,48 99.99,48C95.71,48 92.42,46.36 89.5,43C86.64,39.64 85.18,35.48 85.18,30.61C85.18,25.74 86.65,21.65 89.5,18.29C92.43,14.93 95.92,13.23 99.99,13.23C104.06,13.23 107.55,14.81 109.93,18.02V14.14V14.12ZM144.26,29.97C146.58,31.76 147.73,34.25 147.67,37.41C147.67,40.77 146.52,43.41 144.14,45.24C141.76,47.03 138.89,47.94 135.41,47.94C129.13,47.94 124.87,45.3 122.61,40.11L129.43,35.96C130.34,38.78 132.35,40.25 135.41,40.25C138.22,40.25 139.62,39.33 139.62,37.42C139.62,36.03 137.79,34.78 134.07,33.8C132.66,33.41 131.5,33.01 130.6,32.68C129.31,32.16 128.22,31.56 127.31,30.83C125.05,29.04 123.9,26.68 123.9,23.65C123.9,20.42 124.99,17.85 127.19,16C129.45,14.09 132.19,13.18 135.48,13.18C140.73,13.18 144.56,15.48 147.07,20.16L140.37,24.1C139.4,21.86 137.74,20.74 135.48,20.74C133.11,20.74 131.95,21.65 131.95,23.44C131.95,24.83 133.78,26.08 137.5,27.06C140.37,27.72 142.63,28.7 144.26,29.97H144.27H144.26ZM169.26,22.27H162.37V35.98C162.37,37.63 162.98,38.63 164.15,39.08C165,39.4 166.71,39.47 169.27,39.34V47.05C163.98,47.71 160.14,47.17 157.88,45.41C155.62,43.7 154.53,40.53 154.53,36V22.27H149.23V14.1H154.53V7.46L162.39,4.89V14.12H169.29V22.29H169.27L169.26,22.27ZM194.34,37.1C195.92,35.4 196.71,33.22 196.71,30.58C196.71,27.94 195.92,25.78 194.34,24.05C192.74,22.35 190.79,21.48 188.42,21.48C186.04,21.48 184.09,22.33 182.49,24.05C180.97,25.84 180.18,28 180.18,30.58C180.18,33.16 180.97,35.31 182.49,37.1C184.08,38.81 186.04,39.67 188.42,39.67C190.79,39.67 192.74,38.82 194.34,37.1ZM176.96,42.96C173.85,39.6 172.32,35.52 172.32,30.58C172.32,25.63 173.85,21.62 176.96,18.26C180.07,14.9 183.91,13.19 188.42,13.19C192.92,13.19 196.77,14.9 199.87,18.26C202.97,21.62 204.57,25.77 204.57,30.58C204.57,35.39 202.97,39.6 199.87,42.96C196.76,46.32 192.98,47.96 188.42,47.96C183.85,47.96 180.06,46.32 176.96,42.96ZM230.86,37.29C232.45,35.5 233.24,33.28 233.24,30.58C233.24,27.87 232.45,25.63 230.86,23.93C229.28,22.14 227.26,21.29 224.82,21.29C222.39,21.29 220.37,22.14 218.73,23.93C217.14,25.63 216.35,27.87 216.35,30.58C216.35,33.28 217.14,35.52 218.73,37.29C220.38,38.99 222.45,39.86 224.82,39.86C227.2,39.86 229.27,39 230.86,37.29ZM233.24,0.92H241.11V47.05H233.24V43.17C230.93,46.39 227.63,47.99 223.36,47.99C219.09,47.99 215.75,46.35 212.8,42.98C209.93,39.62 208.48,35.47 208.48,30.6C208.48,25.73 209.95,21.64 212.8,18.28C215.72,14.92 219.26,13.22 223.36,13.22C227.45,13.22 230.93,14.8 233.24,18.01V0.93V0.92ZM268.74,37.07C270.32,35.36 271.12,33.18 271.12,30.54C271.12,27.9 270.32,25.74 268.74,24.01C267.15,22.31 265.21,21.45 262.82,21.45C260.43,21.45 258.5,22.3 256.9,24.01C255.37,25.8 254.58,27.96 254.58,30.54C254.58,33.12 255.37,35.28 256.9,37.07C258.48,38.77 260.44,39.64 262.82,39.64C265.2,39.64 267.14,38.78 268.74,37.07ZM251.36,42.92C248.26,39.56 246.73,35.48 246.73,30.54C246.73,25.6 248.25,21.58 251.36,18.22C254.47,14.86 258.32,13.15 262.82,13.15C267.32,13.15 271.18,14.86 274.27,18.22C277.38,21.58 278.97,25.73 278.97,30.54C278.97,35.35 277.38,39.56 274.27,42.92C271.16,46.28 267.38,47.93 262.82,47.93C258.26,47.93 254.46,46.28 251.36,42.92ZM313,26.78V47.01H305.14V27.84C305.14,25.66 304.59,24.01 303.48,22.77C302.45,21.65 300.98,21.07 299.09,21.07C294.65,21.07 292.39,23.77 292.39,29.24V47.03H284.53V14.1H292.39V17.81C294.28,14.71 297.28,13.19 301.47,13.19C304.82,13.19 307.57,14.37 309.71,16.81C311.91,19.24 313,22.54 313,26.82"
android:fillColor="#fff"/>
</vector>

View File

@@ -27,7 +27,7 @@
android:gravity="center"
android:includeFontPadding="false"
android:paddingHorizontal="5dp"
android:paddingVertical="1dp"
android:paddingVertical="2dp"
android:background="@drawable/bg_image_alt_overlay"
android:text="@string/sk_alt_button"/>

View File

@@ -3,7 +3,6 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="13dp"
android:paddingEnd="4dp"
android:paddingStart="16dp">
@@ -11,6 +10,7 @@
android:id="@+id/more"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginTop="13dp"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:background="?android:actionBarItemBackground"
@@ -23,6 +23,7 @@
android:id="@+id/delete_notification"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginTop="13dp"
android:layout_toStartOf="@id/more"
android:visibility="gone"
android:background="?android:actionBarItemBackground"
@@ -36,6 +37,7 @@
android:id="@+id/visibility"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginTop="13dp"
android:layout_toStartOf="@id/delete_notification"
android:background="?android:actionBarItemBackground"
android:scaleType="center"
@@ -46,6 +48,7 @@
android:id="@+id/collapse_btn"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginTop="13dp"
android:layout_toStartOf="@id/visibility"
android:background="?android:actionBarItemBackground"
android:visibility="gone"
@@ -70,6 +73,7 @@
android:id="@+id/unread_indicator"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginTop="13dp"
android:layout_toStartOf="@id/collapse_btn"
android:visibility="gone"
android:tint="?android:colorAccent"
@@ -83,18 +87,16 @@
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="12dp"
android:layout_marginTop="3dp" />
android:layout_marginTop="16dp" />
<org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout
android:id="@+id/name_wrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginTop="3dp"
android:paddingTop="4sp"
android:layout_toStartOf="@id/unread_indicator"
android:layout_toEndOf="@id/avatar"
android:minHeight="24sp">
android:layout_above="@+id/username_wrap">
<TextView
android:id="@+id/name"
@@ -121,14 +123,15 @@
</org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout>
<org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout
android:id="@id/username_wrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/name_wrap"
android:layout_marginEnd="8dp"
android:layout_toStartOf="@id/unread_indicator"
android:layout_toEndOf="@id/avatar"
android:layout_alignBottom="@id/avatar"
android:layoutDirection="locale"
android:minHeight="20sp"
android:paddingBottom="3sp"
android:orientation="horizontal">
<TextView

View File

@@ -11,7 +11,7 @@
android:layout_height="250dp"
android:layout_gravity="center_horizontal"
android:foreground="?android:selectableItemBackground"
android:maxWidth="400dp">
android:maxWidth="@dimen/layout_max_width">
<ImageView
android:id="@+id/photo"
android:layout_width="match_parent"

View File

@@ -73,7 +73,6 @@
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="16dp"
android:paddingRight="16dp"
android:paddingLeft="16dp">
@@ -81,6 +80,7 @@
android:id="@+id/self_avatar"
android:layout_width="46sp"
android:layout_height="46sp"
android:layout_marginTop="16dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="12dp" />
@@ -90,8 +90,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/self_avatar"
android:paddingTop="4sp"
android:minHeight="24sp"
android:layout_above="@+id/self_username"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="@style/m3_title_medium"
@@ -103,7 +102,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="8sp"
android:layout_toEndOf="@id/self_name"
android:paddingTop="4sp"
android:layout_above="@id/self_username"
android:ellipsize="end"
android:fontFamily="sans-serif"
android:singleLine="true"
@@ -112,15 +111,15 @@
tools:text="@string/sk_local_only" />
<TextView
android:id="@+id/self_username"
android:id="@id/self_username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/self_name"
android:layout_toEndOf="@id/self_avatar"
android:minHeight="20sp"
android:layout_alignBottom="@id/self_avatar"
android:ellipsize="end"
android:singleLine="true"
android:textAppearance="@style/m3_title_small"
android:paddingBottom="3sp"
tools:text="\@Gargron" />
</RelativeLayout>
@@ -417,6 +416,19 @@
android:tooltipText="@string/post_visibility"
android:src="@drawable/ic_fluent_earth_24_regular"/>
<ImageButton
android:id="@+id/btn_content_type"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_marginEnd="12dp"
android:background="?android:attr/actionBarItemBackground"
android:padding="0px"
android:tint="@color/compose_button"
android:tintMode="src_in"
android:contentDescription="@string/sk_content_type"
android:tooltipText="@string/sk_content_type"
android:src="@drawable/ic_fluent_text_edit_style_24_selector"/>
<Space
android:layout_width="0px"
android:layout_height="1px"

View File

@@ -14,7 +14,7 @@
<org.joinmastodon.android.ui.views.MaxWidthFrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxWidth="400dp">
android:maxWidth="@dimen/layout_max_width">
<ImageView
android:id="@+id/photo"

View File

@@ -5,7 +5,8 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:clipToPadding="false">
android:clipToPadding="false"
android:theme="@style/Theme.Mastodon.Dark.SplashFragment">
<View
android:id="@+id/blue_fill"
@@ -26,7 +27,8 @@
android:id="@+id/art_clouds"
android:layout_width="414dp"
android:layout_height="541dp"
android:layout_marginTop="91dp"
android:layout_marginTop="37dp"
android:layout_marginLeft="-27dp"
android:layout_gravity="top|left"
android:alpha="0.3"
android:importantForAccessibility="no"
@@ -36,8 +38,8 @@
android:id="@+id/art_plane_elephant"
android:layout_width="245.64dp"
android:layout_height="72.65dp"
android:layout_marginLeft="-101.55dp"
android:layout_marginTop="238.12dp"
android:layout_marginLeft="-50.775dp"
android:layout_marginTop="184.12dp"
android:layout_gravity="left|top"
android:alpha="0.3"
android:importantForAccessibility="no"
@@ -48,8 +50,8 @@
android:layout_width="150.84dp"
android:layout_height="176.44dp"
android:layout_gravity="top|left"
android:layout_marginLeft="322dp"
android:layout_marginTop="310dp"
android:layout_marginLeft="278dp"
android:layout_marginTop="244dp"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer1"/>
@@ -58,7 +60,8 @@
android:layout_width="197.2dp"
android:layout_height="153.61dp"
android:layout_gravity="top|left"
android:layout_marginTop="294dp"
android:layout_marginTop="252dp"
android:layout_marginLeft="-44dp"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer2"/>
@@ -67,7 +70,8 @@
android:layout_width="400dp"
android:layout_height="346dp"
android:layout_gravity="top|left"
android:layout_marginTop="294dp"
android:layout_marginTop="240dp"
android:layout_marginLeft="-20dp"
android:importantForAccessibility="no"
android:src="@drawable/splash_art_layer3"/>
@@ -86,60 +90,108 @@
android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="vertical">
<ImageView
android:layout_width="300dp"
android:layout_height="78dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="32dp"
android:importantForAccessibility="no"
android:src="@drawable/splash_logo"/>
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="0dp"
<Space
android:layout_width="1px"
android:layout_height="0px"
android:layout_weight="1"/>
<LinearLayout
android:id="@+id/pager_dots"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="16dp"
android:orientation="horizontal">
<View
android:layout_width="8dp"
android:layout_height="8dp"
android:background="@drawable/white_circle"/>
<View
android:layout_width="8dp"
android:layout_height="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:alpha="0.3"
android:background="@drawable/white_circle"/>
<View
android:layout_width="8dp"
android:layout_height="8dp"
android:alpha="0.3"
android:background="@drawable/white_circle"/>
</LinearLayout>
<Button
android:id="@+id/btn_log_in"
android:id="@+id/btn_join_default_server"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
style="@style/Widget.Mastodon.M3.Button.Text"
android:textColor="#fff"
android:text="@string/already_have_account"/>
style="@style/Widget.Mastodon.M3.Button.Filled"
tools:text="@string/join_default_server"/>
<Button
android:id="@+id/btn_get_started"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:text="@string/get_started"/>
android:layout_marginTop="8dp"
android:textColor="#FFF"
style="@style/Widget.Mastodon.M3.Button.Outlined"
android:background="@drawable/bg_button_m3_outlined_white"
android:text="@string/pick_server"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:background="#B2FFFFFF"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:textAllCaps="true"
android:textAppearance="@style/m3_label_large"
android:textColor="#B2FFFFFF"
android:layout_gravity="center_vertical"
android:text="@string/signup_or_login"/>
<View
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:background="#B2FFFFFF"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp">
<Button
android:id="@+id/btn_learn_more"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_weight="1"
android:textColor="#FFF"
style="@style/Widget.Mastodon.M3.Button.Text"
android:background="@drawable/bg_button_m3_text_white"
android:text="@string/learn_more"/>
<Button
android:id="@+id/btn_log_in"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_weight="1"
android:textColor="#FFF"
style="@style/Widget.Mastodon.M3.Button.Text"
android:background="@drawable/bg_button_m3_text_white"
android:text="@string/log_in"/>
</LinearLayout>
</LinearLayout>
</org.joinmastodon.android.ui.views.SizeListenerFrameLayout>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_bottom_sheet"
android:padding="16dp">
<View
android:layout_width="match_parent"
android:layout_height="4dp"
android:layout_marginBottom="16dp"
android:background="@drawable/bg_bottom_sheet_handle"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_headline_medium"
android:textColor="?colorM3OnSurface"
android:text="@string/welcome_to_mastodon"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurface"
android:text="@string/welcome_paragraph1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:textAppearance="@style/m3_headline_medium"
android:textColor="?colorM3OnSurface"
android:text="@string/what_are_servers"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurface"
android:text="@string/welcome_paragraph2"/>
</LinearLayout>
</ScrollView>

View File

@@ -5,7 +5,7 @@
android:layout_height="wrap_content"
android:background="?colorBackgroundLight"
android:elevation="2dp"
android:paddingBottom="16dp">
android:paddingBottom="0dp">
<ImageView
android:id="@+id/cover"
@@ -56,9 +56,9 @@
<TextView
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_alignLeft="@id/name"
android:layout_alignRight="@id/name"
android:layout_height="wrap_content"
android:layout_alignStart="@id/name"
android:layout_alignEnd="@id/name"
android:layout_below="@id/name"
android:singleLine="true"
android:ellipsize="end"
@@ -81,92 +81,110 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/bio"
android:paddingRight="8dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/posts_btn"
android:layout_width="wrap_content"
android:layout_height="48dp"
<org.joinmastodon.android.ui.views.AutoOrientationLinearLayout
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:gravity="center_horizontal"
android:orientation="vertical">
android:layout_gravity="bottom"
android:paddingTop="4dp"
android:gravity="center_vertical"
android:minHeight="44dp">
<TextView
android:id="@+id/posts_count"
<LinearLayout
android:id="@+id/posts_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_large"
tools:text="123" />
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:id="@+id/posts_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_medium"
android:singleLine="true"
android:ellipsize="end"
tools:text="123" />
<TextView
android:id="@+id/posts_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4sp"
android:textAppearance="@style/m3_body_large"
android:singleLine="true"
android:ellipsize="middle"
tools:text="posts" />
</LinearLayout>
<TextView
android:id="@+id/posts_label"
<LinearLayout
android:id="@+id/following_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_small"
tools:text="following" />
</LinearLayout>
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/following_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_medium"
android:singleLine="true"
android:ellipsize="end"
tools:text="123"/>
<TextView
android:id="@+id/following_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4sp"
android:textAppearance="@style/m3_body_large"
android:singleLine="true"
android:ellipsize="middle"
tools:text="following"/>
</LinearLayout>
<LinearLayout
android:id="@+id/followers_btn"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginTop="16dp"
android:layout_marginStart="12dp"
android:orientation="vertical"
android:gravity="center_horizontal">
<TextView
android:id="@+id/followers_count"
<LinearLayout
android:id="@+id/followers_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_large"
tools:text="123"/>
<TextView
android:id="@+id/followers_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_small"
tools:text="following"/>
</LinearLayout>
<LinearLayout
android:id="@+id/following_btn"
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginTop="16dp"
android:layout_marginStart="12dp"
android:orientation="vertical"
android:gravity="center_horizontal">
<TextView
android:id="@+id/following_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_large"
tools:text="123"/>
<TextView
android:id="@+id/following_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_small"
tools:text="following"/>
</LinearLayout>
<Space
android:layout_width="0px"
android:layout_height="1px"
android:layout_weight="1"/>
android:layout_marginTop="2dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:id="@+id/followers_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_title_medium"
android:singleLine="true"
android:ellipsize="end"
tools:text="123"/>
<TextView
android:id="@+id/followers_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4sp"
android:textAppearance="@style/m3_body_large"
android:singleLine="true"
android:ellipsize="middle"
tools:text="followers"/>
</LinearLayout>
</org.joinmastodon.android.ui.views.AutoOrientationLinearLayout>
<FrameLayout
android:id="@+id/reject_btn_wrap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_gravity="bottom"
android:paddingStart="8dp"
android:paddingEnd="4dp"
android:clipToPadding="false"
android:paddingHorizontal="4dp"
android:paddingVertical="8dp"
android:paddingTop="8dp"
android:paddingBottom="16dp"
android:visibility="gone">
<org.joinmastodon.android.ui.views.ProgressBarButton
@@ -194,10 +212,12 @@
android:id="@+id/accept_btn_wrap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_gravity="bottom"
android:paddingStart="4dp"
android:paddingEnd="16dp"
android:clipToPadding="false"
android:paddingHorizontal="4dp"
android:paddingVertical="8dp"
android:paddingTop="8dp"
android:paddingBottom="16dp"
android:visibility="gone">
<org.joinmastodon.android.ui.views.ProgressBarButton
@@ -224,8 +244,11 @@
android:id="@+id/action_btn_wrap"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:padding="8dp"
android:layout_gravity="bottom"
android:paddingStart="8dp"
android:paddingEnd="16dp"
android:paddingTop="8dp"
android:paddingBottom="16dp"
android:clipToPadding="false">
<org.joinmastodon.android.ui.views.ProgressBarButton

View File

@@ -13,7 +13,7 @@
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="32dp"
android:layout_marginEnd="16dp"
android:importantForAccessibility="no"
android:tint="?android:textColorPrimary"
tools:src="@drawable/ic_fluent_color_24_regular"/>
@@ -24,6 +24,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_marginStart="16dp"
android:layout_marginEnd="8dp"
android:paddingVertical="8dp"
android:gravity="center_vertical"

View File

@@ -26,7 +26,7 @@
android:gravity="center"
android:includeFontPadding="false"
android:paddingHorizontal="5dp"
android:paddingVertical="1dp"
android:paddingVertical="2dp"
android:text="@string/sk_alt_button"/>
<ImageButton

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/content_type_group" android:checkableBehavior="single">
<item android:id="@+id/content_type_null" android:title="@string/sk_content_type_unspecified" />
<item android:id="@+id/content_type_plain" android:title="@string/sk_content_type_plain" />
<item android:id="@+id/content_type_markdown" android:title="@string/sk_content_type_markdown" />
<item android:id="@+id/content_type_html" android:title="@string/sk_content_type_html" />
<item android:id="@+id/content_type_bbcode" android:title="@string/sk_content_type_bbcode" />
<item android:id="@+id/content_type_misskey_markdown" android:title="@string/sk_content_type_mfm" />
</group>
</menu>

View File

@@ -0,0 +1,488 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="get_started">الخطوات الأولى</string>
<string name="log_in">تسجيلُ الدخول</string>
<string name="next">التالي</string>
<string name="loading_instance">يَجري الحُصُول على معلومات المَثيل…</string>
<string name="error">خطأ</string>
<string name="not_a_mastodon_instance">%s لا يبدو كمثيل ماستدون.</string>
<string name="ok">حسنًا</string>
<string name="preparing_auth">جَارٍ الإعدَادُ لِلمُصادَقَة…</string>
<string name="finishing_auth">يُنهي المصادقة…</string>
<string name="user_boosted">أعادَ %s تَدوينَها</string>
<string name="in_reply_to">ردًا على %s</string>
<string name="notifications">الإشعارات</string>
<string name="user_followed_you">بَدَأ بِمُتابَعَتِك</string>
<string name="user_sent_follow_request">أرسَلَ طَلَبًا لِمُتابَعَتِك</string>
<string name="user_favorited">فَضَّلَ مَنشُورَك</string>
<string name="notification_boosted">أعادَ تَدوينَ مَنشُورَك</string>
<string name="poll_ended">انتهى استطلاعُ الرأي</string>
<string name="time_seconds">%d ثا</string>
<string name="time_minutes">%d د</string>
<string name="time_hours">%d سا</string>
<string name="time_days">%d يوم</string>
<string name="share_toot_title">شارك</string>
<string name="settings">الإعدادات</string>
<string name="publish">انشر</string>
<string name="discard_draft">أتريد التخلص من المسودة؟</string>
<string name="discard">تخلص</string>
<string name="cancel">إلغاء</string>
<plurals name="followers">
<item quantity="zero">لا متابِعين</item>
<item quantity="one">متابِع</item>
<item quantity="two">متابِعان</item>
<item quantity="few">متابِعين</item>
<item quantity="many">متابِعًا</item>
<item quantity="other">متابِع</item>
</plurals>
<plurals name="following">
<item quantity="zero">لا متابَعين</item>
<item quantity="one">متابَع</item>
<item quantity="two">متابَعان</item>
<item quantity="few">متابَعين</item>
<item quantity="many">متابَعًا</item>
<item quantity="other">متابَع</item>
</plurals>
<plurals name="posts">
<item quantity="zero">لا منشورات</item>
<item quantity="one">منشور</item>
<item quantity="two">منشوران</item>
<item quantity="few">منشورات</item>
<item quantity="many">منشورًا</item>
<item quantity="other">منشور</item>
</plurals>
<string name="posts">منشورات</string>
<string name="posts_and_replies">مَنشُوراتٌ وَرُدُود</string>
<string name="media">وسائط</string>
<string name="profile_about">حَول</string>
<string name="button_follow">تابِع</string>
<string name="button_following">يُتابِع</string>
<string name="edit_profile">حرّر الملف الشخصي</string>
<string name="mention_user">ذِكر @%s</string>
<string name="share_user">مُشارَكَةُ %s</string>
<string name="mute_user">كَتمُ %s</string>
<string name="unmute_user">إلغاء الكَتم عن @%s</string>
<string name="block_user">حَظرُ %s</string>
<string name="unblock_user">رفع الحَظر عن %s</string>
<string name="report_user">الإبلاغُ عَن %s</string>
<string name="block_domain">حَظرُ %s</string>
<string name="unblock_domain">رفع الحَظر عن %s</string>
<plurals name="x_posts">
<item quantity="zero">لا مَنشورات</item>
<item quantity="one">منشورٌ واحِد</item>
<item quantity="two">منشورانِ اثنان</item>
<item quantity="few">%,d منشورات</item>
<item quantity="many">%,d منشورًا</item>
<item quantity="other">%,d منشور</item>
</plurals>
<string name="profile_joined">انضم في</string>
<string name="done">تمّ</string>
<string name="loading">يحمل…</string>
<string name="field_label">التسمية</string>
<string name="field_content">المحتوى</string>
<string name="saving">يحفظ…</string>
<string name="post_from_user">نُشر من %s</string>
<string name="poll_option_hint">الخيار %d</string>
<plurals name="x_minutes">
<item quantity="zero">أقل من دقيقة</item>
<item quantity="one">دقيقة واحدة</item>
<item quantity="two">دقيقتان</item>
<item quantity="few">%d دقائق</item>
<item quantity="many">%d دقيقة</item>
<item quantity="other">%d دقيقة</item>
</plurals>
<plurals name="x_hours">
<item quantity="zero">أقل من ساعة</item>
<item quantity="one">ساعة واحدة</item>
<item quantity="two">ساعتان</item>
<item quantity="few">%d ساعات</item>
<item quantity="many">%d ساعة</item>
<item quantity="other">%d ساعة</item>
</plurals>
<plurals name="x_days">
<item quantity="zero">أقل من يوم</item>
<item quantity="one">يومٌ واحِد</item>
<item quantity="two">يَومان</item>
<item quantity="few">%d أيام</item>
<item quantity="many">%d يومًا</item>
<item quantity="other">%d يوم</item>
</plurals>
<string name="compose_poll_duration">المُدَّة: %s</string>
<plurals name="x_seconds_left">
<item quantity="zero">تتبقى لَحظة</item>
<item quantity="one">تتبقى ثانية واحِدة</item>
<item quantity="two">تتبقى ثانيتان</item>
<item quantity="few">تتبقى %d ثوان</item>
<item quantity="many">تتبقى %d ثانية</item>
<item quantity="other">تتبقى %d ثانية</item>
</plurals>
<plurals name="x_minutes_left">
<item quantity="zero">تبقت أقل من دقيقة</item>
<item quantity="one">تبقت دقيقة</item>
<item quantity="two">تبقت دقيقتان</item>
<item quantity="few">تبقت %d دقائق</item>
<item quantity="many">تبقت %d دقيقة</item>
<item quantity="other">تبقت %d دقيقة</item>
</plurals>
<plurals name="x_hours_left">
<item quantity="zero">تبقت أقل من ساعة</item>
<item quantity="one">تبقت ساعة واحدة</item>
<item quantity="two">تبقت ساعتان</item>
<item quantity="few">تبقت %d ساعات</item>
<item quantity="many">تبقت %d ساعة</item>
<item quantity="other">تبقت %d ساعة</item>
</plurals>
<plurals name="x_days_left">
<item quantity="zero">تبقى أقل من يوم</item>
<item quantity="one">تبقى يوم واحد</item>
<item quantity="two">تبقى يومان</item>
<item quantity="few">تبقى %d أيام</item>
<item quantity="many">تبقى %d يومًا</item>
<item quantity="other">تبقى %d يوم</item>
</plurals>
<plurals name="x_voters">
<item quantity="zero">لا يوجد مصوتون</item>
<item quantity="one">مصوت واحد</item>
<item quantity="two">مصوتان</item>
<item quantity="few">%,d مصوتين</item>
<item quantity="many">%,d مصوتًا</item>
<item quantity="other">%,d مصوت</item>
</plurals>
<string name="poll_closed">انتهى</string>
<string name="confirm_mute_title">اكتم الحساب</string>
<string name="confirm_mute">أكّد كتم %s</string>
<string name="do_mute">اكتم</string>
<string name="confirm_unmute_title">ارفع الكتم عن الحساب</string>
<string name="confirm_unmute">أكِّد رفع الكتم عن %s</string>
<string name="do_unmute">ارفع الكتم</string>
<string name="confirm_block_title">احجب الحساب</string>
<string name="confirm_block_domain_title">احجب النطاق</string>
<string name="confirm_block">أكّد حجب %s</string>
<string name="do_block">احجب</string>
<string name="confirm_unblock_title">ارفع الحجب عن الحساب</string>
<string name="confirm_unblock_domain_title">ارفع الحجب عن النطاق</string>
<string name="confirm_unblock">أكّد رفع الحجب عن %s</string>
<string name="do_unblock">ارفع الحجب</string>
<string name="button_muted">مَكتوم</string>
<string name="button_blocked">محجوب</string>
<string name="action_vote">صَوّت</string>
<string name="tap_to_reveal">اُنقُر لِلكَشف</string>
<string name="delete">احذف</string>
<string name="confirm_delete_title">احذف المنشور</string>
<string name="confirm_delete">أمتأكد من حذف هذا المنشور؟</string>
<string name="deleting">يحذف…</string>
<string name="notification_channel_audio_player">تشغيل الصوت</string>
<string name="play">شغّل</string>
<string name="pause">ألبث</string>
<string name="log_out">خروج</string>
<string name="add_account">أضف حساباً</string>
<string name="search_hint">ابحث</string>
<string name="hashtags">وُسُوم</string>
<string name="news">الأخبار</string>
<string name="for_you">لأجلك</string>
<string name="all_notifications">الكل</string>
<string name="mentions">الذِكر</string>
<plurals name="x_people_talking">
<item quantity="zero">لا أحد يتحدث</item>
<item quantity="one">شخص واحد يتحدث</item>
<item quantity="two">شخصان يتحدثان</item>
<item quantity="few">%d أشخاص يتحدثون</item>
<item quantity="many">%d شخصًا يتحدثون</item>
<item quantity="other">%d شخص يتحدثون</item>
</plurals>
<plurals name="discussed_x_times">
<item quantity="zero">لم يُناقش</item>
<item quantity="one">نوقش مرة واحدة</item>
<item quantity="two">نوقش مرتين</item>
<item quantity="few">نوقش %d مرات</item>
<item quantity="many">نوقش %d مرة</item>
<item quantity="other">نوقش %d مرة</item>
</plurals>
<string name="report_title">بلّغ عن %s</string>
<string name="report_choose_reason">ما هي المشكلة في هذا المنشور؟</string>
<string name="report_choose_reason_account">ما هي المشكلة مع %s؟</string>
<string name="report_choose_reason_subtitle">اختر أفضل تطابق</string>
<string name="report_reason_personal">لا يعجبني</string>
<string name="report_reason_personal_subtitle">ألا ترغب برؤيته</string>
<string name="report_reason_spam">إزعاج</string>
<string name="report_reason_spam_subtitle">روابط خبيثة أو تفاعل كاذب أو ردود متكررة</string>
<string name="report_reason_violation">ينتهك قواعد الخادم</string>
<string name="report_reason_violation_subtitle">تعلم أنه ينتهك قواعد محددة</string>
<string name="report_reason_other">شيء آخر</string>
<string name="report_reason_other_subtitle">لا تندرج هذه المشكلة ضمن فئات أخرى</string>
<string name="report_choose_rule">ما هي القواعد المنتهكة؟</string>
<string name="report_choose_rule_subtitle">اختر كل ما ينطبق</string>
<string name="report_choose_posts">هل توجد منشورات تدعم صحة هذا البلاغ؟</string>
<string name="report_choose_posts_subtitle">اختر كل ما ينطبق</string>
<string name="report_comment_title">هل لديك شيء آخر لتخبرنا به؟</string>
<string name="report_comment_hint">تعليقات إضافية</string>
<string name="sending_report">يرسل البلاغ…</string>
<string name="report_sent_title">شُكرًا لَكَ على التبليغ، سَنَنظُرُ فِي هَذَا الأمر.</string>
<string name="report_sent_subtitle">في أثناء مراجعتنا للبلاغ، يمكنك اتخاذ إجراء ضد @%s.</string>
<string name="unfollow_user">ألغ متابعة %s</string>
<string name="unfollow">ألغ المتابعة</string>
<string name="mute_user_explain">لن ترى منشوراتهم أو إعادة تدوينهم في التغذية الرئيسية. ولن يعلموا أنهم كتموا.</string>
<string name="block_user_explain">لن يتمكنوا من متابعتك أو رؤية منشوراتك، وسيكون بديهيًا لهم أنهم حجبوا.</string>
<string name="report_personal_title">لاترغب في مشاهدة هذا؟</string>
<string name="report_personal_subtitle">عندما ترى ما لا يعجبك في ماستدون، يمكنك إزالة صاحبها من تجربتك كمستخدم.</string>
<string name="back">العودة</string>
<string name="instance_catalog_title">يتكوّن ماستدون من مستخدمين موزّعين عبر خوادم مختلفة.</string>
<string name="instance_catalog_subtitle">اختر خادمًا بناءً على اهتماماتك، منطقتك أو يمكنك حتى اختيارُ مجتمعٍ ذي غرضٍ عام. وسيضل بامكانك التواصل مع المستخدمين من الخوادم الأخرى.</string>
<string name="search_communities">ابحث عن خادم أو أدخل رابطه</string>
<string name="instance_rules_title">بعض القواعد الأساسية</string>
<string name="instance_rules_subtitle">خذ دقيقة لمراجعة القواعد التي حددها وفرضها مديروا %s.</string>
<string name="signup_title">دعنا نجهزك في %s</string>
<string name="edit_photo">حرّر</string>
<string name="display_name">الاسم العلني</string>
<string name="username">اسم المستخدم</string>
<string name="email">البريد الإلكتروني</string>
<string name="password">كلمة المرور</string>
<string name="password_note">ضمّن الأحرف الكبيرة والأحرف الخاصة والأرقام لزيادة قوة كلمة المرور.</string>
<string name="category_academia">أكاديمي</string>
<string name="category_activism">النشطاء</string>
<string name="category_all">الكل</string>
<string name="category_art">فنون</string>
<string name="category_food">طعام</string>
<string name="category_furry">حيوان ذو فرو</string>
<string name="category_games">ألعاب</string>
<string name="category_general">عام</string>
<string name="category_journalism">صحافة</string>
<string name="category_lgbt">LGBT</string>
<string name="category_music">موسيقى</string>
<string name="category_regional">إقليمي</string>
<string name="category_tech">تقني</string>
<string name="confirm_email_title">شيءٌ أخير</string>
<string name="confirm_email_subtitle">أنقر على الرابط المرسل إليك لاستيثاق حسابك.</string>
<string name="resend">أعد الإرسال</string>
<string name="open_email_app">افتح تطبيق البريد الإلكتروني</string>
<string name="resent_email">أُرسلت رسالة التأكيد</string>
<string name="compose_hint">عَبِّر عَمَّ يَجُولُ فِي ذِهنِك</string>
<string name="content_warning">تحذير من المحتوى</string>
<string name="add_image_description">أضف وصفًا للصورة…</string>
<string name="retry_upload">حاول الرفع مجددًا</string>
<string name="edit_image">حرّر الصورة</string>
<string name="save">احفظ</string>
<string name="add_alt_text">أضف نصًا بديلًا</string>
<string name="alt_text_subtitle">يصف النص البديل محتوى الصور للمكفوفين وضعاف البصر. حاول تضمين أكبر قدر ممكن من التفاصيل ليفهموا السياق.</string>
<string name="alt_text_hint">مثال: كلب ينظر حوله بارتياب وعيناه مثبتتان على الكاميرا.</string>
<string name="visibility_public">علني</string>
<string name="visibility_followers_only">للمُتابِعينَ فقط</string>
<string name="visibility_private">لمن ذكرتُهم فقط</string>
<string name="search_all">الكل</string>
<string name="search_people">أشخاص</string>
<string name="recent_searches">عَمَليَّاُت البَحثِ الأخيرَة</string>
<string name="step_x_of_n">الخطوة %1$d من %2$d</string>
<string name="skip">تخطى</string>
<string name="notification_type_follow">متابعُون جُدُد</string>
<string name="notification_type_favorite">المفضلة</string>
<string name="notification_type_reblog">المعاد تدوينها</string>
<string name="notification_type_mention">الذِكر</string>
<string name="notification_type_poll">استطلاع رأي</string>
<string name="choose_account">اختر حسابًا</string>
<string name="err_not_logged_in">يرجى تسجيل الدخول إلى حساب ماستدون أولًا</string>
<plurals name="cant_add_more_than_x_attachments">
<item quantity="zero">يجب عليك إرفاق ملف</item>
<item quantity="one">لا يمكنك إرفاق ملف</item>
<item quantity="two">لا يمكنك إرفاق أكثر من ملفين</item>
<item quantity="few">لا يمكنك إرفاق أكثر من %d ملفات</item>
<item quantity="many">لا يمكنك إرفاق أكثر من %d ملفًا</item>
<item quantity="other">لا يمكنك إرفاق أكثر من %d ملف</item>
</plurals>
<string name="media_attachment_unsupported_type">نوع الملف %s غير مدعوم</string>
<string name="media_attachment_too_big">الملف %1$s يتجاوز حدّ %2$s مب</string>
<string name="settings_theme">المظهر</string>
<string name="theme_auto">تلقائي</string>
<string name="theme_light">فاتح</string>
<string name="theme_dark">داكن</string>
<string name="theme_true_black">الوضع الداكن الحقيقي</string>
<string name="settings_behavior">السلوك</string>
<string name="settings_gif">تشغيل الصور الرمزية المتحركة والرموز التعبيرية المتحركة</string>
<string name="settings_custom_tabs">استخدم المتصفح المضمن</string>
<string name="settings_notifications">الإشعارات</string>
<string name="notify_me_when">أشعِرني عند قيام</string>
<string name="notify_anyone">أيَّ شخصٍ</string>
<string name="notify_follower">مُتابِع</string>
<string name="notify_followed">شخص أُتابِعُه</string>
<string name="notify_none">لَا أحد</string>
<string name="notify_favorites">بِالإعْجاب بِمَنشوري</string>
<string name="notify_follow">بمتابعتي</string>
<string name="notify_reblog">بإعادة تدوين مَنشوري</string>
<string name="notify_mention">ذكرني</string>
<string name="settings_boring">المنطِقَةُ المُملَّة</string>
<string name="settings_account">إعدادات الحساب</string>
<string name="settings_contribute">ساهم في ماستدون</string>
<string name="settings_tos">شروط الخدمة</string>
<string name="settings_privacy_policy">سياسة الخصوصية</string>
<string name="settings_spicy">المنطِقَةُ اللَّاذِعَة</string>
<string name="settings_clear_cache">امسح التخزين المؤقت للوسائط</string>
<string name="settings_app_version">تطبيق ماستدون لأندرويد نسخة %1$s (%2$d)</string>
<string name="media_cache_cleared">مُسح التخزين المؤقت للوسائط</string>
<string name="confirm_log_out">أمتأكد من الخروج؟</string>
<string name="sensitive_content">محتوى حساس</string>
<string name="sensitive_content_explain">علّم المؤلف هته الوسائط كحساسة. اضغط لكشفها.</string>
<string name="media_hidden">اُنقُر لِلكَشف</string>
<string name="avatar_description">انتقل للصفحة الشخصية لـ %s</string>
<string name="more_options">مزيد من الخيارات</string>
<string name="reveal_content">اكشف المحتوى</string>
<string name="hide_content">اخف المحتوى</string>
<string name="new_post">منشور جديد</string>
<string name="button_reply">ردّ</string>
<string name="button_reblog">أعد تدوين</string>
<string name="button_favorite">فضّل</string>
<string name="button_share">شارك</string>
<string name="media_no_description">وسائط بدون وصف</string>
<string name="add_media">أضف وسائط</string>
<string name="add_poll">أضف استطلاع رأي</string>
<string name="emoji">إيموجي</string>
<string name="post_visibility">مرئية المنشور</string>
<string name="home_timeline">الخيط الزمني الرئيسي</string>
<string name="my_profile">ملفي الشخصي</string>
<string name="media_viewer">عارض الوسائط</string>
<string name="follow_user">تابع %s</string>
<string name="unfollowed_user">ألغ متابعة %s</string>
<string name="followed_user">أنت تتابع %s</string>
<string name="open_in_browser">افتح في المتصفح</string>
<string name="hide_boosts_from_user">اخف ما أعاد %s تدوينه</string>
<string name="show_boosts_from_user">أظهر ما أعاد %s تدوينه</string>
<string name="signup_reason">لماذا ترغب في الانضمام؟</string>
<string name="signup_reason_note">هذا سوف يساعدنا في مراجعة تطبيقك.</string>
<string name="clear">امسح</string>
<string name="profile_header">الصورة الفوقية</string>
<string name="profile_picture">صورة الملفّ الشخصي</string>
<string name="reorder">أعد الترتيب</string>
<string name="download">نزّل</string>
<string name="permission_required">يتطلب أذونات</string>
<string name="storage_permission_to_download">يحتاج هذا التطبيق أذن الوصول للتخزين لحفظ الملف.</string>
<string name="open_settings">افتح الإعدادات</string>
<string name="error_saving_file">خطأ أثناء حفظ الملف</string>
<string name="file_saved">حُفظ الملف</string>
<string name="downloading">ينزّل…</string>
<string name="no_app_to_handle_action">لا يوجد تطبيق لمعالجة هذا الإجراء</string>
<string name="local_timeline">المجتمع</string>
<string name="trending_posts_info_banner">هَذِهِ هِيَ المَنشُوراتُ الَّتي تَكْتَسِبُ شَعبِيَّةً فِي الرُّكنِ الخاصِّ بِكَ مِن مَاستودُون.</string>
<string name="trending_hashtags_info_banner">هَذِهِ هِيَ الوُسُومُ الَّتي تَكْتَسِبُ شَعبِيَّةً فِي الرُّكنِ الخاصِّ بِكَ مِن مَاستودُون.</string>
<string name="trending_links_info_banner">هَذِهِ هِيَ القِصَصُ الأخبارِيَّةُ المُتَنَاقَلَةُ بِكِثرَةٍ فِي الرُّكنِ الخاصِّ بِكَ مِن مَاستودُون.</string>
<string name="local_timeline_info_banner">هذه هي أحدث منشورات المستخدمين المتواجدين على نفس الخادم الذي تستخدمه.</string>
<string name="dismiss">رفض</string>
<string name="see_new_posts">استعرض المنشورات الجديدة</string>
<string name="load_missing_posts">حمّل المَنشورات المَفقودَة</string>
<string name="follow_back">رُدّ المتابعة</string>
<string name="button_follow_pending">معلق</string>
<string name="follows_you">يُتابِعُك</string>
<string name="manually_approves_followers">الموافقة اليدوية على طلبات المتابعة</string>
<string name="current_account">الحِسابُ الحاليّ</string>
<string name="log_out_account">تَسجيلُ الخُرُوجِ مِن %s</string>
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
<plurals name="x_followers">
<item quantity="zero">ليس له متابِعون</item>
<item quantity="one">متابِع واحد</item>
<item quantity="two">متابِعان</item>
<item quantity="few">%,d متابِعين</item>
<item quantity="many">%,d متابِعًا</item>
<item quantity="other">%,d متابِع</item>
</plurals>
<plurals name="x_following">
<item quantity="zero">ليس له متابَعون</item>
<item quantity="one">متابَع واحد</item>
<item quantity="two">متابَعان</item>
<item quantity="few">%,d متابَعين</item>
<item quantity="many">%,d متابَعًا</item>
<item quantity="other">%,d متابَع</item>
</plurals>
<plurals name="x_favorites">
<item quantity="zero">دون تفضيلات</item>
<item quantity="one">تفضيل واحد</item>
<item quantity="two">تفضيلان</item>
<item quantity="few">%,d تفضيلات</item>
<item quantity="many">%,d تفضيلًا</item>
<item quantity="other">%,d تفضيل</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="zero">لا إعادات تدوين</item>
<item quantity="one">إعاد تدوين واحدة</item>
<item quantity="two">إعادتا تدوين</item>
<item quantity="few">%,d إعادات تدوين</item>
<item quantity="many">%,d إعادة تدوين</item>
<item quantity="other">%,d إعادة تدوين</item>
</plurals>
<string name="timestamp_via_app">%1$s عبر %2$s</string>
<string name="time_now">الآن</string>
<string name="post_info_reblogs">إعادات التدوين</string>
<string name="post_info_favorites">المفضلة</string>
<string name="edit_history">تاريخ التعديل</string>
<string name="last_edit_at_x">آخر تعديل %s</string>
<string name="time_just_now">للتوّ</string>
<plurals name="x_seconds_ago">
<item quantity="zero">منذ %d ثانية</item>
<item quantity="one">منذ ثانية</item>
<item quantity="two">منذ ثانيتان</item>
<item quantity="few">%d ثواني</item>
<item quantity="many">منذ %d ثانية</item>
<item quantity="other">%d ثواني مضت</item>
</plurals>
<plurals name="x_minutes_ago">
<item quantity="zero">الان</item>
<item quantity="one">منذ دقيقة</item>
<item quantity="two">منذ دقيقتان</item>
<item quantity="few">%d دقائق مضت</item>
<item quantity="many">منذ %d دقائق</item>
<item quantity="other">منذ %d دقائق</item>
</plurals>
<string name="edited_timestamp">عُدّل في %s</string>
<string name="edit_original_post">المنشور الأصلي</string>
<string name="edit_text_edited">تم تعديل النص</string>
<string name="edit_spoiler_added">تم إضافة تحذير المحتوى</string>
<string name="edit_spoiler_edited">تم تعديل تحذير المحتوى</string>
<string name="edit_spoiler_removed">تم حذف تحذير المحتوى</string>
<string name="edit_poll_added">تمت إضافة استطلاع للرأي</string>
<string name="edit_poll_edited">تم تعديل الاستطلاع</string>
<string name="edit_poll_removed">تمت إزالة الاستطلاع</string>
<string name="edit_media_added">تمت إضافة الوسائط</string>
<string name="edit_media_removed">تمت إزالة الوسائط</string>
<string name="edit_media_reordered">تمت إعادة ترتيب الوسائط</string>
<string name="edit_marked_sensitive">مُعَين كحساس</string>
<string name="edit_marked_not_sensitive">مُعَين كمنشور غير حساس</string>
<string name="edit_multiple_changed">عُدّل المنشور</string>
<string name="edit">تعديل</string>
<string name="discard_changes">تجاهل التغييرات؟</string>
<string name="upload_failed">فشلت عملية التحميل</string>
<string name="file_size_bytes">%d بايت</string>
<string name="file_size_kb">%.2f كيلوبايت</string>
<string name="file_size_mb">%.2f ميغابايت</string>
<string name="file_size_gb">%.2f جيجابايت</string>
<string name="file_upload_progress">%1$s من %2$s</string>
<string name="file_upload_time_remaining">%s متبقية</string>
<string name="upload_error_connection_lost">فقد جهازك الاتصال بالإنترنت</string>
<string name="upload_processing">قيد المعالجة…</string>
<!-- %s is version like 1.2.3 -->
<string name="update_available">ماستدون %s للأندرويد جاهز للتنزيل.</string>
<!-- %s is version like 1.2.3 -->
<string name="update_ready">تم تنزيل ماستدون %s للأندرويد ومستعد لتثبيته.</string>
<!-- %s is file size -->
<string name="download_update">جارٍ التنزيل (%s)</string>
<string name="install_update">تثبيت</string>
<string name="privacy_policy_title">ماستدون وخصوصيتك</string>
<string name="privacy_policy_subtitle">على الرغم من أن تطبيق ماستدون لا يجمع أي بيانات، فإن الخادم الذي قمت بالتسجيل من خلاله قد تكون له سياسة مختلفة. خذ دقيقة للمراجعة والموافقة على سياسة خصوصية التطبيق ماستدون وسياسة الخصوصية للخادم الخاص بك.</string>
<string name="i_agree">أنا مُوافِق</string>
<string name="empty_list">هذه القائمة فارغة</string>
<string name="confirm_delete_and_redraft">هل أنت متأكد أنك تريد حذف وإعادة صياغة هذا المنشور؟</string>
<string name="visibility_unlisted">غير مدرج</string>
<string name="list_timelines">القوائم</string>
<string name="follow_requests">طلبات المتابعة</string>
<string name="instance_signup_closed">هذا الخادم لا يقبل تسجيلات جديدة.</string>
<string name="pinned_posts">مدبّس</string>
<string name="delete_and_redraft">حذف وإعادة الصياغة</string>
<string name="confirm_delete_and_redraft_title">حذف وإعادة صياغة الرسالة</string>
<string name="pin_post">تدبيس على الصفحة الشخصية</string>
<string name="confirm_pin_post_title">تدبيس الرسالة على الصفحة الشخصية</string>
<string name="settings_show_federated_timeline">إظهار الخيط الفديرالي</string>
<string name="settings_contribute_fork">المساهمة في Megalodon</string>
<string name="accept_follow_request">قبول طلب المتابعة</string>
<string name="reject_follow_request">رفض طلب المتابعة</string>
<string name="lists_with_user">قوائم بها %s</string>
<string name="text_copied">تم النسخ إلى الحافظة</string>
<string name="add_bookmark">إضافة إلى الفواصل المرجعية</string>
<string name="remove_bookmark">إزالة من الفواصل المرجعية</string>
<string name="bookmarks">الفواصل المرجعية</string>
<string name="your_favorites">مفضلاتك</string>
</resources>

View File

@@ -10,13 +10,11 @@
<string name="ok">حسنًا</string>
<string name="preparing_auth">جَارٍ الإعدَادُ لِلمُصادَقَة…</string>
<string name="finishing_auth">يُنهي المصادقة…</string>
<string name="user_boosted">أعادَ %s تَدوينَها</string>
<string name="in_reply_to">ردًا على %s</string>
<string name="notifications">الإشعارات</string>
<string name="user_followed_you">بَدَأ بِمُتابَعَتِك</string>
<string name="user_sent_follow_request">أرسَلَ طَلَبًا لِمُتابَعَتِك</string>
<string name="user_favorited">فَضَّلَ مَنشُورَك</string>
<string name="notification_boosted">أعادَ تَدوينَ مَنشُورِك</string>
<string name="poll_ended">انتهى استطلاعُ الرأي</string>
<string name="time_seconds">%d ثا</string>
<string name="time_minutes">%d د</string>
@@ -222,7 +220,6 @@
<string name="report_sent_subtitle">في أثناء مراجعتنا للبلاغ، يمكنك اتخاذ إجراء ضد @%s.</string>
<string name="unfollow_user">ألغ متابعة %s</string>
<string name="unfollow">ألغ المتابعة</string>
<string name="mute_user_explain">لن ترى منشوراتهم أو إعادة تدوينهم في التغذية الرئيسية. ولن يعلموا أنهم كتموا.</string>
<string name="block_user_explain">لن يتمكنوا من متابعتك أو رؤية منشوراتك، وسيكون بديهيًا لهم أنهم حجبوا.</string>
<string name="report_personal_title">لاترغب في مشاهدة هذا؟</string>
<string name="report_personal_subtitle">عندما ترى ما لا يعجبك في ماستدون، يمكنك إزالة صاحبها من تجربتك كمستخدم.</string>
@@ -279,7 +276,6 @@
<string name="skip">تخطى</string>
<string name="notification_type_follow">متابعُون جُدُد</string>
<string name="notification_type_favorite">المفضلة</string>
<string name="notification_type_reblog">المعاد تدوينها</string>
<string name="notification_type_mention">الذِكر</string>
<string name="notification_type_poll">استطلاع رأي</string>
<string name="choose_account">اختر حسابًا</string>
@@ -310,7 +306,6 @@
<string name="notify_none">لَا أحد</string>
<string name="notify_favorites">بِالإعْجاب بِمَنشوري</string>
<string name="notify_follow">بمتابعتي</string>
<string name="notify_reblog">بإعادة تدوين مَنشوري</string>
<string name="notify_mention">بِالإشارَةِ إليّ</string>
<string name="settings_boring">المنطِقَةُ المُملَّة</string>
<string name="settings_account">إعدادات الحساب</string>
@@ -331,7 +326,6 @@
<string name="hide_content">اخف المحتوى</string>
<string name="new_post">منشور جديد</string>
<string name="button_reply">ردّ</string>
<string name="button_reblog">أعد تدوين</string>
<string name="button_favorite">فضّل</string>
<string name="button_share">شارك</string>
<string name="media_no_description">وسائط بدون وصف</string>
@@ -346,8 +340,6 @@
<string name="unfollowed_user">ألغ متابعة %s</string>
<string name="followed_user">أنت تتابع %s</string>
<string name="open_in_browser">افتح في المتصفح</string>
<string name="hide_boosts_from_user">اخف ما أعاد %s تدوينه</string>
<string name="show_boosts_from_user">أظهر ما أعاد %s تدوينه</string>
<string name="signup_reason">لماذا تريد الانضمام؟</string>
<string name="signup_reason_note">هذا سوف يساعدنا في مراجعة تطبيقك.</string>
<string name="clear">امسح</string>
@@ -401,17 +393,8 @@
<item quantity="many">%,d تفضيلًا</item>
<item quantity="other">%,d تفضيل</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="zero">لا إعادات تدوين</item>
<item quantity="one">إعاد تدوين واحدة</item>
<item quantity="two">إعادتا تدوين</item>
<item quantity="few">%,d إعادات تدوين</item>
<item quantity="many">%,d إعادة تدوين</item>
<item quantity="other">%,d إعادة تدوين</item>
</plurals>
<string name="timestamp_via_app">%1$s عبر %2$s</string>
<string name="time_now">الآن</string>
<string name="post_info_reblogs">إعادات التدوين</string>
<string name="post_info_favorites">المفضلة</string>
<string name="edit_history">تاريخ التعديل</string>
<string name="last_edit_at_x">آخر تعديل %s</string>
@@ -478,12 +461,6 @@
<string name="login_title">مرحبا بك مجددًا</string>
<string name="login_subtitle">قم بتسجيل الدخول باستخدام الخادم حيث قمتَ بإنشاء حسابك فيه.</string>
<string name="server_url">رابط الخادم</string>
<string name="welcome_page1_title">ما هو ماستدون؟</string>
<string name="welcome_page1_text">تخيل أن لديك عنوان بريد إلكتروني ينتهي بـ @example.com.\n\n رغم ذلك يمكنك إرسال واستقبال رسائل البريد الإلكتروني من أي شخص، حتى إذا كان بريدهم الإلكتروني الخاص ينتهي بـ @gmail.com أو @icloud.com أو @example.com.</string>
<string name="welcome_page2_title">ماستدون هكذا.</string>
<string name="welcome_page2_text">قد يكون مُعرّفُك @gothgirl654@example.social ، ولكنه بإمكانك متابعة وإعادة تدوين ومحادثة @fallout5ever@example.online.</string>
<string name="welcome_page3_title">كيف يمكنني اختيار خادم؟</string>
<string name="welcome_page3_text">يختار الأشخاص المختلفون خوادم مختلفة لأي عدد من الأسباب. يعد art.example مكانًا رائعًا للفنانين ، بينما قد يكون glasgow.example اختيارًا جيدًا للاسكتلنديين. \n\n لا يمكنك أن تخطئ في أي من الخوادم التي نوصي بها ، لذلك بغض النظر عن أي واحد تختاره (أو إذا قمت بإدخال الخادم الخاص بك في شريط البحث) ، فلن يفوتك أي شيء في أي مكان.</string>
<string name="signup_random_server_explain">سوف نختار خادماً بناءً على لغتك إذا قمت بالمتابعة دون إجراء إختيار.</string>
<string name="server_filter_any_language">أي لغة</string>
<string name="server_filter_instant_signup">تسجيل فوري</string>

View File

@@ -10,13 +10,11 @@
<string name="ok">Добра</string>
<string name="preparing_auth">Падрыхтоўка да аўтэнтыфікацыі…</string>
<string name="finishing_auth">Завяршэнне аўтэнтыфікацыі…</string>
<string name="user_boosted">%s пашырыў</string>
<string name="in_reply_to">У адказ %s</string>
<string name="notifications">Апавяшчэнні</string>
<string name="user_followed_you">падпісаўся(-лася) на вас</string>
<string name="user_sent_follow_request">адправіў запыт на падпіску</string>
<string name="user_favorited">упадабаў(-ла) ваш допіс</string>
<string name="notification_boosted">пашырыў(-ла) ваш допіс</string>
<string name="poll_ended">апытанне завершана</string>
<string name="time_seconds">%dсек</string>
<string name="time_minutes">%dхв</string>
@@ -194,7 +192,6 @@
<string name="report_sent_subtitle">Пакуль мы разглядаем яе, вы можаце прыняць меры супраць %s.</string>
<string name="unfollow_user">Адпісацца ад %s</string>
<string name="unfollow">Адпісацца</string>
<string name="mute_user_explain">Вы не ўбачыце іх допісы або пашырэнні ў сваёй хатняй стужцы. Яны не даведаюцца, што вы іх ігнаруеце.</string>
<string name="block_user_explain">Яны больш не змогуць падпісвацца на вас або бачыць вашыя допісы, але змогуць бачыць, што яны былі заблакіраваны.</string>
<string name="report_personal_title">Не хочаце бачыць гэта?</string>
<string name="report_personal_subtitle">Калі вы бачыце на Mastodon нешта, што вам не падабаецца, вы можаце выдаліць чалавека са свайго асяроддзя.</string>
@@ -203,6 +200,7 @@
<string name="instance_catalog_subtitle">Выбірайце сервер у залежнасці ад вашых інтарэсаў, рэгіёна або выберыце сервер агульнага прызначэння. Вы па-ранейшаму можаце ўзаемадзейнічаць з усімі, незалежна ад сервера.</string>
<string name="search_communities">Назва сервера або URL</string>
<string name="instance_rules_title">Правілы сервера</string>
<string name="instance_rules_subtitle">Працягваючы, вы згаджаецеся выконваць правілы, устаноўленыя мадэратарам %s.</string>
<string name="signup_title">Стварыць уліковы запіс</string>
<string name="edit_photo">рэдагаваць</string>
<string name="display_name">Імя</string>
@@ -226,6 +224,8 @@
<string name="category_tech">Тэхналогіі</string>
<string name="confirm_email_title">Праверце паштовую скрыню</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Націсніце на спасылку, якую мы адправілі, каб спраўдзіць %s. Мы вас пачакаем тут.</string>
<string name="confirm_email_didnt_get">Не атрымалі спасылку?</string>
<string name="resend">Адправіць паўторна</string>
<string name="open_email_app">Адкрыць праграму для пошты</string>
<string name="resent_email">Электронны ліст з пацвярджэннем адпраўлены</string>
@@ -248,7 +248,6 @@
<string name="skip">Прапусціць</string>
<string name="notification_type_follow">Новыя падпісчыкі</string>
<string name="notification_type_favorite">Абраныя</string>
<string name="notification_type_reblog">Пашырэнні</string>
<string name="notification_type_mention">Згадванні</string>
<string name="notification_type_poll">Апытанні</string>
<string name="choose_account">Выберыце ўліковы запіс</string>
@@ -277,7 +276,6 @@
<string name="notify_none">ніхто</string>
<string name="notify_favorites">Дадае мой допіс у абранае</string>
<string name="notify_follow">Падпісаўся на мяне</string>
<string name="notify_reblog">Пашырае мой допіс</string>
<string name="notify_mention">Згадвае мяне</string>
<string name="settings_boring">Нудная зона</string>
<string name="settings_account">Налады ўліковага запісу</string>
@@ -298,7 +296,6 @@
<string name="hide_content">Схаваць змест</string>
<string name="new_post">Новы допіс</string>
<string name="button_reply">Адказаць</string>
<string name="button_reblog">Пашырыць</string>
<string name="button_favorite">Абранае</string>
<string name="button_share">Абагуліць</string>
<string name="media_no_description">Медыя без апісання</string>
@@ -312,9 +309,9 @@
<string name="follow_user">Падпісацца на %s</string>
<string name="unfollowed_user">Адпісацца ад %s</string>
<string name="followed_user">Цяпер вы падпісаны на %s</string>
<string name="following_user_requested">Запытана падпісацца на %s</string>
<string name="open_in_browser">Адкрыць у браўзеры</string>
<string name="hide_boosts_from_user">Схаваць пашырэнні ад %s</string>
<string name="show_boosts_from_user">Паказаць пашырэнні ад %s</string>
<string name="signup_reason">Чаму вы хочаце далучыцца?</string>
<string name="signup_reason_note">Гэта дапаможа нам разгледзець вашу заяўку.</string>
<string name="clear">Ачысціць</string>
<string name="profile_header">Відарыс шапкі</string>
@@ -361,15 +358,8 @@
<item quantity="many">%,d абраных</item>
<item quantity="other">%,d абраных</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d рэпост</item>
<item quantity="few">%,d рэпосты</item>
<item quantity="many">%,d пашырэнняў</item>
<item quantity="other">%,d пашырэнняў</item>
</plurals>
<string name="timestamp_via_app">%1$s праз %2$s</string>
<string name="time_now">толькі што</string>
<string name="post_info_reblogs">Пашырэнні</string>
<string name="post_info_favorites">Абраныя</string>
<string name="edit_history">Гісторыя рэдагавання</string>
<string name="last_edit_at_x">Апошняе рэдагаванне %s</string>
@@ -419,6 +409,8 @@
<!-- %s is file size -->
<string name="download_update">Спампаваць (%s)</string>
<string name="install_update">Усталяваць</string>
<string name="privacy_policy_title">Ваша прыватнасць</string>
<string name="privacy_policy_subtitle">Нягледзячы на ​​тое, што праграма Mastodon не збірае даных, сервер, на якім вы рэгіструецеся, можа мець іншую палітыку.\n\nКалі вы адмовіцеся ад палітыкі %s, вы можаце вярнуцца і выбраць іншы сервер.</string>
<string name="i_agree">Я згодны</string>
<string name="empty_list">Гэты ліст пусты</string>
<string name="instance_signup_closed">Гэты сервер не прымае новыя рэгістрацыі.</string>
@@ -430,20 +422,35 @@
<string name="login_title">З вяртаннем</string>
<string name="login_subtitle">Увайдзіце з дапамогай сервера, на якім вы стварылі свой уліковы запіс.</string>
<string name="server_url">URL-адрас сервера</string>
<string name="welcome_page1_text">Уявіце, што ў вас ёсць адрас электроннай пошты, які заканчваецца на @example.com.\n\nВы па-ранейшаму можаце адпраўляць і атрымліваць электронныя лісты ад каго захочаце, нават калі іх электронная пошта заканчваецца на @gmail.com, @icloud.com або @example.com.</string>
<string name="welcome_page2_title">Mastodon такі.</string>
<string name="welcome_page2_text">Ваш ідэнтыфікатар можа быць @gothgirl654@example.social, але вы ўсё яшчэ можаце падпісвацца, пашыраць і перапісвацца з @fallout5ever@example.online.</string>
<string name="welcome_page3_title">Як выбраць сервер?</string>
<string name="welcome_page3_text">Розныя людзі выбіраюць розныя серверы па розных прычынах. art.example з\'яўляецца выдатным месцам для мастакоў, у той час як glasgow.example можа быць добрым выбарам для шатландцаў.\n\nВы не памыліцеся ні з адным з нашых рэкамендаваных сервераў, так што незалежна ад таго, які вы выбераце (або калі ўведзяце ваш уласны ў радку пошуку сервера), вы нідзе нічога не прапусціце.</string>
<string name="signup_random_server_explain">Мы абярэм сервер на аснове вашай мовы, калі вы працягнеце без выбару.</string>
<string name="server_filter_any_language">Любая мова</string>
<string name="server_filter_instant_signup">Імгненная рэгістрацыя</string>
<string name="server_filter_manual_review">Ручная праверка</string>
<string name="server_filter_any_signup_speed">Любая хуткасць рэгістрацыі</string>
<string name="server_filter_region_europe">Еўропа</string>
<string name="server_filter_region_north_america">Паўночная Амерыка</string>
<string name="server_filter_region_south_america">Паўднёвая Амерыка</string>
<string name="server_filter_region_africa">Афрыка</string>
<string name="server_filter_region_asia">Азія</string>
<string name="server_filter_region_oceania">Акіянія</string>
<string name="not_accepting_new_members">Не прымае новых удзельнікаў</string>
<string name="category_special_interests">Асаблівыя інтарэсы</string>
<string name="signup_passwords_dont_match">Паролі не супадаюць</string>
<string name="pick_server_for_me">Падбяры для мяне</string>
<string name="profile_add_row">Дадаць радок</string>
<string name="profile_setup">Налады профілю</string>
<string name="profile_setup_subtitle">Вы можаце завяршыць гэта пазней на ўкладцы Профіль.</string>
<string name="profile_setup_explanation">Вы можаце дадаць да чатырох палёў профіля для ўсяго, што хочаце. Месцазнаходжанне, спасылкі, займеннікі - няма мяжы магчымасцям.</string>
<string name="popular_on_mastodon">Папулярна на Mastodon</string>
<string name="follow_all">Падпісацца на ўсіх</string>
<string name="server_rules_disagree">Не згодны</string>
<string name="privacy_policy_explanation">Мы нічога не збіраем і не апрацоўваем.</string>
<!-- %s is server domain -->
<string name="server_policy_disagree">Не згодны з %s</string>
<string name="profile_bio">Пра мяне</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">Падпісваемся…</string>
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
<string name="signup_email_domain_blocked">%1$s не прымае рэгістрацыю ад %2$s. Паспрабуйце іншы &lt;a&gt;выберыце іншы сервер&lt;/a&gt;.</string>
<string name="signup_username_taken">Гэта імя карыстальніка занята.</string>
</resources>

View File

@@ -12,7 +12,6 @@
<string name="user_followed_you">আপনাকে ফলো করেছেন</string>
<string name="user_sent_follow_request">ফলো করার জন্য অনুরোধ পাঠানো হয়েছে</string>
<string name="user_favorited">আপনার পোস্টটি পছন্দ করেছেন</string>
<string name="notification_boosted">আপনার পোস্টের প্রচার করা হয়েছে</string>
<string name="poll_ended">ভোট শেষ</string>
<string name="time_seconds">%d সে.</string>
<string name="time_minutes">%d মি.</string>

View File

@@ -123,7 +123,6 @@
<string name="report_sent_subtitle">Dok ovo razmatramo, možete poduzeti potrebno za %s.</string>
<string name="unfollow_user">Prestani pratiti %s</string>
<string name="unfollow">Prestani pratiti</string>
<string name="mute_user_explain">Nećete vidjeti objave i odgovore na vašem zidu. Osoba neče znati da ste je isključili.</string>
<string name="block_user_explain">Neće moći više pratiti vaše objave, ali mogu vidjeti ako su blokirani.</string>
<string name="report_personal_title">Ne želite ovo vidjeti?</string>
<string name="report_personal_subtitle">Kada vidite nešto nepoželjno na Mastodon-u, možete blokirati odredjeni profil.</string>
@@ -193,7 +192,6 @@
<string name="notify_none">nikoga</string>
<string name="notify_favorites">Svidjanje objave</string>
<string name="notify_follow">Prati me</string>
<string name="notify_reblog">Ponovio/la moju objavu</string>
<string name="notify_mention">Spominjanje</string>
<string name="settings_boring">Zona dosade</string>
<string name="settings_account">Postavke računa</string>
@@ -214,7 +212,6 @@
<string name="hide_content">Sakrij sadžaj</string>
<string name="new_post">Nova objava</string>
<string name="button_reply">Odgovori</string>
<string name="button_reblog">Dupliraj</string>
<string name="button_favorite">Svidja mi se</string>
<string name="button_share">Dijeli</string>
<string name="media_no_description">Medija bez opisa</string>

View File

@@ -10,13 +10,11 @@
<string name="ok">D\'acord</string>
<string name="preparing_auth">Preparant l\'autenticació…</string>
<string name="finishing_auth">Finalitzant l\'autenticació…</string>
<string name="user_boosted">%s ha impulsat</string>
<string name="in_reply_to">En resposta a %s</string>
<string name="notifications">Notificacions</string>
<string name="user_followed_you">t\'ha seguit</string>
<string name="user_sent_follow_request">ha sol·licitat seguir-te</string>
<string name="user_favorited">ha afavorit la teva publicació</string>
<string name="notification_boosted">ha impulsat la teva publicació</string>
<string name="poll_ended">l\'enquesta ha finalitzat</string>
<string name="time_seconds">%d s</string>
<string name="time_minutes">%d min</string>
@@ -166,7 +164,6 @@
<string name="report_sent_subtitle">Mentre ho revisem, pots prendre mesures contra %s.</string>
<string name="unfollow_user">Deixar de seguir %s</string>
<string name="unfollow">Deixar de seguir</string>
<string name="mute_user_explain">No veuràs les seves publicacions o impulsos a la teva línia de temps personal. No sabran que han estat silenciats.</string>
<string name="block_user_explain">Ja no podran seguir ni veure les teves publicacions, però poden veure si han estat bloquejats.</string>
<string name="report_personal_title">No vols veure això?</string>
<string name="report_personal_subtitle">Quan veus alguna cosa que no t\'agrada a Mastodon, pots eliminar la persona de la vostra experiència.</string>
@@ -221,7 +218,6 @@
<string name="skip">Omet</string>
<string name="notification_type_follow">Seguidors nous</string>
<string name="notification_type_favorite">Favorits</string>
<string name="notification_type_reblog">Impulsos</string>
<string name="notification_type_mention">Mencions</string>
<string name="notification_type_poll">Enquestes</string>
<string name="choose_account">Selecciona un compte</string>
@@ -248,7 +244,6 @@
<string name="notify_none">ningú</string>
<string name="notify_favorites">Ha afavorit la meva publicació</string>
<string name="notify_follow">Em segueix</string>
<string name="notify_reblog">Impulsa la meva publicació</string>
<string name="notify_mention">Em menciona</string>
<string name="settings_boring">La zona avorrida</string>
<string name="settings_account">Configuració del compte</string>
@@ -269,7 +264,6 @@
<string name="hide_content">Amaga el contingut</string>
<string name="new_post">Nova publicació</string>
<string name="button_reply">Respon</string>
<string name="button_reblog">Impulsa</string>
<string name="button_favorite">Favorit</string>
<string name="button_share">Comparteix</string>
<string name="media_no_description">Multimèdia sense descripció</string>
@@ -284,8 +278,6 @@
<string name="unfollowed_user">S\'ha deixat de seguir %s</string>
<string name="followed_user">Ara estàs seguint %s</string>
<string name="open_in_browser">Obre al navegador</string>
<string name="hide_boosts_from_user">Amaga els impulsos de %s</string>
<string name="show_boosts_from_user">Mostra els impulsos de %s</string>
<string name="signup_reason_note">Això ens ajudarà a revisar la teva petició.</string>
<string name="clear">Esborra</string>
<string name="profile_header">Imatge de capçalera</string>
@@ -326,13 +318,8 @@
<item quantity="one">%,d favorit</item>
<item quantity="other">%,d favorits</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d impuls</item>
<item quantity="other">%,d impulsos</item>
</plurals>
<string name="timestamp_via_app">%1$s través de %2$s</string>
<string name="time_now">ara</string>
<string name="post_info_reblogs">Impulsos</string>
<string name="post_info_favorites">Favorits</string>
<string name="edit_history">Editar lhistorial</string>
<string name="last_edit_at_x">Darrera edició: %s</string>

View File

@@ -69,7 +69,7 @@
<string name="sk_translated_using">Traduït amb %s</string>
<string name="sk_post_language">Llengua: %s</string>
<string name="sk_available_languages">Llengües disponibles</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_language_name">%1$s (%2$s)</string>
<string name="sk_confirm_clear_recent_languages">Segur que vols esborrar les llengües recents\?</string>
<string name="sk_welcome_text">El tauró et saluda! Per a començar, introdueix el domini de la instància a continuació.</string>
<string name="sk_tabs_disable_swipe">Desactiva el desplaçament entre pestanyes</string>

View File

@@ -10,13 +10,11 @@
<string name="ok">OK</string>
<string name="preparing_auth">Příprava na autentizaci…</string>
<string name="finishing_auth">Dokončení autentizace…</string>
<string name="user_boosted">Uživatel %s boostnul</string>
<string name="in_reply_to">V odpovědi na %s</string>
<string name="notifications">Upozornění</string>
<string name="user_followed_you">vás začal(a) sledovat</string>
<string name="user_sent_follow_request">vám poslal(a) žádost o sledování</string>
<string name="user_favorited">si oblíbil(a) váš příspěvek</string>
<string name="notification_boosted">boostnul(a) váš příspěvek</string>
<string name="poll_ended">anketa skončila</string>
<string name="time_seconds">%d s</string>
<string name="time_minutes">%d m</string>
@@ -194,14 +192,22 @@
<string name="report_sent_subtitle">Zatímco to posuzujeme, můžete podniknout akce proti %s.</string>
<string name="unfollow_user">Přestat sledovat %s</string>
<string name="unfollow">Přestat sledovat</string>
<string name="mute_user_explain">Neuvidíte příspěvky nebo boosty tohoto uživatele ve svém domovském kanálu. Nebude vědět, že je skryt.</string>
<string name="block_user_explain">Tento uživatel vás již nebude moci sledovat ani vidět vaše příspěvky, ale může zjistit, že je blokován.</string>
<string name="report_personal_title">Nechcete tohle vidět?</string>
<string name="report_personal_subtitle">Když uvidíte něco, co se vám nelíbí na Mastodonu, můžete odstranit tuto osobu ze svého zážitku.</string>
<string name="back">Zpět</string>
<string name="instance_catalog_title">Mastodon tvoří uživatelé z různých serverů.</string>
<string name="instance_catalog_subtitle">Vyberte si server podle na svých zájmů, regionu nebo obecného účelu. Stále se můžete spojit se všemi bez ohledu na server.</string>
<string name="search_communities">Název nebo URL serveru</string>
<string name="instance_rules_title">Pravidla serveru</string>
<string name="instance_rules_subtitle">Pokračováním souhlasíte s následujícími pravidly, která jsou nastavena a prosazována moderátory %s.</string>
<string name="signup_title">Vytvořit účet</string>
<string name="edit_photo">upravit</string>
<string name="display_name">Jméno</string>
<string name="username">Uživatelské jméno</string>
<string name="email">E-mail</string>
<string name="password">Heslo</string>
<string name="confirm_password">Potvrdit heslo</string>
<string name="password_note">Použijte velká písmena, speciální znaky a čísla, abyste zvýšili sílu hesla.</string>
<string name="category_academia">Akademická sféra</string>
<string name="category_activism">Aktivismus</string>
@@ -216,7 +222,10 @@
<string name="category_music">Hudba</string>
<string name="category_regional">Regionální</string>
<string name="category_tech">Technologie</string>
<string name="confirm_email_title">Zkontrolujte si příchozí poštu</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Klepněte na odkaz, který jsme vám poslali, abyste ověřili %s. Budeme tu na vás čekat.</string>
<string name="confirm_email_didnt_get">Nedostali jste odkaz?</string>
<string name="resend">Poslat znovu</string>
<string name="open_email_app">Otevřít e-mailovou aplikaci</string>
<string name="resent_email">Potvrzující e-mail byl odeslán</string>
@@ -239,7 +248,6 @@
<string name="skip">Přeskočit</string>
<string name="notification_type_follow">Noví sledující</string>
<string name="notification_type_favorite">Oblíbené</string>
<string name="notification_type_reblog">Boosty</string>
<string name="notification_type_mention">Zmínky</string>
<string name="notification_type_poll">Ankety</string>
<string name="choose_account">Vybrat účet</string>
@@ -268,7 +276,6 @@
<string name="notify_none">nikoho</string>
<string name="notify_favorites">Oblíbí si můj příspěvek</string>
<string name="notify_follow">Začne mě sledovat</string>
<string name="notify_reblog">Boostne můj příspěvek</string>
<string name="notify_mention">Zmíní mě</string>
<string name="settings_boring">Nudná část</string>
<string name="settings_account">Nastavení účtu</string>
@@ -289,7 +296,6 @@
<string name="hide_content">Skrýt obsah</string>
<string name="new_post">Nový příspěvek</string>
<string name="button_reply">Odpovědět</string>
<string name="button_reblog">Boostnout</string>
<string name="button_favorite">Oblíbit</string>
<string name="button_share">Sdílet</string>
<string name="media_no_description">Média bez popisu</string>
@@ -303,9 +309,9 @@
<string name="follow_user">Sledovat %s</string>
<string name="unfollowed_user">Sledování %s bylo zrušeno</string>
<string name="followed_user">Nyní sledujete %s</string>
<string name="following_user_requested">Požádáno o sledování %s</string>
<string name="open_in_browser">Otevřít v prohlížeči</string>
<string name="hide_boosts_from_user">Skrýt boosty od %s</string>
<string name="show_boosts_from_user">Zobrazit boosty od %s</string>
<string name="signup_reason">Proč se chcete připojit?</string>
<string name="signup_reason_note">Toto nám pomůže posoudit vaši žádost.</string>
<string name="clear">Vyčistit</string>
<string name="profile_header">Obrázek v záhlaví</string>
@@ -352,15 +358,8 @@
<item quantity="many">%,d oblíbení</item>
<item quantity="other">%,d oblíbení</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d boostnul</item>
<item quantity="few">%,d boosty</item>
<item quantity="many">%,d boostů</item>
<item quantity="other">%,d boostů</item>
</plurals>
<string name="timestamp_via_app">%1$s přes %2$s</string>
<string name="time_now">teď</string>
<string name="post_info_reblogs">Boosty</string>
<string name="post_info_favorites">Oblíbení</string>
<string name="edit_history">Historie úprav</string>
<string name="last_edit_at_x">Poslední úprava %s</string>
@@ -410,6 +409,8 @@
<!-- %s is file size -->
<string name="download_update">Stáhnout (%s)</string>
<string name="install_update">Instalovat</string>
<string name="privacy_policy_title">Vaše soukromí</string>
<string name="privacy_policy_subtitle">Přestože aplikace Mastodon neshromažďuje žádná data, server, který se přihlásíte, může mít jiné zásady.\n\nPokud nesouhlasíte se zásadami pro %s, můžete se vrátit a vybrat jiný server.</string>
<string name="i_agree">Souhlasím</string>
<string name="empty_list">Tento seznam je prázdný</string>
<string name="instance_signup_closed">Tento server nepřijímá nové registrace.</string>
@@ -421,12 +422,35 @@
<string name="login_title">Vítejte zpět</string>
<string name="login_subtitle">Přihlaste se pomocí serveru, kde jste vytvořili svůj účet.</string>
<string name="server_url">URL serveru</string>
<string name="welcome_page1_text">Představte si, že máte e-mailovou adresu, která končí @example.com.\n\nStále můžete od kohokoliv odesílat a přijímat e-maily, i když jejich e-mail končí na @gmail.com nebo @icloud.com nebo @example.com.</string>
<string name="welcome_page2_title">Takový je Mastodon.</string>
<string name="welcome_page2_text">Vaše uživatelské jméno může být @gothgirl654@example.social, ale stále můžete sledovat, boostovat a chatovat s @fallout5ever@example.online.</string>
<string name="welcome_page3_title">Jak si vybrat server?</string>
<string name="welcome_page3_text">Různí lidé si vybírají různé servery z různých důvodů. Art.example je skvělým místem pro umělce, zatímco glasgow.example může být dobrou volbou pro Skoty.\n\nS žádným z našich doporučených serverů nemůžete udělat chybu, takže bez ohledu na to, který z nich si vyberete (nebo pokud zadáte svůj vlastní do vyhledávacího řádku serveru), nikde neprohloupíte.</string>
<string name="signup_random_server_explain">Pokud budete pokračovat bez výběru, vybereme server založený na vašem jazyce.</string>
<string name="server_filter_any_language">Libovolný jazyk</string>
<string name="server_filter_instant_signup">Okamžitá registrace</string>
<string name="server_filter_manual_review">Ruční kontrola</string>
<string name="server_filter_any_signup_speed">Jakákoliv rychlost registrace</string>
<string name="server_filter_region_europe">Evropa</string>
<string name="server_filter_region_north_america">Severní Amerika</string>
<string name="server_filter_region_south_america">Jižní Amerika</string>
<string name="server_filter_region_africa">Afrika</string>
<string name="server_filter_region_asia">Asie</string>
<string name="server_filter_region_oceania">Oceánie</string>
<string name="not_accepting_new_members">Nepřijímá nové členy</string>
<string name="category_special_interests">Speciální zájmy</string>
<string name="signup_passwords_dont_match">Hesla se neshodují</string>
<string name="pick_server_for_me">Vybrat pro mě</string>
<string name="profile_add_row">Přidat řádek</string>
<string name="profile_setup">Nastavení profilu</string>
<string name="profile_setup_subtitle">Toto můžete vždy dokončit později v záložce Profil.</string>
<string name="profile_setup_explanation">Můžete přidat až čtyři pole profilu pro cokoliv, co chcete. Umístění, odkazy, oslovení — limitem je obloha.</string>
<string name="popular_on_mastodon">Populární na Mastodonu</string>
<string name="follow_all">Sledovat všechny</string>
<string name="server_rules_disagree">Nesouhlasit</string>
<string name="privacy_policy_explanation">Zkráceně: nic nesbíráme a nezpracováváme.</string>
<!-- %s is server domain -->
<string name="server_policy_disagree">Nesouhlasit s %s</string>
<string name="profile_bio">O vás</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">Sledování uživatelů…</string>
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
<string name="signup_email_domain_blocked">%1$s neumožňuje registraci od %2$s. Zkuste jiný nebo &lt;a&gt;vyberte jiný server&lt;/a&gt;.</string>
<string name="signup_username_taken">Toto uživatelské jméno je obsazené.</string>
</resources>

View File

@@ -40,7 +40,7 @@
<string name="sk_no_update_available">Dim diweddariad ar gael</string>
<string name="sk_check_for_update">Gwirio am ddiweddariad</string>
<string name="sk_poll_allow_multiple">Caniatáu mwy nag un dewis</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_language_name">%1$s (%2$s)</string>
<string name="sk_tabs_disable_swipe">Analluogi llusgo rhwng tabiau</string>
<string name="sk_settings_posting">Dewisiadau postio</string>
<string name="sk_settings_rules">Rheolau</string>

View File

@@ -10,13 +10,13 @@
<string name="ok">Ok</string>
<string name="preparing_auth">Forbereder godkendelse…</string>
<string name="finishing_auth">Afslutter godkendelse…</string>
<string name="user_boosted">%s boostede</string>
<string name="user_boosted">%s fremhævede</string>
<string name="in_reply_to">Som svar til %s</string>
<string name="notifications">Meddelelser</string>
<string name="user_followed_you">begyndte at følge dig</string>
<string name="user_sent_follow_request">sendte dig en følgeanmodning</string>
<string name="user_favorited">favoritmarkerede dit indlæg</string>
<string name="notification_boosted">boostede dit indlæg</string>
<string name="notification_boosted">fremhævede dit indlæg</string>
<string name="poll_ended">afstemning afsluttet</string>
<string name="time_seconds">%ds</string>
<string name="time_minutes">%d m</string>
@@ -166,7 +166,7 @@
<string name="report_sent_subtitle">Mens dette gennemgås, kan du selv bortfiltrere indlæg fra %s.</string>
<string name="unfollow_user">Følg ikke længere %s</string>
<string name="unfollow">Følg ikke længere</string>
<string name="mute_user_explain">Du vil ikke se den pågældendes indlæg eller boosts i din tidslinje. Vedkommende vil ikke få besked om dæmpningen.</string>
<string name="mute_user_explain">Du vil ikke se den pågældendes indlæg eller fremhævninger i din tidslinje. Vedkommende vil ikke få besked om dæmpningen.</string>
<string name="block_user_explain">Vedkommende vil ikke længere kunne følge dig eller se dine indlæg, men vedkommende kan se blokeringen.</string>
<string name="report_personal_title">Ønsker du ikke at se dette?</string>
<string name="report_personal_subtitle">Når du ser noget, du ikke kan lide på Mastodon, kan du fjerne personen fra din tidslinje.</string>
@@ -223,7 +223,7 @@
<string name="skip">Spring over</string>
<string name="notification_type_follow">Nye følgere</string>
<string name="notification_type_favorite">Favoritmarkeringer</string>
<string name="notification_type_reblog">Boosts</string>
<string name="notification_type_reblog">Fremhævninger</string>
<string name="notification_type_mention">Omtaler</string>
<string name="notification_type_poll">Afstemninger</string>
<string name="choose_account">Vælg konto</string>
@@ -250,7 +250,7 @@
<string name="notify_none">ingen</string>
<string name="notify_favorites">Favoritmarkerede mit indlæg</string>
<string name="notify_follow">Følger mig</string>
<string name="notify_reblog">Booster mit indlæg</string>
<string name="notify_reblog">Fremhæver mit indlæg</string>
<string name="notify_mention">Nævner mig</string>
<string name="settings_boring">Den kedelige zone</string>
<string name="settings_account">Kontoindstillinger</string>
@@ -271,7 +271,7 @@
<string name="hide_content">Skjul indhold</string>
<string name="new_post">Nyt indlæg</string>
<string name="button_reply">Svar</string>
<string name="button_reblog">Boost</string>
<string name="button_reblog">Fremhæv</string>
<string name="button_favorite">Favorit</string>
<string name="button_share">Del</string>
<string name="media_no_description">Medier uden beskrivelse</string>
@@ -285,9 +285,10 @@
<string name="follow_user">Følg %s</string>
<string name="unfollowed_user">Følg ikke længere %s</string>
<string name="followed_user">Du følger nu %s</string>
<string name="following_user_requested">Anmodede om at følge %s</string>
<string name="open_in_browser">Åbn i browser</string>
<string name="hide_boosts_from_user">Skjul boosts fra %s</string>
<string name="show_boosts_from_user">Vis boosts fra %s</string>
<string name="hide_boosts_from_user">Skjul fremhævninger fra %s</string>
<string name="show_boosts_from_user">Vis fremhævninger fra %s</string>
<string name="signup_reason">Hvorfor ønsker du at tilmelde dig?</string>
<string name="signup_reason_note">Dette hjælper os med at vurdere din ansøgning.</string>
<string name="clear">Ryd</string>
@@ -330,12 +331,12 @@
<item quantity="other">%,d favoritmarkeringer</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d boost</item>
<item quantity="other">%,d boosts</item>
<item quantity="one">%,d indlæg</item>
<item quantity="other">%,d indlæg</item>
</plurals>
<string name="timestamp_via_app">%1$s via %2$s</string>
<string name="time_now">nu</string>
<string name="post_info_reblogs">Boosts</string>
<string name="post_info_reblogs">Fremhævninger</string>
<string name="post_info_favorites">Favoritmarkeringer</string>
<string name="edit_history">Rediger historik</string>
<string name="last_edit_at_x">Senest ændret: %s</string>
@@ -382,6 +383,7 @@
<string name="download_update">Download (%s)</string>
<string name="install_update">Installer</string>
<string name="privacy_policy_title">Dit privatliv</string>
<string name="privacy_policy_subtitle">Selvom Mastodon-appen ikke indsamler data, kan den server du tilmelder dig gennem, have en anden politik.\n\nHvis du er uenig i politikken for %s, kan du gå tilbage og vælge en anden server.</string>
<string name="i_agree">Jeg accepterer</string>
<string name="empty_list">Denne liste er tom</string>
<string name="instance_signup_closed">Denne server er ikke åben for nye tilmeldinger.</string>
@@ -393,12 +395,6 @@
<string name="login_title">Velkommen tilbage</string>
<string name="login_subtitle">Log ind med serveren hvor du oprettede din bruger.</string>
<string name="server_url">Server-URL</string>
<string name="welcome_page1_title">Hvad er Mastodon?</string>
<string name="welcome_page1_text">Det svarer til at du har en e-mailadresse, der slutter med @eksempel.dk.\n\nAlligevel kan du stadig både sende og modtage e-mails fra alle, selv om deres e-mail ender på @gmail.com eller @icloud.com eller @eksempel.dk.</string>
<string name="welcome_page2_title">Mastodon er ligesådan.</string>
<string name="welcome_page2_text">Dit brugernavn kan være @goth654@eksempel.social, men du kan stadig følge, booste, og chatte med @denanden@eksempel.online.</string>
<string name="welcome_page3_title">Hvordan vælger jeg en server?</string>
<string name="welcome_page3_text">Forskellige mennesker vælger forskellige servere af mange forskellige grunde. art.example er et godt sted for kunstnere, mens glasgow.example kan være et godt pluk for skotter.\n\nDu kan ikke gå galt i byen med en af vores anbefalingsservere, så uanset hvilken du vælger (eller hvis du indtaster din egen i serversøgelinjen), vil du aldrig gå glip af noget nogen steder.</string>
<string name="signup_random_server_explain">Vi vælger en server baseret på dit sprog, hvis du fortsætter uden at foretage et valg.</string>
<string name="server_filter_any_language">Hvilket som helst sprog</string>
<string name="server_filter_instant_signup">Øjeblikkelig tilmelding</string>
@@ -421,7 +417,31 @@
<string name="popular_on_mastodon">Populært på Mastodon</string>
<string name="follow_all">Følg alle</string>
<string name="server_rules_disagree">Ikke enig</string>
<string name="privacy_policy_explanation">TL;DR: Vi indsamler eller behandler ikke noget.</string>
<!-- %s is server domain -->
<string name="server_policy_disagree">Uenig med %s</string>
<string name="profile_bio">Biografi</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">Følger brugere …</string>
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
<string name="signup_email_domain_blocked">%1$s tillader ikke tilmeldinger fra %2$s. Prøv en anden eller &lt;a&gt;vælg en anden server&lt;/a&gt;.</string>
<string name="signup_username_taken">Brugernavnet er allerede i brug.</string>
<string name="spoiler_show">Vis alligevel</string>
<string name="spoiler_hide">Genskjul</string>
<string name="poll_multiple_choice">Vælg en eller flere</string>
<string name="save_changes">Gem ændringer</string>
<string name="profile_featured">Fremhævet</string>
<string name="profile_timeline">Tidslinje</string>
<string name="view_all">Se alle</string>
<string name="profile_endorsed_accounts">Konti</string>
<string name="verified_link">Bekræftet link</string>
<string name="show">Vis</string>
<string name="hide">Skjul</string>
<string name="join_default_server">Tilmeld dig %s</string>
<string name="signup_or_login">eller</string>
<string name="learn_more">Få mere at vide</string>
<string name="welcome_to_mastodon">Velkommen til Mastodon</string>
<string name="welcome_paragraph1">Mastodon er et decentraliseret socialt netværk, hvilket betyder at ingen enkelt virksomhed styrer det. Det består af mange uafhængige servere, alle forbundet sammen.</string>
<string name="what_are_servers">Hvad er servere?</string>
<string name="welcome_paragraph2"><![CDATA[Alle Mastodon-konti har plads på en server. Hver server har sine egne værdier, regler og administratorer. Ligegyldigt hvilken server du vælger, kan du følge og interagere med folk på alle andre servere.]]></string>
</resources>

View File

@@ -10,13 +10,13 @@
<string name="ok">OK</string>
<string name="preparing_auth">Authentifizierung wird vorbereitet </string>
<string name="finishing_auth">Authentifizierung wird abgeschlossen …</string>
<string name="user_boosted">%s hat diesen Beitrag geteilt</string>
<string name="user_boosted">%s hat geteilt</string>
<string name="in_reply_to">Als Antwort auf %s</string>
<string name="notifications">Benachrichtigungen</string>
<string name="user_followed_you">folgt dir jetzt</string>
<string name="user_sent_follow_request">hat dir eine Follower-Anfrage gesendet</string>
<string name="user_favorited">favorisierte</string>
<string name="notification_boosted">teilte</string>
<string name="notification_boosted">teilte deinen Beitrag</string>
<string name="poll_ended">Abstimmung beendet</string>
<string name="time_seconds">vor %d Sekunden</string>
<string name="time_minutes">vor %d Minuten</string>
@@ -250,7 +250,7 @@
<string name="notify_none">niemand</string>
<string name="notify_favorites">meinen Beitrag favorisiert</string>
<string name="notify_follow">mir folgt</string>
<string name="notify_reblog">einen meiner Beiträge geteilt hat</string>
<string name="notify_reblog">Teilte meinen Beitrag</string>
<string name="notify_mention">mich erwähnt</string>
<string name="settings_boring">Langweiliges</string>
<string name="settings_account">Kontoeinstellungen</string>
@@ -285,9 +285,10 @@
<string name="follow_user">%s folgen</string>
<string name="unfollowed_user">%s entfolgt</string>
<string name="followed_user">Du folgst nun %s</string>
<string name="following_user_requested">Deine Follower-Anfrage an %s wurde gesendet</string>
<string name="open_in_browser">Im Browser öffnen</string>
<string name="hide_boosts_from_user">geteilte Beiträge von %s ausblenden</string>
<string name="show_boosts_from_user">geteilte Beiträge von %s anzeigen</string>
<string name="hide_boosts_from_user">Geteilte Beiträge von %s verstecken</string>
<string name="show_boosts_from_user">Geteilte Beiträge von %s anzeigen</string>
<string name="signup_reason">Warum möchtest du beitreten?</string>
<string name="signup_reason_note">Das erleichtert uns die Prüfung deiner Anmeldung.</string>
<string name="clear">Leeren</string>
@@ -330,8 +331,8 @@
<item quantity="other">%,d × favorisiert</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d × geteilt</item>
<item quantity="other">%,d × geteilt</item>
<item quantity="one">%,d geteilter Beitrag</item>
<item quantity="other">%,d geteilte Beiträge</item>
</plurals>
<string name="timestamp_via_app">%1$s via %2$s</string>
<string name="time_now">jetzt</string>
@@ -394,12 +395,6 @@
<string name="login_title">Willkommen zurück</string>
<string name="login_subtitle">Melde dich mit dem Server an, auf dem du dein Konto erstellt hast.</string>
<string name="server_url">Serveradresse</string>
<string name="welcome_page1_title">Was ist Mastodon?</string>
<string name="welcome_page1_text">Angenommen, du hast eine E-Mail-Adresse, die mit @example.com endet.\n\nDu kannst immer noch E-Mails von allen empfangen, auch wenn deren E-Mail-Adresse mit @gmail.com, @icloud.com oder @example.com endet.</string>
<string name="welcome_page2_title">Mastodon ist genau so.</string>
<string name="welcome_page2_text">Dein Nutzer*innenname könnte @GothGirl654@example.social sein, aber du kannst trotzdem @fallout5ever@example.online folgen, deren Beiträge teilen und dich mit der Person unterhalten.</string>
<string name="welcome_page3_title">Wie wähle ich einen Server aus?</string>
<string name="welcome_page3_text">Unterschiedliche Menschen wählen aus verschiedenen Gründen unterschiedliche Server. art.example ist ein toller Ort für Künstler*innen, während glasgow.example eine gute Wahl für Schott*innen sein könnte.\n\nWähle nach Möglichkeit einen kleinen Server aus, mit dessen Regeln du dich wohl fühlst und der dir vertrauenswürdig erscheint (über die Server-Suchleiste kannst du dich direkt mit dem Server deines Vertrauens verbinden).</string>
<string name="signup_random_server_explain">Wenn du ohne Auswahl fortfährst, wählen wir einen Server in deiner Sprache aus.</string>
<string name="server_filter_any_language">Alle Sprachen</string>
<string name="server_filter_instant_signup">Schnellregistrierung</string>
@@ -431,4 +426,20 @@
<!-- %1$s is server domain, %2$s is email domain. You can reorder these placeholders to fit your language better. -->
<string name="signup_email_domain_blocked">%1$s lässt keine Anmeldungen von %2$s zu. Versuche einen anderen oder &lt;a&gt;wähle einen anderen Server&lt;/a&gt;.</string>
<string name="signup_username_taken">Dieser Benutzername ist bereits vergeben.</string>
<string name="spoiler_show">Trotzdem anzeigen</string>
<string name="spoiler_hide">Wieder verstecken</string>
<string name="poll_multiple_choice">Wähle ein/e oder mehrere aus</string>
<string name="save_changes">Änderungen speichern</string>
<string name="profile_featured">Empfohlen</string>
<string name="profile_timeline">Timeline</string>
<string name="view_all">Alle anzeigen</string>
<string name="profile_endorsed_accounts">Konten</string>
<string name="verified_link">Verifizierter Link</string>
<string name="show">Anzeigen</string>
<string name="hide">Ausblenden</string>
<string name="join_default_server">%s beitreten</string>
<string name="signup_or_login">oder</string>
<string name="learn_more">Mehr erfahren</string>
<string name="welcome_to_mastodon">Willkommen auf Mastodon</string>
<string name="what_are_servers">Was sind Server?</string>
</resources>

View File

@@ -50,7 +50,7 @@
<string name="sk_poll_allow_multiple">Mehrfachantworten erlauben</string>
<string name="sk_translated_using">Übersetzt mit %s</string>
<string name="sk_post_language">Sprache: %s</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_language_name">%1$s (%2$s)</string>
<string name="sk_confirm_clear_recent_languages">Sicher, dass du die Liste der zuletzt verwendeten Sprachen leeren willst\?</string>
<string name="sk_translate_post">Übersetzen</string>
<string name="sk_translate_show_original">Original anzeigen</string>
@@ -82,8 +82,8 @@
<string name="sk_settings_translation_availability_note_available">%s unterstützt Übersetzung!</string>
<string name="sk_settings_translation_availability_note_unavailable">%s scheint keine Übersetzung zu unterstützen.</string>
<string name="sk_loading_fediverse_resource_title">Suche im Fediverse</string>
<string name="sk_undo_reblog">Reblog rückgängig machen</string>
<string name="sk_reblog_with_visibility">Rebloggen mit Sichtbarkeit</string>
<string name="sk_undo_reblog">Teilen rückgängig machen</string>
<string name="sk_reblog_with_visibility">Teilen mit Sichtbarkeit</string>
<string name="sk_quote_post">Drüberkommentieren</string>
<string name="sk_hashtags_you_follow">Hashtags, denen du folgst</string>
<string name="sk_copy_link_to_post">Link zum Beitrag kopieren</string>
@@ -96,9 +96,9 @@
<string name="sk_favorite_as">Favorit mit anderem Konto</string>
<string name="sk_favorited_as">Favorisiert als %s</string>
<string name="sk_already_favorited">Bereits favorisiert</string>
<string name="sk_reblog_as">Mit einem anderen Konto boosten</string>
<string name="sk_reblogged_as">Geboostet als %s</string>
<string name="sk_already_reblogged">Bereits geboostet</string>
<string name="sk_reblog_as">Mit einem anderen Konto teilen</string>
<string name="sk_reblogged_as">Geteilt als %s</string>
<string name="sk_already_reblogged">Bereits geteilt</string>
<string name="sk_reply_as">Antworten mit anderem Konto</string>
<string name="sk_settings_uniform_icon_for_notifications">Einheitliches Icon für alle Benachrichtigungen</string>
<string name="sk_forward_report_to">Weiterleiten zu %s</string>
@@ -164,7 +164,7 @@
<string name="sk_alt_text_missing_title">Fehlende Bildbeschreibung</string>
<string name="sk_settings_disable_alt_text_reminder">Erinnerung zum Hinzufügen von Bildbeschreibungen ausschalten</string>
<string name="sk_alt_button">ALT</string>
<string name="sk_notify_update">Bearbeitet einen geteilten Beitrag</string>
<string name="sk_notify_update">einen geteilten Beitrag bearbeitet</string>
<string name="sk_timelines">Timelines</string>
<string name="sk_timeline">Timeline</string>
<string name="sk_hashtag">Hashtag</string>
@@ -267,4 +267,11 @@
<string name="sk_settings_reply_visibility_following">Antworten auf Follows</string>
<string name="sk_settings_reply_visibility_self">Antworten an mich</string>
<string name="sk_quoting_user">Zitiere %s</string>
<string name="sk_notification_action_replied">Antwort an %s gesendet</string>
<string name="sk_show_thread">Thread öffnen</string>
<string name="sk_compact_reblog_reply_line">Kompakte Geteilt-/Geantwortet-Zeile</string>
<string name="sk_reply_line_above_avatar">“Als Antwort auf”-Zeile über Profilbild</string>
<string name="sk_settings_confirm_before_reblog">Vor dem Teilen bestätigen</string>
<string name="sk_reacted">hat reagiert</string>
<string name="sk_reacted_with">hat mit %s reagiert</string>
</resources>

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