Compare commits

...

178 Commits

Author SHA1 Message Date
Grishka
357041b995 Prepare for release 2024-11-15 01:15:59 +03:00
Grishka
6754f004f2 Merge branch 'l10n_master' 2024-11-15 01:13:48 +03:00
Eugen Rochko
3487b0b70d New translations strings.xml (Italian) 2024-11-14 00:11:39 +01:00
Gregory K
f91b887586 Merge pull request #921 from owo-uwu-nyaa/master
Make sure cursor stays under 1MB size limit
2024-11-13 20:30:23 +03:00
Jonas
62cd754f3a Merge branch 'mastodon:master' into master 2024-11-13 18:08:48 +01:00
likeazir
be82274bee consistent naming 2024-11-13 17:52:01 +01:00
likeazir
6779b5cc43 single queries for domains to prevent running into the cursor limit 2024-11-13 17:49:30 +01:00
likeazir
86e369201a remove extra query to get emoji row length 2024-11-13 17:32:46 +01:00
Eugen Rochko
6b2fd26961 New translations strings.xml (Lithuanian) 2024-11-13 11:33:32 +01:00
Eugen Rochko
423718b4f2 New translations strings.xml (Lithuanian) 2024-11-13 09:33:41 +01:00
Eugen Rochko
f6ed37f80f New translations strings.xml (Chinese Traditional) 2024-11-13 01:46:55 +01:00
Eugen Rochko
71a986b280 New translations strings.xml (Swedish) 2024-11-12 22:45:23 +01:00
Eugen Rochko
12375609e3 New translations strings.xml (Interlingua) 2024-11-12 20:42:20 +01:00
Eugen Rochko
02659407f8 New translations strings.xml (Kabyle) 2024-11-12 20:42:18 +01:00
Eugen Rochko
a4f0e577f5 New translations strings.xml (Scottish Gaelic) 2024-11-12 20:42:16 +01:00
Eugen Rochko
9bc4d81321 New translations strings.xml (Filipino) 2024-11-12 20:42:13 +01:00
Eugen Rochko
72dd2e1b65 New translations strings.xml (Welsh) 2024-11-12 20:42:12 +01:00
Eugen Rochko
58e74708f5 New translations strings.xml (Thai) 2024-11-12 20:42:09 +01:00
Eugen Rochko
77855154d3 New translations strings.xml (Persian) 2024-11-12 20:42:07 +01:00
Eugen Rochko
d77fcff253 New translations strings.xml (Indonesian) 2024-11-12 20:42:05 +01:00
Eugen Rochko
5358c889e4 New translations strings.xml (Portuguese, Brazilian) 2024-11-12 20:42:04 +01:00
Eugen Rochko
bcbf3412a7 New translations strings.xml (Galician) 2024-11-12 20:42:03 +01:00
Eugen Rochko
17a481e797 New translations strings.xml (Vietnamese) 2024-11-12 20:42:01 +01:00
Eugen Rochko
dce8d38237 New translations strings.xml (Chinese Traditional) 2024-11-12 20:42:00 +01:00
Eugen Rochko
1cf250765b New translations strings.xml (Chinese Simplified) 2024-11-12 20:41:59 +01:00
Eugen Rochko
d136060b6f New translations strings.xml (Ukrainian) 2024-11-12 20:41:57 +01:00
Eugen Rochko
6dd7d779dd New translations strings.xml (Turkish) 2024-11-12 20:41:56 +01:00
Eugen Rochko
aca2843991 New translations strings.xml (Swedish) 2024-11-12 20:41:55 +01:00
Eugen Rochko
04f46cbecc New translations strings.xml (Slovenian) 2024-11-12 20:41:54 +01:00
Eugen Rochko
9fbca3a7d6 New translations strings.xml (Russian) 2024-11-12 20:41:52 +01:00
Eugen Rochko
a6a71ce8b6 New translations strings.xml (Portuguese) 2024-11-12 20:41:50 +01:00
Eugen Rochko
31d8a85e35 New translations strings.xml (Polish) 2024-11-12 20:41:49 +01:00
Eugen Rochko
63a3069041 New translations strings.xml (Norwegian) 2024-11-12 20:41:48 +01:00
Eugen Rochko
96750bb80a New translations strings.xml (Dutch) 2024-11-12 20:41:47 +01:00
Eugen Rochko
e53df3d1b1 New translations strings.xml (Lithuanian) 2024-11-12 20:41:45 +01:00
Eugen Rochko
8a5a681b86 New translations strings.xml (Korean) 2024-11-12 20:41:44 +01:00
Eugen Rochko
06d2df4773 New translations strings.xml (Japanese) 2024-11-12 20:41:42 +01:00
Eugen Rochko
723bdb9fed New translations strings.xml (Italian) 2024-11-12 20:41:41 +01:00
Eugen Rochko
774601bc6c New translations strings.xml (Armenian) 2024-11-12 20:41:40 +01:00
Eugen Rochko
909fbcb54a New translations strings.xml (Hungarian) 2024-11-12 20:41:38 +01:00
Eugen Rochko
1dd422918a New translations strings.xml (Finnish) 2024-11-12 20:41:36 +01:00
Eugen Rochko
7c433ccea9 New translations strings.xml (Greek) 2024-11-12 20:41:34 +01:00
Eugen Rochko
56602a88e1 New translations strings.xml (German) 2024-11-12 20:41:33 +01:00
Eugen Rochko
dd838689c5 New translations strings.xml (Danish) 2024-11-12 20:41:32 +01:00
Eugen Rochko
8b54f2960b New translations strings.xml (Czech) 2024-11-12 20:41:31 +01:00
Eugen Rochko
782f828073 New translations strings.xml (Catalan) 2024-11-12 20:41:29 +01:00
Eugen Rochko
32c0a3985e New translations strings.xml (Belarusian) 2024-11-12 20:41:28 +01:00
Eugen Rochko
6bfee114db New translations strings.xml (Arabic) 2024-11-12 20:41:27 +01:00
Eugen Rochko
fb0bbe3b11 New translations strings.xml (Spanish) 2024-11-12 20:41:25 +01:00
Eugen Rochko
64d0adc3ff New translations strings.xml (French) 2024-11-12 20:41:23 +01:00
Eugen Rochko
942c9998ba New translations strings.xml (Frisian) 2024-11-12 20:41:21 +01:00
Eugen Rochko
864d6fb7a5 New translations strings.xml (Icelandic) 2024-11-12 20:41:19 +01:00
Eugen Rochko
9286de4580 New translations strings.xml (Basque) 2024-11-12 20:41:18 +01:00
Grishka
6e4590caf2 Fix #820, probably 2024-11-12 22:40:48 +03:00
Grishka
ea1216b352 Show the direction on gaps + bug fix 2024-11-12 22:12:05 +03:00
Eugen Rochko
c2cd886844 New translations strings.xml (Swedish) 2024-11-12 19:38:17 +01:00
Eugen Rochko
83e5a041a3 New translations strings.xml (Swedish) 2024-11-12 18:38:19 +01:00
Eugen Rochko
a10bbab6d2 New translations strings.xml (Interlingua) 2024-11-12 16:55:50 +01:00
Eugen Rochko
ed36774f16 New translations strings.xml (Urdu (India)) 2024-11-12 16:55:49 +01:00
Eugen Rochko
6663c1c2be New translations strings.xml (Kabyle) 2024-11-12 16:55:48 +01:00
Eugen Rochko
6d448fbb5c New translations strings.xml (Igbo) 2024-11-12 16:55:47 +01:00
Eugen Rochko
25a49971bb New translations strings.xml (Occitan) 2024-11-12 16:55:45 +01:00
Eugen Rochko
3300660321 New translations strings.xml (Scottish Gaelic) 2024-11-12 16:55:44 +01:00
Eugen Rochko
39cf4b6678 New translations strings.xml (Sinhala) 2024-11-12 16:55:43 +01:00
Eugen Rochko
0edf1a5653 New translations strings.xml (Bosnian) 2024-11-12 16:55:42 +01:00
Eugen Rochko
52473e69cc New translations strings.xml (Filipino) 2024-11-12 16:55:41 +01:00
Eugen Rochko
0981ef5d68 New translations strings.xml (Welsh) 2024-11-12 16:55:40 +01:00
Eugen Rochko
4ed29cde81 New translations strings.xml (Burmese) 2024-11-12 16:55:39 +01:00
Eugen Rochko
25c05dcc51 New translations strings.xml (Hindi) 2024-11-12 16:55:38 +01:00
Eugen Rochko
afab3a04ca New translations strings.xml (Croatian) 2024-11-12 16:55:36 +01:00
Eugen Rochko
8a6e00d2bb New translations strings.xml (Thai) 2024-11-12 16:55:35 +01:00
Eugen Rochko
678dc12595 New translations strings.xml (Bengali) 2024-11-12 16:55:34 +01:00
Eugen Rochko
7390550cd2 New translations strings.xml (Persian) 2024-11-12 16:55:32 +01:00
Eugen Rochko
e4d193eb6c New translations strings.xml (Indonesian) 2024-11-12 16:55:31 +01:00
Eugen Rochko
ebe19a4393 New translations strings.xml (Portuguese, Brazilian) 2024-11-12 16:55:30 +01:00
Eugen Rochko
fe0ae9a425 New translations strings.xml (Galician) 2024-11-12 16:55:29 +01:00
Eugen Rochko
9b82c8b066 New translations strings.xml (Vietnamese) 2024-11-12 16:55:27 +01:00
Eugen Rochko
0a1df389e7 New translations strings.xml (Chinese Traditional) 2024-11-12 16:55:26 +01:00
Eugen Rochko
1735a3ba9a New translations strings.xml (Chinese Simplified) 2024-11-12 16:55:25 +01:00
Eugen Rochko
7ba6d37ebf New translations strings.xml (Ukrainian) 2024-11-12 16:55:23 +01:00
Eugen Rochko
7d59ca27fc New translations strings.xml (Turkish) 2024-11-12 16:55:22 +01:00
Eugen Rochko
323ede05a9 New translations strings.xml (Swedish) 2024-11-12 16:55:21 +01:00
Eugen Rochko
2c2dcf3c28 New translations strings.xml (Slovenian) 2024-11-12 16:55:20 +01:00
Eugen Rochko
1f5b1ba3f9 New translations strings.xml (Slovak) 2024-11-12 16:55:18 +01:00
Eugen Rochko
ec81a53e88 New translations strings.xml (Russian) 2024-11-12 16:55:17 +01:00
Eugen Rochko
324ef1cce9 New translations strings.xml (Portuguese) 2024-11-12 16:55:16 +01:00
Eugen Rochko
f4cae9c51f New translations strings.xml (Polish) 2024-11-12 16:55:15 +01:00
Eugen Rochko
0e92626755 New translations strings.xml (Norwegian) 2024-11-12 16:55:13 +01:00
Eugen Rochko
0d6658ca72 New translations strings.xml (Dutch) 2024-11-12 16:55:12 +01:00
Eugen Rochko
ac812704f0 New translations strings.xml (Lithuanian) 2024-11-12 16:55:10 +01:00
Eugen Rochko
5dbcf68aca New translations strings.xml (Korean) 2024-11-12 16:55:09 +01:00
Eugen Rochko
6a2395a3c5 New translations strings.xml (Georgian) 2024-11-12 16:55:07 +01:00
Eugen Rochko
be020bd742 New translations strings.xml (Japanese) 2024-11-12 16:55:06 +01:00
Eugen Rochko
1e19fbe4f9 New translations strings.xml (Italian) 2024-11-12 16:55:05 +01:00
Eugen Rochko
b18fecf9d8 New translations strings.xml (Armenian) 2024-11-12 16:55:04 +01:00
Eugen Rochko
3cde5435c0 New translations strings.xml (Hungarian) 2024-11-12 16:55:02 +01:00
Eugen Rochko
b988a455e3 New translations strings.xml (Hebrew) 2024-11-12 16:55:01 +01:00
Eugen Rochko
8c3ebaf784 New translations strings.xml (Irish) 2024-11-12 16:55:00 +01:00
Eugen Rochko
a381d338ef New translations strings.xml (Finnish) 2024-11-12 16:54:59 +01:00
Eugen Rochko
c04733411a New translations strings.xml (Greek) 2024-11-12 16:54:57 +01:00
Eugen Rochko
9218cb728e New translations strings.xml (German) 2024-11-12 16:54:56 +01:00
Eugen Rochko
e00bb3f6e9 New translations strings.xml (Danish) 2024-11-12 16:54:54 +01:00
Eugen Rochko
6727ec5119 New translations strings.xml (Czech) 2024-11-12 16:54:53 +01:00
Eugen Rochko
4d7a6d9476 New translations strings.xml (Catalan) 2024-11-12 16:54:52 +01:00
Eugen Rochko
858cc34298 New translations strings.xml (Belarusian) 2024-11-12 16:54:51 +01:00
Eugen Rochko
5ac37290df New translations strings.xml (Arabic) 2024-11-12 16:54:50 +01:00
Eugen Rochko
efd9690d10 New translations strings.xml (Spanish) 2024-11-12 16:54:48 +01:00
Eugen Rochko
2985c5490b New translations strings.xml (French) 2024-11-12 16:54:47 +01:00
Eugen Rochko
f70101279d New translations strings.xml (Romanian) 2024-11-12 16:54:46 +01:00
Eugen Rochko
9fe52e7853 New translations strings.xml (Frisian) 2024-11-12 16:54:44 +01:00
Eugen Rochko
f8059b2810 New translations strings.xml (Icelandic) 2024-11-12 16:54:43 +01:00
Eugen Rochko
372add3cf8 New translations strings.xml (Basque) 2024-11-12 16:54:42 +01:00
Grishka
134bd13d60 Show followers/following number when blocking a server (AND-233) 2024-11-12 18:49:05 +03:00
Eugen Rochko
a53959d707 New translations strings.xml (Lithuanian) 2024-11-12 12:36:31 +01:00
Eugen Rochko
2a6d87a513 New translations strings.xml (Italian) 2024-11-12 12:36:30 +01:00
Eugen Rochko
b2a9ce998d New translations strings.xml (Italian) 2024-11-12 10:31:58 +01:00
Eugen Rochko
7c63943814 New translations strings.xml (Italian) 2024-11-12 01:19:56 +01:00
likeazir
4b5f84d781 remove stray newline 2024-11-11 17:18:15 +01:00
likeazir
5c75ada632 rudimentary pagination fix to keep emoji size under 1MB cursor limit 2024-11-11 17:05:12 +01:00
Eugen Rochko
964b84ec79 New translations full_description.txt (Icelandic) 2024-11-11 13:02:37 +01:00
Eugen Rochko
55db777906 New translations strings.xml (Chinese Traditional) 2024-11-11 10:19:36 +01:00
Eugen Rochko
16b8724045 New translations strings.xml (Icelandic) 2024-11-10 15:35:26 +01:00
Eugen Rochko
87c425b89c New translations strings.xml (Spanish) 2024-11-10 01:29:53 +01:00
Grishka
20ed47032e Add filters to search (AND-106) 2024-11-08 20:13:31 +03:00
Grishka
91d65b4e27 Fix search view state restoration & animation 2024-11-08 19:53:30 +03:00
Eugen Rochko
5a0ed9b7c1 New translations strings.xml (Italian) 2024-11-07 20:36:16 +01:00
Eugen Rochko
b62963c4f3 New translations strings.xml (Italian) 2024-11-07 19:31:50 +01:00
Eugen Rochko
f0a00f6919 New translations strings.xml (Swedish) 2024-11-07 13:25:16 +01:00
Grishka
8ea049c956 Fix refresh 2024-11-07 14:04:40 +03:00
Grishka
ff5e281db7 Minor fixes in profiles 2024-11-07 14:02:13 +03:00
Eugen Rochko
65189753eb New translations strings.xml (Interlingua) 2024-11-07 11:53:47 +01:00
Eugen Rochko
0944682bef New translations strings.xml (Kabyle) 2024-11-07 11:53:46 +01:00
Eugen Rochko
aa41b9bef2 New translations strings.xml (Scottish Gaelic) 2024-11-07 11:53:43 +01:00
Eugen Rochko
668286215b New translations strings.xml (Welsh) 2024-11-07 11:53:40 +01:00
Eugen Rochko
bf1d709892 New translations strings.xml (Thai) 2024-11-07 11:53:36 +01:00
Eugen Rochko
4ae49029d0 New translations strings.xml (Persian) 2024-11-07 11:53:35 +01:00
Eugen Rochko
90a1860a1c New translations strings.xml (Indonesian) 2024-11-07 11:53:27 +01:00
Eugen Rochko
f3e8a0c6c9 New translations strings.xml (Portuguese, Brazilian) 2024-11-07 11:53:25 +01:00
Eugen Rochko
661a54f006 New translations strings.xml (Vietnamese) 2024-11-07 11:53:23 +01:00
Eugen Rochko
9f9e3f8eba New translations strings.xml (Chinese Traditional) 2024-11-07 11:53:22 +01:00
Eugen Rochko
6a9fb76677 New translations strings.xml (Chinese Simplified) 2024-11-07 11:53:21 +01:00
Eugen Rochko
c81288e694 New translations strings.xml (Ukrainian) 2024-11-07 11:53:20 +01:00
Eugen Rochko
594f044068 New translations strings.xml (Turkish) 2024-11-07 11:53:19 +01:00
Eugen Rochko
147485633c New translations strings.xml (Swedish) 2024-11-07 11:53:17 +01:00
Eugen Rochko
4498a0f226 New translations strings.xml (Slovenian) 2024-11-07 11:53:16 +01:00
Eugen Rochko
1df56fc320 New translations strings.xml (Russian) 2024-11-07 11:53:14 +01:00
Eugen Rochko
1e2f47dd2a New translations strings.xml (Polish) 2024-11-07 11:53:12 +01:00
Eugen Rochko
26f5fbf3b8 New translations strings.xml (Norwegian) 2024-11-07 11:53:11 +01:00
Eugen Rochko
ecd2cecfa6 New translations strings.xml (Dutch) 2024-11-07 11:53:10 +01:00
Eugen Rochko
f6ecd25e1d New translations strings.xml (Lithuanian) 2024-11-07 11:53:09 +01:00
Eugen Rochko
1ac088f5a3 New translations strings.xml (Japanese) 2024-11-07 11:53:06 +01:00
Eugen Rochko
0030a06cd3 New translations strings.xml (Italian) 2024-11-07 11:53:05 +01:00
Eugen Rochko
6b7d1b0981 New translations strings.xml (Armenian) 2024-11-07 11:53:04 +01:00
Eugen Rochko
f1140a0197 New translations strings.xml (Hungarian) 2024-11-07 11:53:03 +01:00
Eugen Rochko
179534e931 New translations strings.xml (Greek) 2024-11-07 11:52:59 +01:00
Eugen Rochko
be2db34586 New translations strings.xml (German) 2024-11-07 11:52:58 +01:00
Eugen Rochko
50b81c3b98 New translations strings.xml (Danish) 2024-11-07 11:52:57 +01:00
Eugen Rochko
31ae0b6e08 New translations strings.xml (Czech) 2024-11-07 11:52:56 +01:00
Eugen Rochko
36fdecd22e New translations strings.xml (Belarusian) 2024-11-07 11:52:53 +01:00
Eugen Rochko
d33f1d59ca New translations strings.xml (Spanish) 2024-11-07 11:52:52 +01:00
Eugen Rochko
b6a978f376 New translations strings.xml (French) 2024-11-07 11:52:50 +01:00
Eugen Rochko
a1da9be14f New translations strings.xml (Frisian) 2024-11-07 11:52:48 +01:00
Eugen Rochko
692ebed8fb New translations strings.xml (Icelandic) 2024-11-07 11:52:47 +01:00
Eugen Rochko
000294d2fa New translations strings.xml (Basque) 2024-11-07 11:52:46 +01:00
Grishka
6406d25938 oops 2024-11-07 13:46:25 +03:00
Grishka
9c95d5f6e5 Make favorites and bookmarks a tab in profile (AND-135) 2024-11-07 13:24:40 +03:00
Eugen Rochko
c15ef07d53 New translations strings.xml (Russian) 2024-11-06 12:56:23 +01:00
Eugen Rochko
7182647574 New translations strings.xml (Icelandic) 2024-11-06 12:56:22 +01:00
Eugen Rochko
2a08b27667 New translations strings.xml (Swedish) 2024-11-06 10:06:02 +01:00
Grishka
56a2510564 Show mutual followers in profile (AND-187) 2024-11-06 11:56:04 +03:00
Grishka
ddaab49976 Support "new post" push notifications
fixes #910
2024-11-06 10:25:21 +03:00
Eugen Rochko
508ea32701 New translations strings.xml (Portuguese, Brazilian) 2024-11-05 22:46:34 +01:00
Grishka
1b17600835 Group settings by account (AND-170) 2024-11-05 23:05:33 +03:00
Grishka
c60d06950f Crash fixes 2024-11-05 20:45:49 +03:00
Eugen Rochko
bbdc3d4038 New translations strings.xml (Italian) 2024-11-05 17:49:45 +01:00
Eugen Rochko
5e2a292aeb New translations strings.xml (Thai) 2024-11-03 20:20:52 +01:00
Eugen Rochko
1f6c48edf8 New translations strings.xml (Thai) 2024-11-03 19:12:56 +01:00
Eugen Rochko
a72acf7d32 New translations strings.xml (German) 2024-11-03 12:51:41 +01:00
118 changed files with 1687 additions and 495 deletions

View File

@@ -0,0 +1,6 @@
- Settings are now split into global settings and account-specific settings for each account you're logged into
- Profiles now show who of the people you follow also follows this person
- More easily swap between posts, profiles and hashtags when using search
- We now tell you exactly how many followers you'd lose when blocking a whole server so you can avoid costly mistakes
- Bookmarks and favourites have moved to a new tab on your profile
- The button that loads missing posts is now more upfront about which direction it's going to load in

View File

