Compare commits

...

153 Commits

Author SHA1 Message Date
sk
32081b71f5 throw exception if no instance for session 2023-05-29 13:31:42 +02:00
sk
7849c34d1f fix account list alignment 2023-05-29 13:25:14 +02:00
sk
24977ec613 bump version 2023-05-29 13:03:18 +02:00
sk
786bbab0d5 Merge remote-tracking branch 'weblate/main' 2023-05-29 13:01:36 +02:00
sk
1facb07c28 Merge remote-tracking branch 'upstream/l10n_master' 2023-05-29 13:01:24 +02:00
sk
bba5aba22d settings icons not important for accessibility 2023-05-29 12:56:36 +02:00
sk
d7b85d6eba move invalid strings 2023-05-29 12:47:38 +02:00
sk
6832bfb95c don't display blocked_by relationship
closes sk22#526
2023-05-29 12:34:53 +02:00
sk
4c379b67a3 only auto-open search on pleroma instances 2023-05-29 03:33:31 +02:00
sk
3a2ae1ce71 clean up preferences when removing account 2023-05-29 02:40:15 +02:00
sk
c80afaf9c0 avoid sessions without instance info 2023-05-29 02:40:02 +02:00
sk
31d22bac47 remove unused method 2023-05-29 02:38:52 +02:00
Jacoco
b5f6687925 More Akkoma improvements (#524)
* Only open account if domain matches
Akkoma will seemingly show results that don't match well. This checks if the domain matches before continuing

* Add "RE:" for quotes where it's missing

* Fix no hashtag history in search

* Skip not implemented discovery and select search on Pleroma

* Set proper max account fields for Pleroma

* Use Pleroma's non-standard poll limits

* Mark notifications as read properly on Pleroma

* Akkoma bubble timeline

* Respect Reply Visibility preference on all timelines

* vertically center if hashtag has no history

* only open account search result if uri equals

* add getInstance and isPleroma methods

* change timelines api, support compatibility checks

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-05-29 02:37:46 +02:00
taniamarquessilva
b3f25af923 Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (286 of 286 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_PT/
2023-05-28 20:19:30 +00:00
taniamarquessilva
78c141e946 Translated using Weblate (Portuguese)
Currently translated at 14.6% (42 of 286 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt/
2023-05-28 20:19:30 +00:00
taniamarquessilva
83d36ce736 Translated using Weblate (Portuguese)
Currently translated at 52.9% (9 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt/
2023-05-28 20:19:30 +00:00
taniamarquessilva
b928357ff1 Translated using Weblate (Portuguese (Portugal))
Currently translated at 100.0% (286 of 286 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_PT/
2023-05-28 20:19:30 +00:00
ihor_ck
c074bc57bc Translated using Weblate (Ukrainian)
Currently translated at 100.0% (286 of 286 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-05-28 20:19:30 +00:00
Linerly
0e80c88b7d Translated using Weblate (Indonesian)
Currently translated at 100.0% (286 of 286 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-05-28 20:19:30 +00:00
Choukajohn
5ffa5b01fc Translated using Weblate (French)
Currently translated at 100.0% (286 of 286 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-05-28 20:19:30 +00:00
gallegonovato
61d9929485 Translated using Weblate (Spanish)
Currently translated at 100.0% (286 of 286 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-05-28 20:19:30 +00:00
sk
231f19d113 ugly workaround for sk22#520
it's really, really ugly :(
2023-05-28 22:14:03 +02:00
sk
bb41f62db5 Merge remote-tracking branch 'upstream/master' 2023-05-28 19:55:27 +02:00
Gregory K
47edc3180b Merge pull request #586 from sk22/fix/hashtags-crash-akkoma
Fix crash when searching for Hashtags on Akkoma servers
2023-05-28 20:55:04 +03:00
sk
9939d99c4b Merge branch 'fix/hashtags-crash-akkoma' 2023-05-28 19:54:39 +02:00
sk
8053e8bb05 fix hashtag search crash on akkoma servers
closes mastodon#468
closes sk22#523
2023-05-28 19:51:29 +02:00
sk
b7e9380bc4 enable unspecified as default formatting option
closes sk22#521
2023-05-28 14:55:53 +02:00
Jacoco
83600087e1 Fix images being stretched on Pleroma (#522)
Closes sk22#488

* Update image bounds after load when metadata is null

* Fix broken image layout in some scenarios

* Transition when image dimensions update

* Replace blurhash with accent color on Pleroma

* fall back to solid color regardless of server

* use fragment's context instead of passing it down

---------

Co-authored-by: sk <sk22@mailbox.org>
2023-05-28 14:44:23 +02:00
Eugen Rochko
fe84dc4823 New translations strings.xml (Chinese Simplified) 2023-05-27 16:39:55 +02:00
sk
c38eb545b1 use matched filter for determining warning title
fixes a bug where, when multiple filters apply, the
WarningFilteredStatusDisplayItem would not check if the warning applies to the
current context. now, matched filter is determined through the predicate
(though not exactly what a predicate is supposed to do, i guess) and passed
down to the WarningFilteredStatusDisplayItem. cc @LucasGGamerM
2023-05-27 13:09:36 +02:00
sk
1fc2f81dab fix creating posts on other people's account timelines
closes sk22#508
2023-05-27 01:50:10 +02:00
LucasGGamerM
69ddc95c2c fix crash when notification markers are null
This would happen when an account had 0 notifications and received one.
After which, the user would tap on the notification icon on the tab bar
and the app would crash.
2023-05-27 01:40:05 +02:00
sk
a6ac68499c use url as fallback for remote url 2023-05-27 01:37:10 +02:00
sk
c10d7cfee4 use remote url; file name as fallback for alt text 2023-05-27 01:32:49 +02:00
sk
f933bdbc53 button with ripple for files and instance picker 2023-05-27 01:13:32 +02:00
LucasGGamerM
274bca84d9 Add display item for unknown/file attachments
Co-authored-by: LucasGGamerM <lucassggabriel@gmail.com>
2023-05-27 01:11:26 +02:00
sk
6abfe6ddd7 add unit tests for status filter predicate 2023-05-26 17:02:39 +02:00
sk
ab7489a049 bump version 2023-05-26 02:37:32 +02:00
sk
a6fd6ae135 add javadoc 2023-05-26 02:37:25 +02:00
Espasant3
b30d4a025f Translated using Weblate (Galician)
Currently translated at 99.6% (274 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/gl/
2023-05-26 00:16:40 +00:00
Daudix_UFO
5b747bfc74 Translated using Weblate (Russian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-05-26 00:16:40 +00:00
gallegonovato
a410d19114 Translated using Weblate (Spanish)
Currently translated at 100.0% (275 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-05-26 00:16:39 +00:00
gicorada
a8589cc5b0 Translated using Weblate (Italian)
Currently translated at 100.0% (17 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/it/
2023-05-26 00:16:39 +00:00
Eryk Michalak
b057c9f7a8 Translated using Weblate (Polish)
Currently translated at 100.0% (17 of 17 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pl/
2023-05-26 00:16:39 +00:00
ihor_ck
96e4a4933c Translated using Weblate (Ukrainian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-05-26 00:16:39 +00:00
Eryk Michalak
630064500d Translated using Weblate (Polish)
Currently translated at 100.0% (275 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2023-05-26 00:16:39 +00:00
gicorada
9543294996 Translated using Weblate (Italian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2023-05-26 00:16:39 +00:00
Linerly
56e9cc3406 Translated using Weblate (Indonesian)
Currently translated at 100.0% (275 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-05-26 00:16:39 +00:00
Choukajohn
be569cbe72 Translated using Weblate (French)
Currently translated at 100.0% (275 of 275 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-05-26 00:16:39 +00:00
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
Eugen Rochko
2e1795dc6f New translations strings.xml (Russian) 2023-05-20 13:04:15 +02:00
Eugen Rochko
cd1be782fa New translations strings.xml (Armenian) 2023-05-16 18:44:56 +02:00
Eugen Rochko
67059f3d71 New translations strings.xml (Armenian) 2023-05-16 17:30:41 +02:00
Eugen Rochko
15f4d3326b New translations strings.xml (Russian) 2023-05-15 08:47:41 +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
Eugen Rochko
e65404a466 New translations strings.xml (Dutch) 2023-05-13 20:26:36 +02:00
Eugen Rochko
3d47d1b4db New translations full_description.txt (Dutch) 2023-05-13 19:05:00 +02:00
Eugen Rochko
d1749ab610 New translations strings.xml (Dutch) 2023-05-13 19:04:59 +02:00
Eugen Rochko
806c264686 New translations strings.xml (Vietnamese) 2023-05-13 17:46:17 +02:00
Eugen Rochko
34a9cb5a74 New translations strings.xml (Dutch) 2023-05-13 17:46:16 +02:00
Eugen Rochko
64fad2e871 New translations strings.xml (Vietnamese) 2023-05-13 16:36:00 +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
Eugen Rochko
9c89c26097 New translations strings.xml (Dutch) 2023-05-13 01:52:41 +02:00
Eugen Rochko
e3b6a5d389 New translations strings.xml (Dutch) 2023-05-13 00:57:05 +02:00
Eugen Rochko
0fb54efde5 New translations strings.xml (Dutch) 2023-05-12 23:58:21 +02:00
Eugen Rochko
a4a3f32dba New translations strings.xml (Dutch) 2023-05-12 22:45:52 +02:00
Eugen Rochko
03a1e29e0c New translations strings.xml (Dutch) 2023-05-12 19:43:17 +02:00
Eugen Rochko
eda9ff272b New translations strings.xml (Dutch) 2023-05-12 18:35:16 +02:00
Eugen Rochko
b3728e06ac New translations strings.xml (Swedish) 2023-05-11 12:28:06 +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
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
Eugen Rochko
e7ad396fc6 New translations strings.xml (Italian) 2023-04-22 19:15:42 +02:00
Eugen Rochko
b1cb4d4257 New translations strings.xml (German) 2023-04-22 16:44:30 +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
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
128 changed files with 2889 additions and 453 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId "org.joinmastodon.android.sk"
minSdk 23
targetSdk 33
versionCode 83
versionName "1.2.2+fork.83"
versionCode 85
versionName "1.2.3+fork.85"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resourceConfigurations += ['ar-rSA', 'ar-rDZ', 'be-rBY', 'bn-rBD', 'bs-rBA', 'ca-rES', 'cs-rCZ', 'da-rDK', 'de-rDE', 'el-rGR', 'es-rES', 'eu-rES', 'fa-rIR', 'fi-rFI', 'fil-rPH', 'fr-rFR', 'ga-rIE', 'gd-rGB', 'gl-rES', 'hi-rIN', 'hr-rHR', 'hu-rHU', 'hy-rAM', 'ig-rNG', 'in-rID', 'is-rIS', 'it-rIT', 'iw-rIL', 'ja-rJP', 'kab', 'ko-rKR', 'my-rMM', 'nl-rNL', 'no-rNO', 'oc-rFR', 'pl-rPL', 'pt-rBR', 'pt-rPT', 'ro-rRO', 'ru-rRU', 'si-rLK', 'sl-rSI', 'sv-rSE', 'th-rTH', 'tr-rTR', 'uk-rUA', 'ur-rIN', 'vi-rVN', 'zh-rCN', 'zh-rTW']
}

View File

@@ -0,0 +1,81 @@
package org.joinmastodon.android.utils;
import static org.joinmastodon.android.model.Filter.FilterAction.*;
import static org.joinmastodon.android.model.Filter.FilterContext.*;
import static org.junit.Assert.*;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Status;
import org.junit.Test;
import java.time.Instant;
import java.util.EnumSet;
import java.util.List;
public class StatusFilterPredicateTest {
private static final Filter hideMeFilter = new Filter(), warnMeFilter = new Filter();
private static final List<Filter> allFilters = List.of(hideMeFilter, warnMeFilter);
private static final Status
hideInHomePublic = Status.ofFake(null, "hide me, please", Instant.now()),
warnInHomePublic = Status.ofFake(null, "display me with a warning", Instant.now());
static {
hideMeFilter.phrase = "hide me";
hideMeFilter.filterAction = HIDE;
hideMeFilter.context = EnumSet.of(PUBLIC, HOME);
warnMeFilter.phrase = "warning";
warnMeFilter.filterAction = WARN;
warnMeFilter.context = EnumSet.of(PUBLIC, HOME);
}
@Test
public void testHide() {
assertFalse("should not pass because matching filter applies to given context",
new StatusFilterPredicate(allFilters, HOME).test(hideInHomePublic));
}
@Test
public void testHideRegardlessOfContext() {
assertTrue("filters without context should always pass",
new StatusFilterPredicate(allFilters, null).test(hideInHomePublic));
}
@Test
public void testHideInDifferentContext() {
assertTrue("should pass because matching filter does not apply to given context",
new StatusFilterPredicate(allFilters, THREAD).test(hideInHomePublic));
}
@Test
public void testHideWithWarningText() {
assertTrue("should pass because matching filter is for warnings",
new StatusFilterPredicate(allFilters, HOME).test(warnInHomePublic));
}
@Test
public void testWarn() {
assertFalse("should not pass because filter applies to given context",
new StatusFilterPredicate(allFilters, HOME, WARN).test(warnInHomePublic));
}
@Test
public void testWarnRegardlessOfContext() {
assertTrue("filters without context should always pass",
new StatusFilterPredicate(allFilters, null, WARN).test(warnInHomePublic));
}
@Test
public void testWarnInDifferentContext() {
assertTrue("should pass because filter does not apply to given context",
new StatusFilterPredicate(allFilters, THREAD, WARN).test(warnInHomePublic));
}
@Test
public void testWarnWithHideText() {
assertTrue("should pass because matching filter is for hiding",
new StatusFilterPredicate(allFilters, HOME, WARN).test(hideInHomePublic));
}
}

View File

@@ -38,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 marginalized 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 marginalized 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

@@ -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;
@@ -53,10 +54,13 @@ public class GlobalUserPreferences{
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
@@ -73,6 +77,16 @@ public class GlobalUserPreferences{
catch (JsonSyntaxException ignored) { return orElse; }
}
public static void removeAccount(String accountId) {
recentLanguages.remove(accountId);
pinnedTimelines.remove(accountId);
accountsInGlitchMode.remove(accountId);
accountsWithLocalOnlySupport.remove(accountId);
accountsWithContentTypesEnabled.remove(accountId);
accountsDefaultContentTypes.remove(accountId);
save();
}
public static void load(){
SharedPreferences prefs=getPrefs();
playGifs=prefs.getBoolean("playGifs", true);
@@ -111,6 +125,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()));
@@ -158,6 +174,8 @@ public class GlobalUserPreferences{
.putStringSet("accountsWithLocalOnlySupport", accountsWithLocalOnlySupport)
.putStringSet("accountsInGlitchMode", accountsInGlitchMode)
.putString("replyVisibility", replyVisibility)
.putStringSet("accountsWithContentTypesEnabled", accountsWithContentTypesEnabled)
.putString("accountsDefaultContentTypes", gson.toJson(accountsDefaultContentTypes))
.apply();
}
@@ -178,4 +196,3 @@ public class GlobalUserPreferences{
DARK
}
}

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

@@ -19,7 +19,6 @@ import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.SearchResult;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.utils.StatusFilterPredicate;
@@ -74,10 +73,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 +89,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 +145,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());
@@ -164,17 +159,13 @@ public class CacheController{
}
}
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(accountSession.domain);
new GetNotifications(maxID, count, onlyPosts ? EnumSet.of(Notification.Type.STATUS) : onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class), instance.pleroma != null)
new GetNotifications(maxID, count, onlyPosts ? EnumSet.of(Notification.Type.STATUS) : onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class), instance.isPleroma())
.setCallback(new Callback<>(){
@Override
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

@@ -0,0 +1,30 @@
package org.joinmastodon.android.api.requests.notifications;
import android.text.TextUtils;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Notification;
import java.util.List;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
public class PleromaMarkNotificationsRead extends MastodonAPIRequest<List<Notification>> {
private String maxID;
public PleromaMarkNotificationsRead(String maxID) {
super(HttpMethod.POST, "/pleroma/notifications/read", new TypeToken<>(){});
this.maxID = maxID;
}
@Override
public RequestBody getRequestBody() {
MultipartBody.Builder builder=new MultipartBody.Builder()
.setType(MultipartBody.FORM);
if(!TextUtils.isEmpty(maxID))
builder.addFormDataPart("max_id", maxID);
return builder.build();
}
}

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

@@ -0,0 +1,23 @@
package org.joinmastodon.android.api.requests.timelines;
import android.text.TextUtils;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
import java.util.List;
public class GetBubbleTimeline extends MastodonAPIRequest<List<Status>> {
public GetBubbleTimeline(String maxID, int limit) {
super(HttpMethod.GET, "/timelines/bubble", new TypeToken<>(){});
if(!TextUtils.isEmpty(maxID))
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", limit+"");
if(GlobalUserPreferences.replyVisibility != null)
addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
}
}

View File

@@ -2,6 +2,7 @@ package org.joinmastodon.android.api.requests.timelines;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
@@ -16,5 +17,7 @@ public class GetHashtagTimeline extends MastodonAPIRequest<List<Status>>{
addQueryParameter("min_id", minID);
if(limit>0)
addQueryParameter("limit", ""+limit);
if(GlobalUserPreferences.replyVisibility != null)
addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
}
}

View File

@@ -2,6 +2,7 @@ package org.joinmastodon.android.api.requests.timelines;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
@@ -18,5 +19,7 @@ public class GetListTimeline extends MastodonAPIRequest<List<Status>> {
addQueryParameter("limit", ""+limit);
if(sinceID!=null)
addQueryParameter("since_id", sinceID);
if(GlobalUserPreferences.replyVisibility != null)
addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
}
}

View File

@@ -4,6 +4,7 @@ import android.text.TextUtils;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
@@ -20,5 +21,7 @@ public class GetPublicTimeline extends MastodonAPIRequest<List<Status>>{
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", limit+"");
if(GlobalUserPreferences.replyVisibility != null)
addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
}
}

View File

@@ -7,6 +7,7 @@ import org.joinmastodon.android.api.StatusInteractionController;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Application;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Markers;
import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.PushSubscription;
@@ -87,4 +88,8 @@ public class AccountSession{
pushSubscriptionManager=new PushSubscriptionManager(getID());
return pushSubscriptionManager;
}
public Instance getInstance() {
return AccountSessionManager.getInstance().getInstanceInfo(domain);
}
}

View File

@@ -15,6 +15,7 @@ import android.util.Log;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
@@ -110,6 +111,12 @@ public class AccountSessionManager{
sessions.put(session.getID(), session);
lastActiveAccountID=session.getID();
writeAccountsFile();
// write initial instance info to file immediately to avoid sessions without instance info
InstanceInfoStorageWrapper wrapper = new InstanceInfoStorageWrapper();
wrapper.instance = instance;
MastodonAPIController.runInBackground(()->writeInstanceInfoFile(wrapper, instance.uri));
updateMoreInstanceInfo(instance, instance.uri);
if(PushSubscriptionManager.arePushNotificationsAvailable()){
session.getPushSubscriptionManager().registerAccountForPush(null);
@@ -178,6 +185,7 @@ public class AccountSessionManager{
AccountSession session=getAccount(id);
session.getCacheController().closeDatabase();
MastodonApp.context.deleteDatabase(id+".db");
GlobalUserPreferences.removeAccount(id);
sessions.remove(id);
if(lastActiveAccountID.equals(id)){
if(sessions.isEmpty())
@@ -455,11 +463,12 @@ public class AccountSessionManager{
}
public Instance getInstanceInfo(String domain){
return instances.get(domain);
}
public Instance getInstanceInfoForAccount(String account) {
return AccountSessionManager.getInstance().getInstanceInfo(instance.getAccount(account).domain);
Instance instance = instances.get(domain);
if (instance == null) {
throw new IllegalStateException("Cannot get instance for " + domain + ". Sessions: "
+ String.join(", ", instances.keySet()));
}
return instance;
}
public void updateAccountInfo(String id, Account account){

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());
}
})
@@ -84,7 +85,8 @@ public class AccountTimelineFragment extends StatusListFragment{
}
protected void onStatusCreated(StatusCreatedEvent ev){
if(!AccountSessionManager.getInstance().isSelf(accountID, ev.status.account))
AccountSessionManager asm = AccountSessionManager.getInstance();
if(!asm.isSelf(accountID, ev.status.account) || !asm.isSelf(accountID, user))
return;
if(filter==GetAccountStatuses.Filter.PINNED) return;
if(filter==GetAccountStatuses.Filter.DEFAULT){
@@ -122,4 +124,10 @@ public class AccountTimelineFragment extends StatusListFragment{
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
// no-op
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.ACCOUNT;
}
}

View File

@@ -68,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;
@@ -268,34 +268,39 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
});
}
@Override
public @Nullable View getFab() {
if (getParentFragment() instanceof HasFab l) return l.getFab();
else return fab;
}
public void animateFab(boolean show) {
@Override
public void showFab() {
View fab = getFab();
if (fab == null) return;
if (show && fab.getVisibility() != View.VISIBLE) {
fab.setVisibility(View.VISIBLE);
TranslateAnimation animate = new TranslateAnimation(
0,
0,
fab.getHeight() * 2,
0);
animate.setDuration(300);
fab.startAnimation(animate);
} else if (!show && 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;
}
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
@@ -312,10 +317,10 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
View fab = getFab();
if (fab!=null && GlobalUserPreferences.autoHideFab) {
if (dy > 0 && fab.getVisibility() == View.VISIBLE) {
animateFab(false);
hideFab();
} else if (dy < 0 && fab.getVisibility() != View.VISIBLE) {
if (list.getChildAt(0).getTop() == 0 || scrollDiff > 400) {
animateFab(true);
showFab();
scrollDiff = 0;
} else {
scrollDiff += Math.abs(dy);
@@ -546,6 +551,14 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
}
}
public void onImageUpdated(MediaGridStatusDisplayItem.Holder holder, int index) {
holder.rebind();
MediaGridStatusDisplayItem.Holder mediaGrid = findHolderOfType(holder.getItemID(), MediaGridStatusDisplayItem.Holder.class);
if(mediaGrid!=null){
adapter.notifyItemChanged(mediaGrid.getAbsoluteAdapterPosition());
}
}
public void onGapClick(GapStatusDisplayItem.Holder item){}
public void onWarningClick(WarningFilteredStatusDisplayItem.Holder warning){

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,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
setRetainInstance(true);
accountID=getArguments().getString("account");
contentType = GlobalUserPreferences.accountsDefaultContentTypes.get(accountID);
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
self=session.self;
instanceDomain=session.domain;
@@ -330,6 +334,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 +369,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 +475,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 +493,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 +543,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 +933,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)");
@@ -1050,9 +1087,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
req.status=text;
req.localOnly=localOnly;
req.visibility=localOnly && instance.pleroma != null ? StatusPrivacy.LOCAL : statusVisibility;
req.visibility=localOnly && instance.isPleroma() ? 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());
@@ -1705,11 +1743,24 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
pollChanged=true;
updatePublishButtonState();
}));
option.edit.setFilters(new InputFilter[]{new InputFilter.LengthFilter(instance.configuration!=null && instance.configuration.polls!=null && instance.configuration.polls.maxCharactersPerOption>0 ? instance.configuration.polls.maxCharactersPerOption : 50)});
int maxCharactersPerOption = 50;
if(instance.configuration!=null && instance.configuration.polls!=null && instance.configuration.polls.maxCharactersPerOption>0)
maxCharactersPerOption = instance.configuration.polls.maxCharactersPerOption;
else if(instance.pollLimits!=null && instance.pollLimits.maxOptionChars>0)
maxCharactersPerOption = instance.pollLimits.maxOptionChars;
option.edit.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxCharactersPerOption)});
pollOptionsView.addView(option.view);
pollOptions.add(option);
if(pollOptions.size()==(instance.configuration!=null && instance.configuration.polls!=null && instance.configuration.polls.maxOptions>0 ? instance.configuration.polls.maxOptions : 4))
int maxPollOptions = 4;
if(instance.configuration!=null && instance.configuration.polls!=null && instance.configuration.polls.maxOptions>0)
maxPollOptions = instance.configuration.polls.maxOptions;
else if (instance.pollLimits!=null && instance.pollLimits.maxOptions>0)
maxPollOptions = instance.pollLimits.maxOptions;
if(pollOptions.size()==maxPollOptions)
addPollOptionBtn.setVisibility(View.GONE);
return option;
}
@@ -1851,7 +1902,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
Menu m=visibilityPopup.getMenu();
MenuItem localOnlyItem = visibilityPopup.getMenu().findItem(R.id.local_only);
boolean prefsSaysSupported = GlobalUserPreferences.accountsWithLocalOnlySupport.contains(accountID);
if (instance.pleroma != null) {
if (instance.isPleroma()) {
m.findItem(R.id.vis_local).setVisible(true);
} else if (localOnly || prefsSaysSupported) {
localOnlyItem.setVisible(true);
@@ -1895,14 +1946,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

@@ -30,8 +30,11 @@ import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.lists.GetLists;
import org.joinmastodon.android.api.requests.tags.GetFollowedHashtags;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.ListTimeline;
import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.DividerItemDecoration;
@@ -164,7 +167,7 @@ public class EditTimelinesFragment extends RecyclerFragment<TimelineDefinition>
makeBackItem(listsMenu);
makeBackItem(hashtagsMenu);
TimelineDefinition.ALL_TIMELINES.forEach(tl -> addTimelineToOptions(tl, timelinesMenu));
TimelineDefinition.getAllTimelines(accountID).forEach(tl -> addTimelineToOptions(tl, timelinesMenu));
listTimelines.stream().map(TimelineDefinition::ofList).forEach(tl -> addTimelineToOptions(tl, listsMenu));
hashtags.stream().map(TimelineDefinition::ofHashtag).forEach(tl -> addTimelineToOptions(tl, hashtagsMenu));
@@ -190,7 +193,7 @@ public class EditTimelinesFragment extends RecyclerFragment<TimelineDefinition>
@Override
protected void doLoadData(int offset, int count){
onDataLoaded(GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.DEFAULT_TIMELINES), false);
onDataLoaded(GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.getDefaultTimelines(accountID)), false);
updateOptionsMenu();
}

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

@@ -4,4 +4,6 @@ import android.view.View;
public interface HasFab {
View getFab();
void showFab();
void hideFab();
}

View File

@@ -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());
}
})
@@ -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

@@ -66,6 +66,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
private int currentTab=R.id.tab_home;
private String accountID;
private boolean isPleroma;
@Override
public void onCreate(Bundle savedInstanceState){
@@ -73,16 +74,20 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
E.register(this);
accountID=getArguments().getString("account");
setTitle(R.string.sk_app_name);
Instance instance = AccountSessionManager.getInstance().getAccount(accountID).getInstance();
isPleroma = instance.isPleroma();
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N)
setRetainInstance(true);
// TODO: clean up
if(savedInstanceState==null){
Bundle args=new Bundle();
args.putString("account", accountID);
homeTabFragment=new HomeTabFragment();
homeTabFragment.setArguments(args);
args=new Bundle(args);
args.putBoolean("disableDiscover", isPleroma);
args.putBoolean("noAutoLoad", true);
searchFragment=new DiscoverFragment();
searchFragment.setArguments(args);
@@ -160,6 +165,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,8 +233,10 @@ 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);
if (tab == R.id.tab_search && isPleroma) searchFragment.selectSearch();
}
private void maybeTriggerLoading(Fragment newFragment){
@@ -288,10 +296,10 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
public void updateNotificationBadge() {
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
Instance instance = session.getInstance();
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.isPleroma())
.setCallback(new Callback<>() {
@Override
public void onSuccess(List<Notification> notifications) {

View File

@@ -106,7 +106,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
super.onCreate(savedInstanceState);
E.register(this);
accountID = getArguments().getString("account");
timelineDefinitions = GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.DEFAULT_TIMELINES);
timelineDefinitions = GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.getDefaultTimelines(accountID));
assert timelineDefinitions != null;
if (timelineDefinitions.size() == 0) timelineDefinitions = List.of(TimelineDefinition.HOME_TIMELINE);
count = timelineDefinitions.size();
@@ -448,10 +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()));
if (fragments[i] instanceof BaseStatusListFragment<?> l) l.animateFab(true);
showFab();
}
@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;
@@ -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