@@ -1 +1 @@
125.txt
128.txt

View File

@@ -42,20 +42,20 @@ Með samræðum, hágæða myndefni, myndskeiðum, hljóðskrám og viðvörunum
Við þurfum ekkert að sýna þér auglýsingar og höfum því enga ástæðu til að halda þér inni í okkar eigin forritum. Mastodon býður upp á mikið úrval forrita frá utanaðkomandi aðilum og samþættingu við önnur kerfi, þannig að þú getir valið það sem þér líkar best.
Thanks to the chronological home feed, its easy to tell when youve caught up on all updates and can move on to something else.
Þökk sé heimastreymi í tímaröð, þá er auðvelt að sjá þegar þú lýkur við að skoða allar nýjar færslur og getur snúið þér að einhverju öðru.
No need to worry that a misclick will ruin your recommendations forever. Við eru ekkert að giska á hvað þú viljir sjá, við látum þér eftir að stýra því.
Þú þarft ekkert að hafa áhyggjur að einn smellur á rangan stað skemmi orðspor þitt að eilífu. Við eru ekkert að giska á hvað þú viljir sjá, við látum þér eftir að stýra því.
SAMSKIPTAMÁTAR, EKKI KERFI
Mastodon is not like a traditional social media platform, but is built on a decentralized protocol. You can sign up on our official server, or choose a 3rd party to host your data and moderate your experience.
Mastodon er ekki hefðbundinn samfélagsmiðill, heldur byggist í kringum samskiptamáta sem ekki er með miðlæga stýringu. Þú getur skráð þig á opinbera netþjóninum okkar eða valið utanaðkomandi þjón til að hýsa gögnin þín og hafa umsjón með umhverfinu þínu.
Thanks to the common protocol, no matter what you choose, you can communicate seamlessly with people on other Mastodon servers. But theres more: With just one account, you can communicate with people from other fediverse platforms.
Þökk sé sameiginlegum samskiptamáta, þá skiptir ekki máli hvaða netþjón þú velur; þú átt að eiga hindranalaus samskipti við fólk á öðrum Mastodon-þjónum. En það er meira til: Með einum notandaaðgangi geturðu átt í samskiptum við önnut tengd kerfi sem tilheyra fedi-heiminum.
Ekki ánægð/ur með valið þitt? Þú getur alltaf skipt yfir á annan Mastodon-þjón og tekið fylgjendurna þína með þér. For advanced users, you can even host your data on your own infrastructure, since Mastodon is open-source.
Ekki ánægð/ur með valið þitt? Þú getur alltaf skipt yfir á annan Mastodon-þjón og tekið fylgjendurna þína með þér. Vanir tölvulæsir notendur geta meira að segja hýst sitt eigið kerfi, enda er Mastodon opinn hugbúnaður.
ÁN HAGNAÐARMARKMIÐA INN AÐ BEINI
Mastodon er skráð sem samtök án hagnaðarmarkmiða í BNA og Þýskalandi. We are not motivated by extracting monetary value from the platform, but by whats best for the platform.
Mastodon er skráð sem samtök án hagnaðarmarkmiða í BNA og Þýskalandi. Við höfum engan hvata til að ná peningum út úr kerfinu, heldur liggur áhuginn í því sem er best fyrir kerfið.
EINS OG BIRST HEFUR Í: TIME, Forbes, Wired, The Guardian, CNN, The Verge, TechCrunch, Financial Times, Gizmodo, PCMAG.com og víðar.

View File

@@ -13,8 +13,8 @@ android {
applicationId "org.joinmastodon.android"
minSdk 23
targetSdk 34
versionCode 125
versionName "2.8.0"
versionCode 128
versionName "2.9.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

View File

@@ -3,6 +3,7 @@ package org.joinmastodon.android;
import android.content.Context;
import android.content.SharedPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
@@ -12,6 +13,10 @@ public class GlobalUserPreferences{
public static boolean altTextReminders, confirmUnfollow, confirmBoost, confirmDeletePost;
public static ThemePreference theme=ThemePreference.AUTO;
public static boolean useDynamicColors;
public static boolean showInteractionCounts;
public static boolean customEmojiInNames;
public static boolean showCWs;
public static boolean hideSensitiveMedia;
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
@@ -31,6 +36,23 @@ public class GlobalUserPreferences{
confirmDeletePost=prefs.getBoolean("confirmDeletePost", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
useDynamicColors=prefs.getBoolean("useDynamicColors", true);
showInteractionCounts=prefs.getBoolean("interactionCounts", true);
customEmojiInNames=prefs.getBoolean("emojiInNames", true);
showCWs=prefs.getBoolean("showCWs", true);
hideSensitiveMedia=prefs.getBoolean("hideSensitive", true);
if(!prefs.getBoolean("perAccountMigrationDone", false)){
AccountSession account=AccountSessionManager.getInstance().getLastActiveAccount();
if(account!=null){
SharedPreferences accPrefs=account.getRawLocalPreferences();
showInteractionCounts=accPrefs.getBoolean("interactionCounts", true);
customEmojiInNames=accPrefs.getBoolean("emojiInNames", true);
showCWs=accPrefs.getBoolean("showCWs", true);
hideSensitiveMedia=accPrefs.getBoolean("hideSensitive", true);
save();
}
// Also applies to new app installs
prefs.edit().putBoolean("perAccountMigrationDone", true).apply();
}
}
public static void save(){
@@ -43,6 +65,10 @@ public class GlobalUserPreferences{
.putBoolean("confirmBoost", confirmBoost)
.putBoolean("confirmDeletePost", confirmDeletePost)
.putBoolean("useDynamicColors", useDynamicColors)
.putBoolean("interactionCounts", showInteractionCounts)
.putBoolean("emojiInNames", customEmojiInNames)
.putBoolean("showCWs", showCWs)
.putBoolean("hideSensitive", hideSensitiveMedia)
.apply();
}

View File

@@ -130,6 +130,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
Notification.Builder builder;
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
boolean hasGroup=false;
int version=AccountSessionManager.get(accountID).getRawLocalPreferences().getInt("notificationChannelsVersion", 1);
List<NotificationChannelGroup> channelGroups=nm.getNotificationChannelGroups();
for(NotificationChannelGroup group:channelGroups){
if(group.getId().equals(accountID)){
@@ -137,7 +138,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
break;
}
}
if(!hasGroup){
if(!hasGroup || version!=2){
NotificationChannelGroup group=new NotificationChannelGroup(accountID, accountName);
nm.createNotificationChannelGroup(group);
List<NotificationChannel> channels=Arrays.stream(PushNotification.Type.values())
@@ -150,6 +151,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
})
.collect(Collectors.toList());
nm.createNotificationChannels(channels);
AccountSessionManager.get(accountID).getRawLocalPreferences().edit().putInt("notificationChannelsVersion", 2).apply();
}
builder=new Notification.Builder(context, accountID+"_"+pn.notificationType);
}else{

View File

@@ -148,7 +148,7 @@ public class CacheController{
.map(ng->{
NotificationViewModel nvm=new NotificationViewModel();
nvm.notification=ng;
nvm.accounts=ng.sampleAccountIds.stream().map(accounts::get).collect(Collectors.toList());
nvm.accounts=ng.sampleAccountIds.stream().map(accounts::get).filter(Objects::nonNull).collect(Collectors.toList());
if(nvm.accounts.size()!=ng.sampleAccountIds.size())
return null;
if(ng.statusId!=null){

View File

@@ -0,0 +1,18 @@
package org.joinmastodon.android.api.requests.accounts;
import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.FamiliarFollowers;
import java.util.Collection;
import java.util.List;
public class GetAccountFamiliarFollowers extends MastodonAPIRequest<List<FamiliarFollowers>>{
public GetAccountFamiliarFollowers(Collection<String> ids){
super(HttpMethod.GET, "/accounts/familiar_followers", new TypeToken<>(){});
for(String id:ids){
addQueryParameter("id[]", id);
}
}
}

View File

@@ -0,0 +1,15 @@
package org.joinmastodon.android.api.requests.accounts;
import org.joinmastodon.android.api.MastodonAPIRequest;
public class GetDomainBlockPreview extends MastodonAPIRequest<GetDomainBlockPreview.Response>{
public GetDomainBlockPreview(String domain){
super(HttpMethod.GET, "/domain_blocks/preview", Response.class);
addQueryParameter("domain", domain);
}
public static class Response{
public int followingCount;
public int followersCount;
}
}

View File

@@ -5,18 +5,10 @@ import android.content.SharedPreferences;
public class AccountLocalPreferences{
private final SharedPreferences prefs;
public boolean showInteractionCounts;
public boolean customEmojiInNames;
public boolean showCWs;
public boolean hideSensitiveMedia;
public boolean serverSideFiltersSupported;
public AccountLocalPreferences(SharedPreferences prefs){
this.prefs=prefs;
showInteractionCounts=prefs.getBoolean("interactionCounts", true);
customEmojiInNames=prefs.getBoolean("emojiInNames", true);
showCWs=prefs.getBoolean("showCWs", true);
hideSensitiveMedia=prefs.getBoolean("hideSensitive", true);
serverSideFiltersSupported=prefs.getBoolean("serverSideFilters", false);
}
@@ -30,10 +22,6 @@ public class AccountLocalPreferences{
public void save(){
prefs.edit()
.putBoolean("interactionCounts", showInteractionCounts)
.putBoolean("emojiInNames", customEmojiInNames)
.putBoolean("showCWs", showCWs)
.putBoolean("hideSensitive", hideSensitiveMedia)
.putBoolean("serverSideFilters", serverSideFiltersSupported)
.apply();
}

View File

@@ -382,21 +382,40 @@ public class AccountSessionManager{
}
private void readInstanceInfo(SQLiteDatabase db, Set<String> domains){
try(Cursor cursor=db.query("instances", null, "`domain` IN ("+String.join(", ", Collections.nCopies(domains.size(), "?"))+")", domains.toArray(new String[0]), null, null, null)){
ContentValues values=new ContentValues();
while(cursor.moveToNext()){
DatabaseUtils.cursorRowToContentValues(cursor, values);
String domain=values.getAsString("domain");
int version=values.getAsInteger("version");
Instance instance=MastodonAPIController.gson.fromJson(values.getAsString("instance_obj"), switch(version){
case 1 -> InstanceV1.class;
case 2 -> InstanceV2.class;
default -> throw new IllegalStateException("Unexpected value: " + version);
});
List<Emoji> emojis=MastodonAPIController.gson.fromJson(values.getAsString("emojis"), new TypeToken<List<Emoji>>(){}.getType());
instances.put(domain, instance);
customEmojis.put(domain, groupCustomEmojis(emojis));
instancesLastUpdated.put(domain, values.getAsLong("last_updated"));
for(String domain : domains){
final int maxEmojiLength=500000;
try(Cursor cursor=db.rawQuery("SELECT domain, instance_obj, substring(emojis,0,?) AS emojis, length(emojis) AS emoji_length, last_updated, version FROM instances WHERE `domain` = ?",
new String[]{String.valueOf(maxEmojiLength) , domain})) {
ContentValues values=new ContentValues();
while(cursor.moveToNext()){
DatabaseUtils.cursorRowToContentValues(cursor, values);
int version=values.getAsInteger("version");
Instance instance=MastodonAPIController.gson.fromJson(values.getAsString("instance_obj"), switch(version){
case 1 -> InstanceV1.class;
case 2 -> InstanceV2.class;
default -> throw new IllegalStateException("Unexpected value: "+version);
});
StringBuilder emojiSB=new StringBuilder();
emojiSB.append(values.getAsString("emojis"));
//get emoji in chunks of 1MB if it didn't fit in the first query
int emojiStringLength=values.getAsInteger("emoji_length");
if(emojiStringLength>maxEmojiLength){
final int pagesize=1000000;
for(int start=maxEmojiLength; start<emojiStringLength; start+=pagesize){
try(Cursor emojiCursor=db.rawQuery("SELECT substr(emojis,?, ?) FROM instances WHERE `domain` = ?", new String[]{String.valueOf(start), String.valueOf(pagesize), domain})){
emojiCursor.moveToNext();
emojiSB.append(emojiCursor.getString(0));
}
}
}
List<Emoji> emojis=MastodonAPIController.gson.fromJson(emojiSB.toString(), new TypeToken<List<Emoji>>(){}.getType());
instances.put(domain, instance);
customEmojis.put(domain, groupCustomEmojis(emojis));
instancesLastUpdated.put(domain, values.getAsLong("last_updated"));
}
}catch(Exception ex){
Log.d(TAG, "readInstanceInfo failed", ex);
return;
}
}
if(!loadedInstances){

View File

@@ -500,7 +500,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
int itemCount=spoilerItem.contentItems.size();
displayItems.addAll(index+1, spoilerItem.contentItems);
if(spoilerItem.spoilerType==Status.SpoilerType.FILTER && spoilerItem.contentItems.get(0) instanceof SpoilerStatusDisplayItem nestedSpoiler
&& nestedSpoiler.spoilerType==Status.SpoilerType.CONTENT_WARNING && !AccountSessionManager.get(accountID).getLocalPreferences().showCWs){
&& nestedSpoiler.spoilerType==Status.SpoilerType.CONTENT_WARNING && !GlobalUserPreferences.showCWs){
status.revealedSpoilers.add(Status.SpoilerType.CONTENT_WARNING);
displayItems.addAll(index+1+itemCount, nestedSpoiler.contentItems);
itemCount+=nestedSpoiler.contentItems.size();

View File

@@ -1,43 +0,0 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetBookmarkedStatuses;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Status;
import me.grishka.appkit.api.SimpleCallback;
public class BookmarkedStatusListFragment extends StatusListFragment{
private String nextMaxID;
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
setTitle(R.string.bookmarks);
loadData();
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetBookmarkedStatuses(offset==0 ? null : nextMaxID, count)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Status> result){
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else
nextMaxID=null;
onDataLoaded(result, nextMaxID!=null);
}
})
.exec(accountID);
}
@Override
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
// no-op
}
}

View File

@@ -1,37 +0,0 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetFavoritedStatuses;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Status;
import me.grishka.appkit.api.SimpleCallback;
public class FavoritedStatusListFragment extends StatusListFragment{
private String nextMaxID;
@Override
public void onAttach(Activity activity){
super.onAttach(activity);
setTitle(R.string.your_favorites);
loadData();
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetFavoritedStatuses(offset==0 ? null : nextMaxID, count)
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Status> result){
if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else
nextMaxID=null;
onDataLoaded(result, nextMaxID!=null);
}
})
.exec(accountID);
}
}

View File

@@ -308,8 +308,9 @@ public class HomeTimelineFragment extends StatusListFragment implements ToolbarD
if(!gap.visible){
gap.visible=true;
gap.enteredFromTop=child.getTop()<list.getHeight()/2;
gaps.remove(gap);
holder.text.setText(gap.enteredFromTop ? R.string.load_missing_posts_above : R.string.load_missing_posts_below);
}
gaps.remove(gap);
}
}
for(GapStatusDisplayItem gap:gaps){

View File

@@ -165,7 +165,10 @@ public class NotificationsListFragment extends BaseNotificationsListFragment{
for(int i=0;i<parent.getChildCount();i++){
View child=parent.getChildAt(i);
if(parent.getChildViewHolder(child) instanceof StatusDisplayItem.Holder<?> holder){
String itemID=getNotificationByID(holder.getItemID()).notification.pageMaxId;
NotificationViewModel n=getNotificationByID(holder.getItemID());
if(n==null)
continue;
String itemID=n.notification.pageMaxId;
if(ObjectIdComparator.INSTANCE.compare(itemID, unreadMarker)>0){
parent.getDecoratedBoundsWithMargins(child, tmpRect);
c.drawRect(tmpRect, paint);

View File

@@ -51,18 +51,22 @@ import android.widget.Toolbar;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountByID;
import org.joinmastodon.android.api.requests.accounts.GetAccountFamiliarFollowers;
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
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.AccountSessionManager;
import org.joinmastodon.android.fragments.account_list.FamiliarFollowerListFragment;
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
import org.joinmastodon.android.fragments.account_list.FollowingListFragment;
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.FamiliarFollowers;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.model.viewmodel.AccountViewModel;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.SimpleViewHolder;
@@ -92,6 +96,8 @@ import java.time.format.FormatStyle;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
@@ -123,6 +129,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
private ProfileFeaturedFragment featuredFragment;
private AccountTimelineFragment timelineFragment;
private ProfileAboutFragment aboutFragment;
private SavedPostsTimelineFragment savedFragment;
private TabLayout tabbar;
private SwipeRefreshLayout refreshLayout;
private View followersBtn, followingBtn;
@@ -139,12 +146,16 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
private ImageButton qrCodeButton;
private ProgressBar innerProgress;
private View actions;
private View familiarFollowersRow;
private ImageView[] familiarFollowersAvatars;
private TextView familiarFollowersLabel;
private Account account;
private String accountID;
private Relationship relationship;
private boolean isOwnProfile;
private ArrayList<AccountField> fields=new ArrayList<>();
private List<Account> familiarFollowers=List.of();
private boolean isInEditMode, editDirty;
private Uri editNewAvatar, editNewCover;
@@ -225,6 +236,13 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
qrCodeButton=content.findViewById(R.id.qr_code);
innerProgress=content.findViewById(R.id.profile_progress);
actions=content.findViewById(R.id.profile_actions);
familiarFollowersRow=content.findViewById(R.id.familiar_followers);
familiarFollowersAvatars=new ImageView[]{
content.findViewById(R.id.familiar_followers_ava1),
content.findViewById(R.id.familiar_followers_ava2),
content.findViewById(R.id.familiar_followers_ava3),
};
familiarFollowersLabel=content.findViewById(R.id.familiar_followers_label);
avatar.setOutlineProvider(OutlineProviders.roundedRect(24));
avatar.setClipToOutline(true);
@@ -237,13 +255,14 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
}
};
tabViews=new FrameLayout[3];
tabViews=new FrameLayout[4];
for(int i=0;i<tabViews.length;i++){
FrameLayout tabView=new FrameLayout(getActivity());
tabView.setId(switch(i){
case 0 -> R.id.profile_featured;
case 1 -> R.id.profile_timeline;
case 2 -> R.id.profile_about;
case 3 -> R.id.profile_saved;
default -> throw new IllegalStateException("Unexpected value: "+i);
});
tabView.setVisibility(View.GONE);
@@ -251,7 +270,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
tabViews[i]=tabView;
}
pager.setOffscreenPageLimit(4);
pager.setOffscreenPageLimit(10);
pager.setAdapter(new ProfilePagerAdapter());
pager.getLayoutParams().height=getResources().getDisplayMetrics().heightPixels;
@@ -265,6 +284,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
case 0 -> R.string.profile_featured;
case 1 -> R.string.profile_timeline;
case 2 -> R.string.profile_about;
case 3 -> R.string.profile_saved_posts;
default -> throw new IllegalStateException();
}));
tabbar.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
@@ -293,11 +313,13 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
cover.setOnClickListener(this::onCoverClick);
refreshLayout.setOnRefreshListener(this);
fab.setOnClickListener(this::onFabClick);
familiarFollowersRow.setOnClickListener(this::onFamiliarFollowersClick);
if(savedInstanceState!=null){
featuredFragment=(ProfileFeaturedFragment) getChildFragmentManager().getFragment(savedInstanceState, "featured");
timelineFragment=(AccountTimelineFragment) getChildFragmentManager().getFragment(savedInstanceState, "timeline");
aboutFragment=(ProfileAboutFragment) getChildFragmentManager().getFragment(savedInstanceState, "about");
savedFragment=(SavedPostsTimelineFragment) getChildFragmentManager().getFragment(savedInstanceState, "saved");
}
if(loaded){
@@ -352,6 +374,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
qf.setArguments(args);
qf.show(getChildFragmentManager(), "qrDialog");
});
familiarFollowersRow.setVisibility(View.GONE);
return sizeWrapper;
}
@@ -379,6 +402,8 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
timelineFragment.onRefresh();
if(featuredFragment.loaded)
featuredFragment.onRefresh();
if(savedFragment!=null && savedFragment.loaded)
savedFragment.onRefresh();
}
V.setVisibilityAnimated(fab, View.VISIBLE);
}
@@ -414,16 +439,21 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
aboutFragment=new ProfileAboutFragment();
aboutFragment.setFields(fields);
}
pager.getAdapter().notifyDataSetChanged();
pager.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){
pager.getViewTreeObserver().removeOnPreDrawListener(this);
pager.setCurrentItem(1, false);
tabbar.selectTab(tabbar.getTabAt(1));
return true;
}
});
if(savedFragment==null && isOwnProfile){
savedFragment=SavedPostsTimelineFragment.newInstance(accountID, account, false);
}
if(!refreshing){
pager.getAdapter().notifyDataSetChanged();
pager.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public boolean onPreDraw(){
pager.getViewTreeObserver().removeOnPreDrawListener(this);
pager.setCurrentItem(1, false);
tabbar.selectTab(tabbar.getTabAt(1));
return true;
}
});
}
super.dataLoaded();
}
@@ -489,6 +519,8 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
getChildFragmentManager().putFragment(outState, "timeline", timelineFragment);
if(aboutFragment.isAdded())
getChildFragmentManager().putFragment(outState, "about", aboutFragment);
if(savedFragment!=null && savedFragment.isAdded())
getChildFragmentManager().putFragment(outState, "saved", savedFragment);
}
@Override
@@ -517,6 +549,8 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
if(timelineFragment!=null && timelineFragment.isAdded() && childInsets!=null){
timelineFragment.onApplyWindowInsets(childInsets);
featuredFragment.onApplyWindowInsets(childInsets);
if(savedFragment!=null)
savedFragment.onApplyWindowInsets(childInsets);
}
}
@@ -560,7 +594,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
ViewImageLoader.loadWithoutAnimation(avatar, avatar.getDrawable(), new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(100), V.dp(100)));
ViewImageLoader.loadWithoutAnimation(cover, cover.getDrawable(), new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.header : account.headerStatic, 1000, 1000));
SpannableStringBuilder ssb=new SpannableStringBuilder(account.displayName);
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
if(GlobalUserPreferences.customEmojiInNames)
HtmlParser.parseCustomEmoji(ssb, account.emojis);
name.setText(ssb);
setTitle(ssb);
@@ -645,6 +679,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
if(onScrollListener!=null){
onScrollListener.setViews(getToolbar());
}
getToolbar().setTranslationZ(tabBarIsAtTop ? 0 : V.dp(3));
}
private CharSequence makeRedString(CharSequence s){
@@ -732,14 +767,6 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
})
.wrapProgress(getActivity(), R.string.loading, false)
.exec(accountID);
}else if(id==R.id.bookmarks){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.go(getActivity(), BookmarkedStatusListFragment.class, args);
}else if(id==R.id.favorites){
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.go(getActivity(), FavoritedStatusListFragment.class, args);
}else if(id==R.id.save){
if(isInEditMode)
saveAndExitEditMode();
@@ -790,6 +817,25 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
}
})
.exec(accountID);
new GetAccountFamiliarFollowers(Set.of(account.id))
.setCallback(new Callback<>(){
@Override
public void onSuccess(List<FamiliarFollowers> result){
for(FamiliarFollowers ff:result){
if(ff.id.equals(account.id)){
familiarFollowers=ff.accounts;
updateFamiliarFollowers();
break;
}
}
}
@Override
public void onError(ErrorResponse error){
}
})
.exec(accountID);
}
private void updateRelationship(){
@@ -800,6 +846,38 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
followsYouView.setVisibility(relationship.followedBy ? View.VISIBLE : View.GONE);
}
private void updateFamiliarFollowers(){
if(!familiarFollowers.isEmpty()){
familiarFollowersRow.setVisibility(View.VISIBLE);
List<AccountViewModel> followers=familiarFollowers.stream().limit(3).map(a->new AccountViewModel(a, accountID, false, getActivity())).collect(Collectors.toList());
String template=switch(familiarFollowers.size()){
case 1 -> getString(R.string.familiar_followers_one, "{first}");
case 2 -> getString(R.string.familiar_followers_two, "{first}", "{second}");
default -> getResources().getQuantityString(R.plurals.familiar_followers_many, familiarFollowers.size()-2, "{first}", "{second}", familiarFollowers.size()-2);
};
SpannableStringBuilder ssb=new SpannableStringBuilder(template);
if(familiarFollowers.size()>1){
int index=template.indexOf("{second}");
ssb.replace(index, index+8, followers.get(1).parsedName);
template=template.replace("{second}", "#".repeat(followers.get(1).parsedName.length()));
}
int index=template.indexOf("{first}");
ssb.replace(index, index+7, followers.get(0).parsedName);
familiarFollowersLabel.setText(ssb);
UiUtils.loadCustomEmojiInTextView(familiarFollowersLabel);
if(familiarFollowers.size()<3)
familiarFollowersAvatars[2].setVisibility(View.GONE);
if(familiarFollowers.size()<2)
familiarFollowersAvatars[1].setVisibility(View.GONE);
int i=0;
for(AccountViewModel avm:followers){
ViewImageLoader.loadWithoutAnimation(familiarFollowersAvatars[i], getResources().getDrawable(R.drawable.image_placeholder, getActivity().getTheme()), avm.avaRequest);
i++;
}
}
}
private void onScrollChanged(View v, int scrollX, int scrollY, int oldScrollX, int oldScrollY){
if(scrollY>cover.getHeight()){
cover.setTranslationY(scrollY-(cover.getHeight()));
@@ -853,6 +931,9 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
editSaveMenuItem.setVisible(!buttonInView);
}
}
if((scrollY==0 && oldScrollY!=0) || (scrollY!=0 && oldScrollY==0)){
refreshLayout.setEnabled(scrollY==0);
}
}
private Fragment getFragmentForPage(int page){
@@ -860,6 +941,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
case 0 -> featuredFragment;
case 1 -> timelineFragment;
case 2 -> aboutFragment;
case 3 -> savedFragment;
default -> throw new IllegalStateException();
};
}
@@ -923,7 +1005,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
pager.setUserInputEnabled(false);
actionButton.setText(R.string.save_changes);
pager.setCurrentItem(2);
for(int i=0;i<3;i++){
for(int i=0;i<4;i++){
tabbar.getTabAt(i).view.setEnabled(false);
}
Drawable overlay=getResources().getDrawable(R.drawable.edit_avatar_overlay).mutate();
@@ -1000,7 +1082,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
invalidateOptionsMenu();
actionButton.setText(R.string.edit_profile);
for(int i=0;i<3;i++){
for(int i=0;i<4;i++){
tabbar.getTabAt(i).view.setEnabled(true);
}
pager.setUserInputEnabled(true);
@@ -1168,6 +1250,14 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
Nav.go(getActivity(), ComposeFragment.class, args);
}
private void onFamiliarFollowersClick(View v){
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("targetAccount", Parcels.wrap(account));
args.putInt("count", familiarFollowers.size());
Nav.go(getActivity(), FamiliarFollowerListFragment.class, args);
}
private void startImagePicker(int requestCode){
Intent intent=UiUtils.getMediaPickerIntent(new String[]{"image/*"}, 1);
startActivityForResult(intent, requestCode);
@@ -1261,7 +1351,7 @@ public class ProfileFragment extends LoaderFragment implements ScrollableToTop,
@Override
public int getItemCount(){
return loaded ? 3 : 0;
return loaded ? (isOwnProfile ? 4 : 3) : 0;
}
@Override

View File

@@ -0,0 +1,169 @@
package org.joinmastodon.android.fragments;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetBookmarkedStatuses;
import org.joinmastodon.android.api.requests.statuses.GetFavoritedStatuses;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.HeaderPaginationList;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.drawables.EmptyDrawable;
import org.joinmastodon.android.ui.views.FilterChipView;
import org.parceler.Parcels;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
import me.grishka.appkit.utils.V;
public class SavedPostsTimelineFragment extends StatusListFragment{
private Account user;
private Mode mode;
private HorizontalScrollView filtersBar;
private FilterChipView favoritesChip, bookmarksChip;
public SavedPostsTimelineFragment(){
setListLayoutId(R.layout.recycler_fragment_no_refresh);
}
public static SavedPostsTimelineFragment newInstance(String accountID, Account profileAccount, boolean load){
SavedPostsTimelineFragment f=new SavedPostsTimelineFragment();
Bundle args=new Bundle();
args.putString("account", accountID);
args.putParcelable("profileAccount", Parcels.wrap(profileAccount));
if(!load)
args.putBoolean("noAutoLoad", true);
args.putBoolean("__is_tab", true);
f.setArguments(args);
return f;
}
@Override
public void onAttach(Activity activity){
user=Parcels.unwrap(getArguments().getParcelable("profileAccount"));
mode=Mode.FAVORITES;
super.onAttach(activity);
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=(switch(mode){
case FAVORITES -> new GetFavoritedStatuses(offset>0 ? getMaxID() : null, count);
case BOOKMARKS -> new GetBookmarkedStatuses(offset>0 ? getMaxID() : null, count);
}).setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(HeaderPaginationList<Status> result){
if(getActivity()==null)
return;
onDataLoaded(result, result.nextPageUri!=null);
}
}).exec(accountID);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
view.setBackground(null); // prevents unnecessary overdraw
}
@Override
protected void onShown(){
super.onShown();
if(!getArguments().getBoolean("noAutoLoad") && !loaded && !dataLoading)
loadData();
}
protected void onStatusCreated(Status status){
// no-op
}
@Override
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
// no-op
}
@Override
protected RecyclerView.Adapter getAdapter(){
filtersBar=new HorizontalScrollView(getActivity());
LinearLayout filtersLayout=new LinearLayout(getActivity());
filtersBar.addView(filtersLayout);
filtersLayout.setOrientation(LinearLayout.HORIZONTAL);
filtersLayout.setPadding(V.dp(16), 0, V.dp(16), V.dp(8));
filtersLayout.setDividerDrawable(new EmptyDrawable(V.dp(8), 1));
filtersLayout.setShowDividers(LinearLayout.SHOW_DIVIDER_MIDDLE);
favoritesChip=new FilterChipView(getActivity());
favoritesChip.setText(R.string.your_favorites);
favoritesChip.setTag(Mode.FAVORITES);
favoritesChip.setSelected(mode==Mode.FAVORITES);
favoritesChip.setOnClickListener(this::onFilterClick);
filtersLayout.addView(favoritesChip);
bookmarksChip=new FilterChipView(getActivity());
bookmarksChip.setText(R.string.bookmarks);
bookmarksChip.setTag(Mode.BOOKMARKS);
bookmarksChip.setSelected(mode==Mode.BOOKMARKS);
bookmarksChip.setOnClickListener(this::onFilterClick);
filtersLayout.addView(bookmarksChip);
View banner=getActivity().getLayoutInflater().inflate(R.layout.discover_info_banner, list, false);
TextView text=banner.findViewById(R.id.banner_text);
text.setText(R.string.profile_saved_posts_explanation);
ImageView icon=banner.findViewById(R.id.icon);
icon.setImageResource(R.drawable.ic_lock_24px);
// Prevents margins messing up things
FrameLayout bannerW=new FrameLayout(getActivity());
bannerW.addView(banner);
MergeRecyclerAdapter mergeAdapter=new MergeRecyclerAdapter();
mergeAdapter.addAdapter(new SingleViewRecyclerAdapter(bannerW));
mergeAdapter.addAdapter(new SingleViewRecyclerAdapter(filtersBar));
mergeAdapter.addAdapter(super.getAdapter());
return mergeAdapter;
}
private FilterChipView getViewForMode(Mode mode){
return switch(mode){
case FAVORITES -> favoritesChip;
case BOOKMARKS -> bookmarksChip;
};
}
private void onFilterClick(View v){
Mode newMode=(Mode) v.getTag();
if(newMode==mode)
return;
if(currentRequest!=null){
currentRequest.cancel();
currentRequest=null;
}
getViewForMode(mode).setSelected(false);
mode=newMode;
v.setSelected(true);
data.clear();
preloadedData.clear();
int size=displayItems.size();
displayItems.clear();
adapter.notifyItemRangeRemoved(0, size);
loaded=false;
dataLoading=true;
doLoadData();
}
private enum Mode{
FAVORITES,
BOOKMARKS
}
}

View File

@@ -68,7 +68,7 @@ public class ThreadFragment extends StatusListFragment implements AssistContentP
knownAccounts.put(inReplyToAccount.id, inReplyToAccount);
data.add(mainStatus);
onAppendItems(Collections.singletonList(mainStatus));
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
if(GlobalUserPreferences.customEmojiInNames)
setTitle(HtmlParser.parseCustomEmoji(getString(R.string.post_from_user, mainStatus.account.displayName), mainStatus.account.emojis));
else
setTitle(getString(R.string.post_from_user, mainStatus.account.displayName));

View File

@@ -0,0 +1,48 @@
package org.joinmastodon.android.fragments.account_list;
import android.os.Bundle;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountFamiliarFollowers;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.FamiliarFollowers;
import org.joinmastodon.android.model.viewmodel.AccountViewModel;
import org.parceler.Parcels;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import me.grishka.appkit.api.SimpleCallback;
public class FamiliarFollowerListFragment extends BaseAccountListFragment{
protected Account account;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
account=Parcels.unwrap(getArguments().getParcelable("targetAccount"));
setTitle("@"+account.acct);
int count=getArguments().getInt("count");
setSubtitle(getResources().getQuantityString(R.plurals.x_followers_you_know, count, count));
}
@Override
protected void doLoadData(int offset, int count){
currentRequest=new GetAccountFamiliarFollowers(Set.of(account.id))
.setCallback(new SimpleCallback<>(this){
@Override
public void onSuccess(List<FamiliarFollowers> result){
onDataLoaded(result.get(0).accounts.stream().map(a->new AccountViewModel(a, accountID, getActivity())).collect(Collectors.toList()), false);
}
})
.exec(accountID);
}
@Override
public void onResume(){
super.onResume();
if(!loaded && !dataLoading)
loadData();
}
}

View File

@@ -42,7 +42,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop{
private static final int QUERY_RESULT=937;
private static final int SCAN_RESULT=456;
private TabLayout tabLayout;
private TabLayout tabLayout, searchTabLayout;
private ViewPager2 pager;
private FrameLayout[] tabViews;
private TabLayoutMediator tabLayoutMediator;
@@ -62,6 +62,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop{
private String currentQuery;
private Intent scannerIntent;
private Runnable searchExitCallback=this::exitSearch;
private SearchResult.Type searchFilter;
@Override
public void onCreate(Bundle savedInstanceState){
@@ -79,6 +80,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop{
LinearLayout view=(LinearLayout) inflater.inflate(R.layout.fragment_discover, container, false);
tabLayout=view.findViewById(R.id.tabbar);
searchTabLayout=view.findViewById(R.id.search_tabbar);
pager=view.findViewById(R.id.pager);
tabViews=new FrameLayout[4];
@@ -205,6 +207,30 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop{
});
tabsDivider=view.findViewById(R.id.tabs_divider);
searchTabLayout.setTabTextColors(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnSurfaceVariant), UiUtils.getThemeColor(getActivity(), R.attr.colorM3Primary));
searchTabLayout.setTabTextSize(V.dp(14));
searchTabLayout.addTab(searchTabLayout.newTab().setText(R.string.posts));
searchTabLayout.addTab(searchTabLayout.newTab().setText(R.string.hashtags));
searchTabLayout.addTab(searchTabLayout.newTab().setText(R.string.search_people));
searchTabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
@Override
public void onTabSelected(TabLayout.Tab tab){
searchFilter=switch(tab.getPosition()){
case 0 -> SearchResult.Type.STATUS;
case 1 -> SearchResult.Type.HASHTAG;
case 2 -> SearchResult.Type.ACCOUNT;
default -> throw new IllegalStateException("Unexpected value: " + tab.getPosition());
};
searchFragment.setQuery(currentQuery, searchFilter);
}
@Override
public void onTabUnselected(TabLayout.Tab tab){}
@Override
public void onTabReselected(TabLayout.Tab tab){}
});
return view;
}
@@ -227,11 +253,11 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop{
searchActive=true;
pager.setVisibility(View.GONE);
tabLayout.setVisibility(View.GONE);
searchTabLayout.setVisibility(View.VISIBLE);
searchView.setVisibility(View.VISIBLE);
searchBack.setImageResource(me.grishka.appkit.R.drawable.ic_arrow_back);
searchBack.setEnabled(true);
searchBack.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
tabsDivider.setVisibility(View.GONE);
addBackCallback(searchExitCallback);
}
}
@@ -242,12 +268,12 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop{
searchActive=false;
pager.setVisibility(View.VISIBLE);
tabLayout.setVisibility(View.VISIBLE);
searchTabLayout.setVisibility(View.GONE);
searchView.setVisibility(View.GONE);
searchText.setText(R.string.search_mastodon);
searchBack.setImageResource(R.drawable.ic_search_24px);
searchBack.setEnabled(false);
searchBack.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
tabsDivider.setVisibility(View.VISIBLE);
currentQuery=null;
removeBackCallback(searchExitCallback);
}
@@ -267,14 +293,14 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop{
if(reqCode==QUERY_RESULT && success){
enterSearch();
currentQuery=result.getString("query");
SearchResult.Type type;
if(result.containsKey("filter")){
type=SearchResult.Type.values()[result.getInt("filter")];
searchFilter=SearchResult.Type.values()[result.getInt("filter")];
}else{
type=null;
searchFilter=SearchResult.Type.STATUS;
}
searchFragment.setQuery(currentQuery, type);
searchFragment.setQuery(currentQuery, searchFilter);
searchText.setText(currentQuery);
updateSearchTabBar();
}
}
@@ -300,6 +326,17 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop{
}
}
private void updateSearchTabBar(){
int tab=switch(searchFilter){
case STATUS -> 0;
case HASHTAG -> 1;
case ACCOUNT -> 2;
};
if(searchTabLayout.getSelectedTabPosition()==tab)
return;
searchTabLayout.selectTab(searchTabLayout.getTabAt(tab));
}
private class DiscoverPagerAdapter extends RecyclerView.Adapter<SimpleViewHolder>{
@NonNull
@Override

View File

@@ -95,7 +95,10 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
goToAccountItem=new ListItem<>("", null, R.drawable.ic_person_24px, this::onGoToAccountClick);
goToStatusSearchItem=new ListItem<>("", null, R.drawable.ic_search_24px, this::onGoToStatusSearchClick);
goToAccountSearchItem=new ListItem<>("", null, R.drawable.ic_group_24px, this::onGoToAccountSearchClick);
currentQuery=getArguments().getString("query");
if(savedInstanceState!=null)
currentQuery=savedInstanceState.getString("query");
else
currentQuery=getArguments().getString("query");
dataLoaded();
doLoadData(0, 0);
@@ -181,6 +184,9 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
setNavigationBarColor(color);
if(currentQuery!=null){
searchViewHelper.setQuery(currentQuery);
}
if(savedInstanceState!=null || currentQuery!=null){
searchIcon.setAlpha(0);
searchIcon.setAlpha(0);
}
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorM3OutlineVariant, 1, 0, 0, vh->!isInRecentMode() && vh.getAbsoluteAdapterPosition()==topOptions.size()-1));
@@ -285,6 +291,12 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
getActivity().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(getActivity().getWindow().getDecorView().getWindowToken(), 0);
}
@Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putString("query", currentQuery);
}
@RequiresApi(api = Build.VERSION_CODES.S)
private float getScreenCornerRadius(WindowInsets insets, int pos){
RoundedCorner corner=insets.getRoundedCorner(pos);
@@ -296,6 +308,8 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
private Animator createTransition(View prev, View container, boolean enter){
int[] loc={0, 0};
View searchBtn=prev.findViewById(R.id.search_wrap);
if(searchBtn==null || searchBtn.getWidth()==0 || searchBtn.getHeight()==0)
return null;
searchBtn.getLocationInWindow(loc);
int btnLeft=loc[0], btnTop=loc[1];
container.getLocationInWindow(loc);
@@ -323,21 +337,22 @@ public class SearchQueryFragment extends MastodonRecyclerFragment<SearchResultVi
ObjectAnimator boundsAnim;
Toolbar toolbar=getToolbar();
float toolbarTX=offX-toolbar.getX();
boolean isRTL=container.getLayoutDirection()==View.LAYOUT_DIRECTION_RTL;
float toolbarTX=isRTL ? (toolbar.getX()-offX) : (offX-toolbar.getX());
float toolbarTY=offY-toolbar.getY()+(searchBtn.getHeight()-toolbar.getHeight())/2f;
ArrayList<Animator> anims=new ArrayList<>();
int searchLayoutXOffset=isRTL ? V.dp(4) : V.dp(-4);
anims.add(boundsAnim=ObjectAnimator.ofFloat(outlineProvider, "boundsFraction", 0f, 1f));
anims.add(ObjectAnimator.ofFloat(outlineProvider, "radius", enter ? buttonRadius : screenRadius, enter ? screenRadius : buttonRadius));
anims.add(ObjectAnimator.ofFloat(toolbar, View.TRANSLATION_X, enter ? toolbarTX : 0, enter ? 0 : toolbarTX));
anims.add(ObjectAnimator.ofFloat(toolbar, View.TRANSLATION_Y, enter ? toolbarTY : 0, enter ? 0 : toolbarTY));
anims.add(ObjectAnimator.ofFloat(searchViewHelper.getSearchLayout(), View.TRANSLATION_X, enter ? V.dp(-4) : 0, enter ? 0 : V.dp(-4)));
anims.add(ObjectAnimator.ofFloat(searchViewHelper.getSearchLayout(), View.TRANSLATION_X, enter ? searchLayoutXOffset : 0, enter ? 0 : searchLayoutXOffset));
anims.add(ObjectAnimator.ofFloat(searchViewHelper.getDivider(), View.ALPHA, enter ? 0 : 1, enter ? 1 : 0));
View parentContent=prev.findViewById(R.id.discover_content);
View parentContentParent=(View) parentContent.getParent();
parentContentParent.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Surface));
if(enter){
anims.add(ObjectAnimator.ofFloat(contentWrap, View.TRANSLATION_Y, V.dp(-16), 0));
}else{
}
anims.add(ObjectAnimator.ofFloat(contentWrap, View.ALPHA, enter ? 0 : 1, enter ? 1 : 0));
for(Animator anim:anims){

View File

@@ -131,7 +131,7 @@ public class AccountActivationFragment extends ToolbarFragment{
private void onOpenEmailClick(View v){
try{
startActivity(Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_EMAIL).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}catch(ActivityNotFoundException x){
}catch(ActivityNotFoundException|IllegalArgumentException x){
Toast.makeText(getActivity(), R.string.no_app_to_handle_action, Toast.LENGTH_SHORT).show();
}
}

View File

@@ -0,0 +1,239 @@
package org.joinmastodon.android.fragments.settings;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.catalog.GetDonationCampaigns;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.donations.DonationCampaign;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.model.viewmodel.SectionHeaderListItem;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.sheets.DonationSheet;
import org.joinmastodon.android.ui.sheets.DonationSuccessfulSheet;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.viewcontrollers.ComposeLanguageAlertViewController;
import java.util.ArrayList;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
import me.grishka.appkit.utils.V;
public class SettingsAccountFragment extends BaseSettingsFragment<Void>{
private static final int DONATION_RESULT=433;
private DonationSheet donationSheet;
private boolean loggedOut;
private ListItem<Void> languageItem;
private Locale postLanguage;
private ComposeLanguageAlertViewController.SelectedOption newPostLanguage;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
AccountSession account=AccountSessionManager.get(accountID);
setTitle(account.getFullUsername());
if(account.preferences!=null && account.preferences.postingDefaultLanguage!=null){
postLanguage=Locale.forLanguageTag(account.preferences.postingDefaultLanguage);
}
ArrayList<ListItem<Void>> items=new ArrayList<>();
items.add(new SectionHeaderListItem(R.string.account_settings));
items.add(new ListItem<>(R.string.settings_privacy, 0, R.drawable.ic_privacy_tip_24px, this::onPrivacyClick));
items.add(new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_filter_alt_24px, this::onFiltersClick));
items.add(new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_notifications_24px, this::onNotificationsClick));
items.add(languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(Locale.getDefault()) : null, R.drawable.ic_language_24px, this::onDefaultLanguageClick));
items.add(new SectionHeaderListItem(account.domain));
items.add(new ListItem<>(getString(R.string.settings_about_this_server), getString(R.string.settings_server_explanation), R.drawable.ic_dns_24px, this::onServerClick));
if(account.isEligibleForDonations()){
items.add(new ListItem<>(R.string.settings_donate, 0, R.drawable.ic_volunteer_activism_24px, this::onDonateClick));
}
items.add(new SectionHeaderListItem(R.string.manage_account));
items.add(new ListItem<>(R.string.switch_to_this_account, 0, R.drawable.ic_switch_account_24px, AccountSessionManager.getInstance().getLastActiveAccountID().equals(accountID) ? null : this::onSwitchAccountClick));
items.add(new ListItem<>(R.string.delete_account, 0, R.drawable.ic_delete_forever_24px, this::onDeleteAccountClick, R.attr.colorM3Error, false));
items.add(new ListItem<>(R.string.log_out, 0, R.drawable.ic_logout_24px, this::onLogOutClick, R.attr.colorM3Error, false));
onDataLoaded(items);
}
@Override
protected void doLoadData(int offset, int count){}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode==DONATION_RESULT){
if(donationSheet!=null)
donationSheet.dismissWithoutAnimation();
if(resultCode==Activity.RESULT_OK){
new DonationSuccessfulSheet(getActivity(), accountID, data.getStringExtra("postText")).showWithoutAnimation();
}
}
}
@Override
protected void onHidden(){
super.onHidden();
if(!loggedOut){
if(newPostLanguage!=null){
AccountSession s=AccountSessionManager.get(accountID);
if(s.preferences==null)
s.preferences=new Preferences();
s.preferences.postingDefaultLanguage=newPostLanguage.locale.toLanguageTag();
s.savePreferencesLater();
}
AccountSessionManager.get(accountID).savePreferencesIfPending();
}
}
@Override
protected void onUpdateToolbar(){
super.onUpdateToolbar();
toolbarTitleView.setAlpha(list.getChildCount()==0 || list.getChildAdapterPosition(list.getChildAt(0))==0 ? 0 : 1);
}
@Override
protected RecyclerView.Adapter<?> getAdapter(){
TextView largeTitle=(TextView) getToolbarLayoutInflater().inflate(R.layout.large_title, list, false);
largeTitle.setText(getTitle());
largeTitle.setPadding(largeTitle.getPaddingLeft(), largeTitle.getPaddingTop(), largeTitle.getPaddingRight(), 0);
MergeRecyclerAdapter adapter=new MergeRecyclerAdapter();
adapter.addAdapter(new SingleViewRecyclerAdapter(largeTitle));
adapter.addAdapter(super.getAdapter());
return adapter;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
private boolean titleVisible=true;
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
boolean newTitleVisible=list.getChildAdapterPosition(list.getChildAt(0))==0;
if(newTitleVisible!=titleVisible){
titleVisible=newTitleVisible;
toolbarTitleView.animate().alpha(titleVisible ? 0 : 1).setDuration(250).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
}
}
});
}
private Bundle makeFragmentArgs(){
Bundle args=new Bundle();
args.putString("account", accountID);
return args;
}
private void onPrivacyClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs());
}
private void onFiltersClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs());
}
private void onNotificationsClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsNotificationsFragment.class, makeFragmentArgs());
}
private void onDefaultLanguageClick(ListItem<?> item){
ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), null, newPostLanguage==null ? new ComposeLanguageAlertViewController.SelectedOption(-1, postLanguage, null) : newPostLanguage, null);
AlertDialog dlg=new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.default_post_language)
.setView(vc.getView())
.setPositiveButton(R.string.cancel, null)
.show();
vc.setSelectionListener(opt->{
if(!opt.locale.equals(postLanguage)){
newPostLanguage=opt;
languageItem.subtitle=newPostLanguage.locale.getDisplayLanguage(Locale.getDefault());
rebindItem(languageItem);
}
dlg.dismiss();
});
}
private void onServerClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsServerFragment.class, makeFragmentArgs());
}
private boolean useStagingEnvironmentForDonations(){
return (BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")) && getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false);
}
private void onDonateClick(ListItem<?> item){
GetDonationCampaigns req=new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed()), "menu");
if(useStagingEnvironmentForDonations()){
req.setStaging(true);
}
req.setCallback(new Callback<>(){
@Override
public void onSuccess(DonationCampaign result){
Activity activity=getActivity();
if(activity==null)
return;
if(result==null){
Toast.makeText(activity, "No campaign available (server misconfiguration?)", Toast.LENGTH_SHORT).show();
return;
}
donationSheet=new DonationSheet(getActivity(), result, accountID, intent->startActivityForResult(intent, DONATION_RESULT));
donationSheet.setOnDismissListener(dialog->donationSheet=null);
donationSheet.show();
}
@Override
public void onError(ErrorResponse error){
error.showToast(getActivity());
}
})
.wrapProgress(getActivity(), R.string.loading, true)
.execNoAuth("");
}
private void onSwitchAccountClick(ListItem<?> item){
if(AccountSessionManager.getInstance().tryGetAccount(accountID)!=null){
AccountSessionManager.getInstance().setLastActiveAccountID(accountID);
((MainActivity)getActivity()).restartHomeFragment();
}
}
private void onDeleteAccountClick(ListItem<?> item){
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
UiUtils.launchWebBrowser(getActivity(), "https://"+session.domain+"/settings/delete");
}
private void onLogOutClick(ListItem<?> item_){
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
new M3AlertDialogBuilder(getActivity())
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
.setPositiveButton(R.string.log_out, (dialog, which)->AccountSessionManager.get(accountID).logOut(getActivity(), ()->{
loggedOut=true;
((MainActivity)getActivity()).restartHomeFragment();
}))
.setNegativeButton(R.string.cancel, null)
.show();
}
}