@@ -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());
}
})
@@ -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

@@ -9,7 +9,10 @@ import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonErrorResponse;
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
import org.joinmastodon.android.api.requests.notifications.PleromaMarkNotificationsRead;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.AllNotificationsSeenEvent;
import org.joinmastodon.android.events.PollUpdatedEvent;
@@ -18,6 +21,7 @@ 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.Instance;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
@@ -40,6 +44,7 @@ import java.util.stream.Stream;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.api.SimpleCallback;
public class NotificationsListFragment extends BaseStatusListFragment<Notification>{
@@ -151,12 +156,16 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
loadRelationships(needRelationships);
maxID=result.maxID;
if(offset==0 && !result.items.isEmpty() && !result.isFromCache()){
if(offset==0 && !result.items.isEmpty() && !result.isFromCache() && AccountSessionManager.getInstance().getAccount(accountID).markers.notifications != null){
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();
if (AccountSessionManager.getInstance().getAccount(accountID).getInstance().isPleroma())
new PleromaMarkNotificationsRead(result.items.get(0).id).exec(accountID);
}
}
});

View File

@@ -20,7 +20,7 @@ public abstract class PinnableStatusListFragment extends StatusListFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
pinnedTimelines = new ArrayList<>(GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.DEFAULT_TIMELINES));
pinnedTimelines = new ArrayList<>(GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.getDefaultTimelines(accountID)));
}
@Override

View File