View File

@@ -1,6 +1,5 @@
package org.joinmastodon.android.fragments.settings;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -13,38 +12,25 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.viewcontrollers.ComposeLanguageAlertViewController;
import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class SettingsBehaviorFragment extends BaseSettingsFragment<Void>{
private ListItem<Void> languageItem, customTabsItem;
private ListItem<Void> customTabsItem;
private CheckableListItem<Void> altTextItem, playGifsItem, confirmUnfollowItem, confirmBoostItem, confirmDeleteItem;
private Locale postLanguage;
private ComposeLanguageAlertViewController.SelectedOption newPostLanguage;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setTitle(R.string.settings_behavior);
AccountSession s=AccountSessionManager.get(accountID);
if(s.preferences!=null && s.preferences.postingDefaultLanguage!=null){
postLanguage=Locale.forLanguageTag(s.preferences.postingDefaultLanguage);
}
onDataLoaded(List.of(
languageItem=new ListItem<>(getString(R.string.default_post_language), postLanguage!=null ? postLanguage.getDisplayName(Locale.getDefault()) : null, R.drawable.ic_language_24px, this::onDefaultLanguageClick),
customTabsItem=new ListItem<>(R.string.settings_custom_tabs, GlobalUserPreferences.useCustomTabs ? R.string.in_app_browser : R.string.system_browser, R.drawable.ic_open_in_browser_24px, this::onCustomTabsClick),
altTextItem=new CheckableListItem<>(R.string.settings_alt_text_reminders, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.altTextReminders, R.drawable.ic_alt_24px, this::toggleCheckableItem),
playGifsItem=new CheckableListItem<>(R.string.settings_gif, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.playGifs, R.drawable.ic_animation_24px, this::toggleCheckableItem),
@@ -57,25 +43,7 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void>{
@Override
protected void doLoadData(int offset, int count){}
private void onDefaultLanguageClick(ListItem<?> item){
ComposeLanguageAlertViewController vc=new ComposeLanguageAlertViewController(getActivity(), null, newPostLanguage==null ? new ComposeLanguageAlertViewController.SelectedOption(-1, postLanguage, null) : newPostLanguage, null);
AlertDialog dlg=new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.default_post_language)
.setView(vc.getView())
.setPositiveButton(R.string.cancel, null)
.show();
vc.setSelectionListener(opt->{
if(!opt.locale.equals(postLanguage)){
newPostLanguage=opt;
languageItem.subtitle=newPostLanguage.locale.getDisplayLanguage(Locale.getDefault());
rebindItem(languageItem);
}
dlg.dismiss();
});
}
private void onCustomTabsClick(ListItem<?> item){
// GlobalUserPreferences.useCustomTabs=customTabsItem.checked;
Intent intent=new Intent(Intent.ACTION_VIEW, Uri.parse("http://example.com"));
ResolveInfo info=getActivity().getPackageManager().resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
final String browserName;
@@ -125,12 +93,5 @@ public class SettingsBehaviorFragment extends BaseSettingsFragment<Void>{
GlobalUserPreferences.confirmBoost=confirmBoostItem.checked;
GlobalUserPreferences.confirmDeletePost=confirmDeleteItem.checked;
GlobalUserPreferences.save();
if(newPostLanguage!=null){
AccountSession s=AccountSessionManager.get(accountID);
if(s.preferences==null)
s.preferences=new Preferences();
s.preferences.postingDefaultLanguage=newPostLanguage.locale.toLanguageTag();
s.savePreferencesLater();
}
}
}

View File

@@ -13,9 +13,6 @@ import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
import org.joinmastodon.android.model.viewmodel.CheckableListItem;
import org.joinmastodon.android.model.viewmodel.ListItem;
@@ -36,8 +33,6 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setTitle(R.string.settings_display);
AccountSession s=AccountSessionManager.get(accountID);
AccountLocalPreferences lp=s.getLocalPreferences();
List<ListItem<Void>> items=new ArrayList<>();
items.add(themeItem=new ListItem<>(R.string.settings_theme, getAppearanceValue(), R.drawable.ic_dark_mode_24px, this::onAppearanceClick));
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.S){
@@ -47,10 +42,10 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
}));
dynamicColorsItem.checkedChangeListener=this::setUseDynamicColors;
}
items.add(showCWsItem=new CheckableListItem<>(R.string.settings_show_cws, 0, CheckableListItem.Style.SWITCH, lp.showCWs, R.drawable.ic_warning_24px, this::toggleCheckableItem));
items.add(hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, lp.hideSensitiveMedia, R.drawable.ic_no_adult_content_24px, this::toggleCheckableItem));
items.add(interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, 0, CheckableListItem.Style.SWITCH, lp.showInteractionCounts, R.drawable.ic_social_leaderboard_24px, this::toggleCheckableItem));
items.add(emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, lp.customEmojiInNames, R.drawable.ic_emoticon_24px, this::toggleCheckableItem));
items.add(showCWsItem=new CheckableListItem<>(R.string.settings_show_cws, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showCWs, R.drawable.ic_warning_24px, this::toggleCheckableItem));
items.add(hideSensitiveMediaItem=new CheckableListItem<>(R.string.settings_hide_sensitive_media, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.hideSensitiveMedia, R.drawable.ic_no_adult_content_24px, this::toggleCheckableItem));
items.add(interactionCountsItem=new CheckableListItem<>(R.string.settings_show_interaction_counts, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showInteractionCounts, R.drawable.ic_social_leaderboard_24px, this::toggleCheckableItem));
items.add(emojiInNamesItem=new CheckableListItem<>(R.string.settings_show_emoji_in_names, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.customEmojiInNames, R.drawable.ic_emoticon_24px, this::toggleCheckableItem));
onDataLoaded(items);
}
@@ -70,13 +65,11 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
@Override
protected void onHidden(){
super.onHidden();
AccountSession s=AccountSessionManager.get(accountID);
AccountLocalPreferences lp=s.getLocalPreferences();
lp.showCWs=showCWsItem.checked;
lp.hideSensitiveMedia=hideSensitiveMediaItem.checked;
lp.showInteractionCounts=interactionCountsItem.checked;
lp.customEmojiInNames=emojiInNamesItem.checked;
lp.save();
GlobalUserPreferences.showCWs=showCWsItem.checked;
GlobalUserPreferences.hideSensitiveMedia=hideSensitiveMediaItem.checked;
GlobalUserPreferences.showInteractionCounts=interactionCountsItem.checked;
GlobalUserPreferences.customEmojiInNames=emojiInNamesItem.checked;
GlobalUserPreferences.save();
E.post(new StatusDisplaySettingsChangedEvent(accountID));
}

View File

@@ -1,53 +1,44 @@
package org.joinmastodon.android.fragments.settings;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import com.squareup.otto.Subscribe;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.E;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.catalog.GetDonationCampaigns;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.SelfUpdateStateChangedEvent;
import org.joinmastodon.android.model.donations.DonationCampaign;
import org.joinmastodon.android.fragments.SplashFragment;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.sheets.AccountSwitcherSheet;
import org.joinmastodon.android.ui.sheets.DonationSheet;
import org.joinmastodon.android.ui.sheets.DonationSuccessfulSheet;
import org.joinmastodon.android.model.viewmodel.SectionHeaderListItem;
import org.joinmastodon.android.model.viewmodel.SettingsAccountListItem;
import org.joinmastodon.android.ui.utils.HideableSingleViewRecyclerAdapter;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.V;
public class SettingsMainFragment extends BaseSettingsFragment<Void>{
private static final int DONATION_RESULT=433;
public class SettingsMainFragment extends BaseSettingsFragment<Object>{
private boolean loggedOut;
private HideableSingleViewRecyclerAdapter bannerAdapter;
private Button updateButton1, updateButton2;
private TextView updateText;
private DonationSheet donationSheet;
private Runnable updateDownloadProgressUpdater=new Runnable(){
@Override
public void run(){
@@ -63,27 +54,35 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setTitle(R.string.settings);
setSubtitle(AccountSessionManager.get(accountID).getFullUsername());
ArrayList<ListItem<Void>> items=new ArrayList<>();
if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){
items.add(new ListItem<>("Debug settings", null, R.drawable.ic_settings_24px, i->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null, 0, true));
ArrayList<ListItem<?>> items=new ArrayList<>();
items.add(new SectionHeaderListItem(R.string.settings_accounts));
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
ImageLoaderRequest req;
if(session.self.avatar!=null)
req=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? session.self.avatar : session.self.avatarStatic, V.dp(50), V.dp(50));
else
req=null;
items.add(new SettingsAccountListItem<>(session.getFullUsername(), null, req, this::onAccountClick, session, false));
}
items.addAll(List.of(
new ListItem<>(R.string.settings_behavior, 0, R.drawable.ic_settings_24px, this::onBehaviorClick),
new ListItem<>(R.string.settings_display, 0, R.drawable.ic_style_24px, this::onDisplayClick),
new ListItem<>(R.string.settings_privacy, 0, R.drawable.ic_privacy_tip_24px, this::onPrivacyClick),
new ListItem<>(R.string.settings_filters, 0, R.drawable.ic_filter_alt_24px, this::onFiltersClick),
new ListItem<>(R.string.settings_notifications, 0, R.drawable.ic_notifications_24px, this::onNotificationsClick),
new ListItem<>(AccountSessionManager.get(accountID).domain, getString(R.string.settings_server_explanation), R.drawable.ic_dns_24px, this::onServerClick),
new ListItem<>(getString(R.string.about_app, getString(R.string.app_name)), null, R.drawable.ic_info_24px, this::onAboutClick, null, 0, true)
new ListItem<>(R.string.settings_add_account, 0, R.drawable.ic_add_24px, this::onAddAccountClick),
new SectionHeaderListItem(R.string.settings_app_settings),
new ListItem<>(R.string.settings_behavior, 0, R.drawable.ic_tune_24px, this::onBehaviorClick),
new ListItem<>(R.string.settings_display, 0, R.drawable.ic_style_24px, this::onDisplayClick)
));
if(AccountSessionManager.get(accountID).isEligibleForDonations()){
items.add(new ListItem<>(R.string.settings_donate, 0, R.drawable.ic_volunteer_activism_24px, this::onDonateClick));
items.add(new ListItem<>(R.string.settings_manage_donations, 0, R.drawable.ic_settings_heart_24px, this::onManageDonationClick, 0, true));
items.add(new ListItem<>(R.string.settings_manage_donations, 0, R.drawable.ic_settings_heart_24px, this::onManageDonationClick));
}
items.add(new ListItem<>(R.string.manage_accounts, 0, R.drawable.ic_switch_account_24px, this::onManageAccountsClick));
items.add(new ListItem<>(R.string.log_out, 0, R.drawable.ic_logout_24px, this::onLogOutClick, R.attr.colorM3Error, false));
onDataLoaded(items);
items.add(new ListItem<>(getString(R.string.about_app, getString(R.string.app_name)), null, R.drawable.ic_info_24px, this::onAboutClick, null));
if(BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")){
items.add(new ListItem<>("Debug settings", null, R.drawable.ic_bug_report_24px, i->Nav.go(getActivity(), SettingsDebugFragment.class, makeFragmentArgs()), null));
}
//noinspection unchecked
onDataLoaded((List<ListItem<Object>>)(Object)items);
AccountSession session=AccountSessionManager.get(accountID);
session.reloadPreferences(null);
@@ -100,13 +99,6 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
@Override
protected void doLoadData(int offset, int count){}
@Override
protected void onHidden(){
super.onHidden();
if(!loggedOut)
AccountSessionManager.get(accountID).savePreferencesIfPending();
}
@Override
protected RecyclerView.Adapter<?> getAdapter(){
View banner=getActivity().getLayoutInflater().inflate(R.layout.item_settings_banner, list, false);
@@ -137,23 +129,22 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode==DONATION_RESULT){
if(donationSheet!=null)
donationSheet.dismissWithoutAnimation();
if(resultCode==Activity.RESULT_OK){
new DonationSuccessfulSheet(getActivity(), accountID, data.getStringExtra("postText")).showWithoutAnimation();
}
}
}
private Bundle makeFragmentArgs(){
Bundle args=new Bundle();
args.putString("account", accountID);
return args;
}
private void onAccountClick(SettingsAccountListItem<AccountSession> item){
Bundle args=new Bundle();
args.putString("account", item.parentObject.getID());
Nav.go(getActivity(), SettingsAccountFragment.class, args);
}
private void onAddAccountClick(ListItem<?> item_){
Nav.go(getActivity(), SplashFragment.class, null);
}
private void onBehaviorClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsBehaviorFragment.class, makeFragmentArgs());
}
@@ -162,73 +153,16 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
Nav.go(getActivity(), SettingsDisplayFragment.class, makeFragmentArgs());
}
private void onPrivacyClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsPrivacyFragment.class, makeFragmentArgs());
}
private void onFiltersClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsFiltersFragment.class, makeFragmentArgs());
}
private void onNotificationsClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsNotificationsFragment.class, makeFragmentArgs());
}
private void onServerClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsServerFragment.class, makeFragmentArgs());
}
private void onAboutClick(ListItem<?> item_){
Nav.go(getActivity(), SettingsAboutAppFragment.class, makeFragmentArgs());
}
private void onManageAccountsClick(ListItem<?> item){
new AccountSwitcherSheet(getActivity(), null).setOnLoggedOutCallback(()->loggedOut=true).show();
}
private void onLogOutClick(ListItem<?> item_){
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
new M3AlertDialogBuilder(getActivity())
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
.setPositiveButton(R.string.log_out, (dialog, which)->AccountSessionManager.get(accountID).logOut(getActivity(), ()->{
loggedOut=true;
((MainActivity)getActivity()).restartHomeFragment();
}))
.setNegativeButton(R.string.cancel, null)
.show();
}
private void onDonateClick(ListItem<?> item){
GetDonationCampaigns req=new GetDonationCampaigns(Locale.getDefault().toLanguageTag().replace('-', '_'), String.valueOf(AccountSessionManager.get(accountID).getDonationSeed()), "menu");
if(getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false)){
req.setStaging(true);
}
req.setCallback(new Callback<>(){
@Override
public void onSuccess(DonationCampaign result){
Activity activity=getActivity();
if(activity==null)
return;
if(result==null){
Toast.makeText(activity, "No campaign available (server misconfiguration?)", Toast.LENGTH_SHORT).show();
return;
}
donationSheet=new DonationSheet(getActivity(), result, accountID, intent->startActivityForResult(intent, DONATION_RESULT));
donationSheet.setOnDismissListener(dialog->donationSheet=null);
donationSheet.show();
}
@Override
public void onError(ErrorResponse error){
error.showToast(getActivity());
}
})
.wrapProgress(getActivity(), R.string.loading, true)
.execNoAuth("");
private boolean useStagingEnvironmentForDonations(){
return (BuildConfig.DEBUG || BuildConfig.BUILD_TYPE.equals("appcenterPrivateBeta")) && getActivity().getSharedPreferences("debug", Context.MODE_PRIVATE).getBoolean("donationsStaging", false);
}
private void onManageDonationClick(ListItem<?> item){
UiUtils.launchWebBrowser(getActivity(), "https://sponsor.staging.joinmastodon.org/donate/manage");
UiUtils.launchWebBrowser(getActivity(), useStagingEnvironmentForDonations() ? "https://sponsor.staging.joinmastodon.org/donate/manage" : "https://sponsor.joinmastodon.org/donate/manage");
}
@Subscribe

View File