@@ -31,7 +31,6 @@ import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.inputmethod.InputMethodManager;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
@@ -51,6 +50,7 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
import org.joinmastodon.android.fragments.account_list.FollowingListFragment;
@@ -58,6 +58,7 @@ import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AccountField;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.SimpleViewHolder;
@@ -137,6 +138,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private Account account;
private String accountID;
private String domain;
private Relationship relationship;
private int statusBarHeight;
private boolean isOwnProfile;
@@ -151,7 +153,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private PhotoViewer currentPhotoViewer;
private boolean editModeLoading;
private static final int MAX_FIELDS=4;
private int maxFields = 4;
// from ProfileAboutFragment
public UsableRecyclerView list;
@@ -172,6 +174,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
setRetainInstance(true);
accountID=getArguments().getString("account");
domain=AccountSessionManager.getInstance().getAccount(accountID).domain;
if(getArguments().containsKey("profileAccount")){
account=Parcels.unwrap(getArguments().getParcelable("profileAccount"));
profileAccountID=account.id;
@@ -179,6 +182,12 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
loaded=true;
if(!isOwnProfile)
loadRelationship();
else {
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(domain);
if (instance.isPleroma()) {
maxFields = instance.pleroma.metadata.fieldsLimits.maxFields;
}
}
}else{
profileAccountID=getArguments().getString("profileAccountID");
if(!getArguments().getBoolean("noAutoLoad", false))
@@ -324,7 +333,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
username.setOnLongClickListener(v->{
String usernameString=account.acct;
if(!usernameString.contains("@")){
usernameString+="@"+AccountSessionManager.getInstance().getAccount(accountID).domain;
usernameString+="@"+domain;
}
UiUtils.copyText(username, '@'+usernameString);
return true;
@@ -510,7 +519,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
ssb.append(account.acct);
if(isSelf){
ssb.append('@');
ssb.append(AccountSessionManager.getInstance().getAccount(accountID).domain);
ssb.append(domain);
}
ssb.append(" ");
Drawable lock=username.getResources().getDrawable(R.drawable.ic_lock, getActivity().getTheme()).mutate();
@@ -520,7 +529,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
username.setText(ssb);
}else{
// noinspection SetTextI18n
username.setText('@'+account.acct+(isSelf ? ('@'+AccountSessionManager.getInstance().getAccount(accountID).domain) : ""));
username.setText('@'+account.acct+(isSelf ? ('@'+domain) : ""));
}
CharSequence parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
if(TextUtils.isEmpty(parsedBio)){
@@ -758,6 +767,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){
@@ -1179,7 +1198,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
public int getItemCount(){
if(isInEditMode){
int size=metadataListData.size();
if(size<MAX_FIELDS)
if(size<maxFields)
size++;
return size;
}
@@ -1296,7 +1315,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
@Override
public void onClick(){
metadataListData.add(new AccountField());
if(metadataListData.size()==MAX_FIELDS){ // replace this row with new row
if(metadataListData.size()==maxFields){ // replace this row with new row
adapter.notifyItemChanged(metadataListData.size()-1);
}else{
adapter.notifyItemInserted(metadataListData.size()-1);

View File

@@ -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);
@@ -99,7 +105,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
imageCache = ImageCache.getInstance(getActivity());
accountID=getArguments().getString("account");
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
Instance instance = session.getInstance();
String instanceName = UiUtils.getInstanceName(accountID);
if(GithubSelfUpdater.needSelfUpdating()){
@@ -217,7 +223,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
GlobalUserPreferences.showReplies=i.checked;
GlobalUserPreferences.save();
}));
if (instance.pleroma != null) {
if (instance.isPleroma()) {
items.add(new ButtonItem(R.string.sk_settings_reply_visibility, R.drawable.ic_fluent_chat_24_regular, b->{
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
popupMenu.inflate(R.menu.reply_visibility);
@@ -239,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();
}));
@@ -330,6 +336,34 @@ 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);
}));
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) {
@@ -500,6 +534,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();
@@ -1007,7 +1069,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

@@ -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

@@ -74,7 +74,7 @@ public class ThreadFragment extends StatusListFragment{
}
AccountSession account=AccountSessionManager.getInstance().getAccount(accountID);
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(account.domain);
if(instance.pleroma != null){
if(instance.isPleroma()){
List<String> threadIds=new ArrayList<>();
threadIds.add(mainStatus.id);
for(Status s:result.descendants){
@@ -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

@@ -0,0 +1,55 @@
package org.joinmastodon.android.fragments.discover;
import android.os.Bundle;
import android.view.View;
import org.joinmastodon.android.api.requests.timelines.GetBubbleTimeline;
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
import org.joinmastodon.android.fragments.StatusListFragment;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import java.util.List;
import java.util.stream.Collectors;
import me.grishka.appkit.api.SimpleCallback;
public class BubbleTimelineFragment extends StatusListFragment {
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.BUBBLE_TIMELINE);
private String maxID;
@Override
protected boolean wantsComposeButton() {
return true;
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetBubbleTimeline(refreshing ? null : maxID, count)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<Status> result){
if(!result.isEmpty())
maxID=result.get(result.size()-1).id;
if (getActivity() == null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
onDataLoaded(result, !result.isEmpty());
}
})
.exec(accountID);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
bannerHelper.maybeAddBanner(contentWrap);
}
@Override
protected Filter.FilterContext getFilterContext() {
return Filter.FilterContext.PUBLIC;
}
}

View File

@@ -19,6 +19,7 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.ui.SimpleViewHolder;
@@ -238,7 +239,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
else scrollToTop();
}
private void selectSearch() {
public void selectSearch() {
searchEdit.requestFocus();
onSearchEditFocusChanged(searchEdit, true);
getActivity().getSystemService(InputMethodManager.class).showSoftInput(searchEdit, 0);
@@ -272,6 +273,8 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
searchBack.setEnabled(false);
searchBack.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
getActivity().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(searchEdit.getWindowToken(), 0);
if (getArguments().getBoolean("disableDiscover"))
((HomeFragment) getParentFragment()).onBackPressed();
}
@Override

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

@@ -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

@@ -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

@@ -1,5 +1,8 @@
package org.joinmastodon.android.fragments.discover;
import static org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem.Holder.withHistoryParams;
import static org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem.Holder.withoutHistoryParams;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
@@ -105,6 +108,14 @@ public class TrendingHashtagsFragment extends RecyclerFragment<Hashtag> implemen
@Override
public void onBind(Hashtag item){
title.setText('#'+item.name);
if (item.history == null || item.history.isEmpty()) {
subtitle.setText(null);
chart.setVisibility(View.GONE);
title.setLayoutParams(withoutHistoryParams);
return;
}
chart.setVisibility(View.VISIBLE);
title.setLayoutParams(withHistoryParams);
int numPeople=item.history.get(0).accounts;
if(item.history.size()>1)
numPeople+=item.history.get(1).accounts;

View File

@@ -124,6 +124,7 @@ public class CustomWelcomeFragment extends InstanceCatalogFragment {
super.onViewCreated(view, savedInstanceState);
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorWindowBackground));
list.setItemAnimator(new BetterItemAnimator());
((UsableRecyclerView) list).setSelector(null);
}
@Override

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

@@ -86,6 +86,8 @@ public class Instance extends BaseModel{
public Pleroma pleroma;
public PleromaPollLimits pollLimits;
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();
@@ -134,6 +136,10 @@ public class Instance extends BaseModel{
return ci;
}
public boolean isPleroma() {
return pleroma != null;
}
@Parcel
public static class Rule{
public String id;
@@ -198,6 +204,28 @@ public class Instance extends BaseModel{
@Parcel
public static class Pleroma extends BaseModel {
// metadata etc
public Pleroma.Metadata metadata;
@Parcel
public static class Metadata {
public List<String> features;
public Pleroma.Metadata.FieldsLimits fieldsLimits;
@Parcel
public static class FieldsLimits {
public int maxFields;
public int maxRemoteFields;
public int nameLength;
public int valueLength;
}
}
}
@Parcel
public static class PleromaPollLimits {
public int maxExpiration;
public int maxOptionChars;
public int maxOptions;
public int minExpiration;
}
}

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

@@ -50,6 +50,8 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
public long favouritesCount;
public long repliesCount;
public Instant editedAt;
// might not be provided (by older mastodon servers),
// so megalodon will use the locally cached filters if filtered == null
public List<FilterResult> filtered;
public String url;
@@ -101,6 +103,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;
@@ -177,7 +182,6 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
s.mentions = List.of();
s.tags = List.of();
s.emojis = List.of();
s.filtered = List.of();
return s;
}

View File

@@ -8,17 +8,20 @@ import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
import org.joinmastodon.android.fragments.HomeTimelineFragment;
import org.joinmastodon.android.fragments.ListTimelineFragment;
import org.joinmastodon.android.fragments.NotificationsListFragment;
import org.joinmastodon.android.fragments.discover.BubbleTimelineFragment;
import org.joinmastodon.android.fragments.discover.FederatedTimelineFragment;
import org.joinmastodon.android.fragments.discover.LocalTimelineFragment;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
public class TimelineDefinition {
private TimelineType type;
@@ -58,6 +61,14 @@ public class TimelineDefinition {
this.type = type;
}
public boolean isCompatible(AccountSession session) {
return true;
}
public boolean wantsDefault(AccountSession session) {
return true;
}
public String getTitle(Context ctx) {
return title != null ? title : getDefaultTitle(ctx);
}
@@ -78,6 +89,7 @@ public class TimelineDefinition {
case POST_NOTIFICATIONS -> ctx.getString(R.string.sk_timeline_posts);
case LIST -> listTitle;
case HASHTAG -> hashtagName;
case BUBBLE -> ctx.getString(R.string.sk_timeline_bubble);
};
}
@@ -89,6 +101,7 @@ public class TimelineDefinition {
case POST_NOTIFICATIONS -> Icon.POST_NOTIFICATIONS;
case LIST -> Icon.LIST;
case HASHTAG -> Icon.HASHTAG;
case BUBBLE -> Icon.BUBBLE;
};
}
@@ -100,6 +113,7 @@ public class TimelineDefinition {
case LIST -> new ListTimelineFragment();
case HASHTAG -> new HashtagTimelineFragment();
case POST_NOTIFICATIONS -> new NotificationsListFragment();
case BUBBLE -> new BubbleTimelineFragment();
};
}
@@ -156,7 +170,7 @@ public class TimelineDefinition {
return args;
}
public enum TimelineType { HOME, LOCAL, FEDERATED, POST_NOTIFICATIONS, LIST, HASHTAG }
public enum TimelineType { HOME, LOCAL, FEDERATED, POST_NOTIFICATIONS, LIST, HASHTAG, BUBBLE }
public enum Icon {
HEART(R.drawable.ic_fluent_heart_24_regular, R.string.sk_icon_heart),
@@ -219,7 +233,8 @@ public class TimelineDefinition {
FEDERATED(R.drawable.ic_fluent_earth_24_regular, R.string.sk_timeline_federated, true),
POST_NOTIFICATIONS(R.drawable.ic_fluent_chat_24_regular, R.string.sk_timeline_posts, true),
LIST(R.drawable.ic_fluent_people_24_regular, R.string.sk_list, true),
HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true);
HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true),
BUBBLE(R.drawable.ic_fluent_circle_24_regular, R.string.sk_timeline_bubble, true);
public final int iconRes, nameRes;
public final boolean hidden;
@@ -239,14 +254,49 @@ public class TimelineDefinition {
public static final TimelineDefinition LOCAL_TIMELINE = new TimelineDefinition(TimelineType.LOCAL);
public static final TimelineDefinition FEDERATED_TIMELINE = new TimelineDefinition(TimelineType.FEDERATED);
public static final TimelineDefinition POSTS_TIMELINE = new TimelineDefinition(TimelineType.POST_NOTIFICATIONS);
public static final TimelineDefinition BUBBLE_TIMELINE = new TimelineDefinition(TimelineType.BUBBLE) {
@Override
public boolean isCompatible(AccountSession session) {
// still enabling the bubble timeline for all pleroma/akkoma instances since i know of
// at least one instance that supports it, but doesn't list "bubble_timeline"
return session.getInstance().isPleroma();
}
public static final List<TimelineDefinition> DEFAULT_TIMELINES = BuildConfig.BUILD_TYPE.equals("playRelease")
? List.of(HOME_TIMELINE.copy(), LOCAL_TIMELINE.copy())
: List.of(HOME_TIMELINE.copy(), LOCAL_TIMELINE.copy(), FEDERATED_TIMELINE.copy());
public static final List<TimelineDefinition> ALL_TIMELINES = List.of(
HOME_TIMELINE.copy(),
LOCAL_TIMELINE.copy(),
FEDERATED_TIMELINE.copy(),
POSTS_TIMELINE.copy()
@Override
public boolean wantsDefault(AccountSession session) {
Instance instance = session.getInstance();
return instance.isPleroma() && instance.pleroma.metadata.features.contains("bubble_timeline");
}
};
public static List<TimelineDefinition> getDefaultTimelines(String accountId) {
AccountSession session = AccountSessionManager.getInstance().getAccount(accountId);
return DEFAULT_TIMELINES.stream()
.filter(tl -> tl.isCompatible(session) && tl.wantsDefault(session))
.map(TimelineDefinition::copy)
.collect(Collectors.toList());
}
public static List<TimelineDefinition> getAllTimelines(String accountId) {
AccountSession session = AccountSessionManager.getInstance().getAccount(accountId);
return ALL_TIMELINES.stream()
.filter(tl -> tl.isCompatible(session))
.map(TimelineDefinition::copy)
.collect(Collectors.toList());
}
private static final List<TimelineDefinition> DEFAULT_TIMELINES = List.of(
HOME_TIMELINE,
LOCAL_TIMELINE,
BUBBLE_TIMELINE,
FEDERATED_TIMELINE
);
private static final List<TimelineDefinition> ALL_TIMELINES = List.of(
HOME_TIMELINE,
LOCAL_TIMELINE,
FEDERATED_TIMELINE,
POSTS_TIMELINE,
BUBBLE_TIMELINE
);
}

View File

@@ -18,13 +18,15 @@ package org.joinmastodon.android.ui;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewPropertyAnimator;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.SimpleItemAnimator;
import org.joinmastodon.android.ui.displayitems.MediaGridStatusDisplayItem;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import java.util.ArrayList;
@@ -358,7 +360,14 @@ public class BetterItemAnimator extends SimpleItemAnimator{
mChangeAnimations.add(changeInfo.oldHolder);
oldViewAnim.translationX(changeInfo.toX - changeInfo.fromX);
oldViewAnim.translationY(changeInfo.toY - changeInfo.fromY);
oldViewAnim.alpha(0).setListener(new AnimatorListenerAdapter() {
float alpha = 0;
if (holder instanceof MediaGridStatusDisplayItem.Holder mediaItemHolder) {
if (mediaItemHolder.isSizeUpdating()) {
alpha = 1; // Image will flicker out and then in if alpha is 0
mediaItemHolder.sizeUpdated();
}
}
oldViewAnim.alpha(alpha).setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animator) {
dispatchChangeStarting(changeInfo.oldHolder, true);

View File

@@ -0,0 +1,64 @@
package org.joinmastodon.android.ui.displayitems;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.Card;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.drawables.BlurhashCrossfadeDrawable;
import org.joinmastodon.android.ui.utils.UiUtils;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
public class FileStatusDisplayItem extends StatusDisplayItem{
private final Attachment attachment;
public FileStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Attachment attachment) {
super(parentID, parentFragment);
this.attachment=attachment;
}
@Override
public Type getType() {
return Type.FILE;
}
public static class Holder extends StatusDisplayItem.Holder<FileStatusDisplayItem> {
private final TextView title, domain;
public Holder(Context context, ViewGroup parent) {
super(context, R.layout.display_item_file, parent);
title=findViewById(R.id.title);
domain=findViewById(R.id.domain);
findViewById(R.id.inner).setOnClickListener(this::onClick);
}
@Override
public void onBind(FileStatusDisplayItem item) {
Uri url = Uri.parse(getUrl());
title.setText(item.attachment.description != null
? item.attachment.description
: url.getLastPathSegment());
title.setEllipsize(item.attachment.description != null ? TextUtils.TruncateAt.END : TextUtils.TruncateAt.MIDDLE);
domain.setText(url.getHost());
}
private void onClick(View v) {
UiUtils.openURL(itemView.getContext(), item.parentFragment.getAccountID(), getUrl());
}
private String getUrl() {
return item.attachment.remoteUrl == null ? item.attachment.url : item.attachment.remoteUrl;
}
}
}

View File

@@ -1,7 +1,9 @@
package org.joinmastodon.android.ui.displayitems;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.joinmastodon.android.R;
@@ -25,6 +27,13 @@ public class HashtagStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<HashtagStatusDisplayItem>{
private final TextView title, subtitle;
private final HashtagChartView chart;
public static final RelativeLayout.LayoutParams
withHistoryParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT),
withoutHistoryParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
static {
withoutHistoryParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
}
public Holder(Context context, ViewGroup parent){
super(context, R.layout.item_trending_hashtag, parent);
@@ -37,6 +46,14 @@ public class HashtagStatusDisplayItem extends StatusDisplayItem{
public void onBind(HashtagStatusDisplayItem _item){
Hashtag item=_item.tag;
title.setText('#'+item.name);
if (item.history == null || item.history.isEmpty()) {
subtitle.setText(null);
chart.setVisibility(View.GONE);
title.setLayoutParams(withoutHistoryParams);
return;
}
chart.setVisibility(View.VISIBLE);
title.setLayoutParams(withHistoryParams);
int numPeople=item.history.get(0).accounts;
if(item.history.size()>1)
numPeople+=item.history.get(1).accounts;

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;
@@ -217,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

@@ -7,6 +7,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Activity;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.view.View;
@@ -17,7 +18,6 @@ import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Attachment;
@@ -40,7 +40,7 @@ import me.grishka.appkit.utils.CubicBezierInterpolator;
public class MediaGridStatusDisplayItem extends StatusDisplayItem{
private static final String TAG="MediaGridDisplayItem";
private final PhotoLayoutHelper.TiledLayoutResult tiledLayout;
private PhotoLayoutHelper.TiledLayoutResult tiledLayout;
private final TypedObjectPool<GridItemType, MediaAttachmentViewController> viewPool;
private final List<Attachment> attachments;
private final ArrayList<ImageLoaderRequest> requests=new ArrayList<>();
@@ -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));
}
@@ -98,6 +98,8 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
private int altTextIndex=-1;
private Animator altTextAnimator;
private boolean sizeUpdating = false;
public Holder(Activity activity, ViewGroup parent){
super(new FrameLayoutThatOnlyMeasuresFirstChild(activity));
wrapper=(FrameLayout)itemView;
@@ -126,6 +128,7 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
}
layout.removeAllViews();
controllers.clear();
int i=0;
for(Attachment att:item.attachments){
MediaAttachmentViewController c=item.viewPool.obtain(switch(att.type){
@@ -158,6 +161,19 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
@Override
public void setImage(int index, Drawable drawable){
Rect bounds=drawable.getBounds();
drawable.setBounds(bounds.left, bounds.top, bounds.left+drawable.getIntrinsicWidth(), bounds.top+drawable.getIntrinsicHeight());
if(item.attachments.get(index).meta==null){
Attachment.Metadata metadata = new Attachment.Metadata();
metadata.width=drawable.getIntrinsicWidth();
metadata.height=drawable.getIntrinsicHeight();
item.attachments.get(index).meta=metadata;
item.tiledLayout=PhotoLayoutHelper.processThumbs(item.attachments);
sizeUpdating = true;
item.parentFragment.onImageUpdated(this, index);
}
controllers.get(index).setImage(drawable);
}
@@ -314,5 +330,13 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
layout.setClipChildren(clip);
wrapper.setClipChildren(clip);
}
public boolean isSizeUpdating() {
return sizeUpdating;
}
public void sizeUpdated() {
sizeUpdating = false;
}
}
}

View File

@@ -2,6 +2,7 @@ package org.joinmastodon.android.ui.displayitems;
import android.app.Activity;
import android.content.Context;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
@@ -9,6 +10,7 @@ import android.view.ViewGroup;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
@@ -20,12 +22,14 @@ import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.model.DisplayItemsParent;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.Poll;
import org.joinmastodon.android.model.ScheduledStatus;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.PhotoLayoutHelper;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import org.parceler.Parcels;
@@ -78,21 +82,14 @@ public abstract class StatusDisplayItem{
case EXTENDED_FOOTER -> new ExtendedFooterStatusDisplayItem.Holder(activity, parent);
case MEDIA_GRID -> new MediaGridStatusDisplayItem.Holder(activity, parent);
case WARNING -> new WarningFilteredStatusDisplayItem.Holder(activity, parent);
case FILE -> new FileStatusDisplayItem.Holder(activity, parent);
};
}
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,14 +99,6 @@ 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);
}
ReblogOrReplyLineStatusDisplayItem replyLine = null;
boolean threadReply = statusForContent.inReplyToAccountId != null &&
statusForContent.inReplyToAccountId.equals(statusForContent.account.id);
@@ -177,14 +166,32 @@ public abstract class StatusDisplayItem{
items.add(replyLine);
}
if (statusForContent.quote != null) {
boolean hasQuoteInlineTag = statusForContent.content.contains("<span class=\"quote-inline\">");
if (!hasQuoteInlineTag) {
String quoteUrl = statusForContent.quote.url;
String quoteInline = String.format("<span class=\"quote-inline\">%sRE: <a href=\"%s\">%s</a></span>",
statusForContent.content.endsWith("</p>") ? "" : "<br/><br/>", quoteUrl, quoteUrl);
statusForContent.content += quoteInline;
}
}
if(!TextUtils.isEmpty(statusForContent.content))
items.add(new TextStatusDisplayItem(parentID, HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID), fragment, statusForContent, disableTranslate));
else if (!GlobalUserPreferences.replyLineAboveHeader && replyLine != null)
replyLine.needBottomPadding=true;
else
header.needBottomPadding=true;
List<Attachment> imageAttachments=statusForContent.mediaAttachments.stream().filter(att->att.type.isImage()).collect(Collectors.toList());
List<Attachment> imageAttachments=statusForContent.mediaAttachments.stream()
.filter(att->att.type.isImage() && !att.type.equals(Attachment.Type.UNKNOWN))
.collect(Collectors.toList());
if(!imageAttachments.isEmpty()){
int color = UiUtils.getThemeColor(fragment.getContext(), R.attr.colorAccentLightest);
for (Attachment att : imageAttachments) {
if (att.blurhashPlaceholder == null) {
att.blurhashPlaceholder = new ColorDrawable(color);
}
}
PhotoLayoutHelper.TiledLayoutResult layout=PhotoLayoutHelper.processThumbs(imageAttachments);
items.add(new MediaGridStatusDisplayItem(parentID, fragment, layout, imageAttachments, statusForContent));
}
@@ -193,6 +200,12 @@ public abstract class StatusDisplayItem{
items.add(new AudioStatusDisplayItem(parentID, fragment, statusForContent, att));
}
}
statusForContent.mediaAttachments.stream()
.filter(att->att.type.equals(Attachment.Type.UNKNOWN))
.map(att -> new FileStatusDisplayItem(parentID, fragment, att))
.forEach(items::add);
if(statusForContent.poll!=null){
buildPollItems(parentID, fragment, statusForContent.poll, items);
}
@@ -208,8 +221,15 @@ public abstract class StatusDisplayItem{
item.index=i++;
}
Filter applyingFilter = null;
if (!statusForContent.filterRevealed) {
StatusFilterPredicate predicate = new StatusFilterPredicate(accountID, filterContext, Filter.FilterAction.WARN);
statusForContent.filterRevealed = predicate.test(status);
applyingFilter = predicate.getApplyingFilter();
}
ArrayList<StatusDisplayItem> result = statusForContent.filterRevealed ? items :
new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items)));
new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items, applyingFilter)));
if (addFooter && status.hasGapAfter && !(fragment instanceof ThreadFragment)) {
StatusDisplayItem gap = new GapStatusDisplayItem(parentID, fragment);
@@ -242,7 +262,8 @@ public abstract class StatusDisplayItem{
GAP,
EXTENDED_FOOTER,
MEDIA_GRID,
WARNING
WARNING,
FILE
}
public static abstract class Holder<T extends StatusDisplayItem> extends BindableViewHolder<T> implements UsableRecyclerView.DisableableClickable{

View File

@@ -65,6 +65,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
spoilerEmojiHelper.setText(parsedSpoilerText);
}
session = AccountSessionManager.getInstance().getAccount(parentFragment.getAccountID());
UiUtils.loadMaxWidth(parentFragment.getContext());
}
public void setTranslationShown(boolean translationShown) {
@@ -241,8 +242,19 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
readMore.setVisibility(View.GONE);
}
// incredibly ugly workaround for https://github.com/sk22/megalodon/issues/520
// i am so, so sorry. FIXME
// attempts to use OnPreDrawListener, OnGlobalLayoutListener and .post have failed -
// the view didn't want to reliably update after calling .setVisibility etc :(
int width = parent.getWidth() != 0 ? parent.getWidth()
: item.parentFragment.getView().getWidth() != 0
? item.parentFragment.getView().getWidth()
: item.parentFragment.getParentFragment() != null && item.parentFragment.getParentFragment().getView().getWidth() != 0
? item.parentFragment.getParentFragment().getView().getWidth() // YIKES
: UiUtils.MAX_WIDTH;
text.measure(
View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
if (GlobalUserPreferences.collapseLongPosts && !item.status.textExpandable) {

View File

@@ -7,6 +7,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Status;
import java.util.List;
@@ -15,11 +16,13 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
public boolean loading;
public final Status status;
public List<StatusDisplayItem> filteredItems;
public Filter applyingFilter;
public WarningFilteredStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status, List<StatusDisplayItem> filteredItems){
public WarningFilteredStatusDisplayItem(String parentID, BaseStatusListFragment<?> parentFragment, Status status, List<StatusDisplayItem> filteredItems, Filter applyingFilter){
super(parentID, parentFragment);
this.status=status;
this.filteredItems = filteredItems;
this.applyingFilter = applyingFilter;
}
@Override
@@ -41,7 +44,7 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
@Override
public void onBind(WarningFilteredStatusDisplayItem item) {
filteredItems = item.filteredItems;
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.status.filtered.get(item.status.filtered.size() -1).filter.title));
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.applyingFilter.title));
}
@Override

View File

@@ -38,6 +38,7 @@ public class DiscoverInfoBannerHelper{
case LOCAL_TIMELINE -> R.string.local_timeline_info_banner;
case FEDERATED_TIMELINE -> R.string.sk_federated_timeline_info_banner;
case POST_NOTIFICATIONS -> R.string.sk_notify_posts_info_banner;
case BUBBLE_TIMELINE -> R.string.sk_bubble_timeline_info_banner;
});
}
}
@@ -63,6 +64,7 @@ public class DiscoverInfoBannerHelper{
LOCAL_TIMELINE,
FEDERATED_TIMELINE,
POST_NOTIFICATIONS,
// ACCOUNTS
// ACCOUNTS,
BUBBLE_TIMELINE
}
}

View File