@@ -42,7 +42,7 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
private TextView bannerText;
private Button bannerButton;
private CheckableListItem<Void> mentionsItem, boostsItem, favoritesItem, followersItem, pollsItem;
private CheckableListItem<Void> mentionsItem, boostsItem, favoritesItem, followersItem, pollsItem, statusesItem;
private List<CheckableListItem<Void>> typeItems;
private boolean needUpdateNotificationSettings;
private boolean notificationsAllowed=true;
@@ -62,7 +62,8 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
boostsItem=new CheckableListItem<>(R.string.notification_type_reblog, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.reblog, this::toggleCheckableItem),
favoritesItem=new CheckableListItem<>(R.string.notification_type_favorite, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.favourite, this::toggleCheckableItem),
followersItem=new CheckableListItem<>(R.string.notification_type_follow, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.follow, this::toggleCheckableItem),
pollsItem=new CheckableListItem<>(R.string.notification_type_poll, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.poll, this::toggleCheckableItem)
pollsItem=new CheckableListItem<>(R.string.notification_type_poll, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.poll, this::toggleCheckableItem),
statusesItem=new CheckableListItem<>(R.string.notification_type_status, 0, CheckableListItem.Style.CHECKBOX, pushSubscription.alerts.status, this::toggleCheckableItem)
));
typeItems=List.of(mentionsItem, boostsItem, favoritesItem, followersItem, pollsItem);
@@ -82,13 +83,15 @@ public class SettingsNotificationsFragment extends BaseSettingsFragment<Void>{
|| boostsItem.checked!=ps.alerts.reblog
|| favoritesItem.checked!=ps.alerts.favourite
|| followersItem.checked!=ps.alerts.follow
|| pollsItem.checked!=ps.alerts.poll;
|| pollsItem.checked!=ps.alerts.poll
|| statusesItem.checked!=ps.alerts.status;
if(needUpdateNotificationSettings && PushSubscriptionManager.arePushNotificationsAvailable()){
ps.alerts.mention=mentionsItem.checked;
ps.alerts.reblog=boostsItem.checked;
ps.alerts.favourite=favoritesItem.checked;
ps.alerts.follow=followersItem.checked;
ps.alerts.poll=pollsItem.checked;
ps.alerts.status=statusesItem.checked;
AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().updatePushSettings(pushSubscription);
}
}

View File

@@ -0,0 +1,20 @@
package org.joinmastodon.android.model;
import org.joinmastodon.android.api.AllFieldsAreRequired;
import org.joinmastodon.android.api.ObjectValidationException;
import java.util.List;
@AllFieldsAreRequired
public class FamiliarFollowers extends BaseModel{
public String id;
public List<Account> accounts;
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();
for(Account acc:accounts){
acc.postprocess();
}
}
}

View File

@@ -43,7 +43,9 @@ public class PushNotification extends BaseModel{
@SerializedName("follow")
FOLLOW(R.string.notification_type_follow),
@SerializedName("poll")
POLL(R.string.notification_type_poll);
POLL(R.string.notification_type_poll),
@SerializedName("status")
STATUS(R.string.notification_type_status);
@StringRes
public final int localizedName;

View File

@@ -41,21 +41,23 @@ public class PushSubscription extends BaseModel implements Cloneable{
public boolean reblog;
public boolean mention;
public boolean poll;
public boolean status;
public static Alerts ofAll(){
Alerts alerts=new Alerts();
alerts.follow=alerts.favourite=alerts.reblog=alerts.mention=alerts.poll=true;
alerts.follow=alerts.favourite=alerts.reblog=alerts.mention=alerts.poll=alerts.status=true;
return alerts;
}
@Override
public String toString(){
return "Alerts{"+
"follow="+follow+
", favourite="+favourite+
"favourite="+favourite+
", follow="+follow+
", reblog="+reblog+
", mention="+mention+
", poll="+poll+
", status="+status+
'}';
}

View File

@@ -5,7 +5,6 @@ import android.text.Spannable;
import android.text.SpannableStringBuilder;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AccountField;
import org.joinmastodon.android.ui.text.HtmlParser;
@@ -33,7 +32,7 @@ public class AccountViewModel{
this.account=account;
avaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(50), V.dp(50));
emojiHelper=new CustomEmojiHelper();
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
if(GlobalUserPreferences.customEmojiInNames)
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
else
parsedName=account.displayName;

View File

@@ -4,7 +4,6 @@ import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Card;
import org.joinmastodon.android.ui.text.HtmlParser;
@@ -31,7 +30,7 @@ public class CardViewModel{
if(authorAccount!=null){
parsedAuthorName=new SpannableStringBuilder(authorAccount.displayName);
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
if(GlobalUserPreferences.customEmojiInNames)
HtmlParser.parseCustomEmoji(parsedAuthorName, authorAccount.emojis);
authorNameEmojiHelper.setText(parsedAuthorName);
authorAvaRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? authorAccount.avatar : authorAccount.avatarStatic, V.dp(50), V.dp(50));

View File

@@ -0,0 +1,20 @@
package org.joinmastodon.android.model.viewmodel;
import org.joinmastodon.android.R;
import androidx.annotation.StringRes;
public class SectionHeaderListItem extends ListItem<Void>{
public SectionHeaderListItem(String title){
super(title, null, null);
}
public SectionHeaderListItem(@StringRes int title){
super(title, 0, null);
}
@Override
public int getItemViewType(){
return R.id.list_item_section_header;
}
}

View File

@@ -0,0 +1,21 @@
package org.joinmastodon.android.model.viewmodel;
import org.joinmastodon.android.R;
import java.util.function.Consumer;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
public class SettingsAccountListItem<T> extends ListItem<T>{
public ImageLoaderRequest avatar;
public SettingsAccountListItem(String title, String subtitle, ImageLoaderRequest avatar, Consumer<SettingsAccountListItem<T>> onClick, T parentObject, boolean dividerAfter){
super(title, subtitle, 0, (Consumer<ListItem<T>>)(Object)onClick, parentObject, 0, dividerAfter);
this.avatar=avatar;
}
@Override
public int getItemViewType(){
return R.id.list_item_settings_account;
}
}

View File

@@ -67,6 +67,7 @@ public class SearchViewHelper{
searchEdit.setTextAppearance(R.style.m3_body_large);
searchEdit.setHintTextColor(UiUtils.getThemeColor(toolbarContext, R.attr.colorM3OnSurfaceVariant));
searchEdit.setTextColor(UiUtils.getThemeColor(toolbarContext, R.attr.colorM3OnSurface));
searchEdit.setTextAlignment(View.TEXT_ALIGNMENT_VIEW_START);
searchLayout.addView(searchEdit, new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.MATCH_PARENT, 1f));
clearSearchButton=new ImageButton(context);

View File

@@ -5,17 +5,19 @@ import android.view.ViewGroup;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.viewmodel.AvatarPileListItem;
import org.joinmastodon.android.model.viewmodel.ListItem;
import org.joinmastodon.android.model.viewmodel.SettingsAccountListItem;
import org.joinmastodon.android.ui.viewholders.AvatarPileListItemViewHolder;
import org.joinmastodon.android.ui.viewholders.CheckboxOrRadioListItemViewHolder;
import org.joinmastodon.android.ui.viewholders.ListItemViewHolder;
import org.joinmastodon.android.ui.viewholders.OptionsListItemViewHolder;
import org.joinmastodon.android.ui.viewholders.SectionHeaderListItemViewHolder;
import org.joinmastodon.android.ui.viewholders.SettingsAccountListItemViewHolder;
import org.joinmastodon.android.ui.viewholders.SimpleListItemViewHolder;
import org.joinmastodon.android.ui.viewholders.SwitchListItemViewHolder;
import java.util.List;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
import me.grishka.appkit.imageloader.ListImageLoaderWrapper;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
@@ -49,6 +51,10 @@ public class GenericListItemsAdapter<T> extends UsableRecyclerView.Adapter<ListI
return new OptionsListItemViewHolder(parent.getContext(), parent);
if(viewType==R.id.list_item_avatar_pile)
return new AvatarPileListItemViewHolder(parent.getContext(), parent);
if(viewType==R.id.list_item_settings_account)
return new SettingsAccountListItemViewHolder(parent.getContext(), parent);
if(viewType==R.id.list_item_section_header)
return new SectionHeaderListItemViewHolder(parent.getContext(), parent);
throw new IllegalArgumentException("Unexpected view type "+viewType);
}
@@ -74,6 +80,8 @@ public class GenericListItemsAdapter<T> extends UsableRecyclerView.Adapter<ListI
ListItem<?> item=items.get(position);
if(item instanceof AvatarPileListItem<?> avatarPileListItem)
return avatarPileListItem.avatars.size();
if(item instanceof SettingsAccountListItem<?>)
return 1;
return 0;
}
@@ -82,6 +90,8 @@ public class GenericListItemsAdapter<T> extends UsableRecyclerView.Adapter<ListI
ListItem<?> item=items.get(position);
if(item instanceof AvatarPileListItem<?> avatarPileListItem)
return avatarPileListItem.avatars.get(image);
if(item instanceof SettingsAccountListItem<?> accountItem)
return accountItem.avatar;
return null;
}
}

View File