@@ -99,6 +99,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@@ -633,9 +634,9 @@ public class UiUtils {
if (relationship.blocking) {
button.setText(R.string.button_blocked);
secondaryStyle = true;
} else if (relationship.blockedBy) {
button.setText(R.string.button_follow);
secondaryStyle = false;
// } else if (relationship.blockedBy) {
// button.setText(R.string.button_follow);
// secondaryStyle = false;
} else if (relationship.requested) {
button.setText(R.string.button_follow_pending);
secondaryStyle = true;
@@ -649,7 +650,8 @@ public class UiUtils {
if (keepText) button.setText(textBefore);
button.setEnabled(!relationship.blockedBy);
// https://github.com/sk22/megalodon/issues/526
// button.setEnabled(!relationship.blockedBy);
int attr = secondaryStyle ? R.attr.secondaryButtonStyle : android.R.attr.buttonStyle;
TypedArray ta = button.getContext().obtainStyledAttributes(new int[]{attr});
int styleRes = ta.getResourceId(0, 0);
@@ -946,7 +948,7 @@ public class UiUtils {
public static String getInstanceName(String accountID) {
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
Instance instance = session.getInstance();
return instance != null && !instance.title.isBlank() ? instance.title : session.domain;
}
@@ -1112,14 +1114,20 @@ public class UiUtils {
if (!results.statuses.isEmpty()) {
args.putParcelable("status", Parcels.wrap(results.statuses.get(0)));
Nav.go((Activity) context, ThreadFragment.class, args);
} else if (!results.accounts.isEmpty()) {
args.putParcelable("profileAccount", Parcels.wrap(results.accounts.get(0)));
Nav.go((Activity) context, ProfileFragment.class, args);
} else {
if (launchBrowser) launchWebBrowser(context, url);
else
Toast.makeText(context, R.string.sk_resource_not_found, Toast.LENGTH_SHORT).show();
return;
}
Optional<Account> account = results.accounts.stream()
.filter(a -> uri.equals(Uri.parse(a.url))).findAny();
if (account.isPresent()) {
args.putParcelable("profileAccount", Parcels.wrap(account.get()));
Nav.go((Activity) context, ProfileFragment.class, args);
return;
}
if (launchBrowser) {
launchWebBrowser(context, url);
return;
}
Toast.makeText(context, R.string.sk_resource_not_found, Toast.LENGTH_SHORT).show();
}
@Override

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

@@ -85,7 +85,7 @@ public class MastodonLanguage {
private final MastodonLanguage fallbackLanguage;
public LanguageResolver(Instance instanceInfo) {
String fallbackLanguageTag = !instanceInfo.languages.isEmpty() ? instanceInfo.languages.get(0) : ENGLISH.languageTag;
String fallbackLanguageTag = (instanceInfo.languages != null && !instanceInfo.languages.isEmpty()) ? instanceInfo.languages.get(0) : ENGLISH.languageTag;
fallbackLanguage = allLanguages.stream()
.filter(l->l.languageTag.equalsIgnoreCase(fallbackLanguageTag)).findAny()
.orElse(ENGLISH);

View File

@@ -6,54 +6,80 @@ import org.joinmastodon.android.model.Status;
import java.time.Instant;
import java.util.List;
import java.util.Optional;
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;
private Filter applyingFilter;
public StatusFilterPredicate(List<Filter> filters){
this.filters=filters;
/**
* @param context null makes the predicate pass automatically
* @param action defines what the predicate should check:
* status should not be hidden or should not display with warning
*/
public StatusFilterPredicate(List<Filter> filters, Filter.FilterContext context, Filter.FilterAction action){
this.filters = filters;
this.context = context;
this.action = action;
}
public StatusFilterPredicate(String accountID, Filter.FilterContext context){
public StatusFilterPredicate(List<Filter> filters, Filter.FilterContext context){
this(filters, context, Filter.FilterAction.HIDE);
}
/**
* @param context null makes the predicate pass automatically
* @param action defines what the predicate should check:
* status 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;
}
/**
* @param context null makes the predicate pass automatically
*/
public StatusFilterPredicate(String accountID, Filter.FilterContext context){
this(accountID, context, Filter.FilterAction.HIDE);
}
/**
* @return whether the status should be displayed without being hidden/warned about.
* will always return true if the context is null.
* true = display this status,
* false = filter this status
*/
@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;
Stream<Filter> matchingFilters = 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));
Optional<Filter> applyingFilter = matchingFilters
// 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
.filter(filter -> filter.filterAction == null ? action == Filter.FilterAction.HIDE : filter.filterAction == action)
.findAny();
this.applyingFilter = applyingFilter.orElse(null);
return applyingFilter.isEmpty();
}
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;
public Filter getApplyingFilter() {
return applyingFilter;
}
}

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<ripple
xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:drawable="@drawable/bg_search_field" />
</ripple>

View File

@@ -0,0 +1,9 @@
<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="M11.772,3.744C14.114,1.4 17.913,1.4 20.256,3.744C22.539,6.027 22.597,9.692 20.431,12.046L20.243,12.243L11.443,21.041L11.407,21.072C9.945,22.388 7.691,22.344 6.284,20.936C4.965,19.617 4.843,17.555 5.918,16.098C5.941,16.052 5.969,16.009 6.002,15.968L6.056,15.908L6.143,15.82L6.284,15.672L6.287,15.675L13.723,8.221C13.989,7.954 14.405,7.93 14.699,8.147L14.783,8.22C15.05,8.485 15.075,8.902 14.857,9.196L14.785,9.28L7.19,16.893C6.473,17.769 6.522,19.063 7.34,19.881C8.169,20.71 9.488,20.749 10.364,19.999L19.197,11.168C20.952,9.411 20.952,6.562 19.195,4.804C17.493,3.102 14.766,3.049 12.999,4.645L12.831,4.804L12.819,4.819L3.282,14.355C2.989,14.648 2.515,14.648 2.222,14.355C1.955,14.089 1.931,13.672 2.149,13.378L2.222,13.294L11.771,3.744L11.772,3.744Z"
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.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,59 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<org.joinmastodon.android.ui.views.MaxWidthFrameLayout
android:id="@+id/inner"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:maxWidth="@dimen/layout_max_width">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="4dp"
android:background="@drawable/bg_search_button"
android:paddingVertical="12dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="18dp"
android:importantForAccessibility="no"
android:src="@drawable/ic_fluent_attach_24_regular" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingHorizontal="16dp"
android:orientation="vertical">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_body_large"
android:singleLine="true"
android:ellipsize="middle"
tools:text="07a9d88625a9d63d680f35baf040156e71ed87e5f068f14d332c0c5a83f7a939.webm"/>
<TextView
android:id="@+id/domain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_body_medium"
android:textColor="?android:textColorSecondary"
tools:text="example.com"/>
</LinearLayout>
</LinearLayout>
</org.joinmastodon.android.ui.views.MaxWidthFrameLayout>
</FrameLayout>

View File

@@ -416,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

@@ -29,10 +29,10 @@
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="24sp"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/avatar"
android:layout_toStartOf="@id/button"
android:layout_marginTop="2sp"
android:layout_above="@+id/username"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center_vertical"
@@ -40,16 +40,16 @@
tools:text="User"/>
<TextView
android:id="@+id/username"
android:id="@id/username"
android:layout_width="match_parent"
android:layout_height="20sp"
android:layout_below="@id/name"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/avatar"
android:layout_toStartOf="@id/button"
android:layout_alignBottom="@id/avatar"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center_vertical"
android:textAppearance="@style/m3_title_small"
android:paddingBottom="3sp"
tools:text="\@user@server"/>
<View

View File

@@ -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"
@@ -87,15 +87,18 @@
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:paddingBottom="16dp"
android:layout_marginStart="16dp">
android:layout_marginBottom="16dp"
android:layout_marginStart="16dp"
android:layout_gravity="bottom"
android:paddingTop="4dp"
android:gravity="center_vertical"
android:minHeight="44dp">
<LinearLayout
android:id="@+id/posts_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp"
android:gravity="center_vertical"
android:orientation="horizontal">
@@ -122,7 +125,7 @@
android:id="@+id/following_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginTop="2dp"
android:layout_marginEnd="8dp"
android:orientation="horizontal"
android:gravity="center_vertical">
@@ -149,7 +152,7 @@
android:id="@+id/followers_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginTop="2dp"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView

View File

@@ -8,7 +8,7 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_search_field">
android:background="@drawable/bg_search_button">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"

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

@@ -33,6 +33,7 @@
android:textColor="?android:textColorSecondary" />
<ImageView
android:id="@+id/icon"
android:importantForAccessibility="no"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>

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

@@ -465,21 +465,7 @@
<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>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sk_confirm_delete_and_redraft">هل أنت متأكد أنك تريد حذف وإعادة صياغة هذا المنشور؟</string>
<string name="sk_visibility_unlisted">غير مدرج</string>
<string name="sk_list_timelines">القوائم</string>
<string name="sk_follow_requests">طلبات المتابعة</string>
<string name="sk_pinned_posts">مدبّس</string>
<string name="sk_delete_and_redraft">حذف وإعادة الصياغة</string>
<string name="sk_confirm_delete_and_redraft_title">حذف وإعادة صياغة الرسالة</string>
<string name="sk_pin_post">تدبيس على الصفحة الشخصية</string>
<string name="sk_confirm_pin_post_title">تدبيس الرسالة على الصفحة الشخصية</string>
<string name="sk_settings_show_federated_timeline">إظهار الخيط الفديرالي</string>
<string name="sk_settings_contribute">المساهمة في Megalodon</string>
<string name="sk_accept_follow_request">قبول طلب المتابعة</string>
<string name="sk_reject_follow_request">رفض طلب المتابعة</string>
<string name="sk_lists_with_user">قوائم بها %s</string>
</resources>

View File

@@ -10,11 +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 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">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>
@@ -164,6 +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 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>
@@ -220,6 +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">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>
@@ -246,6 +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">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>
@@ -266,6 +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">Fremhæv</string>
<string name="button_favorite">Favorit</string>
<string name="button_share">Del</string>
<string name="media_no_description">Medier uden beskrivelse</string>
@@ -279,7 +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 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>
@@ -321,8 +330,13 @@
<item quantity="one">%,d favoritmarkering</item>
<item quantity="other">%,d favoritmarkeringer</item>
</plurals>
<plurals name="x_reblogs">
<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">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>
@@ -369,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>
@@ -402,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,11 +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 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 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>
@@ -164,6 +166,7 @@
<string name="report_sent_subtitle">Während wir den Vorfall überprüfen, kannst du gegen %s weitere Maßnahmen ergreifen.</string>
<string name="unfollow_user">%s entfolgen</string>
<string name="unfollow">Entfolgen</string>
<string name="mute_user_explain">Du wirst die eigenen und geteilten Beiträge des Kontos nicht mehr sehen können. Dass du das Profil stummgeschaltet hast, erfährt die Person nicht.</string>
<string name="block_user_explain">Dir wird es nicht länger möglich sein, die Beiträge dieses Konto zu sehen. Das blockierte Profil wird nicht mehr in der Lage sein, deine Beiträge zu sehen oder dir zu folgen. Die Person hinter dem Konto wird mitbekommen, dass du ihr Konto gesperrt hast.</string>
<string name="report_personal_title">Möchtest du das nicht mehr sehen?</string>
<string name="report_personal_subtitle">Wenn du etwas auf Mastodon siehst, das dir nicht gefällt, kannst du die Person aus deinem Umfeld entfernen.</string>
@@ -220,6 +223,7 @@
<string name="skip">Überspringen</string>
<string name="notification_type_follow">Neue Follower</string>
<string name="notification_type_favorite">Favoriten</string>
<string name="notification_type_reblog">Geteilte Beiträge</string>
<string name="notification_type_mention">Erwähnungen</string>
<string name="notification_type_poll">Umfragen</string>
<string name="choose_account">Konto auswählen</string>
@@ -246,6 +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">Teilte meinen Beitrag</string>
<string name="notify_mention">mich erwähnt</string>
<string name="settings_boring">Langweiliges</string>
<string name="settings_account">Kontoeinstellungen</string>
@@ -266,6 +271,7 @@
<string name="hide_content">Inhalt ausblenden</string>
<string name="new_post">Neuer Beitrag</string>
<string name="button_reply">Antworten</string>
<string name="button_reblog">Teilen</string>
<string name="button_favorite">Favorisieren</string>
<string name="button_share">Teilen</string>
<string name="media_no_description">Medien ohne Beschreibung</string>
@@ -281,6 +287,8 @@
<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 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>
@@ -322,8 +330,13 @@
<item quantity="one">%,d × favorisiert</item>
<item quantity="other">%,d × favorisiert</item>
</plurals>
<plurals name="x_reblogs">
<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>
<string name="post_info_reblogs">Geteilte Beiträge</string>
<string name="post_info_favorites">Favoriten</string>
<string name="edit_history">Verlauf bearbeiten</string>
<string name="last_edit_at_x">Zuletzt bearbeitet: %s</string>
@@ -413,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

@@ -6,11 +6,11 @@
<string name="next">Επόμενο</string>
<string name="loading_instance">Ανάκτηση πληροφοριών διακομιστή…</string>
<string name="error">Σφάλμα</string>
<string name="not_a_mastodon_instance">%s δεν φαίνεται να είναι διακομιστής Mastodon.</string>
<string name="not_a_mastodon_instance">Το %s δε φαίνεται να είναι διακομιστής Mastodon.</string>
<string name="ok">ΟΚ</string>
<string name="preparing_auth">Προετοιμασία για έλεγχο ταυτότητας…</string>
<string name="finishing_auth">Ολοκλήρωση ταυτοποίησης…</string>
<string name="user_boosted">%s ενισχύθηκε</string>
<string name="user_boosted">Ο χρήστης %s ενίσχυσε</string>
<string name="in_reply_to">Σε απάντηση στο %s</string>
<string name="notifications">Ειδοποιήσεις</string>
<string name="user_followed_you">σε ακολουθεί</string>
@@ -61,7 +61,7 @@
<item quantity="other">%,d αναρτήσεις</item>
</plurals>
<string name="profile_joined">Έγινε μέλος</string>
<string name="done">Εγινε</string>
<string name="done">Έγινε</string>
<string name="loading">Φόρτωση…</string>
<string name="field_label">Περιγραφή</string>
<string name="field_content">Περιεχόμενο</string>
@@ -122,7 +122,7 @@
<string name="tap_to_reveal">Πάτα για εμφάνιση</string>
<string name="delete">Διαγραφή</string>
<string name="confirm_delete_title">Διαγραφή ανάρτησης</string>
<string name="confirm_delete">Είσαι βέβαιοος ότι θες να διαγράψεις την ανάρτηση;</string>
<string name="confirm_delete">Είσαι βέβαιος ότι θες να διαγράψεις την ανάρτηση;</string>
<string name="deleting">Διαγραφή…</string>
<string name="notification_channel_audio_player">Αναπαραγωγή ήχου</string>
<string name="play">Αναπαραγωγή</string>
@@ -146,9 +146,9 @@
<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_choose_reason_subtitle">Διάλεξε την καλύτερη αντιστοίχιση</string>
<string name="report_reason_personal">Δεν μου αρέσει</string>
<string name="report_reason_personal_subtitle">Δεν είναι κάτι που θα ηθέλες να δεις</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>
@@ -160,22 +160,22 @@
<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="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="mute_user_explain">Δε θα βλέπεις τις αναρτήσεις ή τις ενισχύσεις τους στην αρχική σελίδα σου. Δε θα ξέρουν ότι βρίσκονται σε σίγαση.</string>
<string name="block_user_explain">Δε θα μπορούν πλέον να σε ακολουθούν ή να βλέπουν τις αναρτήσεις σου, αλλά μπορούν να δουν αν έχουν αποκλειστεί.</string>
<string name="report_personal_title">Δε θες να το βλέπεις αυτό;</string>
<string name="report_personal_subtitle">Όταν βλέπεις κάτι που δεν σου αρέσει στο Mastodon, μπορείς να αφαιρέσεις το άτομο από την εμπειρία σου.</string>
<string name="report_personal_subtitle">Όταν βλέπεις κάτι που δε σου αρέσει στο Mastodon, μπορείς να αφαιρέσεις το άτομο από την εμπειρία σου.</string>
<string name="back">Πίσω</string>
<string name="instance_catalog_title">Το Mastodon αποτελείται από χρήστες σε διαφορετικούς διακομιστές.</string>
<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="instance_rules_subtitle">Συνεχίζοντας, συμφωνείς να τηρείς τους ακόλουθους κανόνες που έχουν οριστεί και επιβάλλονται από τους %s συντονιστές.</string>
<string name="signup_title">Δημιουργία Λογαριασμού</string>
<string name="edit_photo">επεξεργασία</string>
<string name="display_name">Όνομα</string>
@@ -197,14 +197,14 @@
<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_title">Έλεγξε τα Εισερχόμενα σου</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Πάτησε το σύνδεσμο που σου στείλαμε για να επαληθεύσεις το %s. Θα σε περιμένουμε εδώ.</string>
<string name="confirm_email_didnt_get">Έλαβες τον σύνδεσμο;</string>
<string name="confirm_email_didnt_get">Δεν έλαβες τον σύνδεσμο;</string>
<string name="resend">Επαναποστολή</string>
<string name="open_email_app">Άνοιγμα εφαρμογής email</string>
<string name="resent_email">Το email επιβεβαίωσης εστάλη</string>
<string name="compose_hint">Πληκτρολόγησε ή επικολλησε τι υπάρχει στο μυαλό σου</string>
<string name="compose_hint">Πληκτρολόγησε ή επικόλλησε τί έχεις στο μυαλό σου</string>
<string name="content_warning">Προειδοποίηση περιεχομένου</string>
<string name="add_image_description">Προσθήκη περιγραφής εικόνας…</string>
<string name="retry_upload">Επανάληψη μεταμόρφωσης</string>
@@ -212,7 +212,7 @@
<string name="save">Αποθήκευση</string>
<string name="add_alt_text">Προσθήκη εναλλακτικού κειμένου</string>
<string name="alt_text_subtitle">Το εναλλακτικό κείμενο περιγράφει τις φωτογραφίες σου για άτομα με χαμηλή ή καθόλου όραση. Προσπάθησε να συμπεριλάβεις μόνο όσες λεπτομέρειες χρειάζεται για να γίνει κατανοητό το περιεχόμενο.</string>
<string name="alt_text_hint">π.χ. Ένας σκύλος που κοιτάζει γύρω του ύποπτα με μισόκλειστα μάτια στην κάμερα.</string>
<string name="alt_text_hint">πχ. Ένας σκύλος που κοιτάζει γύρω του ύποπτα με μισόκλειστα μάτια στην κάμερα.</string>
<string name="visibility_public">Δημόσιο</string>
<string name="visibility_followers_only">Μόνο ακόλουθοι</string>
<string name="visibility_private">Μόνο άτομα που επισημαίνω</string>
@@ -252,14 +252,14 @@
<string name="notify_follow">Με ακολουθεί</string>
<string name="notify_reblog">Ενισχύει την ανάρτησή μου</string>
<string name="notify_mention">Με επισημαίνει</string>
<string name="settings_boring">Η βαρετή ζώνη</string>
<string name="settings_boring">Η ζώνη της βαρεμάρας</string>
<string name="settings_account">Ρυθμίσεις λογαριασμού</string>
<string name="settings_contribute">Συνείσφερε στο Mastodon</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">Mastodon για Android έκδοση %1$s (%2$d)</string>
<string name="settings_app_version">Mastodon για Android v%1$s (%2$d)</string>
<string name="media_cache_cleared">Η προσωρινή μνήμη πολυμέσων καθαρίστηκε</string>
<string name="confirm_log_out">Είσαι βέβαιος ότι θες να αποσυνδεθείς;</string>
<string name="sensitive_content">Ευαίσθητο περιεχόμενο</string>
@@ -285,7 +285,7 @@
<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="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>
@@ -297,7 +297,7 @@
<string name="reorder">Αναδιάταξη</string>
<string name="download">Λήψη</string>
<string name="permission_required">Απαιτούνται δικαιώματα</string>
<string name="storage_permission_to_download">Η εφαρμογή χρειάζεται πρόσβαση στον αποθηκευτικό σου χώρο για να αποθηκεύσεις αυτό το αρχείο.</string>
<string name="storage_permission_to_download">Η εφαρμογή χρειάζεται πρόσβαση στον αποθηκευτικό σου χώρο για να αποθηκεύσει αυτό το αρχείο.</string>
<string name="open_settings">Άνοιγμα ρυθμίσεων</string>
<string name="error_saving_file">Σφάλμα αποθήκευσης αρχείου</string>
<string name="file_saved">Το αρχείο αποθηκεύτηκε</string>
@@ -311,7 +311,7 @@
<string name="dismiss">Παράβλεψη</string>
<string name="see_new_posts">Δες νέες αναρτήσεις</string>
<string name="load_missing_posts">Φόρτωση αναρτήσεων που λείπουν</string>
<string name="follow_back">Ακολούθησε Και Συ</string>
<string name="follow_back">Ακολούθησε και εσύ</string>
<string name="button_follow_pending">Εκκρεμεί</string>
<string name="follows_you">Σε ακολουθεί</string>
<string name="manually_approves_followers">Χειροκίνητη έγκριση ακολούθων</string>
@@ -438,11 +438,11 @@
<string name="show">Εμφάνιση</string>
<string name="hide">Απόκρυψη</string>
<string name="join_default_server">Συμμετοχή %s</string>
<string name="pick_server">Επίλεξε το δικό μου διακομιστή</string>
<string name="pick_server">Διάλεξε άλλο διακομιστή</string>
<string name="signup_or_login">ή</string>
<string name="learn_more">Μάθε περισσότερα</string>
<string name="welcome_to_mastodon">Καλώς ήρθες στο Mastodon</string>
<string name="welcome_paragraph1">Το Mastodon είναι ένα αποκεντρωμένο κοινωνικό δίκτυο, που σημαίνει ότι καμία εταιρεία δεν το ελέγχει. Αποτελείται από πολλούς ανεξάρτητους διακομιστές, όλοι συνδεδεμένοι μαζί.</string>
<string name="welcome_paragraph1">Το Mastodon είναι ένα αποκεντρωμένο κοινωνικό δίκτυο που σημαίνει ότι καμία εταιρεία δεν το ελέγχει. Αποτελείται από πολλούς ανεξάρτητους διακομιστές, όλοι συνδεδεμένοι μαζί.</string>
<string name="what_are_servers">Τι είναι οι διακομιστές;</string>
<string name="welcome_paragraph2"><![CDATA[Κάθε λογαριασμός Mastodon φιλοξενείται σε ένα διακομιστή - ο καθένας με τις δικές του αξίες, κανόνες, & διαχειριστές. Ανεξάρτητα από το ποιον μπορεί να επιλέξεις, μπορείς να ακολουθήσεις και να αλληλεπιδράσεις με άτομα από οποιονδήποτε διακομιστή.]]></string>
<string name="welcome_paragraph2"><![CDATA[Κάθε λογαριασμός Mastodon φιλοξενείται σε ένα διακομιστή - ο καθένας με τις δικές του αξίες, κανόνες και διαχειριστές. Ανεξάρτητα από το ποιον μπορεί να επιλέξεις, μπορείς να ακολουθήσεις και να αλληλεπιδράσεις με άτομα από οποιονδήποτε διακομιστή.]]></string>
</resources>

View File

@@ -10,11 +10,13 @@
<string name="ok">Aceptar</string>
<string name="preparing_auth">Preparando para autenticación…</string>
<string name="finishing_auth">Finalizando autenticación…</string>
<string name="user_boosted">%s retooteó</string>
<string name="in_reply_to">En respuesta a %s</string>
<string name="notifications">Notificaciones</string>
<string name="user_followed_you">ha empezado a seguirte</string>
<string name="user_sent_follow_request">te envió una solicitud de seguimiento</string>
<string name="user_favorited">marcó como favorita</string>
<string name="notification_boosted">retooteó tu publicación</string>
<string name="poll_ended">encuesta finalizada</string>
<string name="time_seconds">%ds</string>
<string name="time_minutes">%dm</string>
@@ -164,6 +166,7 @@
<string name="report_sent_subtitle">Mientras revisamos esto, puedes tomar medidas contra %s.</string>
<string name="unfollow_user">Dejar de seguir a %s</string>
<string name="unfollow">Dejar de seguir</string>
<string name="mute_user_explain">No verás sus publicaciones o reblogueos en tu línea temporal. No sabrán que han sido silenciados.</string>
<string name="block_user_explain">Ya no podrán seguir o ver tus mensajes, pero pueden ver si han sido bloqueados.</string>
<string name="report_personal_title">¿No quieres ver esto?</string>
<string name="report_personal_subtitle">Cuando vea en Mastodon algo que no le agrada, puede sacar a la persona de su experiencia.</string>
@@ -220,6 +223,7 @@
<string name="skip">Saltar</string>
<string name="notification_type_follow">Nuevos seguidores</string>
<string name="notification_type_favorite">Favoritos</string>
<string name="notification_type_reblog">Retoots</string>
<string name="notification_type_mention">Menciones</string>
<string name="notification_type_poll">Encuestas</string>
<string name="choose_account">Elegir cuenta</string>
@@ -246,6 +250,7 @@
<string name="notify_none">nadie</string>
<string name="notify_favorites">Marca mi post como favorito</string>
<string name="notify_follow">Me sigue</string>
<string name="notify_reblog">Retootearán mi publicación</string>
<string name="notify_mention">Me menciona</string>
<string name="settings_boring">La zona aburrida</string>
<string name="settings_account">Ajustes de la cuenta</string>
@@ -266,6 +271,7 @@
<string name="hide_content">Ocultar contenido</string>
<string name="new_post">Nuevo post</string>
<string name="button_reply">Responder</string>
<string name="button_reblog">Retootear</string>
<string name="button_favorite">Favorito</string>
<string name="button_share">Compartir</string>
<string name="media_no_description">Medios sin descripción</string>
@@ -281,6 +287,8 @@
<string name="followed_user">Ahora estás siguiendo a %s</string>
<string name="following_user_requested">%s solicitó seguirte</string>
<string name="open_in_browser">Abrir en el navegador</string>
<string name="hide_boosts_from_user">Ocultar retoots de %s</string>
<string name="show_boosts_from_user">Mostrar retoots de %s</string>
<string name="signup_reason">¿Por qué quieres unirte?</string>
<string name="signup_reason_note">Esto nos ayudará a revisar su solicitud.</string>
<string name="clear">Borrar</string>
@@ -322,8 +330,13 @@
<item quantity="one">%,d favorito</item>
<item quantity="other">%,d favoritos</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d retooteo</item>
<item quantity="other">%,d retooteos</item>
</plurals>
<string name="timestamp_via_app">%1$s a través de %2$s</string>
<string name="time_now">ahora</string>
<string name="post_info_reblogs">Retoots</string>
<string name="post_info_favorites">Favoritos</string>
<string name="edit_history">Editar historial</string>
<string name="last_edit_at_x">Última edición: %s</string>
@@ -413,4 +426,23 @@
<!-- %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 no permite registros desde %2$s. Prueba uno diferente o &lt;a&gt;elige un servidor diferente&lt;/a&gt;.</string>
<string name="signup_username_taken">Este nombre de usuario ya existe.</string>
<string name="spoiler_show">Mostrar de todos modos</string>
<string name="spoiler_hide">Volver a ocultar</string>
<string name="poll_multiple_choice">Escoge una o más</string>
<string name="save_changes">Guardar cambios</string>
<string name="profile_featured">Destacado</string>
<string name="profile_timeline">Línea de tiempo</string>
<string name="view_all">Ver todo</string>
<string name="profile_endorsed_accounts">Cuentas</string>
<string name="verified_link">Enlace verificado</string>
<string name="show">Mostrar</string>
<string name="hide">Ocultar</string>
<string name="join_default_server">Unirse a %s</string>
<string name="pick_server">Elegir otro servidor</string>
<string name="signup_or_login">o</string>
<string name="learn_more">Saber más</string>
<string name="welcome_to_mastodon">Bienvenido/da a Mastodon</string>
<string name="welcome_paragraph1">Mastodon es una red social descentralizada, lo que significa que no la controla una sola compañía. Está formada por muchos servidores independientes, todos juntos conectados.</string>
<string name="what_are_servers">¿Qué son los servidores?</string>
<string name="welcome_paragraph2"><![CDATA[Cada cuenta de Mastodon está alojada en un servidor — cada uno con sus propios valores, reglas y administradores. No importa cual elijas, puede seguir e interactuar con personas en cualquier servidor.]]></string>
</resources>

View File

@@ -83,8 +83,8 @@
<string name="sk_settings_translation_availability_note_unavailable">%s no parece admitir la traducción.</string>
<string name="sk_loading_fediverse_resource_title">Buscándolo en el Fediverso</string>
<string name="sk_quote_post">Publicar sobre esto</string>
<string name="sk_undo_reblog">Deshacer reblogueo</string>
<string name="sk_reblog_with_visibility">Rebloguea con visibilidad</string>
<string name="sk_undo_reblog">Deshacer compartir</string>
<string name="sk_reblog_with_visibility">Comparte con visibilidad</string>
<string name="sk_hashtags_you_follow">Etiquetas que sigues</string>
<string name="sk_copy_link_to_post">Copiar enlace de la publicación</string>
<string name="sk_open_with_account">Abrir con otra cuenta</string>
@@ -94,9 +94,9 @@
<string name="sk_already_bookmarked">Ya en marcadores</string>
<string name="sk_favorited_as">Marcado favorito como %s</string>
<string name="sk_already_favorited">Ya es un favorito</string>
<string name="sk_reblog_as">Impulsar con otra cuenta</string>
<string name="sk_reblogged_as">Impulsado como %s</string>
<string name="sk_already_reblogged">Ya se había impulsado</string>
<string name="sk_reblog_as">Compartir con otra cuenta</string>
<string name="sk_reblogged_as">Compartido como %s</string>
<string name="sk_already_reblogged">Ya impulsado</string>
<string name="sk_reply_as">Responder con otra cuenta</string>
<string name="sk_bookmark_as">Añadir a marcadores con otra cuenta</string>
<string name="sk_favorite_as">Marcar favorito con otra cuenta</string>
@@ -214,7 +214,7 @@
<string name="sk_alt_button">ALT</string>
<string name="sk_post_edited">editado</string>
<string name="sk_notification_type_update">Publicaciones editadas</string>
<string name="sk_notify_update">Editó una publicación impulsada</string>
<string name="sk_notify_update">editado una publicación compartida</string>
<string name="sk_searching">Buscando…</string>
<string name="sk_no_results">Sin resultados</string>
<string name="sk_save_draft">¿Guardar el borrador\?</string>
@@ -271,6 +271,19 @@
<string name="sk_notification_action_replied">Respuesta enviada a %s</string>
<string name="sk_reply_line_above_avatar">\"En respuesta a\" línea sobre el avatar</string>
<string name="sk_show_thread">Mostrar hilo</string>
<string name="sk_compact_reblog_reply_line">Línea compacta de reblog/respuesta</string>
<string name="sk_compact_reblog_reply_line">Línea compacta compartida/respondida</string>
<string name="sk_settings_confirm_before_reblog">Confirmar antes de volver a publicar</string>
<string name="sk_reacted_with">reaccionó con %s</string>
<string name="sk_reacted">reaccionó</string>
<string name="sk_content_type">Tipo del contenido</string>
<string name="sk_content_type_unspecified">Sin especificar</string>
<string name="sk_content_type_plain">Texto sin formato</string>
<string name="sk_content_type_html">HTML</string>
<string name="sk_content_type_markdown">Markdown</string>
<string name="sk_content_type_bbcode">BBCode</string>
<string name="sk_content_type_mfm">MFM</string>
<string name="sk_settings_content_types">Habilitar el formato de los mensajes</string>
<string name="sk_settings_default_content_type">Contenido por defecto</string>
<string name="sk_settings_content_types_explanation">Permite establecer un tipo de contenido como Markdown al crear una entrada. Ten en cuenta que no todas las instancias lo admiten.</string>
<string name="sk_settings_default_content_type_explanation">Permite preseleccionar un tipo de contenido al crear nuevas entradas, anulando el valor establecido en \"Preferencias de publicación\".</string>
</resources>

View File

@@ -274,4 +274,17 @@
<string name="sk_compact_reblog_reply_line">Ligne boost/réponse compacte</string>
<string name="sk_reply_line_above_avatar">Ligne \"En réponse à\" au-dessus de l\'avatar</string>
<string name="sk_settings_confirm_before_reblog">Confirmer avant de booster</string>
<string name="sk_reacted">a réagi</string>
<string name="sk_reacted_with">a réagi avec %s</string>
<string name="sk_content_type">Type de contenu</string>
<string name="sk_content_type_plain">Texte brut</string>
<string name="sk_content_type_html">HTML</string>
<string name="sk_content_type_markdown">Markdown</string>
<string name="sk_content_type_bbcode">BBCode</string>
<string name="sk_content_type_mfm">MFM</string>
<string name="sk_settings_content_types">Activer la mise en forme du message</string>
<string name="sk_settings_default_content_type_explanation">Cela vous permet de présélectionner un type de contenu lors de la création de nouveaux messages, en remplaçant la valeur définie dans \"Préférences de publication\".</string>
<string name="sk_content_type_unspecified">Non spécifié</string>
<string name="sk_settings_content_types_explanation">Permet de définir un type de contenu comme Markdown lors de la création d\'un message. Gardez à l\'esprit que toutes les instances ne le prennent pas en charge.</string>
<string name="sk_settings_default_content_type">Type de contenu par défaut</string>
</resources>

View File

@@ -1,16 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="get_started">Cruthaich cunntas</string>
<string name="already_have_account">Tha cunntas agam mu thràth</string>
<string name="log_in">Clàraich a-steach</string>
<string name="next">Air adhart</string>
<string name="loading_instance">A faighinn fiosrachadh an fhrithealaiche…</string>
<string name="error">Mearachd</string>
<string name="not_a_mastodon_instance">Tha coltas nach eil %s na fhrithealaiche Mastodon.</string>
<string name="ok">Ceart ma-thà</string>
<string name="preparing_auth">Ag ullachadh an dearbhaidh…</string>
<string name="finishing_auth">A crìochnachadh an dearbhaidh…</string>
<string name="user_boosted">Ga bhrosnachadh le %s</string>
<string name="in_reply_to">A freagairt dha %s</string>
<string name="notifications">Brathan</string>
<string name="user_followed_you"> s iad gad leantainn a-nis</string>
<string name="user_sent_follow_request"> s iad air iarrtas leantainn a chur thugad</string>
<string name="user_favorited"> s iad air am post agad a chur ris na h-annsachdan aca</string>
<string name="notification_boosted"> s iad air a phost agad a bhrosnachadh</string>
<string name="poll_ended">Thàinig cunntas-bheachd gu crìoch</string>
<string name="time_seconds">%dd</string>
<string name="time_minutes">%dm</string>
@@ -188,13 +194,23 @@
<string name="report_sent_subtitle">Fhad s a bhios sinn a toirt sùil air, seo nas urrainn dhut dèanamh an aghaidh %s.</string>
<string name="unfollow_user">Na lean %s tuilleadh</string>
<string name="unfollow">Na lean tuilleadh</string>
<string name="mute_user_explain">Chan fhaic thu na postaichean aca is na bhrosnaich iad nad dachaigh tuilleadh. Cha bhi fios aca gun do mhùch thu iad.</string>
<string name="block_user_explain">Chan urrainn dhaibh gad leantainn is chan fhaic iad na postaichean agad tuilleadh ach chì iad gun deach am bacadh.</string>
<string name="report_personal_title">Nach eil thu airson seo fhaicinn?</string>
<string name="report_personal_subtitle">Nuair a chì thu rudeigin nach toigh leat air Mastodon, s urrainn dhut an neach a chumail fad air falbh uat.</string>
<string name="back">Air ais</string>
<string name="instance_catalog_title">Tha cleachdaichean Mhastodon air iomadh frithealaiche eadar-dhealaichte.</string>
<string name="instance_catalog_subtitle">Tagh frithealaiche stèidhichte air d ùidhean, air far a bheil thu no fear coitcheann. S urrainn dhut conaltradh leis a h-uile duine fhathast ge b e am frithealaiche.</string>
<string name="search_communities">Ainm no URL an fhrithealaiche</string>
<string name="instance_rules_title">Riaghailtean an fhrithealaiche</string>
<string name="instance_rules_subtitle">Ma leanas tu air adhart, aontaichidh tu ris na riaghailtean a tha gan suidheachadh is èigneachadh leis na maoir aig %s.</string>
<string name="signup_title">Cruthaich cunntas</string>
<string name="edit_photo">deasaich</string>
<string name="display_name">Ainm</string>
<string name="username">Ainm-cleachdaiche</string>
<string name="email">Post-d</string>
<string name="password">Facal-faire</string>
<string name="confirm_password">Dearbh am facal-faire</string>
<string name="password_note">Gabh a-steach litrichean mòra, caractaran sònraichte agus àireamhan airson am facal-faire agad a dhèanamh nas treasa.</string>
<string name="category_academia">Sgoilearachd</string>
<string name="category_activism">Iomairteachd</string>
@@ -209,7 +225,10 @@
<string name="category_music">Ceòl</string>
<string name="category_regional">Sgìreil</string>
<string name="category_tech">Teicneolas</string>
<string name="confirm_email_title">Thoir sùil air a bhogsa a-steach agad</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Thoir gnogag air a cheangal a chuir sinn thugad a dhearbhadh %s. Fuirichidh sinn ort an-seo.</string>
<string name="confirm_email_didnt_get">Nach dfhuair thu ceangal?</string>
<string name="resend">Cuir a-rithist</string>
<string name="open_email_app">Fosgail aplacaid a phuist-d</string>
<string name="resent_email">Chaidh post-d dearbhaidh a chur</string>
@@ -232,6 +251,7 @@
<string name="skip">Leum thairis air</string>
<string name="notification_type_follow">Luchd-leantainn ùr</string>
<string name="notification_type_favorite">Annsachdan</string>
<string name="notification_type_reblog">Brosnachaidhean</string>
<string name="notification_type_mention">Iomraidhean</string>
<string name="notification_type_poll">Cunntasan-bheachd</string>
<string name="choose_account">Tagh cunntas</string>
@@ -260,6 +280,7 @@
<string name="notify_none">nach bi duine sam bith</string>
<string name="notify_favorites">air post uam a chur ris na h-annsachdan</string>
<string name="notify_follow">air mo leantainn</string>
<string name="notify_reblog">air post agam a bhrosnachadh</string>
<string name="notify_mention">air iomradh a thoirt orm</string>
<string name="settings_boring">An earrann ràsanach</string>
<string name="settings_account">Roghainnean a chunntais</string>
@@ -280,6 +301,7 @@
<string name="hide_content">Falaich an t-susbaint</string>
<string name="new_post">Post ùr</string>
<string name="button_reply">Freagair</string>
<string name="button_reblog">Brosnaich</string>
<string name="button_favorite">Cuir ris na h-annsachdan</string>
<string name="button_share">Co-roinn</string>
<string name="media_no_description">Meadhan gun tuairisgeul</string>
@@ -293,7 +315,11 @@
<string name="follow_user">Lean %s</string>
<string name="unfollowed_user">Chan eil thu a leantainn %s tuilleadh</string>
<string name="followed_user">Tha thu a leantainn %s a-nis</string>
<string name="following_user_requested">Dhiarr thu %s a leantainn</string>
<string name="open_in_browser">Fosgail sa bhrabhsair</string>
<string name="hide_boosts_from_user">Falaich na brosnachaidhean o %s</string>
<string name="show_boosts_from_user">Seall na brosnachaidhean o %s</string>
<string name="signup_reason">Carson a bu mhiann leat ballrachd fhaighinn?</string>
<string name="signup_reason_note">Bidh e nas fhasa dhuinn lèirmheas a dhèanamh air d iarrtas.</string>
<string name="clear">Falamhaich</string>
<string name="profile_header">Dealbh a bhanna-chinn</string>
@@ -340,8 +366,15 @@
<item quantity="few">%,d annsachdan</item>
<item quantity="other">%,d annsachd</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d bhrosnachadh</item>
<item quantity="two">%,d bhrosnachadh</item>
<item quantity="few">%,d brosnachaidhean</item>
<item quantity="other">%,d brosnachadh</item>
</plurals>
<string name="timestamp_via_app">%1$s slighe %2$s</string>
<string name="time_now">an-dràsta</string>
<string name="post_info_reblogs">Brosnachaidhean</string>
<string name="post_info_favorites">Annsachdan</string>
<string name="edit_history">Eachdraidh nan deasachaidhean</string>
<string name="last_edit_at_x">An deasachadh mu dheireadh %s</string>
@@ -391,9 +424,67 @@
<!-- %s is file size -->
<string name="download_update">Luchdaich a-nuas (%s)</string>
<string name="install_update">Stàlaich</string>
<string name="privacy_policy_title">Do phrìobhaideachd</string>
<string name="privacy_policy_subtitle">Ged nach cruinnich aplacaid Mastodon fhèin dàta sam bith, dhfhaoidte gu bheil poileasaidh eadar-dhealaichte aig an fhrithealaiche leis a chlàraicheas tu.\n\nMur aontaich thu ris a phoileasaidh aig %s, rach air ais is tagh frithealaiche eile.</string>
<string name="i_agree">Gabhaidh mi ris</string>
<string name="empty_list">Tha an liosta seo falamh</string>
<string name="instance_signup_closed">Chan eil am frithealaiche seo a gabhail ri clàraidhean ùra.</string>
<string name="text_copied">Chaidh lethbhreac dheth a chur air an stòr-bhòrd</string>
<string name="add_bookmark">Cruthaich comharra-lìn</string>
<string name="remove_bookmark">Thoir an comharra-lìn air falbh</string>
<string name="bookmarks">Comharran-lìn</string>
<string name="your_favorites">Na h-annsachdan agad</string>
<string name="login_title">Fàilte air ais</string>
<string name="login_subtitle">Clàraich a-steach leis an fhrithealaiche far an do chruthaich thu an cunntas agad.</string>
<string name="server_url">URL an fhrithealaiche</string>
<string name="signup_random_server_explain">Taghaidh sinn frithealaiche dhut stèidhichte air a chànan agad ma leanas tu air adhart gun taghadh.</string>
<string name="server_filter_any_language">Cànan sam bith</string>
<string name="server_filter_instant_signup">Clàradh sa bhad</string>
<string name="server_filter_manual_review">Lèirmheas a làimh</string>
<string name="server_filter_any_signup_speed">Luaths clàraidh sam bith</string>
<string name="server_filter_region_europe">An Roinn-Eòrpa</string>
<string name="server_filter_region_north_america">Aimeireaga a Tuath</string>
<string name="server_filter_region_south_america">Aimeireaga a Deas</string>
<string name="server_filter_region_africa">Afraga</string>
<string name="server_filter_region_asia">Àisia</string>
<string name="server_filter_region_oceania">Roinn a Chuain Sèimh</string>
<string name="not_accepting_new_members">Gun ghabhail ri buill ùra</string>
<string name="category_special_interests">Ùidhean sònraichte</string>
<string name="signup_passwords_dont_match">Chan eil an dà fhacal-faire co-ionnann</string>
<string name="pick_server_for_me">Taghaibh fear dhomh</string>
<string name="profile_add_row">Cuir ràgh ris</string>
<string name="profile_setup">Suidheachadh na pròifile</string>
<string name="profile_setup_subtitle">S urrainn dhut seo a choileanadh air taba na Pròifile uair sam bith.</string>
<string name="profile_setup_explanation">S urrainn dhut suas ri ceithir raointean a chur ris a phròifil agad airson rud sam bith a thogras tu. Ionad, ceanglaichean, roimhearan no ge b e dè eile.</string>
<string name="popular_on_mastodon">Fèillmhor air Mastodon</string>
<string name="follow_all">Lean na h-uile</string>
<string name="server_rules_disagree">Diùlt</string>
<string name="privacy_policy_explanation">Gu goirid: Cha chruinnich is cha dèan sinn pròiseasadh air dad sam bith.</string>
<!-- %s is server domain -->
<string name="server_policy_disagree">Diùlt %s</string>
<string name="profile_bio">Cunntas-beatha</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">A leantainn cleachdaichean…</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">Cha cheadaich %1$s clàradh o %2$s. Feuch fear eile no &lt;a&gt;tagh frithealaiche eile&lt;/a&gt;.</string>
<string name="signup_username_taken">Tha an t-ainm-cleachdaiche seo aig cuideigin eile.</string>
<string name="spoiler_show">Seall e co-dhiù</string>
<string name="spoiler_hide">Falaich a-rithist</string>
<string name="poll_multiple_choice">Tagh co-dhiù aonan</string>
<string name="save_changes">Sàbhail na h-atharraichean</string>
<string name="profile_featured">Ga bhrosnachadh</string>
<string name="profile_timeline">Loidhne-ama</string>
<string name="view_all">Seall a h-uile</string>
<string name="profile_endorsed_accounts">Cunntasan</string>
<string name="verified_link">Ceangal dearbhte</string>
<string name="show">Seall</string>
<string name="hide">Falaich</string>
<string name="join_default_server">Faigh ballrachd aig %s</string>
<string name="pick_server">Tagh frithealaiche eile</string>
<string name="signup_or_login">no</string>
<string name="learn_more">Barrachd fiosrachaidh</string>
<string name="welcome_to_mastodon">Fàilte gu Mastodon</string>
<string name="welcome_paragraph1">S e lìonra sòisealta sgaoilte a th ann am Mastodon agus is ciall dha seo nach eil e fo smachd aon chompanaidh a-mhàin. Tha e dèanta de ghrunn fhrithealaichean a tha gan ruith gu neo-eisimeileach ach ceangailte ri chèile.</string>
<string name="what_are_servers">Dè th anns na frithealaichean?</string>
<string name="welcome_paragraph2"><![CDATA[Tha gach cunntas Mastodon ga òstadh air frithealaiche tha luachan, riaghailtean ⁊ rianairean sònraichte aig gach fear. Ge b e dè am frithealaiche a thaghas tu, s urrainn dhut daoine air frithealaiche sam bith a leantainn is bruidhinn riutha.]]></string>
</resources>

View File

@@ -10,11 +10,13 @@
<string name="ok">OK</string>
<string name="preparing_auth">Preparándose para a autenticación…</string>
<string name="finishing_auth">Rematando coa autenticación…</string>
<string name="user_boosted">%s promoveu</string>
<string name="in_reply_to">Como resposta a %s</string>
<string name="notifications">Notificacións</string>
<string name="user_followed_you">séguete</string>
<string name="user_sent_follow_request">enviouche unha solicitude de seguimento</string>
<string name="user_favorited">marcou a túa publicación como favorita</string>
<string name="notification_boosted">promoveu a túa publicación</string>
<string name="poll_ended">rematou a enquisa</string>
<string name="time_seconds">%ds</string>
<string name="time_minutes">%dm</string>
@@ -164,6 +166,7 @@
<string name="report_sent_subtitle">Mestras revisamos, podes tomar accións contra %s.</string>
<string name="unfollow_user">Deixar de seguir a %s</string>
<string name="unfollow">Deixar de seguir</string>
<string name="mute_user_explain">Non verás as súas publicacións ou repeticións na túa cronoloxía. Non saberá que foi acalada.</string>
<string name="block_user_explain">Non poderá seguirte nin ver o que publicas, pero pode ver se foi bloqueada.</string>
<string name="report_personal_title">Non queres ver esto?</string>
<string name="report_personal_subtitle">Cando ves en Mastodon algo que non che gusta podes retirar a esa persoa da túa experiencia como usuaria.</string>
@@ -220,6 +223,7 @@
<string name="skip">Omitir</string>
<string name="notification_type_follow">Novas seguidoras</string>
<string name="notification_type_favorite">Favoritas</string>
<string name="notification_type_reblog">Promocións</string>
<string name="notification_type_mention">Mencións</string>
<string name="notification_type_poll">Enquisas</string>
<string name="choose_account">Elixir conta</string>
@@ -246,6 +250,7 @@
<string name="notify_none">ninguén</string>
<string name="notify_favorites">Favorece unha publicación miña</string>
<string name="notify_follow">Me segue</string>
<string name="notify_reblog">Promove a miña publicación</string>
<string name="notify_mention">Me menciona</string>
<string name="settings_boring">A zona aburrida</string>
<string name="settings_account">Axustes da conta</string>
@@ -266,6 +271,7 @@
<string name="hide_content">Agochar contido</string>
<string name="new_post">Nova publicación</string>
<string name="button_reply">Responder</string>
<string name="button_reblog">Promover</string>
<string name="button_favorite">Favorecer</string>
<string name="button_share">Compartir</string>
<string name="media_no_description">Multimedia sen descrición</string>
@@ -281,6 +287,8 @@
<string name="followed_user">Estás a seguir a %s</string>
<string name="following_user_requested">Solicitaches seguir a %s</string>
<string name="open_in_browser">Abrir nun navegador</string>
<string name="hide_boosts_from_user">Agochar promocións de @%s</string>
<string name="show_boosts_from_user">Mostrar promocións de %s</string>
<string name="signup_reason">Por qué queres unirte?</string>
<string name="signup_reason_note">Esto axudaranos a revisar a tua solicitude.</string>
<string name="clear">Limpar</string>
@@ -322,8 +330,13 @@
<item quantity="one">%,d favorita</item>
<item quantity="other">%,d favoritas</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d promoción</item>
<item quantity="other">%,d promocións</item>
</plurals>
<string name="timestamp_via_app">%1$s vía %2$s</string>
<string name="time_now">agora</string>
<string name="post_info_reblogs">Promocións</string>
<string name="post_info_favorites">Favoritas</string>
<string name="edit_history">Editar historial</string>
<string name="last_edit_at_x">Última edición %s</string>
@@ -413,4 +426,22 @@
<!-- %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 non acepta rexistros desde %2$s. Proba outro ou &lt;a&gt;elixe outro servidor&lt;/a&gt;.</string>
<string name="signup_username_taken">Este nome de usuaria xa está en uso.</string>
<string name="spoiler_show">Mostrar igualmente</string>
<string name="spoiler_hide">Volver agochar</string>
<string name="poll_multiple_choice">Elixe unha ou varias</string>
<string name="save_changes">Gardar cambios</string>
<string name="profile_featured">Destacadas</string>
<string name="profile_timeline">Cronoloxía</string>
<string name="view_all">Ver todos</string>
<string name="profile_endorsed_accounts">Contas</string>
<string name="verified_link">Ligazón verificada</string>
<string name="show">Mostrar</string>
<string name="hide">Agochar</string>
<string name="join_default_server">Únete a %s</string>
<string name="signup_or_login">ou</string>
<string name="learn_more">Saber máis</string>
<string name="welcome_to_mastodon">Benvida a Mastodon</string>
<string name="welcome_paragraph1">Mastodon é unha rede social descentralizada, onde ningunha empresa ten o control. Está formada por moitos servidores independentes comunicándose entre si.</string>
<string name="what_are_servers">Que son os servidores?</string>
<string name="welcome_paragraph2"><![CDATA[Cada conta Mastodon está hospedada nun servidor — cada unha coas súas regras, valores e admins. Non importa cal elixas, podes seguir e interactuar con persoas de outros servidores.]]></string>
</resources>

View File

@@ -273,4 +273,6 @@
<string name="sk_show_thread">Mostrar chío</string>
<string name="sk_compact_reblog_reply_line">Compactar liña de impulso/resposta</string>
<string name="sk_settings_confirm_before_reblog">Confirma antes de impulsar</string>
<string name="sk_reacted_with">Redactado con %s</string>
<string name="sk_reacted">redactado</string>
</resources>

View File

@@ -1,15 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="get_started">Ստեղծել հաշիվ</string>
<string name="already_have_account">Արդեն հաշիվ ունեմ</string>
<string name="log_in">Մուտք գործել</string>
<string name="next">Հաջորդը</string>
<string name="error">Սխալ</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>
@@ -47,12 +52,279 @@
<string name="block_user">Արգելափակել%s</string>
<string name="unblock_user">Հանել արգելափակումից %s</string>
<string name="report_user">Բողոքել %s</string>
<string name="block_domain">Արգելափակել %s-ին</string>
<plurals name="x_posts">
<item quantity="one">%,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>
<plurals name="x_minutes">
<item quantity="one">%d րոպե</item>
<item quantity="other">%d րոպե</item>
</plurals>
<plurals name="x_hours">
<item quantity="one">%d ժամ</item>
<item quantity="other">%d ժամ</item>
</plurals>
<plurals name="x_days">
<item quantity="one">%d օր</item>
<item quantity="other">%d օր</item>
</plurals>
<string name="compose_poll_duration">Տեւողությունը՝ %s</string>
<plurals name="x_seconds_left">
<item quantity="one">Մնաց %d վայրկյան</item>
<item quantity="other">Մնաց %d վայրկյան</item>
</plurals>
<plurals name="x_minutes_left">
<item quantity="one">Մնաց %d րոպե</item>
<item quantity="other">Մնաց %d րոպե</item>
</plurals>
<plurals name="x_hours_left">
<item quantity="one">Մնաց %d ժամ</item>
<item quantity="other">Մնաց %d ժամ</item>
</plurals>
<plurals name="x_days_left">
<item quantity="one">Մնաց %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_block_title">Արգելափակել հաշիվը</string>
<string name="confirm_block_domain_title">Արգելափակել տիրույթը</string>
<string name="confirm_block">Հաստատեք %s-ի արգելափակումը</string>
<string name="do_block">Արգելափակել</string>
<string name="do_unblock">Արգելաբացել</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="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>
<string name="report_title">Զեկուցել %s-ի մասին</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_choose_rule">Ո՞ր կանոններն են խախտվել։</string>
<string name="report_comment_hint">Լրացուցիչ մեկնաբանություններ</string>
<string name="sending_report">Զեկույցը ուղարկվում է․․․</string>
<string name="mute_user_explain">Դուք չեք տեսնի նրա գրառումները ձեր հիմնական հոսքում։ Նա չի իմանա, որ խլեցվել է։</string>
<string name="block_user_explain">Նա չի կարողանա ձեզ հետևել և չի տեսնի ձեր գրառումները, բայց կարող է տեսնել, որ արգելափակված է։</string>
<string name="report_personal_title">Չե՞ք ուզում սա տեսնել։</string>
<string name="back">Ետ</string>
<string name="instance_catalog_subtitle">Ընտրեք ձեր հետաքրքրություններին կամ տարածաշրջանին համապատասխան սպասարկիչ, կամ ընտրեք ընդհանուր սպասարկիչ։ Դուք կկարողանաք շփվել բոլորի հետ՝ անկախ սպասարկչից։</string>
<string name="search_communities">Սպասարկչի անուն կամ հասցե</string>
<string name="instance_rules_title">Սպասարկչի կանոնները</string>
<string name="signup_title">Ստեղծել հաշիվ</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="confirm_password">Գաղտնաբառի հաստատում</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_games">Խաղեր</string>
<string name="category_general">Ընդհանուր</string>
<string name="category_journalism">Լրագրություն</string>
<string name="category_music">Երաժշտություն</string>
<string name="category_regional">Տարածաշրջանային</string>
<string name="category_tech">Տեխնոլոգիա</string>
<!-- %s is the email address -->
<string name="resend">Ուղարկել նորից</string>
<string name="open_email_app">Բացել էլ․ փոստի հավելվածը</string>
<string name="content_warning">Նախազգուշացում</string>
<string name="add_image_description">Ավելացնել պատկերի նկարագրություն</string>
<string name="edit_image">Խմբագրել նկարը</string>
<string name="save">Պահպանել</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>
<string name="theme_light">Բաց</string>
<string name="theme_dark">Մուգ</string>
<string name="theme_true_black">Իսկական սև</string>
<string name="settings_behavior">Պահվածքը</string>
<string name="settings_custom_tabs">Օգտագործել ներքին բրաուզերը</string>
<string name="settings_notifications">Ծանուցումներ</string>
<string name="notify_anyone">որեւե մեկը</string>
<string name="notify_follower">որեւե հետեւորդ</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_app_version">Մաստոդոն Android-ի համար, տարբերակ %1$s (%2$d)</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="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="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="follow_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_picture">Պրոֆիլի նկար</string>
<string name="reorder">Վերադասավորել</string>
<string name="download">Ներբեռնել</string>
<string name="permission_required">Անհրաժեշտ է թույլտվություն</string>
<string name="open_settings">Բացել կարգավորումները</string>
<string name="downloading">Բեռնում․․․</string>
<string name="local_timeline">Համայնք</string>
<string name="trending_posts_info_banner">Այս գրառումները տարածված են Մաստոդոնի ձեր անկյունում։</string>
<string name="trending_hashtags_info_banner">Այս պիտակները տարածված են Մաստոդոնի ձեր անկյունում։</string>
<string name="dismiss">Չեղարկել</string>
<string name="see_new_posts">Նոր գրառումներ</string>
<string name="follows_you">Հետեւում է ձեզ</string>
<string name="current_account">Ընթացիկ հաշիվ</string>
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
<plurals name="x_followers">
<item quantity="one">%,d հետեւորդ</item>
<item quantity="other">%,d հետեւորդ</item>
</plurals>
<plurals name="x_favorites">
<item quantity="one">%,d նախընտրելի</item>
<item quantity="other">%,d նախընտրելի</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,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="one">%d վայրկյան առաջ</item>
<item quantity="other">%d վայրկյան առաջ</item>
</plurals>
<plurals name="x_minutes_ago">
<item quantity="one">%d րոպե առաջ</item>
<item quantity="other">%d րոպե առաջ</item>
</plurals>
<string name="edit_text_edited">Տեքստը փոփոխվել է</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_marked_sensitive">Նշվել է որպես դյուրազգաց</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>
<!-- %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="i_agree">Համաձայն եմ</string>
<string name="empty_list">Ցանկը դատարկ է</string>
<string name="instance_signup_closed">Սպասարկիչը գրանցումներ չի ընդունում։</string>
<string name="text_copied">Պատճենվել է</string>
<string name="bookmarks">Էջանիշեր</string>
<string name="your_favorites">Հավանածներ</string>
<string name="login_title">Բարի վերադարձ</string>
<string name="server_url">Սերվերի հասցե</string>
<string name="signup_random_server_explain">Եթե շարունակեք՝ առանց ընտրելու, մենք կընտրենք սերվեր՝ ըստ ձեր լեզվի։</string>
<string name="server_filter_any_language">Որևե լեզու</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="signup_passwords_dont_match">Գաղտնաբառը չի համապատասխանում</string>
<string name="pick_server_for_me">Ընտրել իմ համար</string>
<string name="privacy_policy_explanation">Կարճ ասած՝ մենք ոչինչ չենք հավաքում։</string>
<!-- %s is server domain -->
<string name="profile_bio">Կենսագրություն</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<!-- %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>
<string name="spoiler_show">Ցույց տալ</string>
<string name="spoiler_hide">Թաքցնել</string>
<string name="save_changes">Պահպանել</string>
<string name="profile_timeline">Հոսք</string>
<string name="view_all">Դիտել բոլորը</string>
<string name="profile_endorsed_accounts">Հաշիվներ</string>
<string name="verified_link">Հաստատված հղում</string>
<string name="show">Ցույց տալ</string>
<string name="hide">Թաքցնել</string>
<string name="join_default_server">Միանալ %s-ին</string>
<string name="pick_server">Ընտրել ուրիշ սերվեր</string>
<string name="signup_or_login">կամ</string>
<string name="learn_more">Իմանալ ավելին</string>
<string name="welcome_to_mastodon">Բարի գալուստ Մաստոդոն</string>
<string name="welcome_paragraph1">Մաստոդոնը ապակենտրոնացված սոցցանց է, այսինքն՝ այն չի պատկանում մի ընկերության։ Այն բաղկացած է բազմաթիվ անկախ և կապակցված սերվերներից։</string>
<string name="what_are_servers">Ի՞նչ է սերվերը։</string>
<string name="welcome_paragraph2"><![CDATA[Մաստոդոնի որևէ հաշիվ գտնվում է սերվերի վրա - ամեն մեկը՝ իր արժեքներով, կանոններով և ադմիններով։ Դուք կարող եք հետևել և շփվել որևէ սերվերի մարդկանց հետ՝ անկախ ձեր ընտրությունից։]]></string>
</resources>

View File

@@ -10,6 +10,7 @@
<string name="ok">Oke</string>
<string name="preparing_auth">Menyiapkan untuk autentikasi…</string>
<string name="finishing_auth">Menyelesaikan autentikasi…</string>
<string name="user_boosted">%s di-boost-kan</string>
<string name="in_reply_to">Membalas ke %s</string>
<string name="notifications">Notifikasi</string>
<string name="user_followed_you">mengikuti Anda</string>
@@ -151,6 +152,7 @@
<string name="report_sent_subtitle">Saat kami sedang meninjau ini, Anda dapat mengambil tindakan terhadap %s.</string>
<string name="unfollow_user">Berhenti mengikuti %s</string>
<string name="unfollow">Berhenti mengikuti</string>
<string name="mute_user_explain">Anda tidak akan melihat kiriman atau boost mereka pada linimasa Anda. Mereka tidak akan tahu bahwa mereka telah dibisukan.</string>
<string name="block_user_explain">Mereka tidak akan dapat mengikuti atau melihat kiriman Anda lagi, tetapi mereka dapat melihat jika mereka telah diblokir.</string>
<string name="report_personal_title">Tidak ingin melihat ini?</string>
<string name="report_personal_subtitle">Ketika Anda melihat sesuatu yang Anda tidak suka di Mastodon, Anda dapat menghapus orang dari pengalaman Anda.</string>
@@ -207,6 +209,7 @@
<string name="skip">Lewati</string>
<string name="notification_type_follow">Pengikut baru</string>
<string name="notification_type_favorite">Favorit</string>
<string name="notification_type_reblog">Boost</string>
<string name="notification_type_mention">Sebutan</string>
<string name="notification_type_poll">Pemungutan suara</string>
<string name="choose_account">Pilih akun</string>
@@ -232,6 +235,7 @@
<string name="notify_none">tidak ada</string>
<string name="notify_favorites">Memfavorit kiriman saya</string>
<string name="notify_follow">Mengikuti saya</string>
<string name="notify_reblog">Boost kiriman saya</string>
<string name="notify_mention">Menyebut saya</string>
<string name="settings_boring">Zona membosankan</string>
<string name="settings_account">Pengaturan akun</string>
@@ -252,6 +256,7 @@
<string name="hide_content">Sembunyikan konten</string>
<string name="new_post">Kiriman baru</string>
<string name="button_reply">Balas</string>
<string name="button_reblog">Boost</string>
<string name="button_favorite">Favorit</string>
<string name="button_share">Bagikan</string>
<string name="media_no_description">Media tanpa deskripsi</string>
@@ -267,6 +272,8 @@
<string name="followed_user">Anda sekarang mengikuti %s</string>
<string name="following_user_requested">Diminta untuk mengikuti %s</string>
<string name="open_in_browser">Buka di peramban</string>
<string name="hide_boosts_from_user">Sembunyikan boost dari %s</string>
<string name="show_boosts_from_user">Tampilkan boost dari %s</string>
<string name="signup_reason">Mengapa Anda ingin bergabung?</string>
<string name="signup_reason_note">Ini akan membantu kami meninjau aplikasi Anda.</string>
<string name="clear">Hapus</string>
@@ -305,8 +312,12 @@
<plurals name="x_favorites">
<item quantity="other">%,d favorit</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="other">%,d boost</item>
</plurals>
<string name="timestamp_via_app">%1$s melalui %2$s</string>
<string name="time_now">sekarang</string>
<string name="post_info_reblogs">Boost</string>
<string name="post_info_favorites">Favorit</string>
<string name="edit_history">Riwayat penyuntingan</string>
<string name="last_edit_at_x">Terakhir disunting %s</string>
@@ -394,7 +405,11 @@
<!-- %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 tidak memperbolehkan pendaftaran dari %2$s. Coba yang lain atau &lt;a&gt;pilih server lain&lt;/a&gt;.</string>
<string name="signup_username_taken">Nama pengguna ini sudah diambil.</string>
<string name="spoiler_show">Tampilkan saja</string>
<string name="spoiler_hide">Sembunyikan ulang</string>
<string name="poll_multiple_choice">Pilih satu atau lebih</string>
<string name="save_changes">Simpan perubahan</string>
<string name="profile_featured">Sorotan</string>
<string name="profile_timeline">Linimasa</string>
<string name="view_all">Lihat semua</string>
<string name="profile_endorsed_accounts">Akun</string>
@@ -402,6 +417,10 @@
<string name="show">Tampilkan</string>
<string name="hide">Sembunyikan</string>
<string name="join_default_server">Gabung %s</string>
<string name="signup_or_login">atau</string>
<string name="learn_more">Pelajari lebih lanjut</string>
<string name="welcome_to_mastodon">Selamat datang di Mastodon</string>
<string name="welcome_paragraph1">Mastodon adalah jejaring sosial terdesentralisasi, tidak ada satu pun perusahaan yang mengontrol. Semua dijalankan oleh server independen, terkoneksi bersama.</string>
<string name="what_are_servers">Apa itu server?</string>
<string name="welcome_paragraph2"><![CDATA[Semua akun Mastodon berada pada sebuah server — dengan nilai, aturan, dan admin masing-masing. Mana pun yang kamu pilih, kamu bisa mengikuti dan berinteraksi dengan server mana pun.]]></string>
</resources>

View File

@@ -274,4 +274,17 @@
<string name="sk_show_thread">Tampilkan utasan</string>
<string name="sk_compact_reblog_reply_line">Baris berbagi/balasan</string>
<string name="sk_settings_confirm_before_reblog">Konfirmasi sebelum membagikan ulang</string>
<string name="sk_reacted_with">bereaksi dengan %s</string>
<string name="sk_reacted">bereaksi</string>
<string name="sk_content_type_plain">Teks biasa</string>
<string name="sk_content_type_html">HTML</string>
<string name="sk_content_type_markdown">Markdown</string>
<string name="sk_content_type_bbcode">BBCode</string>
<string name="sk_content_type_mfm">MFM</string>
<string name="sk_settings_content_types">Aktifkan pemformatan kiriman</string>
<string name="sk_settings_default_content_type">Jenis konten bawaan</string>
<string name="sk_settings_default_content_type_explanation">Ini memungkinkan Anda untuk menerapkan jenis konten yang sudah ditentukan saat membuat kiriman baru, menimpa nilai yang ditetapkan dalam “Preferensi kiriman”.</string>
<string name="sk_content_type">Jenis konten</string>
<string name="sk_content_type_unspecified">Tidak ditentukan</string>
<string name="sk_settings_content_types_explanation">Memperbolehkan menetapkan jenis konten seperti Markdown ketika membuat kiriman. Perlu diingat bahwa tidak semua server mendukung ini.</string>
</resources>

View File

@@ -10,11 +10,13 @@
<string name="ok">Í lagi</string>
<string name="preparing_auth">Undirbý auðkenningu…</string>
<string name="finishing_auth">Lýk auðkenningu…</string>
<string name="user_boosted">%s endurbirti</string>
<string name="in_reply_to">Sem svar til %s</string>
<string name="notifications">Tilkynningar</string>
<string name="user_followed_you">fylgdi þér</string>
<string name="user_sent_follow_request">sendi þér beiðni um að fylgjast með þér</string>
<string name="user_favorited">setti færslu frá þér í eftirlæti</string>
<string name="notification_boosted">endurbirti færsluna þína</string>
<string name="poll_ended">könnun er lokið</string>
<string name="time_seconds">%ds</string>
<string name="time_minutes">%dm</string>
@@ -164,6 +166,8 @@
<string name="report_sent_subtitle">Á meðan við yfirförum þetta, geturðu tekið til aðgerða gegn %s.</string>
<string name="unfollow_user">Hætta að fylgjast með %s</string>
<string name="unfollow">Hætta að fylgjast með</string>
<string name="mute_user_explain">Þú munt ekki sjá færslur eða endurbirtingar frá viðkomandi á streyminu þínu.
Viðkomandi aðilar munu ekki vita að þaggað hefur verið niður í þeim.</string>
<string name="block_user_explain">Viðkomandi mun ekki lengur geta fylgst með eða séð færslurnar þínar, en munu sjá ef viðkomandi hefur verið útilokaður.</string>
<string name="report_personal_title">Langar þig ekki til að sjá þetta?</string>
<string name="report_personal_subtitle">Þegar þú sér eitthvað á Mastodon sem þér líkar ekki, þá geturðu fjarlægt viðkomandi eintakling úr umhverfinu þínu.</string>
@@ -220,6 +224,7 @@
<string name="skip">Sleppa</string>
<string name="notification_type_follow">Nýir fylgjendur</string>
<string name="notification_type_favorite">Eftirlæti</string>
<string name="notification_type_reblog">Endurbirtingar</string>
<string name="notification_type_mention">Minnst á</string>
<string name="notification_type_poll">Kannanir</string>
<string name="choose_account">Veldu aðgang</string>
@@ -246,6 +251,7 @@
<string name="notify_none">enginn</string>
<string name="notify_favorites">Setur færsluna mína í eftirlæti</string>
<string name="notify_follow">Fylgist með mér</string>
<string name="notify_reblog">Endurbirtir færsluna mína</string>
<string name="notify_mention">Minnist á mig</string>
<string name="settings_boring">Óhressa svæðið</string>
<string name="settings_account">Stillingar aðgangs</string>
@@ -266,6 +272,7 @@
<string name="hide_content">Fela efni</string>
<string name="new_post">Ný færsla</string>
<string name="button_reply">Svara</string>
<string name="button_reblog">Endurbirting</string>
<string name="button_favorite">Eftirlæti</string>
<string name="button_share">Deila</string>
<string name="media_no_description">Myndefni án lýsingar</string>
@@ -281,6 +288,8 @@
<string name="followed_user">Þú fylgist núna með %s</string>
<string name="following_user_requested">Bað um að fylgjast með %s</string>
<string name="open_in_browser">Opna í vafra</string>
<string name="hide_boosts_from_user">Fela endurbirtingar frá %s</string>
<string name="show_boosts_from_user">Sýna endurbirtingar frá %s</string>
<string name="signup_reason">Hvers vegna vilt þú taka þátt?</string>
<string name="signup_reason_note">Þetta mun hjálpa okkur við að yfirfara umsóknina þína.</string>
<string name="clear">Hreinsa</string>
@@ -322,8 +331,13 @@
<item quantity="one">%,d eftirlæti</item>
<item quantity="other">%,d eftirlæti</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d endurbirting</item>
<item quantity="other">%,d endurbirtingar</item>
</plurals>
<string name="timestamp_via_app">%1$s með %2$s</string>
<string name="time_now">núna</string>
<string name="post_info_reblogs">Endurbirtingar</string>
<string name="post_info_favorites">Eftirlæti</string>
<string name="edit_history">Breytingaferill</string>
<string name="last_edit_at_x">Síðasta breyting %s</string>
@@ -413,4 +427,23 @@
<!-- %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 leyfir ekki nýskráningar frá %2$s. Veldu eitthvað annað lén eða &lt;a&gt;veldu annan netþjón&lt;/a&gt;.</string>
<string name="signup_username_taken">Þetta notandanafn er þegar í notkun.</string>
<string name="spoiler_show">Birta samt</string>
<string name="spoiler_hide">Fela aftur</string>
<string name="poll_multiple_choice">Veldu eitt eiða fleiri</string>
<string name="save_changes">Vista breytingar</string>
<string name="profile_featured">Með aukið vægi</string>
<string name="profile_timeline">Tímalína</string>
<string name="view_all">Skoða allt</string>
<string name="profile_endorsed_accounts">Notandaaðgangar</string>
<string name="verified_link">Sannreyndur tengill</string>
<string name="show">Sýna</string>
<string name="hide">Fela</string>
<string name="join_default_server">Taka þátt í %s</string>
<string name="pick_server">Veldu annan netþjón</string>
<string name="signup_or_login">eða</string>
<string name="learn_more">Kanna nánar</string>
<string name="welcome_to_mastodon">Velkomin í Mastodon</string>
<string name="welcome_paragraph1">Mastodon er dreyfhýst samfélagsnet, sem þýðir að ekkert eitt fyrirtæki ræður yfir því. Netið samanstendur af mörgum sjálfstætt reknum netþjónum sem tengjast innbyrðis.</string>
<string name="what_are_servers">Hvað eru netþjónar?</string>
<string name="welcome_paragraph2"><![CDATA[Hver einasti Mastodon-aðgangur er hýstur á sínum netþjóni — hver slíkur er með sín eigin gildi, reglur og stjórnendur. Það skiftir ekki máli hvern þeirra þú velur, þú getur fylgst fylgst með og átt í samskiptum við fólk á hvaða netþjóni sem er.]]></string>
</resources>

View File

@@ -250,6 +250,7 @@
<string name="notify_none">nessuno</string>
<string name="notify_favorites">Apprezza i miei post</string>
<string name="notify_follow">Mi segue</string>
<string name="notify_reblog">Condivide il mio post</string>
<string name="notify_mention">Mi menziona</string>
<string name="settings_boring">La zona noiosa</string>
<string name="settings_account">Impostazioni dell\'account</string>
@@ -437,9 +438,11 @@
<string name="show">Mostra</string>
<string name="hide">Nascondi</string>
<string name="join_default_server">Unisciti a %s</string>
<string name="pick_server">Scegli il mio server</string>
<string name="pick_server">Scegli un altro server</string>
<string name="signup_or_login">o</string>
<string name="learn_more">Scopri di più</string>
<string name="welcome_to_mastodon">Benvenuto/a su Mastodon</string>
<string name="welcome_paragraph1">Mastodon è un social network decentralizzato, il che significa che nessuna singola azienda lo controlla. È composto da molti server indipendenti e tutti connessi insieme.</string>
<string name="what_are_servers">Cosa sono i server?</string>
<string name="welcome_paragraph2"><![CDATA[Ogni account Mastodon è ospitato su un server — ognuno con i propri valori, regole, e amministratori. Non importa quale scegliere, è possibile seguire e interagire con le persone su qualsiasi server.]]></string>
</resources>

View File

@@ -67,8 +67,8 @@
<string name="sk_favorite_as">Aggiungi ai preferiti con un altro account</string>
<string name="sk_favorited_as">Inserito tra i preferiti come %s</string>
<string name="sk_already_favorited">Già aggiunto ai preferiti</string>
<string name="sk_reblog_as">Condividi con un altro account</string>
<string name="sk_already_reblogged">Già condiviso</string>
<string name="sk_reblog_as">Boost con un altro account</string>
<string name="sk_already_reblogged">Già boostato</string>
<string name="sk_settings_profile">Impostazioni del profilo</string>
<string name="sk_settings_posting">Preferenze di pubblicazione</string>
<string name="sk_settings_filters">Configura i filtri</string>
@@ -86,8 +86,8 @@
<string name="sk_clear_all_notifications_confirm">Sei sicuro di voler eliminare tutte le notifiche\?</string>
<string name="sk_loading_fediverse_resource_title">Cercando nel Fediverso</string>
<string name="sk_quote_post">Crea un post riguardo a questo</string>
<string name="sk_undo_reblog">Annulla la condivisione</string>
<string name="sk_reblog_with_visibility">Reblog con visibilità</string>
<string name="sk_undo_reblog">Annulla il boost</string>
<string name="sk_reblog_with_visibility">Boost con visibilità</string>
<string name="sk_copy_link_to_post">Copia il link al post</string>
<string name="sk_open_with_account">Apri con un altro account</string>
<string name="sk_resource_not_found">Non è stato possibile trovare la risorsa</string>
@@ -131,7 +131,7 @@
<string name="sk_loading_resource_on_instance_title">Cercando su %s</string>
<string name="sk_hashtags_you_follow">Hashtag che segui</string>
<string name="sk_already_bookmarked">Già aggiunto ai segnalibri</string>
<string name="sk_reblogged_as">Condivisione eseguita come %s</string>
<string name="sk_reblogged_as">Boost eseguito come %s</string>
<string name="sk_unsent_posts">Post non pubblicati</string>
<string name="sk_confirm_save_draft">Salvare la bozza\?</string>
<string name="sk_confirm_save_changes">Salvare le modifiche\?</string>
@@ -220,7 +220,7 @@
<string name="sk_icon_globe">Mappamondo</string>
<string name="sk_edit_timeline">Modifica timeline</string>
<string name="sk_edit_timelines">Modifica timeline</string>
<string name="sk_notify_update">Modifica un post condiviso</string>
<string name="sk_notify_update">Modifica un post boostato</string>
<string name="sk_notification_type_update">Post modificati</string>
<string name="sk_attach_file">Allega file</string>
<string name="sk_icon_pin">Puntina</string>
@@ -239,7 +239,7 @@
<string name="sk_separator">·</string>
<string name="sk_local_only">Solo istanza locale</string>
<string name="sk_instance_features">Funzionalità dell\'istanza</string>
<string name="sk_settings_support_local_only">Il server supporta solo post locali</string>
<string name="sk_settings_support_local_only">Il server supporta anche post solo locali</string>
<string name="sk_settings_local_only_explanation">La tua istanza deve supportare post solo locali per far funzionare questa opzione. Molte versioni modificate di Mastodon lo fanno, ma Mastodon no.</string>
<string name="sk_settings_glitch_instance">Modalità solo locale di Glitch</string>
<string name="sk_settings_glitch_mode_explanation">Abilita se la tua istanza utilizza Glitch. Non necessario per Hometown o Akkoma.</string>
@@ -261,4 +261,17 @@
<string name="sk_follow_as">Segui con un altro account</string>
<string name="sk_followed_as">Seguito con %s</string>
<string name="sk_settings_hide_fab">Nascondi automaticamente il pulsante Pubblica</string>
<string name="sk_in_reply">In risposta</string>
<string name="sk_quoting_user">Citando %s</string>
<string name="sk_settings_reply_visibility">Visibilità delle risposte</string>
<string name="sk_settings_reply_visibility_all">Tutte le risposte</string>
<string name="sk_settings_reply_visibility_following">Risposte ai miei follower</string>
<string name="sk_settings_reply_visibility_self">Mi risponde</string>
<string name="sk_notification_action_replied">Risposta inviata a %s</string>
<string name="sk_settings_confirm_before_reblog">Conferma prima del boost</string>
<string name="sk_reacted">ha reagito</string>
<string name="sk_show_thread">Mostra discussione</string>
<string name="sk_compact_reblog_reply_line">Linea boost/risposta compatta</string>
<string name="sk_reacted_with">ha reagito con %s</string>
<string name="sk_reply_line_above_avatar">Linea \"In risposta a\" sopra l\'avatar</string>
</resources>

View File

@@ -10,11 +10,13 @@
<string name="ok">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>
@@ -148,8 +150,9 @@
<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_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>
@@ -206,6 +209,7 @@
<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>
@@ -229,9 +233,10 @@
<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_mention">メンションされた</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">Mastodonに貢献する</string>
@@ -251,6 +256,7 @@
<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>
@@ -261,10 +267,13 @@
<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="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>
@@ -303,8 +312,12 @@
<plurals name="x_favorites">
<item quantity="other">%,d お気に入り</item>
</plurals>
<plurals name="x_reblogs">
<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>
@@ -392,4 +405,23 @@
<!-- %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>
<string name="spoiler_show">表示する</string>
<string name="spoiler_hide">非表示</string>
<string name="poll_multiple_choice">1つまたは複数を選択</string>
<string name="save_changes">変更を保存</string>
<string name="profile_featured">特徴</string>
<string name="profile_timeline">タイムライン</string>
<string name="view_all">すべて表示</string>
<string name="profile_endorsed_accounts">アカウント</string>
<string name="verified_link">確認済みのリンク</string>
<string name="show">見る</string>
<string name="hide">非表示</string>
<string name="join_default_server">%s に登録</string>
<string name="pick_server">ほかのサーバーをさがす</string>
<string name="signup_or_login">または</string>
<string name="learn_more">詳しく学ぶ</string>
<string name="welcome_to_mastodon">Mastodon とは</string>
<string name="welcome_paragraph1">Mastodon は、いち企業の統制に依存しない非中央集権型のソーシャルネットワークです。たくさんの独立したサーバーが相互につながり合い、ひとつのネットワークを形成しています。</string>
<string name="what_are_servers">サーバーとは</string>
<string name="welcome_paragraph2"><![CDATA[Mastodon のアカウントはいずれかのサーバーに所属します。それぞれのサーバーは異なる価値観やルールをもち、それらを管理する管理者がいます。どのサーバーにいても、ほかのあらゆるサーバーのユーザーをフォローして、かかわりをもつことができるでしょう。]]></string>
</resources>

View File

@@ -8,13 +8,15 @@
<string name="error">Fout</string>
<string name="not_a_mastodon_instance">%s lijkt geen Mastodonserver te zijn.</string>
<string name="ok">OK</string>
<string name="preparing_auth">Verificatie aan het voorbereiden…</string>
<string name="preparing_auth">Verificatie voorbereiden…</string>
<string name="finishing_auth">Verificatie afronden…</string>
<string name="user_boosted">%s boostte</string>
<string name="in_reply_to">Als reactie op %s</string>
<string name="notifications">Meldingen</string>
<string name="user_followed_you">volgt jou</string>
<string name="user_sent_follow_request">heeft je een volgverzoek gestuurd</string>
<string name="user_favorited">markeerde als favoriet</string>
<string name="user_sent_follow_request">wil jou graag volgen</string>
<string name="user_favorited">markeerde bericht als favoriet</string>
<string name="notification_boosted">boostte jouw bericht</string>
<string name="poll_ended">poll is beëindigd</string>
<string name="time_seconds">%ds</string>
<string name="time_minutes">%dm</string>
@@ -45,20 +47,20 @@
<string name="button_follow">Volgen</string>
<string name="button_following">Volgend</string>
<string name="edit_profile">Profiel bewerken</string>
<string name="mention_user">Vermelden</string>
<string name="mention_user">%s vermelden</string>
<string name="share_user">%s delen</string>
<string name="mute_user">Negeren</string>
<string name="unmute_user">Niet langer negeren</string>
<string name="block_user">Blokkeren</string>
<string name="unblock_user">Deblokkeren</string>
<string name="mute_user">%s negeren</string>
<string name="unmute_user">%s niet langer negeren</string>
<string name="block_user">%s blokkeren</string>
<string name="unblock_user">%s deblokkeren</string>
<string name="report_user">%s rapporteren</string>
<string name="block_domain">Blokkeren</string>
<string name="unblock_domain">Deblokkeren</string>
<string name="block_domain">%s blokkeren</string>
<string name="unblock_domain">%s deblokkeren</string>
<plurals name="x_posts">
<item quantity="one">%,d bericht</item>
<item quantity="other">%,d berichten</item>
</plurals>
<string name="profile_joined">Geregistreerd op</string>
<string name="profile_joined">Geregistreerd</string>
<string name="done">Klaar</string>
<string name="loading">Aan het laden…</string>
<string name="field_label">Label</string>
@@ -96,23 +98,23 @@
<item quantity="other">%d dagen resterend</item>
</plurals>
<plurals name="x_voters">
<item quantity="one">%,d persoon</item>
<item quantity="other">%,d mensen</item>
<item quantity="one">%,d stem</item>
<item quantity="other">%,d stemmen</item>
</plurals>
<string name="poll_closed">Gesloten</string>
<string name="confirm_mute_title">Account negeren</string>
<string name="confirm_mute">Bevestig om %s te negeren</string>
<string name="confirm_mute">Het negeren van %s bevestigen</string>
<string name="do_mute">Negeren</string>
<string name="confirm_unmute_title">Account niet langer negeren</string>
<string name="confirm_unmute">Bevestig om %s niet langer te negeren</string>
<string name="confirm_unmute">Het niet langer negeren van %s bevestigen</string>
<string name="do_unmute">Niet langer negeren</string>
<string name="confirm_block_title">Account blokkeren</string>
<string name="confirm_block_domain_title">Domein blokkeren</string>
<string name="confirm_block">Bevestig om %s te blokkeren</string>
<string name="confirm_block">Het blokkeren van %s bevestigen</string>
<string name="do_block">Blokkeren</string>
<string name="confirm_unblock_title">Account deblokkeren</string>
<string name="confirm_unblock_domain_title">Domein deblokkeren</string>
<string name="confirm_unblock">Bevestig om %s te deblokkeren</string>
<string name="confirm_unblock">Het deblokkeren van %s bevestigen</string>
<string name="do_unblock">Deblokkeren</string>
<string name="button_muted">Genegeerd</string>
<string name="button_blocked">Geblokkeerd</string>
@@ -164,6 +166,7 @@
<string name="report_sent_subtitle">Terwijl wij jouw rapportage beoordelen, kun je deze acties tegen %s ondernemen.</string>
<string name="unfollow_user">Ontvolgen</string>
<string name="unfollow">Ontvolgen</string>
<string name="mute_user_explain">Je ziet hun berichten en boosts niet op je starttijdlijn. Ze zullen niet weten dat ze worden genegeerd.</string>
<string name="block_user_explain">Het is niet meer mogelijk om je te volgen of om je berichten te zien, maar het is wel mogelijk om erachter te komen dat je deze account hebt geblokkeerd.</string>
<string name="report_personal_title">Wil je dit niet zien?</string>
<string name="report_personal_subtitle">Als je iets ziet dat je niet leuk vindt op Mastodon, dan kun je de persoon op meerdere manieren van je tijdlijn verwijderen.</string>
@@ -172,7 +175,7 @@
<string name="instance_catalog_subtitle">Kies een server gebaseerd op je interesses, regio, of voor algemene doeleinden. Je kunt nog steeds met iedereen in contact komen, ongeacht de server.</string>
<string name="search_communities">Servernaam of URL</string>
<string name="instance_rules_title">Serverregels</string>
<string name="instance_rules_subtitle">Door verder te gaan, ga je akkoord met het volgen van de regels ingesteld door de %s-moderators.</string>
<string name="instance_rules_subtitle">Door verder te gaan, ga je akkoord met het volgen van de regels ingesteld door de %s-moderatoren.</string>
<string name="signup_title">Account registreren</string>
<string name="edit_photo">bewerken</string>
<string name="display_name">Naam</string>
@@ -190,14 +193,14 @@
<string name="category_games">Games</string>
<string name="category_general">Algemeen</string>
<string name="category_journalism">Journalistiek</string>
<string name="category_lgbt">LGBT</string>
<string name="category_lgbt">LHBTQIA+</string>
<string name="category_music">Muziek</string>
<string name="category_regional">Regionaal</string>
<string name="category_tech">Tech</string>
<string name="confirm_email_title">Controleer je Postvak In</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Klik op de link die we je hebben gestuurd om %s te verifiëren. We wachten op je.</string>
<string name="confirm_email_didnt_get">Geen link gekregen?</string>
<string name="confirm_email_didnt_get">Geen verificatielink ontvangen?</string>
<string name="resend">Opnieuw verzenden</string>
<string name="open_email_app">E-mail-app openen</string>
<string name="resent_email">Bevestigingsmail verzonden</string>
@@ -208,7 +211,7 @@
<string name="edit_image">Afbeelding bewerken</string>
<string name="save">Opslaan</string>
<string name="add_alt_text">Alt-tekst toevoegen</string>
<string name="alt_text_subtitle">Alt-tekst beschrijft uw foto\'s voor mensen met weinig of geen zicht. Probeer alleen genoeg details toe te voegen om de context te begrijpen.</string>
<string name="alt_text_subtitle">Alt-tekst beschrijft jouw foto\'s voor blinde of slechtziende mensen. Probeer alleen genoeg details toe te voegen om de context te begrijpen.</string>
<string name="alt_text_hint">bijv.: een hond die met versmalde ogen verdacht rondkijkt naar de camera.</string>
<string name="visibility_public">Openbaar</string>
<string name="visibility_followers_only">Alleen volgers</string>
@@ -220,6 +223,7 @@
<string name="skip">Overslaan</string>
<string name="notification_type_follow">Nieuwe volgers</string>
<string name="notification_type_favorite">Favorieten</string>
<string name="notification_type_reblog">Boosts</string>
<string name="notification_type_mention">Vermeldingen</string>
<string name="notification_type_poll">Polls</string>
<string name="choose_account">Account kiezen</string>
@@ -236,16 +240,17 @@
<string name="theme_dark">Donker</string>
<string name="theme_true_black">Echt zwart gebruiken</string>
<string name="settings_behavior">Gedrag</string>
<string name="settings_gif">Geanimeerde avatars en emoji\'s afspelen</string>
<string name="settings_gif">Geanimeerde profielfoto\'s en emoji\'s afspelen</string>
<string name="settings_custom_tabs">In-appbrowser gebruiken</string>
<string name="settings_notifications">Meldingen</string>
<string name="notify_me_when">Melding tonen wanneer</string>
<string name="notify_anyone">iedereen</string>
<string name="notify_anyone">iemand</string>
<string name="notify_follower">een volger</string>
<string name="notify_followed">iemand die ik volg</string>
<string name="notify_none">niemand</string>
<string name="notify_favorites">Mijn bericht als favoriet markeert</string>
<string name="notify_follow">Mij volgt</string>
<string name="notify_reblog">Mijn bericht boost</string>
<string name="notify_mention">Mij vermeldt</string>
<string name="settings_boring">De saaie zone</string>
<string name="settings_account">Accountinstellingen</string>
@@ -266,7 +271,8 @@
<string name="hide_content">Inhoud verbergen</string>
<string name="new_post">Nieuw bericht</string>
<string name="button_reply">Reageren</string>
<string name="button_favorite">Toevoegen aan favorieten</string>
<string name="button_reblog">Boosten</string>
<string name="button_favorite">Als favoriet markeren</string>
<string name="button_share">Delen</string>
<string name="media_no_description">Media zonder beschrijving</string>
<string name="add_media">Media toevoegen</string>
@@ -280,7 +286,9 @@
<string name="unfollowed_user">%s ontvolgd</string>
<string name="followed_user">Je volgt %s nu</string>
<string name="following_user_requested">Je volgverzoek is aan %s verstuurd</string>
<string name="open_in_browser">Openen in browser</string>
<string name="open_in_browser">In browser openen</string>
<string name="hide_boosts_from_user">Boosts van %s verbergen</string>
<string name="show_boosts_from_user">Boosts van %s tonen</string>
<string name="signup_reason">Waarom wil je je hier registreren?</string>
<string name="signup_reason_note">Dit helpt ons om jouw aanvraag te beoordelen.</string>
<string name="clear">Leegmaken</string>
@@ -301,7 +309,7 @@
<string name="trending_links_info_banner">Dit zijn nieuwsartikelen die populair zijn op jouw Mastodon-server.</string>
<string name="local_timeline_info_banner">Dit zijn de meest recente berichten van mensen die ook op jouw Mastodon-server zitten.</string>
<string name="dismiss">Sluiten</string>
<string name="see_new_posts">Nieuwe berichten bekijken</string>
<string name="see_new_posts">Nieuwe berichten</string>
<string name="load_missing_posts">Resterende berichten laden</string>
<string name="follow_back">Terugvolgen</string>
<string name="button_follow_pending">In afwachting</string>
@@ -322,8 +330,13 @@
<item quantity="one">%,d favoriet</item>
<item quantity="other">%,d favorieten</item>
</plurals>
<plurals name="x_reblogs">
<item quantity="one">%,d boost</item>
<item quantity="other">%,d boosts</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_favorites">Favorieten</string>
<string name="edit_history">Bewerkingsgeschiedenis</string>
<string name="last_edit_at_x">Laatste bewerking op %s</string>
@@ -370,7 +383,7 @@
<string name="download_update">Downloaden (%s)</string>
<string name="install_update">Installeren</string>
<string name="privacy_policy_title">Jouw privacy</string>
<string name="privacy_policy_subtitle">Hoewel de Mastodon-app geen gegevens verzamelt, kan de server waar je je aanmeldt een ander beleid hebben.\n\nAls je het niet eens bent met het beleid voor %s, kun je teruggaan en een andere server kiezen.</string>
<string name="privacy_policy_subtitle">Hoewel de Mastodon-app geen gegevens verzamelt, kan de server waar je je aanmeldt een ander beleid hebben.\n\nAls je niet akkoord gaat met het beleid voor %s, kun je teruggaan en een andere server kiezen.</string>
<string name="i_agree">Ik ga akkoord</string>
<string name="empty_list">Deze lijst is leeg</string>
<string name="instance_signup_closed">Deze server accepteert geen nieuwe registraties.</string>
@@ -403,14 +416,33 @@
<string name="profile_setup_explanation">Je kunt tot vier profielvelden toevoegen voor alles wat je wilt. Locatie, links, voornaamwoorden de mogelijkheden zijn eindeloos.</string>
<string name="popular_on_mastodon">Populair op Mastodon</string>
<string name="follow_all">Volg iedereen</string>
<string name="server_rules_disagree">Oneens</string>
<string name="server_rules_disagree">Ik ga niet akkoord</string>
<string name="privacy_policy_explanation">TL;DR: We verzamelen of verwerken niets.</string>
<!-- %s is server domain -->
<string name="server_policy_disagree">Oneens met %s</string>
<string name="server_policy_disagree">Niet akkoord met %s</string>
<string name="profile_bio">Bio</string>
<!-- Shown in a progress dialog when you tap "follow all" -->
<string name="sending_follows">Gevolgde gebruikers…</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 staat geen registraties toe van %2$s. Probeer het met een andere e-mailprovider of &lt;a&gt;kies een andere server&lt;/a&gt;.</string>
<string name="signup_username_taken">Deze gebruikersnaam wordt al gebruikt.</string>
<string name="spoiler_show">Alsnog tonen</string>
<string name="spoiler_hide">Opnieuw verbergen</string>
<string name="poll_multiple_choice">Maak een of meerdere keuzes</string>
<string name="save_changes">Wijzigingen opslaan</string>
<string name="profile_featured">Aanbevolen</string>
<string name="profile_timeline">Tijdlijn</string>
<string name="view_all">Alles bekijken</string>
<string name="profile_endorsed_accounts">Accounts</string>
<string name="verified_link">Geverifieerde link</string>
<string name="show">Tonen</string>
<string name="hide">Verbergen</string>
<string name="join_default_server">Registreren op %s</string>
<string name="pick_server">Kies een andere server</string>
<string name="signup_or_login">of</string>
<string name="learn_more">Meer informatie</string>
<string name="welcome_to_mastodon">Welkom bij Mastodon</string>
<string name="welcome_paragraph1">Mastodon is een gedecentraliseerd sociaal netwerk, wat betekent dat geen enkel bedrijf het controleert. Het bestaat uit veel onafhankelijk opererende servers, allemaal met elkaar verbonden.</string>
<string name="what_are_servers">Wat zijn servers?</string>
<string name="welcome_paragraph2"><![CDATA[Elk Mastodonaccount wordt op een server gehost - elk met diens eigen waarden, regels en beheerders. Het maakt niet uit welke server je kiest, je kunt mensen op elke server volgen en ermee communiceren.]]></string>
</resources>

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