@@ -40,6 +40,7 @@ public class GapStatusDisplayItem extends StatusDisplayItem{
public void onBind(GapStatusDisplayItem item){
text.setVisibility(item.loading ? View.GONE : View.VISIBLE);
progress.setVisibility(item.loading ? View.VISIBLE : View.GONE);
text.setText(item.enteredFromTop ? R.string.load_missing_posts_above : R.string.load_missing_posts_below);
}
@Override

View File

@@ -75,7 +75,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
this.accountID=accountID;
parsedName=new SpannableStringBuilder(user.displayName);
this.status=status;
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames)
if(GlobalUserPreferences.customEmojiInNames)
HtmlParser.parseCustomEmoji(parsedName, user.emojis);
emojiHelper.setText(parsedName);
if(status!=null){

View File

@@ -9,7 +9,6 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.OutlineProviders;
@@ -36,7 +35,7 @@ public class InlineStatusStatusDisplayItem extends StatusDisplayItem{
this.status=status;
parsedName=new SpannableStringBuilder(status.account.displayName);
if(AccountSessionManager.get(parentFragment.getAccountID()).getLocalPreferences().customEmojiInNames)
if(GlobalUserPreferences.customEmojiInNames)
HtmlParser.parseCustomEmoji(parsedName, status.account.emojis);
parsedPostText=HtmlParser.parse(status.content, status.emojis, status.mentions, status.tags, parentFragment.getAccountID(), status.getContentStatus(), parentFragment.getActivity());

View File

@@ -209,18 +209,22 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
@Override
public void setImage(int index, Drawable drawable){
controllers.get(index).setImage(drawable);
if(index<controllers.size())
controllers.get(index).setImage(drawable);
}
@Override
public void clearImage(int index){
controllers.get(index).clearImage();
if(index<controllers.size())
controllers.get(index).clearImage();
}
@Override
public void onImageLoadingFailed(int index, Throwable error){
controllers.get(index).showFailedOverlay();
thereAreFailedImages=true;
if(index<controllers.size()){
controllers.get(index).showFailedOverlay();
thereAreFailedImages=true;
}
}
private void onViewClick(View v){

View File

@@ -7,8 +7,8 @@ import android.text.SpannableStringBuilder;
import android.view.ViewGroup;
import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.ui.text.HtmlParser;
@@ -31,7 +31,7 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon){
super(parentID, parentFragment);
SpannableStringBuilder ssb=new SpannableStringBuilder(text);
if(AccountSessionManager.get(parentFragment.getAccountID()).getLocalPreferences().customEmojiInNames)
if(GlobalUserPreferences.customEmojiInNames)
HtmlParser.parseCustomEmoji(ssb, emojis);
this.text=ssb;
emojiHelper.setText(ssb);

View File

@@ -8,8 +8,8 @@ import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.model.Account;
@@ -97,7 +97,7 @@ public abstract class StatusDisplayItem{
ArrayList<StatusDisplayItem> items=new ArrayList<>();
Status statusForContent=status.getContentStatus();
HeaderStatusDisplayItem header=null;
boolean hideCounts=!AccountSessionManager.get(accountID).getLocalPreferences().showInteractionCounts;
boolean hideCounts=!GlobalUserPreferences.showInteractionCounts;
if((flags & FLAG_NO_HEADER)==0){
if(status.reblog!=null){
items.add(new ReblogOrReplyLineStatusDisplayItem(parentID, fragment, fragment.getString(R.string.user_boosted, status.account.displayName), status.account.emojis, R.drawable.ic_repeat_wght700_20px));
@@ -134,7 +134,7 @@ public abstract class StatusDisplayItem{
SpoilerStatusDisplayItem spoilerItem=new SpoilerStatusDisplayItem(parentID, fragment, null, status, statusForContent, Type.SPOILER, Status.SpoilerType.CONTENT_WARNING);
contentItems.add(spoilerItem);
contentItems=spoilerItem.contentItems;
if(!AccountSessionManager.get(accountID).getLocalPreferences().showCWs && !filtered){
if(!GlobalUserPreferences.showCWs && !filtered){
status.revealedSpoilers.add(Status.SpoilerType.CONTENT_WARNING);
needAddCWItems=true;
}
@@ -158,7 +158,7 @@ public abstract class StatusDisplayItem{
if((flags & FLAG_MEDIA_FORCE_HIDDEN)!=0){
mediaGrid.sensitiveTitle=fragment.getString(R.string.media_hidden);
mediaGrid.sensitiveRevealed=false;
}else if(statusForContent.sensitive && !AccountSessionManager.get(accountID).getLocalPreferences().hideSensitiveMedia){
}else if(statusForContent.sensitive && !GlobalUserPreferences.hideSensitiveMedia){
mediaGrid.sensitiveRevealed=true;
}
contentItems.add(mediaGrid);

View File

@@ -66,10 +66,10 @@ public abstract class AccountRestrictionConfirmationSheet extends BottomSheet{
});
}
protected void addRow(@DrawableRes int icon, CharSequence text){
protected TextView addRow(@DrawableRes int icon, CharSequence text){
TextView tv=new TextView(getContext());
tv.setTextAppearance(R.style.m3_body_large);
tv.setTextColor(UiUtils.getThemeColor(getContext(), R.attr.colorM3OnSurfaceVariant));
tv.setTextColor(UiUtils.getThemeColor(getContext(), R.attr.colorM3OnSurface));
tv.setCompoundDrawableTintList(ColorStateList.valueOf(UiUtils.getThemeColor(getContext(), R.attr.colorM3Primary)));
tv.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
tv.setText(text);
@@ -78,6 +78,7 @@ public abstract class AccountRestrictionConfirmationSheet extends BottomSheet{
tv.setCompoundDrawablesRelative(drawable, null, null, null);
tv.setCompoundDrawablePadding(V.dp(16));
contentWrap.addView(tv, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
return tv;
}
protected void addRow(@DrawableRes int icon, @StringRes int text){

View File

@@ -1,24 +1,33 @@
package org.joinmastodon.android.ui.sheets;
import android.content.Context;
import android.graphics.Typeface;
import android.view.View;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetDomainBlockPreview;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.ui.utils.UiUtils;
import androidx.annotation.NonNull;
import me.grishka.appkit.api.APIRequest;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
public class BlockDomainConfirmationSheet extends AccountRestrictionConfirmationSheet{
public BlockDomainConfirmationSheet(@NonNull Context context, Account user, ConfirmCallback confirmCallback, ConfirmCallback blockUserConfirmCallback){
private APIRequest<?> currentRequest;
public BlockDomainConfirmationSheet(@NonNull Context context, Account user, ConfirmCallback confirmCallback, ConfirmCallback blockUserConfirmCallback, String accountID){
super(context, user, confirmCallback);
titleView.setText(R.string.block_domain_confirm_title);
confirmBtn.setText(R.string.do_block_server);
secondaryBtn.setText(context.getString(R.string.block_user_x_instead, user.getDisplayUsername()));
icon.setImageResource(R.drawable.ic_domain_disabled_24px);
subtitleView.setText(user.getDomain());
TextView relationsRow=addRow(R.drawable.ic_person_remove_24px, "");
addRow(R.drawable.ic_campaign_24px, R.string.users_cant_see_blocked);
addRow(R.drawable.ic_visibility_off_24px, R.string.you_wont_see_server_posts);
addRow(R.drawable.ic_person_remove_24px, R.string.server_followers_will_be_removed);
addRow(R.drawable.ic_reply_24px, R.string.server_cant_mention_or_follow_you);
addRow(R.drawable.ic_history_24px, R.string.server_can_interact_with_older);
@@ -32,5 +41,44 @@ public class BlockDomainConfirmationSheet extends AccountRestrictionConfirmation
loading=false;
});
});
relationsRow.setVisibility(View.GONE);
relationsRow.setTypeface(Typeface.DEFAULT_BOLD);
currentRequest=new GetDomainBlockPreview(user.getDomain())
.setCallback(new Callback<>(){
@Override
public void onSuccess(GetDomainBlockPreview.Response result){
currentRequest=null;
if(result.followersCount>0 || result.followingCount>0){
UiUtils.beginLayoutTransition(container);
relationsRow.setVisibility(View.VISIBLE);
if(result.followersCount>0 && result.followingCount>0){
relationsRow.setText(context.getString(R.string.server_x_followers_and_following_will_be_removed,
context.getResources().getQuantityString(R.plurals.will_lose_x_followers, result.followersCount, result.followersCount),
context.getResources().getQuantityString(R.plurals.will_lose_x_following, result.followingCount, result.followingCount)));
}else if(result.followersCount>0){
relationsRow.setText(context.getResources().getQuantityString(R.plurals.server_x_followers_will_be_removed, result.followersCount, result.followersCount));
}else{
relationsRow.setText(context.getString(R.string.server_x_following_will_be_removed,
context.getResources().getQuantityString(R.plurals.will_lose_x_following, result.followingCount, result.followingCount)));
}
}
}
@Override
public void onError(ErrorResponse error){
currentRequest=null;
}
})
.exec(accountID);
}
@Override
public void dismiss(){
if(currentRequest!=null){
currentRequest.cancel();
currentRequest=null;
}
super.dismiss();
}
}

View File

@@ -11,8 +11,8 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.text.HtmlParser;
@@ -57,7 +57,7 @@ public class NonMutualPreReplySheet extends PreReplySheet{
name.setEllipsize(TextUtils.TruncateAt.END);
name.setTextAppearance(R.style.m3_title_medium);
name.setTextColor(UiUtils.getThemeColor(context, R.attr.colorM3OnSurface));
if(AccountSessionManager.get(accountID).getLocalPreferences().customEmojiInNames){
if(GlobalUserPreferences.customEmojiInNames){
name.setText(HtmlParser.parseCustomEmoji(account.displayName, account.emojis));
UiUtils.loadCustomEmojiInTextView(name);
}else{

View File

@@ -501,7 +501,7 @@ public class UiUtils{
}
})
.exec(accountID);
}).show();
}, accountID).show();
}else{
new SetDomainBlocked(account.getDomain(), false)
.setCallback(new Callback<>(){
@@ -651,6 +651,9 @@ public class UiUtils{
}
public static <T> void updateList(List<T> oldList, List<T> newList, RecyclerView list, RecyclerView.Adapter<?> adapter, BiPredicate<T, T> areItemsSame){
RecyclerView.ItemAnimator animator=list.getItemAnimator();
if(animator!=null)
animator.endAnimations();
// Save topmost item position and offset because for some reason RecyclerView would scroll the list to weird places when you insert items at the top
int topItem, topItemOffset;
if(list.getChildCount()==0){

View File

@@ -28,7 +28,7 @@ public abstract class ListItemViewHolder<T extends ListItem<?>> extends Bindable
title=findViewById(R.id.title);
subtitle=findViewById(R.id.subtitle);
icon=findViewById(R.id.icon);
view=(LinearLayout) itemView;
view=itemView instanceof LinearLayout ll ? ll : null;
}
@Override
@@ -52,12 +52,7 @@ public abstract class ListItemViewHolder<T extends ListItem<?>> extends Bindable
subtitle.setText(item.subtitle);
}
if(item.iconRes!=0){
icon.setVisibility(View.VISIBLE);
icon.setImageResource(item.iconRes);
}else{
icon.setVisibility(View.GONE);
}
bindIcon(item);
if(item.colorOverrideAttr!=0){
int color=UiUtils.getThemeColor(view.getContext(), item.colorOverrideAttr);
@@ -68,6 +63,15 @@ public abstract class ListItemViewHolder<T extends ListItem<?>> extends Bindable
view.setAlpha(item.isEnabled ? 1 : .4f);
}
protected void bindIcon(T item){
if(item.iconRes!=0){
icon.setVisibility(View.VISIBLE);
icon.setImageResource(item.iconRes);
}else{
icon.setVisibility(View.GONE);
}
}
@Override
public boolean isEnabled(){
return item.isEnabled;

View File

@@ -0,0 +1,22 @@
package org.joinmastodon.android.ui.viewholders;
import android.content.Context;
import android.text.TextUtils;
import android.view.ViewGroup;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.viewmodel.SectionHeaderListItem;
public class SectionHeaderListItemViewHolder extends ListItemViewHolder<SectionHeaderListItem>{
public SectionHeaderListItemViewHolder(Context context, ViewGroup parent){
super(context, R.layout.item_generic_list_header, parent);
}
@Override
public void onBind(SectionHeaderListItem item){
if(TextUtils.isEmpty(item.title))
title.setText(item.titleRes);
else
title.setText(item.title);
}
}

View File

@@ -0,0 +1,34 @@
package org.joinmastodon.android.ui.viewholders;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.ViewGroup;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.viewmodel.SettingsAccountListItem;
import org.joinmastodon.android.ui.OutlineProviders;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
public class SettingsAccountListItemViewHolder extends ListItemViewHolder<SettingsAccountListItem<?>> implements ImageLoaderViewHolder{
public SettingsAccountListItemViewHolder(Context context, ViewGroup parent){
super(context, R.layout.item_generic_list, parent);
icon.setOutlineProvider(OutlineProviders.OVAL);
icon.setClipToOutline(true);
icon.setImageTintList(null);
}
@Override
protected void bindIcon(SettingsAccountListItem<?> item){}
@Override
public void setImage(int index, Drawable image){
icon.setImageDrawable(image);
}
@Override
public void clearImage(int index){
icon.setImageResource(R.drawable.image_placeholder);
}
}

View File

@@ -0,0 +1,59 @@
package org.joinmastodon.android.ui.views;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.widget.ImageView;
import org.joinmastodon.android.ui.utils.UiUtils;
import me.grishka.appkit.utils.CustomViewHelper;
public class FamiliarFollowersImageView extends ImageView implements CustomViewHelper{
private Paint clearPaint=new Paint(Paint.ANTI_ALIAS_FLAG);
private Path path=new Path(), rectPath=new Path();
public FamiliarFollowersImageView(Context context){
this(context, null);
}
public FamiliarFollowersImageView(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public FamiliarFollowersImageView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
UiUtils.setAllPaddings(this, 2);
setOutlineProvider(new ViewOutlineProvider(){
@Override
public void getOutline(View view, Outline outline){
outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), getResources().getDisplayMetrics().density*8.5f);
}
});
setClipToOutline(true);
clearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
@Override
protected void onDraw(Canvas canvas){
float offset=dp(2);
float radius=dp(6);
rectPath.rewind();
rectPath.addRoundRect(offset, offset, getWidth()-offset, getHeight()-offset, radius, radius, Path.Direction.CW);
canvas.save();
canvas.clipPath(rectPath); // Unless I do this, the corner pixels still end up dirty
super.onDraw(canvas);
canvas.restore();
path.rewind();
path.addRect(0, 0, getWidth(), getHeight(), Path.Direction.CW);
path.op(rectPath, Path.Op.DIFFERENCE);
canvas.drawPath(path, clearPaint);
}
}

View File

@@ -1,9 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M7,17.95 L12,15.8 17,17.95V5Q17,5 17,5Q17,5 17,5H7Q7,5 7,5Q7,5 7,5ZM5,21V5Q5,4.175 5.588,3.587Q6.175,3 7,3H17Q17.825,3 18.413,3.587Q19,4.175 19,5V21L12,18ZM17,5H12H7Q7,5 7,5Q7,5 7,5H17Q17,5 17,5Q17,5 17,5Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M480,760Q546,760 593,713Q640,666 640,600L640,440Q640,374 593,327Q546,280 480,280Q414,280 367,327Q320,374 320,440L320,600Q320,666 367,713Q414,760 480,760ZM400,640L560,640L560,560L400,560L400,640ZM400,480L560,480L560,400L400,400L400,480ZM480,520Q480,520 480,520Q480,520 480,520L480,520Q480,520 480,520Q480,520 480,520Q480,520 480,520Q480,520 480,520L480,520Q480,520 480,520Q480,520 480,520ZM480,840Q415,840 359.5,808Q304,776 272,720L160,720L160,640L244,640Q241,620 240.5,600Q240,580 240,560L160,560L160,480L240,480Q240,460 240.5,440Q241,420 244,400L160,400L160,320L272,320Q286,297 303.5,277Q321,257 344,242L280,176L336,120L422,206Q450,197 479,197Q508,197 536,206L624,120L680,176L614,242Q637,257 655.5,276.5Q674,296 688,320L800,320L800,400L716,400Q719,420 719.5,440Q720,460 720,480L800,480L800,560L720,560Q720,580 719.5,600Q719,620 716,640L800,640L800,720L688,720Q656,776 600.5,808Q545,840 480,840Z"/>
</vector>

View File

@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960">
<path
android:fillColor="@android:color/white"
android:pathData="M376,660L480,556L584,660L640,604L536,500L640,396L584,340L480,444L376,340L320,396L424,500L320,604L376,660ZM280,840Q247,840 223.5,816.5Q200,793 200,760L200,240L160,240L160,160L360,160L360,120L600,120L600,160L800,160L800,240L760,240L760,760Q760,793 736.5,816.5Q713,840 680,840L280,840ZM680,240L280,240L280,760Q280,760 280,760Q280,760 280,760L680,760Q680,760 680,760Q680,760 680,760L680,240ZM280,240L280,240L280,760Q280,760 280,760Q280,760 280,760L280,760Q280,760 280,760Q280,760 280,760L280,240Z"/>
</vector>

View File

@@ -1,5 +1,6 @@
<?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="75dp"
android:background="@drawable/bg_timeline_gap">
@@ -9,10 +10,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginHorizontal="16dp"
android:gravity="center_horizontal"
android:textAppearance="@style/m3_body_large"
android:textColor="?android:textColorSecondary"
android:text="@string/load_missing_posts"/>
android:maxLines="2"
android:ellipsize="end"
tools:text="@string/load_missing_posts_above"/>
<ProgressBar
android:id="@+id/progress"

View File

@@ -71,6 +71,20 @@
app:tabMode="auto"
android:background="?colorM3Surface"/>
<org.joinmastodon.android.ui.tabs.TabLayout
android:id="@+id/search_tabbar"
android:layout_width="match_parent"
android:layout_height="48dp"
app:tabGravity="fill"
app:tabIndicator="@drawable/tab_indicator_m3"
app:tabIndicatorAnimationMode="elastic"
app:tabIndicatorColor="?colorM3Primary"
app:tabIndicatorFullWidth="false"
app:tabMinWidth="0dp"
app:tabMode="fixed"
android:visibility="gone"
android:background="?colorM3Surface"/>
<View
android:id="@+id/tabs_divider"
android:layout_width="match_parent"

View File

@@ -239,6 +239,62 @@
</LinearLayout>
</LinearLayout>
<LinearLayout
android:id="@+id/familiar_followers"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginBottom="12dp"
android:paddingVertical="4dp"
android:paddingHorizontal="16dp"
android:clipToPadding="false"
android:orientation="horizontal"
android:background="?android:selectableItemBackground">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginVertical="-4dp"
android:paddingTop="4dp"
android:clipToPadding="false"
android:layerType="hardware">
<org.joinmastodon.android.ui.views.FamiliarFollowersImageView
android:id="@+id/familiar_followers_ava1"
android:layout_width="30dp"
android:layout_height="30dp"
android:rotation="-4"
tools:src="#f00"/>
<org.joinmastodon.android.ui.views.FamiliarFollowersImageView
android:id="@+id/familiar_followers_ava2"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="-10dp"
android:rotation="2"
tools:src="#0f0"/>
<org.joinmastodon.android.ui.views.FamiliarFollowersImageView
android:id="@+id/familiar_followers_ava3"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="-10dp"
android:rotation="-2"
tools:src="#00f"/>
</LinearLayout>
<TextView
android:id="@+id/familiar_followers_label"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="10dp"
android:gravity="start|center_vertical"
android:textAppearance="@style/m3_body_small"
android:textColor="?colorM3OnSurfaceVariant"
android:maxLines="2"
android:ellipsize="end"
tools:text="Followed by blah and blah"/>
</LinearLayout>
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
android:id="@+id/name_edit_wrap"

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="36dp"
android:layout_marginTop="24dp"
android:paddingStart="16dp"
android:paddingEnd="24dp"
android:gravity="center_vertical"
android:singleLine="true"
android:ellipsize="end"
android:textAppearance="@style/m3_title_small"
android:textColor="?colorM3OnSurfaceVariant"
tools:text="Section header"/>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/real_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:paddingTop="4dp"
android:paddingBottom="24dp"
android:textAppearance="@style/m3_headline_small"
android:textColor="?colorM3OnSurface"
tools:text="mastodon.social" />

View File

@@ -1,7 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/bookmarks" android:title="@string/bookmarks" android:icon="@drawable/ic_bookmark_24px" android:showAsAction="always"/>
<item android:id="@+id/favorites" android:title="@string/your_favorites" android:icon="@drawable/ic_star_24px" android:showAsAction="always"/>
<item android:id="@+id/share" android:title="@string/share_user" android:icon="@drawable/ic_share_24px" android:showAsAction="always"/>
<!-- TODO add to list -->
</menu>

View File

@@ -272,7 +272,6 @@
<string name="local_timeline_info_banner">هذه هي جميع المشاركات من جميع المستخدمين في الخادم الخاص بك (%s).</string>
<string name="recommended_accounts_info_banner">قد تعجبك هذه الحسابات استنادا إلى حسابات أخرى تتابعها.</string>
<string name="see_new_posts">المنشورات الجديدة</string>
<string name="load_missing_posts">حمّل المَنشورات المَفقودَة</string>
<string name="button_follow_pending">معلق</string>
<string name="follows_you">يُتابِعُك</string>
<string name="manually_approves_followers">الموافقة اليدوية على طلبات المتابعة</string>
@@ -697,4 +696,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -259,7 +259,6 @@
<string name="local_timeline_info_banner">Гэта ўсе допісы ад усіх карыстальнікаў на вашым серверы (%s).</string>
<string name="recommended_accounts_info_banner">Вам могуць спадабацца гэтыя ўліковыя запісы на аснове вашых падпісак.</string>
<string name="see_new_posts">Новыя допісы</string>
<string name="load_missing_posts">Загрузіць адсутныя допісы</string>
<string name="follow_back">Падпісацца ў адказ</string>
<string name="button_follow_pending">Чакаюць</string>
<string name="follows_you">Падпісаны(-а) на вас</string>
@@ -340,7 +339,6 @@
<string name="add_bookmark">Закладка</string>
<string name="remove_bookmark">Выдаліць закладку</string>
<string name="bookmarks">Закладкі</string>
<string name="your_favorites">Вашыя ўпадабанні</string>
<string name="login_title">З вяртаннем</string>
<string name="login_subtitle">Увайдзіце з дапамогай сервера, на якім вы стварылі свой уліковы запіс.</string>
<string name="server_url">URL-адрас сервера</string>
@@ -730,7 +728,6 @@
<string name="block_user_x_instead">Замест гэтага заблакіруйце %s</string>
<string name="users_cant_see_blocked">Вы не ўбачыце допісаў і апавяшчэнняў ад карыстальнікаў на гэтым серверы.</string>
<string name="you_wont_see_server_posts">Вы не ўбачыце ніякіх допісаў ад карыстальнікаў гэтага сервера.</string>
<string name="server_followers_will_be_removed">Вашы падпісчыкі з гэтага сервера будуць выдаленыя.</string>
<string name="server_cant_mention_or_follow_you">Ніхто з гэтага сервера ня можа сачыць за вамі.</string>
<string name="server_can_interact_with_older">Людзі з гэтага сервера могуць узаемадзейнічаць з вашымі старымі допісамі.</string>
<string name="unblocked_domain_x">Разблакіраваны дамен %s</string>
@@ -843,4 +840,7 @@
<string name="text_show_more">Больш</string>
<string name="avatar_move_and_scale">Перасоўванне і маштабаванне</string>
<string name="confirm_avatar_crop">Выбраць</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -187,4 +187,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -158,4 +158,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -182,7 +182,6 @@
<string name="error_saving_file">Error en desar el fitxer</string>
<string name="downloading">S\'està baixant…</string>
<!-- %s is the server domain -->
<string name="load_missing_posts">Carrega les publicacions faltants</string>
<string name="button_follow_pending">Pendent</string>
<string name="follows_you">Et segueix</string>
<string name="manually_approves_followers">Aprova seguidors manualment</string>
@@ -290,4 +289,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -259,7 +259,6 @@
<string name="local_timeline_info_banner">Toto jsou všechny příspěvky od všech uživatelů na vašem serveru (%s).</string>
<string name="recommended_accounts_info_banner">Podle toho, koho sledujete, by se vám mohly líbit tyto účty.</string>
<string name="see_new_posts">Nové příspěvky</string>
<string name="load_missing_posts">Načíst chybějící příspěvky</string>
<string name="follow_back">Také sledovat</string>
<string name="button_follow_pending">Čekající</string>
<string name="follows_you">Sleduje vás</string>
@@ -340,7 +339,6 @@
<string name="add_bookmark">Přidat do záložek</string>
<string name="remove_bookmark">Odstranit záložku</string>
<string name="bookmarks">Záložky</string>
<string name="your_favorites">Vaše oblíbené</string>
<string name="login_title">Vítej zpět</string>
<string name="login_subtitle">Přihlaste se pomocí serveru, kde jste vytvořili svůj účet.</string>
<string name="server_url">URL serveru</string>
@@ -730,7 +728,6 @@
<string name="block_user_x_instead">Zablokovat místo toho %s</string>
<string name="users_cant_see_blocked">Neuvidíte příspěvky a upozornění od uživatelů na tomto serveru.</string>
<string name="you_wont_see_server_posts">Neuvidíte žádné příspěvky od uživatelů na tomto serveru.</string>
<string name="server_followers_will_be_removed">Vaši sledující z tohoto serveru budou odstraněni.</string>
<string name="server_cant_mention_or_follow_you">Nikdo z tohoto serveru vás nemůže sledovat.</string>
<string name="server_can_interact_with_older">Lidé z tohoto serveru mohou reagovat na vaše staré příspěvky.</string>
<string name="unblocked_domain_x">Odblokovat doménu %s</string>
@@ -830,4 +827,7 @@
<string name="settings_donate">Podpořit Mastodon</string>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -256,7 +256,6 @@
<string name="trending_posts_info_banner">Dyma\'r postiadau sy\'n denu tipyn o sylw ar draws Mastodon.</string>
<!-- %s is the server domain -->
<string name="see_new_posts">Postiadau newydd</string>
<string name="load_missing_posts">Llwytho postau coll</string>
<string name="follow_back">Dilyn yn ôl</string>
<string name="button_follow_pending">Yn aros</string>
<string name="follows_you">Yn eich dilyn chi</string>
@@ -335,7 +334,6 @@
<string name="add_bookmark">Tudalnodi</string>
<string name="remove_bookmark">Tynnu nod tudalen</string>
<string name="bookmarks">Nodau Tudalen</string>
<string name="your_favorites">Eich ffefrynnau</string>
<string name="login_title">Croeso nôl</string>
<string name="login_subtitle">Mewngofnodwch gyda\'r gweinydd lle gwnaethoch chi greu eich cyfrif.</string>
<string name="server_url">URL y Gweinydd</string>
@@ -660,4 +658,7 @@
<string name="settings_manage_donations">Rheoli rhoddion</string>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -233,7 +233,6 @@
<string name="local_timeline_info_banner">Disse er alle indlæg fra alle brugere på din server (%s).</string>
<string name="recommended_accounts_info_banner">Baseret på andre, du følger, vil du måske synes om disse konti.</string>
<string name="see_new_posts">Nye indlæg</string>
<string name="load_missing_posts">Indlæs manglende indlæg</string>
<string name="follow_back">Følg tilbage</string>
<string name="button_follow_pending">Afventer</string>
<string name="follows_you">Følger dig</string>
@@ -302,7 +301,6 @@
<string name="add_bookmark">Bogmærk</string>
<string name="remove_bookmark">Fjern bogmærke</string>
<string name="bookmarks">Bogmærker</string>
<string name="your_favorites">Dine favoritter</string>
<string name="login_title">Velkommen tilbage</string>
<string name="login_subtitle">Log ind med serveren, på hvilken din konto blev oprettet.</string>
<string name="server_url">Server-URL</string>
@@ -664,7 +662,6 @@ Jo flere folk, man følger, jo mere aktivt og interessant vil det være.</string
<string name="block_user_x_instead">Blokér %s i stedet</string>
<string name="users_cant_see_blocked">Du vil ikke se indlæg eller notifikationer fra brugere på denne server.</string>
<string name="you_wont_see_server_posts">Du vil ikke se indlæg fra brugere på denne server.</string>
<string name="server_followers_will_be_removed">Alle følgerne fra denne server fjernes.</string>
<string name="server_cant_mention_or_follow_you">Ingen fra denne server kan følge dig.</string>
<string name="server_can_interact_with_older">Folk fra denne server kan interagere med de gamle indlæg.</string>
<string name="unblocked_domain_x">Domænet %s afblokeret</string>
@@ -761,4 +758,7 @@ Jo flere folk, man følger, jo mere aktivt og interessant vil det være.</string
<string name="settings_manage_donations">Håndtér donationer</string>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -235,7 +235,6 @@
<string name="local_timeline_info_banner">Dies sind alle Beiträge von allen Benutzern auf deinem Server (%s).</string>
<string name="recommended_accounts_info_banner">Dir könnten diese Konten gefallen, basierend auf Leuten, denen du folgst.</string>
<string name="see_new_posts">Neue Beiträge</string>
<string name="load_missing_posts">Weitere Beiträge laden</string>
<string name="follow_back">Ebenfalls folgen</string>
<string name="button_follow_pending">Ausstehend</string>
<string name="follows_you">Folgt dir</string>
@@ -304,7 +303,6 @@
<string name="add_bookmark">Lesezeichen setzen</string>
<string name="remove_bookmark">Lesezeichen entfernen</string>
<string name="bookmarks">Lesezeichen</string>
<string name="your_favorites">Deine Favoriten</string>
<string name="login_title">Willkommen zurück</string>
<string name="login_subtitle">Melde dich mit dem Server an, auf dem du dein Konto erstellt hast.</string>
<string name="server_url">Serveradresse</string>
@@ -665,7 +663,6 @@
<string name="block_user_x_instead">Stattdessen %s blockieren</string>
<string name="users_cant_see_blocked">Du wirst keine Beiträge oder Benachrichtigungen von Profilen auf diesem Server sehen.</string>
<string name="you_wont_see_server_posts">Du wirst keine Beiträge von Profilen auf jenem Server mehr sehen.</string>
<string name="server_followers_will_be_removed">Deine Follower von jenem Server werden entfernt werden.</string>
<string name="server_cant_mention_or_follow_you">Niemand von jenem Server kann dir mehr folgen.</string>
<string name="server_can_interact_with_older">Die Leute jenes Servers können mit deinen alten Beiträgen interagieren.</string>
<string name="unblocked_domain_x">Domain %s entblockt</string>
@@ -800,4 +797,8 @@
<string name="moderation_warning_action_silence">Dein Konto wurde eingeschränkt.</string>
<string name="moderation_warning_action_suspend">Dein Konto wurde gesperrt.</string>
<string name="moderation_warning_learn_more">Mehr erfahren</string>
<string name="confirm_avatar_crop">Bestätigen</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -234,7 +234,6 @@
<string name="local_timeline_info_banner">Αυτές είναι όλες οι αναρτήσεις από όλους τους χρήστες στο διακομιστή σου (%s).</string>
<string name="recommended_accounts_info_banner">Μπορεί να σού αρέσουν αυτοί οι λογαριασμοί με βάση άλλους που ακολουθείς.</string>
<string name="see_new_posts">Νέες αναρτήσεις</string>
<string name="load_missing_posts">Φόρτωση αναρτήσεων που λείπουν</string>
<string name="follow_back">Ακολούθησε και εσύ</string>
<string name="button_follow_pending">Εκκρεμεί</string>
<string name="follows_you">Σε ακολουθεί</string>
@@ -303,7 +302,6 @@
<string name="add_bookmark">Σελιδοδείκτης</string>
<string name="remove_bookmark">Αφαίρεση σελιδοδείκτη</string>
<string name="bookmarks">Σελιδοδείκτες</string>
<string name="your_favorites">Τα αγαπημένα σου</string>
<string name="login_title">Καλωσόρισες και πάλι</string>
<string name="login_subtitle">Συνδέσου με τον διακομιστή όπου δημιούργησες τον λογαριασμό σου.</string>
<string name="server_url">URL διακομιστή</string>
@@ -664,7 +662,6 @@
<string name="block_user_x_instead">Αποκλεισμός %s αντ\' αυτού</string>
<string name="users_cant_see_blocked">Δεν θα βλέπεις αναρτήσεις ή ειδοποιήσεις από χρήστες σε αυτόν το διακομιστή.</string>
<string name="you_wont_see_server_posts">Δε θα βλέπεις καμία ανάρτηση από χρήστες σε αυτό το διακομιστή.</string>
<string name="server_followers_will_be_removed">Οι ακόλουθοί σου από αυτόν τον διακομιστή θα αφαιρεθούν.</string>
<string name="server_cant_mention_or_follow_you">Κανείς από αυτόν τον διακομιστή δεν μπορεί να σε ακολουθήσει.</string>
<string name="server_can_interact_with_older">Άτομα από αυτόν τον διακομιστή μπορούν να αλληλεπιδράσουν με τις παλιές αναρτήσεις σου.</string>
<string name="unblocked_domain_x">Άρση αποκλεισμού τομέα %s</string>
@@ -778,4 +775,7 @@
<string name="moderation_warning_action_silence">Ο λογαριασμός σου έχει περιοριστεί.</string>
<string name="moderation_warning_action_suspend">Ο λογαριασμός σου έχει ανασταλεί.</string>
<string name="moderation_warning_learn_more">Μάθε περισσότερα</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -235,7 +235,6 @@
<string name="local_timeline_info_banner">Estos son todos los mensajes de todos los usuarios de tu servidor (%s).</string>
<string name="recommended_accounts_info_banner">Es posible que te gusten estas cuentas basadas en otras que sigues.</string>
<string name="see_new_posts">Nuevas publicaciones</string>
<string name="load_missing_posts">Cargar publicaciones faltantes</string>
<string name="follow_back">Seguir también</string>
<string name="button_follow_pending">Pendiente</string>
<string name="follows_you">Te sigue</string>
@@ -304,7 +303,7 @@
<string name="add_bookmark">Añadir marcador</string>
<string name="remove_bookmark">Eliminar marcador</string>
<string name="bookmarks">Marcadores</string>
<string name="your_favorites">Tus favoritos</string>
<string name="your_favorites">Favoritos</string>
<string name="login_title">Bienvenido/da de nuevo</string>
<string name="login_subtitle">Inicia sesión con el servidor donde creaste tu cuenta.</string>
<string name="server_url">URL del servidor</string>
@@ -666,7 +665,6 @@ Mientras más personas sigas, más activo e interesante será.</string>
<string name="block_user_x_instead">Bloquear a %s en su lugar</string>
<string name="users_cant_see_blocked">No verás publicaciones ni notificaciones de usuarios en este servidor.</string>
<string name="you_wont_see_server_posts">No verás ninguna publicación de usuarios en este servidor.</string>
<string name="server_followers_will_be_removed">Tus seguidores de este servidor serán eliminados.</string>
<string name="server_cant_mention_or_follow_you">Nadie de este servidor puede seguirte.</string>
<string name="server_can_interact_with_older">Las personas de este servidor pueden interactuar con tus mensajes antiguos.</string>
<string name="unblocked_domain_x">El dominio %s ya no está bloqueado</string>
@@ -802,4 +800,36 @@ Mientras más personas sigas, más activo e interesante será.</string>
<string name="moderation_warning_action_suspend">Tu cuenta ha sido suspendida.</string>
<string name="moderation_warning_learn_more">Saber más</string>
<string name="text_show_more">Más</string>
<string name="avatar_move_and_scale">Mover y ajustar</string>
<string name="confirm_avatar_crop">Seleccionar</string>
<string name="settings_use_dynamic_colors">Usar color dinámico del sistema</string>
<string name="settings_accounts">Cuentas</string>
<string name="settings_add_account">Añadir cuenta...</string>
<string name="settings_app_settings">Ajustes de la aplicación</string>
<string name="account_settings">Ajustes de la cuenta</string>
<string name="settings_about_this_server">Acerca de este servidor</string>
<string name="manage_account">Administrar cuenta</string>
<string name="switch_to_this_account">Cambiar a esta cuenta</string>
<string name="delete_account">Eliminar cuenta</string>
<string name="notification_type_status">Nuevas publicaciones</string>
<plurals name="user_and_x_more_followed">
<item quantity="one">%1$s y %2$,d otro te siguieron</item>
<item quantity="other">%1$s y %2$,d otros te siguieron</item>
</plurals>
<string name="familiar_followers_one">Seguido por %s</string>
<string name="familiar_followers_two">Seguido por %s y %s</string>
<string name="profile_saved_posts">Guardado</string>
<string name="profile_saved_posts_explanation">Tus publicaciones guardadas solo son visibles para ti.</string>
<string name="search_people">Personas</string>
<plurals name="familiar_followers_many">
<item quantity="one">Seguido por %1$s, %2$s y %3$,d otro</item>
<item quantity="other">Seguido por %1$s, %2$s y %3$,d otros</item>
</plurals>
<plurals name="x_followers_you_know">
<item quantity="one">%,d seguidor que tú conoces</item>
<item quantity="other">%,d seguidores que tú conoces</item>
</plurals>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -235,7 +235,6 @@
<string name="local_timeline_info_banner">Hauek dira zure zerbitzariko (%s) erabiltzaile guztien mezuak.</string>
<string name="recommended_accounts_info_banner">Jarraitzen dituzun beste batzuetan oinarrituta, baliteke kontu hauek gustuko izatea.</string>
<string name="see_new_posts">Bidalketa berriak</string>
<string name="load_missing_posts">Falta diren bidalketak kargatu</string>
<string name="follow_back">Jarraitu bueltan</string>
<string name="button_follow_pending">Zain</string>
<string name="follows_you">Jarraitzen dizu</string>
@@ -304,7 +303,6 @@
<string name="add_bookmark">Laster-marka</string>
<string name="remove_bookmark">Kendu laster-marka</string>
<string name="bookmarks">Laster-markak</string>
<string name="your_favorites">Zure gogokoak</string>
<string name="login_title">Ongi etorri berriro ere</string>
<string name="login_subtitle">Hasi saioa kontua sortu zenuen zerbitzariarekin.</string>
<string name="server_url">Zerbitzariaren URLa</string>
@@ -666,7 +664,6 @@ Zenbat eta jende gehiago jarraitu, orduan eta aktiboagoa eta interesgarriagoa iz
<string name="block_user_x_instead">Blokeatu %s haren ordez</string>
<string name="users_cant_see_blocked">Ez dituzu zerbitzari honetako erabiltzaileen bidalketarik edota jakinarazpenik ikusiko.</string>
<string name="you_wont_see_server_posts">Ez dituzu zerbitzari honetako erabiltzaileen bidalketarik ikusiko.</string>
<string name="server_followers_will_be_removed">Zerbitzari honetako zure jarraitzaileak ezabatu egingo dira.</string>
<string name="server_cant_mention_or_follow_you">Zerbitzari honetako inork ezin zaitu jarraitu.</string>
<string name="server_can_interact_with_older">Zerbitzari honetako erabiltzaileek zure bidalketa zaharrekin elkarreragin dezakete.</string>
<string name="unblocked_domain_x">%s domeinua desblokeatu da</string>
@@ -799,4 +796,7 @@ Zenbat eta jende gehiago jarraitu, orduan eta aktiboagoa eta interesgarriagoa iz
<string name="moderation_warning_action_silence">Zure kontuari mugak jarri zaizkio.</string>
<string name="moderation_warning_action_suspend">Zure kontua behin-behinean egotzi da.</string>
<string name="moderation_warning_learn_more">Informazio gehiago</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -235,7 +235,6 @@
<string name="local_timeline_info_banner">این‌ها همه فرسته‌های همه کاربران در سرور شما (%s) هستند.</string>
<string name="recommended_accounts_info_banner">ممکن است این حساب‌ها را بر اساس حساب‌های دیگری که پی می‌گیرید بپسندید.</string>
<string name="see_new_posts">فرسته‌های جدید</string>
<string name="load_missing_posts">بارگذاری فرسته‌های گم شده</string>
<string name="follow_back">پیگیری متقابل</string>
<string name="button_follow_pending">منتظر</string>
<string name="follows_you">پی‌گیرتان است</string>
@@ -304,7 +303,6 @@
<string name="add_bookmark">نشانک</string>
<string name="remove_bookmark">برداشتن نشانک</string>
<string name="bookmarks">نشانک‌ها</string>
<string name="your_favorites">برگزیده‌های شما</string>
<string name="login_title">خوش برگشتید</string>
<string name="login_subtitle">با کارسازی که حساب خود را در آن ایجاد کردید وارد شوید.</string>
<string name="server_url">نشانی کارساز</string>
@@ -655,7 +653,6 @@
<string name="do_block_server">مسدود کردن کارساز</string>
<string name="block_user_x_instead">درعوض %s را مسدود کنید</string>
<string name="you_wont_see_server_posts">شما هیچ پستی از افراد این سرور نخواهید دید.</string>
<string name="server_followers_will_be_removed">دنبال کننده های شما در این سرور حذف خواهند شد.</string>
<string name="server_cant_mention_or_follow_you">هیچ‌کسی از این کارساز نمی‌تواند پیتان بگیرد.</string>
<string name="server_can_interact_with_older">افراد روی این کارساز می‌توانند با فرسته‌های قدیمیتان تعامل داشته باشند.</string>
<string name="unblocked_domain_x">مسدودیت دامنه %s رفع شد</string>
@@ -747,4 +744,7 @@
<string name="moderation_warning_action_silence">حسابتان محدود شده.</string>
<string name="moderation_warning_action_suspend">حسابتان معلّق شده.</string>
<string name="moderation_warning_learn_more">بیشتر بدانید</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -220,7 +220,6 @@
<string name="local_timeline_info_banner">Nämä ovat julkaisut kaikilta palvelimesi (%s) käyttäjiltä.</string>
<string name="recommended_accounts_info_banner">Muiden seuraamiesi perusteella saattaisit pitää näistä tileistä.</string>
<string name="see_new_posts">Uudet julkaisut</string>
<string name="load_missing_posts">Lataa puuttuvat julkaisut</string>
<string name="button_follow_pending">Pyydetty</string>
<string name="follows_you">Seuraa sinua</string>
<string name="manually_approves_followers">Hyväksyy seuraajat käsin</string>
@@ -587,4 +586,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -167,7 +167,6 @@
<string name="error_saving_file">Error sa pag-save ng file</string>
<string name="downloading">Nagda-download…</string>
<!-- %s is the server domain -->
<string name="load_missing_posts">Mag-Load ng nawawalang mga post</string>
<string name="button_follow_pending">Nakabinbin</string>
<string name="follows_you">Sinundan ka</string>
<string name="manually_approves_followers">Manu-manong aprubahan ang mga tagasunod</string>
@@ -253,4 +252,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -233,7 +233,6 @@
<string name="local_timeline_info_banner">Voici tous les messages de tous les comptes de votre serveur (%s).</string>
<string name="recommended_accounts_info_banner">Vous pourriez aimer ces comptes en fonction des autres que vous suivez.</string>
<string name="see_new_posts">Nouveaux messages </string>
<string name="load_missing_posts">Charger les messages manquants</string>
<string name="follow_back">Suivre en retour</string>
<string name="button_follow_pending">En attente</string>
<string name="follows_you">Vous suit</string>
@@ -302,7 +301,6 @@
<string name="add_bookmark">Ajouter aux marque-pages</string>
<string name="remove_bookmark">Supprimer le marque-page</string>
<string name="bookmarks">Marque-pages</string>
<string name="your_favorites">Vos favoris</string>
<string name="login_title">Bienvenue à nouveau</string>
<string name="login_subtitle">Connectez-vous avec le serveur sur lequel vous avez créé votre compte.</string>
<string name="server_url">URL du serveur</string>
@@ -663,7 +661,6 @@
<string name="block_user_x_instead">Bloquer %s à la place</string>
<string name="users_cant_see_blocked">Vous ne verrez plus les messages ou les notifications des utilisateur·rice·s de ce serveur.</string>
<string name="you_wont_see_server_posts">Vous ne verrez aucun message des utilisateur·rice·s de ce serveur.</string>
<string name="server_followers_will_be_removed">Vos abonné·e·s de ce serveur seront supprimés.</string>
<string name="server_cant_mention_or_follow_you">Personne de ce serveur ne peut vous suivre.</string>
<string name="server_can_interact_with_older">Les personnes de ce serveur peuvent interagir avec vos anciennes publications.</string>
<string name="unblocked_domain_x">Débloquage du domaine %s</string>
@@ -760,4 +757,7 @@
<string name="settings_manage_donations">Gestion des dons</string>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -235,7 +235,6 @@
<string name="local_timeline_info_banner">Dit binne alle berjochten fan alle brûkers op jo server (%s).</string>
<string name="recommended_accounts_info_banner">Mooglik fine jo dizze accounts aardich op basis fan oare accounts dyt jo folgje.</string>
<string name="see_new_posts">Nije berjochten</string>
<string name="load_missing_posts">Mear berjochten lade</string>
<string name="follow_back">Weromfolgje</string>
<string name="button_follow_pending">Yn ôfwachting</string>
<string name="follows_you">Folget jo</string>
@@ -304,7 +303,6 @@
<string name="add_bookmark">Blêdwizer tafoegje</string>
<string name="remove_bookmark">Blêdwizer fuortsmite</string>
<string name="bookmarks">Blêdwizers</string>
<string name="your_favorites">Jo favoriten</string>
<string name="login_title">Wolkom werom</string>
<string name="login_subtitle">Oanmelde by de server dêrt jo jo account oanmakke hawwe.</string>
<string name="server_url">Server-URL</string>
@@ -548,4 +546,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -28,4 +28,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -261,7 +261,6 @@
<string name="local_timeline_info_banner">Seo gach post o gach cleachdaiche an fhrithealaiche agad (%s).</string>
<string name="recommended_accounts_info_banner">Dhfhaoidte gun còrd na cunntasan seo riut stèidhichte air feadhainn eile a tha thu a leantainn.</string>
<string name="see_new_posts">Postaichean ùra</string>
<string name="load_missing_posts">Luchdaich postaichean a dhìth</string>
<string name="follow_back">Lean air ais</string>
<string name="button_follow_pending">Ri dhèiligeadh</string>
<string name="follows_you">Gad leantainn</string>
@@ -342,7 +341,6 @@
<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>
@@ -731,7 +729,6 @@
<string name="block_user_x_instead">Bac %s na àite</string>
<string name="users_cant_see_blocked">Chan fhaic thu postaichean no brathan o chleachdaichean a th air an fhrithealaiche seo.</string>
<string name="you_wont_see_server_posts">Chan fhaic thu post sam bith o chleachdaichean a th air an fhrithealaiche seo.</string>
<string name="server_followers_will_be_removed">Thèid an luchd-leantainn agad a th air an fhrithealaiche seo a thoirt air falbh.</string>
<string name="server_cant_mention_or_follow_you">Chan urrainn do neach sam bith a th air an fhrithealaiche seo do leantainn.</string>
<string name="server_can_interact_with_older">S urrainn do dhaoine a th air an fhrithealaiche seo eadar-ghabhail leis na seann-phostaichean agad.</string>
<string name="unblocked_domain_x">Dhì-bhac thu an àrainn %s</string>
@@ -883,4 +880,7 @@
<string name="text_show_more">Barrachd</string>
<string name="avatar_move_and_scale">Gluais is sgèilich</string>
<string name="confirm_avatar_crop">Tagh</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -220,7 +220,6 @@
<string name="local_timeline_info_banner">Estas son as publicacións das usuarias do teu servidor (%s).</string>
<string name="recommended_accounts_info_banner">Poderían interesarche estas contas en función doutras que segues.</string>
<string name="see_new_posts">Novas publicacións</string>
<string name="load_missing_posts">Cargar publicacións que faltan</string>
<string name="button_follow_pending">Pendente</string>
<string name="follows_you">Séguete</string>
<string name="manually_approves_followers">Aprobar manualmente os seguimentos</string>
@@ -627,4 +626,7 @@ Canta máis xente sigas, máis activo e interesante será.</string>
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -348,4 +348,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -203,4 +203,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -232,7 +232,6 @@
<string name="local_timeline_info_banner">Ezek a kiszolgálója (%s) felhasználóinak összes bejegyzése.</string>
<string name="recommended_accounts_info_banner">Ezek a fiókok tetszhetnek neked a követéseid alapján.</string>
<string name="see_new_posts">Új bejegyzések</string>
<string name="load_missing_posts">Hiányzó bejegyzések betöltése</string>
<string name="follow_back">Visszakövetés</string>
<string name="button_follow_pending">Függőben</string>
<string name="follows_you">Követi önt</string>
@@ -301,7 +300,6 @@
<string name="add_bookmark">Könyvjelzőzés</string>
<string name="remove_bookmark">Könyvjelző eltávolítása</string>
<string name="bookmarks">Könyvjelzők</string>
<string name="your_favorites">Kedvencek</string>
<string name="login_title">Üdv újra itt</string>
<string name="login_subtitle">Azon a kiszolgálón jelentkezzen be, ahol a fiókját létrehozta.</string>
<string name="server_url">Kiszolgáló webcíme</string>
@@ -659,7 +657,6 @@ Minél több embert követsz, annál aktívabb és érdekesebb lesz.</string>
<string name="block_user_x_instead">Helyette %s letiltása</string>
<string name="users_cant_see_blocked">Nem látsz majd bejegyzéseket vagy értesítéseket ennek a kiszolgálónak a felhasználóitól.</string>
<string name="you_wont_see_server_posts">Nem látsz majd bejegyzéseket ennek a kiszolgálónak a felhasználóitól.</string>
<string name="server_followers_will_be_removed">Az ezen a kiszolgálón lévő követőid el lesznek távolítva.</string>
<string name="server_cant_mention_or_follow_you">Erről a kiszolgálóról senki sem követhet.</string>
<string name="server_can_interact_with_older">Az ezen a kiszolgálón lévő emberek interakcióba léphetnek a régi bejegyzéseiddel.</string>
<string name="unblocked_domain_x">%s domain tiltása feloldva</string>
@@ -730,4 +727,7 @@ Minél több embert követsz, annál aktívabb és érdekesebb lesz.</string>
<string name="view_favorites">Kedvencek megtekintése</string>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -233,7 +233,6 @@
<string name="local_timeline_info_banner">Ձեր սերվերի (%s) բոլոր օգտատերերի բոլոր գրառումները այստեղ են։</string>
<string name="recommended_accounts_info_banner">Ըստ ձեր հետևած հաշիվների` գուցե ձեզ դուր կգան այս հաշիվները։</string>
<string name="see_new_posts">Նոր գրառումներ</string>
<string name="load_missing_posts">Բեռնել բաց թողնված գրառումները</string>
<string name="follow_back">Հետևել</string>
<string name="button_follow_pending">Սպասվող</string>
<string name="follows_you">Հետեւում է ձեզ</string>
@@ -302,7 +301,6 @@
<string name="add_bookmark">Ավելացնել էջանիշ</string>
<string name="remove_bookmark">Հեռացնել էջանիշը</string>
<string name="bookmarks">Էջանիշեր</string>
<string name="your_favorites">Հավանածներ</string>
<string name="login_title">Բարի վերադարձ</string>
<string name="login_subtitle">Մուտք գործեք այն սպասարկչի միջոցով, որտեղ ստեղծել եք ձեր հաշիվը։</string>
<string name="server_url">Սպասարկչի հասցե</string>
@@ -663,7 +661,6 @@
<string name="block_user_x_instead">Փոխարենը արգելափակել %s-ին</string>
<string name="users_cant_see_blocked">Դուք չեք տեսնի այս սպասարկչի օգտատերերի գրառումները կամ ծանուցումները։</string>
<string name="you_wont_see_server_posts">Դուք չեք տեսնի այս սպասարկչի օգտատերերից ոչ մի գրառում։</string>
<string name="server_followers_will_be_removed">Այս սպասարկչից ձեր հետևորդները կհանվեն։</string>
<string name="server_cant_mention_or_follow_you">Այս սպասարկչից ոչ մեկ չի կարողանա ձեզ հետևել։</string>
<string name="server_can_interact_with_older">Այս սպասարկչից մարդիկ կկարողանան փոխազդել ձեր հին գրառումների հետ։</string>
<string name="unblocked_domain_x">%s տիրույթը ապակողպվել է</string>
@@ -691,4 +688,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -233,7 +233,6 @@
<string name="local_timeline_info_banner">Ecce tote le messages de tote le usatores in tu servitor (%s).</string>
<string name="recommended_accounts_info_banner">Iste contos poterea placer te, considerante le alteres que tu seque.</string>
<string name="see_new_posts">Nove messages</string>
<string name="load_missing_posts">Cargar messages mancante</string>
<string name="follow_back">Sequer in retorno</string>
<string name="button_follow_pending">In tractamento</string>
<string name="follows_you">Te seque</string>
@@ -302,7 +301,6 @@
<string name="add_bookmark">Adder al marcapaginas</string>
<string name="remove_bookmark">Remover marcapagina</string>
<string name="bookmarks">Marcapaginas</string>
<string name="your_favorites">Tu favorites</string>
<string name="login_title">Benvenite de novo</string>
<string name="login_subtitle">Aperi session con le servitor ubi tu ha create tu conto.</string>
<string name="server_url">URL del servitor</string>
@@ -664,7 +662,6 @@ Quanto plus personas tu seque, tanto plus active e interessante illo essera.</st
<string name="block_user_x_instead">Blocar %s in su loco</string>
<string name="users_cant_see_blocked">Tu non videra messages o notificationes de usatores sur iste servitor.</string>
<string name="you_wont_see_server_posts">Tu non videra messages de usatores sur iste servitor.</string>
<string name="server_followers_will_be_removed">Tu sequitores de iste servitor essera removite.</string>
<string name="server_cant_mention_or_follow_you">Necuno de iste servitor pote sequer te.</string>
<string name="server_can_interact_with_older">Le personas de iste servitor pote interager con tu messages ancian.</string>
<string name="unblocked_domain_x">Dominio %s disblocate</string>
@@ -755,4 +752,7 @@ Quanto plus personas tu seque, tanto plus active e interessante illo essera.</st
<string name="settings_manage_donations">Gerer donationes</string>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -28,4 +28,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -222,7 +222,6 @@
<string name="local_timeline_info_banner">Ini adalah kiriman dari semua pengguna di server Anda (%s).</string>
<string name="recommended_accounts_info_banner">Anda mungkin suka akun berikut berdasarkan orang-orang yang Anda ikuti.</string>
<string name="see_new_posts">Kiriman baru</string>
<string name="load_missing_posts">Muat kiriman yang hilang</string>
<string name="follow_back">Ikuti balik</string>
<string name="button_follow_pending">Ditunda</string>
<string name="follows_you">Mengikuti Anda</string>
@@ -285,7 +284,6 @@
<string name="add_bookmark">Markah</string>
<string name="remove_bookmark">Hapus bookmark</string>
<string name="bookmarks">Markah</string>
<string name="your_favorites">Favorit Anda</string>
<string name="login_title">Selamat datang kembali</string>
<string name="login_subtitle">Masuk dengan server di mana Anda buat akun Anda.</string>
<string name="server_url">URL Server</string>
@@ -632,7 +630,6 @@
<string name="block_user_x_instead">Blokir %s saja</string>
<string name="users_cant_see_blocked">Anda tidak akan melihat kiriman atau notifikasi dari pengguna di server ini.</string>
<string name="you_wont_see_server_posts">Anda tidak akan melihat kiriman apa pun dari pengguna di server ini.</string>
<string name="server_followers_will_be_removed">Pengikut Anda dari server ini akan dihapus.</string>
<string name="server_cant_mention_or_follow_you">Tidak ada siapa pun dari server ini yang dapat mengikuti Anda.</string>
<string name="server_can_interact_with_older">Orang-orang dari server ini dapat berinteraksi dengan kiriman lama Anda.</string>
<string name="unblocked_domain_x">Domain %s dibuka pemblokirannya</string>
@@ -761,4 +758,7 @@
<string name="moderation_warning_action_silence">Akun Anda telah dibatasi.</string>
<string name="moderation_warning_action_suspend">Akun Anda telah ditangguhkan.</string>
<string name="moderation_warning_learn_more">Pelajari lebih lanjut</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -235,7 +235,6 @@
<string name="local_timeline_info_banner">Þetta eru allar færslur frá öllum notendum á netþjóninum þínum (%s).</string>
<string name="recommended_accounts_info_banner">Þú gætir einnig haft áhuga á þessum aðgöngum, miðað við hverjum þú ert að fylgjast með.</string>
<string name="see_new_posts">Nýjar færslur</string>
<string name="load_missing_posts">Hlaða inn færslum sem vantar</string>
<string name="follow_back">Fylgjast með til baka</string>
<string name="button_follow_pending">Í bið</string>
<string name="follows_you">Fylgist með þér</string>
@@ -304,7 +303,7 @@
<string name="add_bookmark">Bókamerki</string>
<string name="remove_bookmark">Fjarlægja bókamerki</string>
<string name="bookmarks">Bókamerki</string>
<string name="your_favorites">Eftirlætin þín</string>
<string name="your_favorites">Eftirlæti</string>
<string name="login_title">Velkomin aftur</string>
<string name="login_subtitle">Skráðu þig inn á netþjóninn þar sem þú útbjóst notandaaðganginn þinn.</string>
<string name="server_url">Vefslóð netþjóns</string>
@@ -666,7 +665,6 @@
<string name="block_user_x_instead">Útiloka %s í staðinn</string>
<string name="users_cant_see_blocked">Þú munt ekki sjá neinar færslur eða tilkynningar frá notendum á þessum netþjóni.</string>
<string name="you_wont_see_server_posts">Þú munt ekki sjá neinar færslur frá notendum á þessum netþjóni.</string>
<string name="server_followers_will_be_removed">Fylgjendur þínir af þessum netþjóni verða fjarlægðir.</string>
<string name="server_cant_mention_or_follow_you">Enginn frá þessum netþjóni getur fylgst með þér.</string>
<string name="server_can_interact_with_older">Fólk frá þessum netþjóni getur sýslað með eldri færslur þínar.</string>
<string name="unblocked_domain_x">Aflétti útilokun af léninu %s</string>
@@ -802,4 +800,36 @@
<string name="moderation_warning_action_suspend">Notandaaðgangurinn þinn hefur verið settur í frysti.</string>
<string name="moderation_warning_learn_more">Kanna nánar</string>
<string name="text_show_more">Meira</string>
<string name="avatar_move_and_scale">Færa og kvarða</string>
<string name="confirm_avatar_crop">Veldu</string>
<string name="settings_use_dynamic_colors">Nota breytilegan lit frá kerfinu</string>
<string name="settings_accounts">Aðgangar</string>
<string name="settings_add_account">Bæta við notandaaðgangi...</string>
<string name="settings_app_settings">Stillingar forrits</string>
<string name="account_settings">Stillingar aðgangs</string>
<string name="settings_about_this_server">Um þennan netþjón</string>
<string name="manage_account">Sýsla með notandaaðgang</string>
<string name="switch_to_this_account">Skipta yfir á þennan aðgang</string>
<string name="delete_account">Eyða notandaaðgangi</string>
<string name="notification_type_status">Nýjar færslur</string>
<plurals name="user_and_x_more_followed">
<item quantity="one">%1$s og %2$,d fór að fylgjast með þér</item>
<item quantity="other">%1$s og %2$,d fóru að fylgjast með þér</item>
</plurals>
<string name="familiar_followers_one">Fylgt af %s</string>
<string name="familiar_followers_two">Fylgt af %s og %s</string>
<string name="profile_saved_posts">Vistað</string>
<string name="profile_saved_posts_explanation">Vistaðar færslur þínar eru einungis sýnilegar þér.</string>
<string name="search_people">Fólk</string>
<plurals name="familiar_followers_many">
<item quantity="one">Fylgt af%1$s, %2$s, og %3$,d til viðbótar</item>
<item quantity="other">Fylgt af%1$s, %2$s, og %3$,d til viðbótar</item>
</plurals>
<plurals name="x_followers_you_know">
<item quantity="one">%,d fylgjandi sem þú þekkir</item>
<item quantity="other">%,d fylgjendur sem þú þekkir</item>
</plurals>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -235,7 +235,6 @@
<string name="local_timeline_info_banner">Questi sono tutti i post di tutti gli utenti nel tuo server (%s).</string>
<string name="recommended_accounts_info_banner">Questi account potrebbero piacerti in base agli altri che segui.</string>
<string name="see_new_posts">Nuovi post</string>
<string name="load_missing_posts">Carica i post mancanti</string>
<string name="follow_back">Segui anche tu</string>
<string name="button_follow_pending">In attesa</string>
<string name="follows_you">Ha iniziato a seguirti</string>
@@ -304,7 +303,7 @@
<string name="add_bookmark">Segnalibro</string>
<string name="remove_bookmark">Rimuovi segnalibro</string>
<string name="bookmarks">Segnalibri</string>
<string name="your_favorites">I tuoi preferiti</string>
<string name="your_favorites">Preferiti</string>
<string name="login_title">Bentornato/a</string>
<string name="login_subtitle">Accedi con il server in cui hai creato il tuo account.</string>
<string name="server_url">URL del server</string>
@@ -666,7 +665,6 @@ Più persone segui, più sarà attivo e interessante.</string>
<string name="block_user_x_instead">Blocca %s invece</string>
<string name="users_cant_see_blocked">Non vedrai post o notifiche dagli utenti su questo server.</string>
<string name="you_wont_see_server_posts">Non vedrai alcun post dagli utenti su questo server.</string>
<string name="server_followers_will_be_removed">I tuoi seguaci da questo server verranno rimossi.</string>
<string name="server_cant_mention_or_follow_you">Nessuno da questo server può seguirti.</string>
<string name="server_can_interact_with_older">Le persone da questo server possono interagire con i tuoi vecchi post.</string>
<string name="unblocked_domain_x">Dominio %s sbloccato</string>
@@ -802,4 +800,52 @@ Più persone segui, più sarà attivo e interessante.</string>
<string name="moderation_warning_action_suspend">Il tuo account è stato sospeso.</string>
<string name="moderation_warning_learn_more">Per saperne di più</string>
<string name="text_show_more">Altro</string>
<string name="avatar_move_and_scale">Sposta e ridimensiona</string>
<string name="confirm_avatar_crop">Scegli</string>
<string name="settings_use_dynamic_colors">Utilizzare il colore dinamico del sistema</string>
<string name="settings_accounts">Account</string>
<string name="settings_add_account">Aggiungi account...</string>
<string name="settings_app_settings">Impostazioni dell\'app</string>
<string name="account_settings">Impostazioni dell\'account</string>
<string name="settings_about_this_server">Riguardo questo server</string>
<string name="manage_account">Gestisci l\'account</string>
<string name="switch_to_this_account">Passa a questo account</string>
<string name="delete_account">Cancella l\'account</string>
<string name="notification_type_status">Nuovi post</string>
<plurals name="user_and_x_more_followed">
<item quantity="one">%1$s e %2$,d altro hanno iniziato a seguirti</item>
<item quantity="other">%1$s e altri %2$,d hanno iniziato a seguirti</item>
</plurals>
<string name="familiar_followers_one">Seguito da %s</string>
<string name="familiar_followers_two">Seguito da %s e %s</string>
<string name="profile_saved_posts">Salvati</string>
<string name="profile_saved_posts_explanation">I tuoi post salvati sono visibili solo da te.</string>
<string name="search_people">Persone</string>
<plurals name="familiar_followers_many">
<item quantity="one">Seguito da %1$s, %2$s e %3$,d altro</item>
<item quantity="other">Seguito da %1$s, %2$s e altri %3$,d</item>
</plurals>
<plurals name="x_followers_you_know">
<item quantity="one">%,d seguace che conosci</item>
<item quantity="other">%,d seguaci che conosci</item>
</plurals>
<!-- appears when you're about to block a server -->
<plurals name="server_x_followers_will_be_removed">
<item quantity="one">%,d seguace sarà rimosso da questo server.</item>
<item quantity="other">%,d seguaci saranno rimossi da questo server.</item>
</plurals>
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<string name="server_x_followers_and_following_will_be_removed">Perderai %1$s seguaci e %2$s persone che segui.</string>
<plurals name="will_lose_x_followers">
<item quantity="one">%,d seguace</item>
<item quantity="other">%,d seguaci</item>
</plurals>
<plurals name="will_lose_x_following">
<item quantity="one">%,d persona che segui</item>
<item quantity="other">%,d persone che segui</item>
</plurals>
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
<string name="server_x_following_will_be_removed">Perderai %s persone che segui.</string>
<string name="load_missing_posts_above">Carica i post mancanti sopra</string>
<string name="load_missing_posts_below">Carica i post mancanti sotto</string>
</resources>

View File

@@ -84,4 +84,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -222,7 +222,6 @@
<string name="local_timeline_info_banner">あなたのサーバー (%s) の全ユーザーの全投稿です。</string>
<string name="recommended_accounts_info_banner">こちらは、あなたがフォローしている人に基づいた、おすすめのアカウントです。</string>
<string name="see_new_posts">新しい投稿</string>
<string name="load_missing_posts">不足している投稿を読み込む</string>
<string name="follow_back">フォローバック</string>
<string name="button_follow_pending">保留</string>
<string name="follows_you">フォローされています</string>
@@ -285,7 +284,6 @@
<string name="add_bookmark">ブックマーク</string>
<string name="remove_bookmark">ブックマークから削除</string>
<string name="bookmarks">ブックマーク</string>
<string name="your_favorites">お気に入り</string>
<string name="login_title">お帰りなさい</string>
<string name="login_subtitle">アカウントがあるサーバーの URL を入力してください。</string>
<string name="server_url">サーバーの URL</string>
@@ -633,7 +631,6 @@
<string name="block_user_x_instead">代わりに %s さんをブロック</string>
<string name="users_cant_see_blocked">このサーバーのユーザーからのすべての投稿と通知が閲覧できなくなります。</string>
<string name="you_wont_see_server_posts">相手のサーバーのユーザーのすべての投稿を閲覧できなくなります。</string>
<string name="server_followers_will_be_removed">このサーバーからのあなたへのフォローはすべて外れます。</string>
<string name="server_cant_mention_or_follow_you">このサーバーのユーザーはあなたをフォローできなくなります。</string>
<string name="server_can_interact_with_older">このサーバーのユーザーはあなたの古い投稿に反応できます。</string>
<string name="unblocked_domain_x">ドメイン %s のブロックを解除</string>
@@ -761,4 +758,7 @@
<string name="moderation_warning_action_silence">あなたのアカウントは制限されています。</string>
<string name="moderation_warning_action_suspend">あなたのアカウントは停止されています。</string>
<string name="moderation_warning_learn_more">詳細</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -293,4 +293,7 @@
<string name="new_post_notifications_disabled">თქვენ აღარ მიიღებთ შეტყობინებებს ახალი პოსტის შესახებ.</string>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -176,7 +176,6 @@
<string name="downloading">Asader…</string>
<!-- %s is the server domain -->
<string name="see_new_posts">Tisuffaɣ timaynutin</string>
<string name="load_missing_posts">Sali tisuffaɣ i iruḥen</string>
<string name="button_follow_pending">Yettraǧu</string>
<string name="follows_you">Yeṭṭafaṛ-ik·em-id</string>
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
@@ -191,7 +190,6 @@
<string name="i_agree">Qebleɣ</string>
<string name="add_bookmark">Creḍ</string>
<string name="bookmarks">Ticraḍ</string>
<string name="your_favorites">Ismenyifen-ik·im</string>
<string name="login_title">Ansuf yes-k·m tikkelt niḍen</string>
<string name="server_filter_any_language">Yal tutlayt</string>
<string name="server_filter_region_europe">Turuft</string>
@@ -253,4 +251,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -164,7 +164,6 @@
<string name="error_saving_file">파일 저장 오류</string>
<string name="downloading">다운로드 중…</string>
<!-- %s is the server domain -->
<string name="load_missing_posts">놓친 게시물 불러오기</string>
<string name="button_follow_pending">대기 중</string>
<string name="follows_you">나를 팔로우합니다</string>
<string name="manually_approves_followers">수동으로 팔로워 승인</string>
@@ -259,4 +258,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -261,7 +261,6 @@
<string name="local_timeline_info_banner">Tai visų naudotojų įrašai serveryje (%s).</string>
<string name="recommended_accounts_info_banner">Galbūt šios paskyros tau patiks pagal kitas, kurias seki.</string>
<string name="see_new_posts">Nauji įrašai</string>
<string name="load_missing_posts">Įkelti trūkstamus įrašus</string>
<string name="follow_back">Sekti atgal</string>
<string name="button_follow_pending">Laukiama</string>
<string name="follows_you">Seka tave</string>
@@ -342,7 +341,7 @@
<string name="add_bookmark">Pridėti į žymės</string>
<string name="remove_bookmark">Pašalinti žymę</string>
<string name="bookmarks">Žymės</string>
<string name="your_favorites">Tavo mėgstami</string>
<string name="your_favorites">Mėgstami</string>
<string name="login_title">Sveiki sugrįžę</string>
<string name="login_subtitle">Prisijunk prie serverio, kuriame susikūrei paskyrą.</string>
<string name="server_url">Serverio URL</string>
@@ -732,7 +731,6 @@ Kuo daugiau žmonių seki, tuo aktyvesnis ir įdomesnis jis bus.</string>
<string name="block_user_x_instead">Blokuoti %s vietoj to</string>
<string name="users_cant_see_blocked">Nematysi naudotojų įrašų ar pranešimų šiame serveryje.</string>
<string name="you_wont_see_server_posts">Nematysi jokių naudotojų įrašų šiame serveryje.</string>
<string name="server_followers_will_be_removed">Tavo sekėjai iš šio serverio bus pašalinti.</string>
<string name="server_cant_mention_or_follow_you">Niekas iš šio serverio negali tavęs sekti.</string>
<string name="server_can_interact_with_older">Žmonės iš šio serverio gali bendrauti su tavo senomis įrašomis.</string>
<string name="unblocked_domain_x">Atblokuotas domenas %s</string>
@@ -881,4 +879,39 @@ Kuo daugiau žmonių seki, tuo aktyvesnis ir įdomesnis jis bus.</string>
<string name="moderation_warning_action_silence">Tavo paskyra buvo apribota.</string>
<string name="moderation_warning_action_suspend">Tavo paskyra buvo pristabdyta.</string>
<string name="moderation_warning_learn_more">Sužinoti daugiau</string>
<string name="text_show_more">Daugiau</string>
<string name="avatar_move_and_scale">Perkelti ir keisti mastelį</string>
<string name="confirm_avatar_crop">Pasirinkti</string>
<string name="settings_use_dynamic_colors">Naudoti sistemos dinaminę spalvą</string>
<string name="settings_accounts">Paskyros</string>
<string name="settings_add_account">Pridėti paskyrą...</string>
<string name="settings_app_settings">Programėlės nustatymai</string>
<string name="account_settings">Paskyros nustatymai</string>
<string name="settings_about_this_server">Apie šį serverį</string>
<string name="manage_account">Tvarkyti paskyrą</string>
<string name="switch_to_this_account">Perjungti į šią paskyrą</string>
<string name="delete_account">Ištrinti paskyrą</string>
<string name="notification_type_status">Nauji įrašai</string>
<plurals name="user_and_x_more_followed">
<item quantity="one">%1$s ir %2$,d kitas seka jus</item>
<item quantity="few">%1$s ir %2$,d kiti seka jus</item>
<item quantity="many">%1$s ir %2$,d kitos seka jus</item>
<item quantity="other">%1$s ir %2$,d kitų seka jus</item>
</plurals>
<string name="familiar_followers_one">Sekama %s</string>
<string name="familiar_followers_two">Sekama %s ir %s</string>
<string name="profile_saved_posts">Išsaugota</string>
<string name="search_people">Žmonės</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<plurals name="will_lose_x_followers">
<item quantity="one">%,d sekėjas</item>
<item quantity="few">%,d sekėjai</item>
<item quantity="many">%,d sekėjo</item>
<item quantity="other">%,d sekėjų</item>
</plurals>
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
<string name="server_x_following_will_be_removed">Prarasite %s.</string>
<string name="load_missing_posts_above">Įkelti trūkstamus įrašus aukščiau</string>
<string name="load_missing_posts_below">Įkelti trūkstamus įrašus žemiau</string>
</resources>

View File

@@ -162,4 +162,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -235,7 +235,6 @@
<string name="local_timeline_info_banner">Dit zijn alle berichten van alle gebruikers op jouw server (%s).</string>
<string name="recommended_accounts_info_banner">Mogelijk vind je deze accounts leuk op basis van andere accounts die je volgt.</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>
<string name="follows_you">Volgt jou</string>
@@ -304,7 +303,6 @@
<string name="add_bookmark">Bladwijzer toevoegen</string>
<string name="remove_bookmark">Bladwijzer verwijderen</string>
<string name="bookmarks">Bladwijzers</string>
<string name="your_favorites">Jouw favorieten</string>
<string name="login_title">Welkom terug</string>
<string name="login_subtitle">Bij de server waar je je account hebt aangemaakt inloggen.</string>
<string name="server_url">Server-URL</string>
@@ -665,7 +663,6 @@
<string name="block_user_x_instead">In plaats hiervan %s blokkeren</string>
<string name="users_cant_see_blocked">Je ziet geen berichten of meldingen meer van gebruikers op deze server.</string>
<string name="you_wont_see_server_posts">Je ziet geen berichten meer van gebruikers op deze server.</string>
<string name="server_followers_will_be_removed">Jouw volgers van deze server worden ontvolgd.</string>
<string name="server_cant_mention_or_follow_you">Niemand op deze server kan jou volgen.</string>
<string name="server_can_interact_with_older">Mensen op deze server kunnen interactie hebben met jouw oude berichten.</string>
<string name="unblocked_domain_x">De server %s is gedeblokkeerd</string>
@@ -800,4 +797,7 @@
<string name="moderation_warning_action_silence">Jouw account is beperkt.</string>
<string name="moderation_warning_action_suspend">Jouw account is opgeschort.</string>
<string name="moderation_warning_learn_more">Meer informatie</string>
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -232,7 +232,6 @@
<string name="local_timeline_info_banner">Dette er alle innlegg fra alle brukere på din server (%s).</string>
<string name="recommended_accounts_info_banner">Du liker kanskje disse kontoene basert på de andre du følger.</string>
<string name="see_new_posts">Nye innlegg</string>
<string name="load_missing_posts">Last inn manglende innlegg</string>
<string name="follow_back">Følg tilbake</string>
<string name="button_follow_pending">Ventende</string>
<string name="follows_you">Følger deg</string>
@@ -301,7 +300,6 @@
<string name="add_bookmark">Bokmerke</string>
<string name="remove_bookmark">Fjern bokmerke</string>
<string name="bookmarks">Bokmerker</string>
<string name="your_favorites">Dine favoritter</string>
<string name="login_title">Velkommen tilbake</string>
<string name="login_subtitle">Logg inn med serveren der du opprettet kontoen din.</string>
<string name="server_url">Server link</string>
@@ -705,4 +703,7 @@ Jo flere folk du følger, jo mer aktiv og interessant blir den.</string>
</plurals>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -80,4 +80,7 @@
<!-- %s is the username -->
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

View File

@@ -256,7 +256,6 @@
<string name="local_timeline_info_banner">To są wszystkie posty od wszystkich użytkowników na Twoim serwerze (%s).</string>
<string name="recommended_accounts_info_banner">Może spodobają się Tobie te konta, bazując na tych, których już obserwujesz?</string>
<string name="see_new_posts">Zobacz nowe posty</string>
<string name="load_missing_posts">Załaduj brakujące wpisy</string>
<string name="follow_back">Obserwuj wzajemnie</string>
<string name="button_follow_pending">Oczekujące</string>
<string name="follows_you">Obserwuje cię</string>
@@ -336,7 +335,6 @@
<string name="text_copied">Skopiowano do schowka</string>
<string name="add_bookmark">Dodaj zakładkę</string>
<string name="bookmarks">Zakładki</string>
<string name="your_favorites">Twoje ulubione</string>
<string name="login_title">Witaj ponownie</string>
<string name="login_subtitle">Zaloguj się na serwer, na którym utworzyłeś swoje konto.</string>
<string name="server_url">Adres URL serwera</string>
@@ -688,7 +686,6 @@ Im więcej ludzi obserwujesz, tym aktywniejsza i bardziej interesująca się sta
<string name="block_user_x_instead">Zamiast tego blokuj %s</string>
<string name="users_cant_see_blocked">Nie zobaczysz postów ani powiadomień od użytkowników na tym serwerze.</string>
<string name="you_wont_see_server_posts">Nie zobaczysz postów od użytkowników na tym serwerze.</string>
<string name="server_followers_will_be_removed">Twoi obserwujący z tego serwera zostaną usunięci.</string>
<string name="server_cant_mention_or_follow_you">Nikt z tego serwera nie może Cię obserwować.</string>
<string name="server_can_interact_with_older">Ludzie z tego serwera mogą wchodzić w interakcje z Twoimi starymi wpisami.</string>
<string name="unblocked_domain_x">Odblokowano domenę %s</string>
@@ -748,4 +745,7 @@ Im więcej ludzi obserwujesz, tym aktywniejsza i bardziej interesująca się sta
<string name="notifications_allowed">%s pojawi się teraz na liście powiadomień.</string>
<!-- %1$s is your server domain, %2$s is the domain that was blocked, %3$,d is the follower count, %4$s is the `x_accounts` plural string -->
<!-- %1$s is the domain that was blocked, %2$,d is the follower count, %3$s is the `x_accounts` plural string -->
<!-- appears when you're about to block a server -->
<!-- The complete string will look like "You will lose X followers and Y people you follow". See will_lose_x_followers and will_lose_x_following -->
<!-- The complete string will look like "You will lose X people you follow". See will_lose_x_following -->
</resources>

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