Compare commits

...

114 Commits

Author SHA1 Message Date
sk
452ee8e1a5 update readme, bump version 2022-12-17 21:49:23 +01:00
sk
88c62427aa Merge remote-tracking branch 'weblate/main' 2022-12-17 21:46:52 +01:00
gallegonovato
09458c5ecb Translated using Weblate (Spanish)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-17 20:46:15 +00:00
Choukajohn
4171a5d210 Translated using Weblate (French)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-17 20:46:15 +00:00
tippete
1362a03877 Translated using Weblate (Italian)
Currently translated at 100.0% (60 of 60 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2022-12-17 20:46:15 +00:00
Choukajohn
34ae099b89 Translated using Weblate (French)
Currently translated at 100.0% (60 of 60 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-17 20:46:14 +00:00
gallegonovato
679bd4588f Translated using Weblate (Spanish)
Currently translated at 100.0% (60 of 60 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-17 20:46:14 +00:00
sk
7d4c69bc82 tweak gray colors 2022-12-17 21:36:19 +01:00
sk
1749fcacb1 fix text view cutting off text
closes #157
2022-12-17 21:16:35 +01:00
sk
683f87cc19 Merge branch 'feature/lists' 2022-12-17 21:13:23 +01:00
sk
2ef19be3c7 add missing lists with handling
fix #158
2022-12-17 21:11:48 +01:00
sk
fb5289372d fix updating wrong status when interacting with reblog
see mastodon#467
2022-12-17 21:01:10 +01:00
sk
f8d9d00dac Merge branch 'feature/animate-buttons' 2022-12-17 19:56:24 +01:00
sk
a7c707f62e animate footer icons
closes sk22#154
2022-12-17 19:48:20 +01:00
sk
336ebb71cf Merge branch 'feature/follow-requests' 2022-12-17 16:35:53 +01:00
sk
a5f98f5c50 fix follow request list issues
closes #153
2022-12-17 16:35:41 +01:00
sk
9d5d4b7957 make red theme less orange 2022-12-17 15:47:04 +01:00
LucasGGamerM
3626da7362 custom, darker grays for everyone 2022-12-17 15:41:42 +01:00
sk
400e340859 Merge branch 'fix-toolbar-styles-api-24' 2022-12-17 14:58:09 +01:00
sk
31cad1efbe move api 24 styles into extra styles.xml 2022-12-17 14:56:26 +01:00
sk
e5da24a44d add red theme 2022-12-16 14:41:53 +01:00
sk
d63e5af8d0 use custom instead of app name 2022-12-16 14:21:54 +01:00
sk
abdce64b99 for pink shall remain the default
also, save color name as a string
2022-12-16 14:00:43 +01:00
kaea
d5696684fa Translated using Weblate (Polish)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2022-12-16 12:39:36 +00:00
itslameni
d168794d4e Translated using Weblate (Russian)
Currently translated at 37.5% (3 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ru/
2022-12-16 12:39:36 +00:00
itslameni
52c5057e85 Translated using Weblate (Russian)
Currently translated at 89.8% (53 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2022-12-16 12:39:36 +00:00
tippete
21167f64c9 Translated using Weblate (Italian)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2022-12-16 12:39:36 +00:00
AiOO
26343ce10b Translated using Weblate (Korean)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-16 12:39:36 +00:00
nitrogenez
238d930c48 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-16 12:39:36 +00:00
jonta
87ade4a020 Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.2% (55 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-16 12:39:36 +00:00
kaea
db9bb58b3c Translated using Weblate (Polish)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2022-12-16 12:39:36 +00:00
Choukajohn
99cbc8f071 Translated using Weblate (French)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-16 12:39:36 +00:00
AiOO
d2a4ae8f59 Translated using Weblate (Korean)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-16 12:39:36 +00:00
sk
9a47530ab8 Merge remote-tracking branch 'upstream/master' 2022-12-16 02:52:55 +01:00
sk
ed1d9165e1 use default posting language from server 2022-12-16 02:14:06 +01:00
sk
ef421dd5dd set material3 theme as default 2022-12-16 02:02:48 +01:00
sk
acbf27f025 add button styles for each theme 2022-12-16 01:33:28 +01:00
sk
f54e2375be material you and true black improvements 2022-12-16 01:20:39 +01:00
sk
1a66db065f fix wrong button colors 2022-12-16 01:16:45 +01:00
sk
c51b2bb2e7 add m3 colors to colors.xml for compatibility 2022-12-16 00:24:04 +01:00
sk
4de3da09b3 introduce dedicated button colors 2022-12-16 00:13:01 +01:00
Grishka
e0febda372 Minor fixes 2022-12-15 20:16:32 +03:00
sk
516f97e679 improve material you colors 2022-12-15 18:03:06 +01:00
Grishka
069d141451 Fix crash in ComposeFragment::onSaveInstanceState in release builds
fixes #452, fixes #453, fixes #457
2022-12-15 20:02:26 +03:00
Grishka
166401ea18 Signup flow redesign 2022-12-15 19:41:38 +03:00
sk
55e5c03b5f add missing string 2022-12-15 17:03:24 +01:00
sk
c950b6e6c1 simplify code 2022-12-15 17:03:17 +01:00
LucasGGamerM
2dc884b1bb Making material you setting work fine. Its ready for release 2022-12-15 16:44:16 +01:00
LucasGGamerM
c49660950d Adding the color things 2022-12-15 16:37:31 +01:00
sk
9162908173 Merge branch 'more-distinct-filled-boost-icon' 2022-12-15 16:18:42 +01:00
sk
2789169dd7 slightly more padding for fill 2022-12-15 16:18:21 +01:00
sk
0728b00381 Merge branch 'more-distinct-filled-boost-icon' 2022-12-13 15:45:30 +01:00
sk
34b82337b1 add distinct filled boost icon 2022-12-13 15:45:19 +01:00
sk
f25d4e4d44 update screenshots 2022-12-13 12:04:34 +01:00
sk
ac3176c0d8 Merge branch 'external-share-include-subject' 2022-12-13 09:18:42 +01:00
sk
021fc9e5a0 add empty line after subject
closes #149
2022-12-13 09:18:18 +01:00
sk
a48c11332c Merge branch 'feature/translate-button' 2022-12-13 09:15:34 +01:00
sk
93bccc02bf add missing language null check
fix #143
2022-12-13 09:15:15 +01:00
sk
7a594be3f2 update metadata 2022-12-13 00:03:37 +01:00
sk
c9f4df3d4e bump version, update changelog 2022-12-12 23:35:54 +01:00
sk22
9078667d51 Translated using Weblate (German)
Currently translated at 100.0% (59 of 59 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-12 22:29:04 +00:00
sk
7569e1aef6 add strings back 2022-12-12 23:26:52 +01:00
nitrogenez
723983dadf Translated using Weblate (Ukrainian)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2022-12-12 22:25:44 +00:00
lunarna
f87e020abd Translated using Weblate (Polish)
Currently translated at 25.0% (2 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pl/
2022-12-12 22:25:44 +00:00
AiOO
fb5729d5cc Translated using Weblate (Korean)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-12 22:25:44 +00:00
Adolfo Jayme Barrientos
2ff6c53d6d Translated using Weblate (Spanish)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-12 22:25:44 +00:00
edxkl
cfc6895711 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2022-12-12 22:25:44 +00:00
Choukajohn
1c27fc68ee Translated using Weblate (French)
Currently translated at 100.0% (8 of 8 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-12 22:25:44 +00:00
nitrogenez
df0d578573 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2022-12-12 22:25:44 +00:00
edxkl
2fa3c69af1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 96.4% (54 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-12 22:25:44 +00:00
lunarna
095bf92fed Translated using Weblate (Polish)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2022-12-12 22:25:44 +00:00
Choukajohn
debe017f12 Translated using Weblate (French)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-12 22:25:44 +00:00
Adolfo Jayme Barrientos
f956e12167 Translated using Weblate (Spanish)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-12 22:25:44 +00:00
AiOO
2c50c38d82 Translated using Weblate (Korean)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-12 22:25:44 +00:00
sk22
b4980101ad Translated using Weblate (German)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2022-12-12 22:25:44 +00:00
sk22
8395fca60f Translated using Weblate (English)
Currently translated at 100.0% (56 of 56 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/en/
2022-12-12 22:25:44 +00:00
AiOO
b22e7d277f Translated using Weblate (Korean)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/ko/
2022-12-12 22:25:44 +00:00
edxkl
c0e67593ee Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/pt_BR/
2022-12-12 22:25:44 +00:00
edxkl
5dc4235724 Translated using Weblate (Portuguese (Brazil))
Currently translated at 97.8% (46 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-12 22:25:43 +00:00
kaea
f77caeefae Translated using Weblate (Polish)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pl/
2022-12-12 22:25:43 +00:00
Adolfo Jayme Barrientos
c1ef23bbe8 Translated using Weblate (Spanish)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-12 22:25:43 +00:00
plutonemhikari
e7e80bcf7d Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2022-12-12 22:25:43 +00:00
AiOO
c27f5aaf30 Translated using Weblate (Korean)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ko/
2022-12-12 22:25:43 +00:00
gallegonovato
d52728f22e Translated using Weblate (Spanish)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/es/
2022-12-12 22:25:43 +00:00
Christian Elbrianno
3c7c962320 Translated using Weblate (Indonesian)
Currently translated at 71.4% (5 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/id/
2022-12-12 22:25:43 +00:00
Choukajohn
abf570d177 Translated using Weblate (French)
Currently translated at 100.0% (7 of 7 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/fr/
2022-12-12 22:25:43 +00:00
edxkl
46422cd62d Translated using Weblate (Portuguese (Brazil))
Currently translated at 93.6% (44 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/pt_BR/
2022-12-12 22:25:43 +00:00
tippete
f1ffa2629e Translated using Weblate (Italian)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/it/
2022-12-12 22:25:43 +00:00
Christian Elbrianno
2074f3c33b Translated using Weblate (Indonesian)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2022-12-12 22:25:43 +00:00
Choukajohn
7c51803674 Translated using Weblate (French)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2022-12-12 22:25:43 +00:00
Adolfo Jayme Barrientos
6d80c62f30 Translated using Weblate (Spanish)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-12 22:25:43 +00:00
gallegonovato
64907a7e1c Translated using Weblate (Spanish)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2022-12-12 22:25:43 +00:00
ca
17922ca1d5 Translated using Weblate (Catalan)
Currently translated at 100.0% (47 of 47 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ca/
2022-12-12 22:25:43 +00:00
sk
01ac219854 remove strings 2022-12-12 23:25:31 +01:00
sk
9bbf8c4618 add custom login fragment 2022-12-12 23:18:01 +01:00
sk
978beaec77 use system default language for translation
fix #144
2022-12-12 09:09:45 +01:00
sk
0950e2eb7f Merge branch 'better-poll-voting' 2022-12-10 22:40:46 +01:00
sk
116328adb9 hide icons in own polls
closes #137
2022-12-10 22:40:35 +01:00
sk
32a2c66c34 Merge branch 'feature/language-selector' 2022-12-10 22:30:25 +01:00
sk
231ea46f9f change wording in string 2022-12-10 22:29:22 +01:00
sk
661f545e35 Merge branch 'feature/language-selector' 2022-12-10 22:24:05 +01:00
sk
600be455a3 save languages per account 2022-12-10 22:17:51 +01:00
sk
a4df06726f don't add to recent languages if replying 2022-12-10 21:31:04 +01:00
sk
e45e2c31d1 use mastodon languages list
fix #139
2022-12-10 21:07:34 +01:00
sk
d1e0cd3c20 Merge branch 'feature/display-reply-visibility' 2022-12-10 17:55:41 +01:00
sk
db16dde073 fix wrong visibility in reply
fix #140
2022-12-10 17:55:29 +01:00
sk
b3fe44bc08 update push settings on app start
fix #138, hopefully
2022-12-10 17:37:09 +01:00
sk
e5fab4a555 update changelog, bump version 2022-12-09 21:25:24 +01:00
sk
abe28179ec use saved default status visibility 2022-12-09 21:23:20 +01:00
sk
60d4e4d396 use default posting language 2022-12-09 21:15:11 +01:00
sk
435e73d718 Merge branch 'feature/language-selector' 2022-12-09 20:56:09 +01:00
sk
17dc0850d5 apply language when replying 2022-12-09 20:53:56 +01:00
sk
9667a32e44 save recently used languages 2022-12-09 20:48:51 +01:00
sk
4e6ba84bb3 implement language selector 2022-12-09 19:34:43 +01:00
140 changed files with 3695 additions and 978 deletions

View File

@@ -134,6 +134,7 @@ There's also a handful of custom strings exclusive to this projects that would n
* [Add push notification setting for post notifications](https://github.com/sk22/megalodon/commit/b190480d7739be47f23543d9e7644660f9b4b4ee)
* [Add option to allow voting for multiple options on polls](https://github.com/sk22/megalodon/commit/5b28468efd49387b4f8b83f142f3adf3104ca60c)
* [Add translate function](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/translate-button)
* [Add language selector](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/language-selector)
### Behavior
@@ -160,6 +161,10 @@ There's also a handful of custom strings exclusive to this projects that would n
* [Profile header tweaks](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:ui/profile-header-tweaks)
* [Custom color themes](https://github.com/sk22/megalodon/pull/124) by [@LucasGGamerM](https://github.com/LucasGGamerM)
* [Custom "megalodon" text logo](https://github.com/sk22/megalodon/commit/563afd487ca5c608cfbb00fa3909d3c27384acc0) by [@LucasGGamerM](https://github.com/LucasGGamerM)
* [Custom login screen](https://github.com/sk22/megalodon/commit/9bbf8c4618dbe13accaeb3b5482bf3fe88cac4c0)
* [More distinct filled boost icon](https://github.com/sk22/megalodon/commits/more-distinct-filled-boost-icon)
* [Material You color theme] by [@LucasGGamerM](https://github.com/LucasGGamerM)
* [Animations for interaction buttons](https://github.com/mastodon/mastodon-android/compare/master...sk22:megalodon:feature/animate-buttons)
## Building

View File

@@ -9,13 +9,10 @@ android {
applicationId "org.joinmastodon.android.sk"
minSdk 23
targetSdk 33
versionCode 57
versionName "1.1.4+fork.57"
versionCode 60
versionName "1.1.5+fork.60"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resConfigs "en", "ar-rSA", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES",
"eu-rES", "fi-rFI", "fr-rFR", "gl-rES", "hr-rHR", "hy-rAM", "it-rIT", "iw-rIL",
"ja-rJP", "kab", "ko-rKR", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ru-rRU",
"sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
resConfigs "ar-rSA", "be-rBY", "bn-rBD", "bs-rBA", "ca-rES", "cs-rCZ", "de-rDE", "el-rGR", "es-rES", "eu-rES", "fi-rFI", "fil-rPH", "fr-rFR", "ga-rIE", "gd-rGB", "gl-rES", "hi-rIN", "hr-rHR", "hu-rHU", "hy-rAM", "in-rID", "is-rIS", "it-rIT", "iw-rIL", "ja-rJP", "kab", "ko-rKR", "nl-rNL", "oc-rFR", "pl-rPL", "pt-rBR", "pt-rPT", "ro-rRO", "ru-rRU", "si-rLK", "sl-rSI", "sv-rSE", "th-rTH", "tr-rTR", "uk-rUA", "vi-rVN", "zh-rCN", "zh-rTW"
}
buildTypes {
@@ -80,4 +77,4 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.4-alpha05'
androidTestImplementation 'androidx.test:runner:1.5.0-alpha02'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0-alpha05'
}
}

View File

@@ -52,7 +52,7 @@ public class ExternalShareActivity extends FragmentStackActivity{
Intent intent=getIntent();
StringBuilder builder=new StringBuilder();
if (intent.hasExtra(Intent.EXTRA_SUBJECT)) builder.append(intent.getStringExtra(Intent.EXTRA_SUBJECT)).append("\n");
if (intent.hasExtra(Intent.EXTRA_SUBJECT)) builder.append(intent.getStringExtra(Intent.EXTRA_SUBJECT)).append("\n\n");
if (intent.hasExtra(Intent.EXTRA_TEXT)) builder.append(intent.getStringExtra(Intent.EXTRA_TEXT)).append("\n");
String text=builder.toString();
List<Uri> mediaUris;

View File

@@ -1,8 +1,20 @@
package org.joinmastodon.android;
import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.annotation.NonNull;
import com.google.gson.JsonSyntaxException;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class GlobalUserPreferences{
public static boolean playGifs;
public static boolean useCustomTabs;
@@ -18,10 +30,18 @@ public class GlobalUserPreferences{
public static ThemePreference theme;
public static ColorPreference color;
private final static Type recentLanguagesType = new TypeToken<Map<String, List<String>>>() {}.getType();
public static Map<String, List<String>> recentLanguages;
private static SharedPreferences getPrefs(){
return MastodonApp.context.getSharedPreferences("global", Context.MODE_PRIVATE);
}
private static <T> T fromJson(String json, Type type, T orElse) {
try { return gson.fromJson(json, type); }
catch (JsonSyntaxException ignored) { return orElse; }
}
public static void load(){
SharedPreferences prefs=getPrefs();
playGifs=prefs.getBoolean("playGifs", true);
@@ -36,7 +56,14 @@ public class GlobalUserPreferences{
disableMarquee=prefs.getBoolean("disableMarquee", false);
voteButtonForSingleChoice=prefs.getBoolean("voteButtonForSingleChoice", true);
theme=ThemePreference.values()[prefs.getInt("theme", 0)];
color=ColorPreference.values()[prefs.getInt("color", 0)];
recentLanguages=fromJson(prefs.getString("recentLanguages", "{}"), recentLanguagesType, new HashMap<>());
try {
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.PINK.name()));
} catch (IllegalArgumentException|ClassCastException ignored) {
// invalid color name or color was previously saved as integer
color=ColorPreference.PINK;
}
}
public static void save(){
@@ -52,16 +79,20 @@ public class GlobalUserPreferences{
.putBoolean("alwaysExpandContentWarnings", alwaysExpandContentWarnings)
.putBoolean("disableMarquee", disableMarquee)
.putInt("theme", theme.ordinal())
.putInt("color", color.ordinal())
.putString("color", color.name())
.putString("recentLanguages", gson.toJson(recentLanguages))
.apply();
}
public enum ColorPreference{
MATERIAL3,
PINK,
PURPLE,
GREEN,
BLUE,
BROWN,
RED,
ORANGE,
YELLOW
}

View File

@@ -14,9 +14,9 @@ import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.ComposeFragment;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.SplashFragment;
import org.joinmastodon.android.fragments.ThreadFragment;
import org.joinmastodon.android.fragments.onboarding.AccountActivationFragment;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
@@ -33,7 +33,7 @@ public class MainActivity extends FragmentStackActivity{
if(savedInstanceState==null){
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
showFragmentClearingBackStack(new SplashFragment());
showFragmentClearingBackStack(new CustomWelcomeFragment());
}else{
AccountSessionManager.getInstance().maybeUpdateLocalInfo();
AccountSession session;

View File

@@ -64,7 +64,7 @@ public class OAuthActivity extends Activity{
.setCallback(new Callback<>(){
@Override
public void onSuccess(Account account){
AccountSessionManager.getInstance().addAccount(instance, token, account, app, true);
AccountSessionManager.getInstance().addAccount(instance, token, account, app, null);
progress.dismiss();
finish();
// not calling restartMainActivity() here on purpose to have it recreated (notice different flags)

View File

@@ -370,7 +370,7 @@ public class PushSubscriptionManager{
for(AccountSession session:AccountSessionManager.getInstance().getLoggedInAccounts()){
if(session.pushSubscription==null || forceReRegister)
session.getPushSubscriptionManager().registerAccountForPush(session.pushSubscription);
else if(session.needUpdatePushSettings)
else
session.getPushSubscriptionManager().updatePushSettings(session.pushSubscription);
}
}

View File

@@ -11,6 +11,7 @@ import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.model.Status;
import java.util.HashMap;
import java.util.function.Consumer;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
@@ -25,7 +26,7 @@ public class StatusInteractionController{
this.accountID=accountID;
}
public void setFavorited(Status status, boolean favorited){
public void setFavorited(Status status, boolean favorited, Consumer<Status> cb){
if(!Looper.getMainLooper().isCurrentThread())
throw new IllegalStateException("Can only be called from main thread");
@@ -38,6 +39,8 @@ public class StatusInteractionController{
@Override
public void onSuccess(Status result){
runningFavoriteRequests.remove(status.id);
result.favouritesCount = Math.max(0, status.favouritesCount) + (favorited ? 1 : -1);
cb.accept(result);
E.post(new StatusCountersUpdatedEvent(result));
}
@@ -46,24 +49,17 @@ public class StatusInteractionController{
runningFavoriteRequests.remove(status.id);
error.showToast(MastodonApp.context);
status.favourited=!favorited;
if(favorited)
status.favouritesCount--;
else
status.favouritesCount++;
cb.accept(status);
E.post(new StatusCountersUpdatedEvent(status));
}
})
.exec(accountID);
runningFavoriteRequests.put(status.id, req);
status.favourited=favorited;
if(favorited)
status.favouritesCount++;
else
status.favouritesCount--;
E.post(new StatusCountersUpdatedEvent(status));
}
public void setReblogged(Status status, boolean reblogged){
public void setReblogged(Status status, boolean reblogged, Consumer<Status> cb){
if(!Looper.getMainLooper().isCurrentThread())
throw new IllegalStateException("Can only be called from main thread");
@@ -76,6 +72,8 @@ public class StatusInteractionController{
@Override
public void onSuccess(Status result){
runningReblogRequests.remove(status.id);
result.reblogsCount = Math.max(0, status.reblogsCount) + (reblogged ? 1 : -1);
cb.accept(result);
E.post(new StatusCountersUpdatedEvent(result));
}
@@ -84,24 +82,21 @@ public class StatusInteractionController{
runningReblogRequests.remove(status.id);
error.showToast(MastodonApp.context);
status.reblogged=!reblogged;
if(reblogged)
status.reblogsCount--;
else
status.reblogsCount++;
cb.accept(status);
E.post(new StatusCountersUpdatedEvent(status));
}
})
.exec(accountID);
runningReblogRequests.put(status.id, req);
status.reblogged=reblogged;
if(reblogged)
status.reblogsCount++;
else
status.reblogsCount--;
E.post(new StatusCountersUpdatedEvent(status));
}
public void setBookmarked(Status status, boolean bookmarked){
setBookmarked(status, bookmarked, r->{});
}
public void setBookmarked(Status status, boolean bookmarked, Consumer<Status> cb){
if(!Looper.getMainLooper().isCurrentThread())
throw new IllegalStateException("Can only be called from main thread");
@@ -114,6 +109,7 @@ public class StatusInteractionController{
@Override
public void onSuccess(Status result){
runningBookmarkRequests.remove(status.id);
cb.accept(result);
E.post(new StatusCountersUpdatedEvent(result));
}
@@ -122,6 +118,7 @@ public class StatusInteractionController{
runningBookmarkRequests.remove(status.id);
error.showToast(MastodonApp.context);
status.bookmarked=!bookmarked;
cb.accept(status);
E.post(new StatusCountersUpdatedEvent(status));
}
})

View File

@@ -0,0 +1,11 @@
package org.joinmastodon.android.api.session;
public class AccountActivationInfo{
public String email;
public long lastEmailConfirmationResend;
public AccountActivationInfo(String email, long lastEmailConfirmationResend){
this.email=email;
this.lastEmailConfirmationResend=lastEmailConfirmationResend;
}
}

View File

@@ -30,17 +30,19 @@ public class AccountSession{
public List<Filter> wordFilters=new ArrayList<>();
public String pushAccountID;
public Preferences preferences;
public AccountActivationInfo activationInfo;
private transient MastodonAPIController apiController;
private transient StatusInteractionController statusInteractionController;
private transient CacheController cacheController;
private transient PushSubscriptionManager pushSubscriptionManager;
AccountSession(Token token, Account self, Application app, String domain, boolean activated){
AccountSession(Token token, Account self, Application app, String domain, boolean activated, AccountActivationInfo activationInfo){
this.token=token;
this.self=self;
this.domain=domain;
this.app=app;
this.activated=activated;
this.activationInfo=activationInfo;
infoLastUpdated=System.currentTimeMillis();
}

View File

@@ -102,9 +102,9 @@ public class AccountSessionManager{
maybeUpdateShortcuts();
}
public void addAccount(Instance instance, Token token, Account self, Application app, boolean active){
public void addAccount(Instance instance, Token token, Account self, Application app, AccountActivationInfo activationInfo){
instances.put(instance.uri, instance);
AccountSession session=new AccountSession(token, self, app, instance.uri, active);
AccountSession session=new AccountSession(token, self, app, instance.uri, activationInfo==null, activationInfo);
sessions.put(session.getID(), session);
lastActiveAccountID=session.getID();
writeAccountsFile();

View File

@@ -1,5 +1,9 @@
package org.joinmastodon.android.fragments;
import static org.joinmastodon.android.GlobalUserPreferences.recentLanguages;
import static org.joinmastodon.android.utils.MastodonLanguage.allLanguages;
import static org.joinmastodon.android.utils.MastodonLanguage.defaultRecentLanguages;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
@@ -29,11 +33,13 @@ import android.text.Spanned;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
@@ -55,6 +61,7 @@ import android.widget.Toast;
import com.twitter.twittertext.TwitterTextEmojiRegex;
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.MastodonAPIController;
@@ -95,6 +102,7 @@ import org.joinmastodon.android.ui.views.ComposeEditText;
import org.joinmastodon.android.ui.views.ComposeMediaLayout;
import org.joinmastodon.android.ui.views.ReorderableLinearLayout;
import org.joinmastodon.android.ui.views.SizeListenerLinearLayout;
import org.joinmastodon.android.utils.MastodonLanguage;
import org.parceler.Parcel;
import org.parceler.Parcels;
@@ -105,6 +113,7 @@ import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -145,7 +154,8 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private String accountID;
private int charCount, charLimit, trimmedCharCount;
private Button publishButton;
private Button publishButton, languageButton;
private PopupMenu languagePopup;
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, visibilityBtn;
private ImageView sensitiveIcon;
private ComposeMediaLayout attachmentsView;
@@ -190,6 +200,9 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private boolean ignoreSelectionChanges=false;
private Runnable updateUploadEtaRunnable;
private String language;
private MastodonLanguage.LanguageResolver languageResolver;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
@@ -201,6 +214,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
instanceDomain=session.domain;
customEmojis=AccountSessionManager.getInstance().getCustomEmojis(instanceDomain);
instance=AccountSessionManager.getInstance().getInstanceInfo(instanceDomain);
languageResolver=new MastodonLanguage.LanguageResolver(instance);
if(getArguments().containsKey("editStatus")){
editingStatus=Parcels.unwrap(getArguments().getParcelable("editStatus"));
redraftStatus=getArguments().getBoolean("redraftStatus");
@@ -219,8 +233,6 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
charLimit=instance.configuration.statuses.maxCharacters;
else
charLimit=500;
loadDefaultStatusVisibility(savedInstanceState);
}
@Override
@@ -375,6 +387,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
statusVisibility=editingStatus.visibility;
}
loadDefaultStatusVisibility(savedInstanceState);
updateVisibilityIcon();
autocompleteViewController=new ComposeAutocompleteViewController(getActivity(), accountID);
@@ -403,6 +416,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
outState.putBoolean("sensitive", sensitive);
outState.putBoolean("hasSpoiler", hasSpoiler);
outState.putString("language", language);
if(!attachments.isEmpty()){
ArrayList<Parcelable> serializedAttachments=new ArrayList<>(attachments.size());
for(DraftMediaAttachment att:attachments){
@@ -494,14 +508,14 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
spoilerEdit.addTextChangedListener(new SimpleTextWatcher(e->updateCharCounter()));
if(replyTo!=null){
replyText.setText(getString(R.string.in_reply_to, replyTo.account.displayName));
int visibilityNameRes = switch (statusVisibility) {
int visibilityNameRes = switch (replyTo.visibility) {
case PUBLIC -> R.string.visibility_public;
case UNLISTED -> R.string.sk_visibility_unlisted;
case PRIVATE -> R.string.visibility_followers_only;
case DIRECT -> R.string.visibility_private;
};
replyText.setContentDescription(getString(R.string.in_reply_to, replyTo.account.displayName) + ". " + getString(R.string.post_visibility) + ": " + getString(visibilityNameRes));
Drawable visibilityIcon = getActivity().getDrawable(switch(statusVisibility){
Drawable visibilityIcon = getActivity().getDrawable(switch(replyTo.visibility){
case PUBLIC -> R.drawable.ic_fluent_earth_20_regular;
case UNLISTED -> R.drawable.ic_fluent_people_community_20_regular;
case PRIVATE -> R.drawable.ic_fluent_people_checkmark_20_regular;
@@ -542,6 +556,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
spoilerEdit.setText(replyTo.spoilerText);
spoilerBtn.setSelected(true);
}
if (replyTo.language != null && !replyTo.language.isEmpty()) updateLanguage(replyTo.language);
}
}else if (editingStatus==null || editingStatus.inReplyToId==null){
// TODO: remove workaround after https://github.com/mastodon/mastodon-android/issues/341 gets fixed
@@ -554,6 +569,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
ignoreSelectionChanges=true;
mainEditText.setSelection(mainEditText.length());
ignoreSelectionChanges=false;
updateLanguage(editingStatus.language);
if(!editingStatus.mediaAttachments.isEmpty()){
attachmentsView.setVisibility(View.VISIBLE);
for(Attachment att:editingStatus.mediaAttachments){
@@ -616,6 +632,10 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
sendError.setVisibility(View.GONE);
sendProgress.setVisibility(View.GONE);
LinearLayout.LayoutParams langParams=new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
langParams.setMarginEnd(V.dp(8));
wrap.addView(buildLanguageSelector(), langParams);
wrap.addView(publishButton, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
wrap.setPadding(V.dp(16), V.dp(4), V.dp(16), V.dp(8));
wrap.setClipToPadding(false);
@@ -625,6 +645,59 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
updatePublishButtonState();
}
private void updateLanguage(String lang) {
updateLanguage(languageResolver.from(lang));
}
private void updateLanguage(MastodonLanguage loc) {
language = loc.getLanguage();
languageButton.setText(loc.getLanguageName());
languageButton.setContentDescription(getActivity().getString(R.string.sk_post_language, loc.getDefaultName()));
}
@SuppressLint("ClickableViewAccessibility")
private Button buildLanguageSelector() {
TypedValue typedValue = new TypedValue();
getActivity().getTheme().resolveAttribute(android.R.attr.textColorSecondary, typedValue, true);
languageButton=new Button(getActivity());
languageButton.setTextColor(typedValue.data);
languageButton.setBackground(getActivity().getDrawable(R.drawable.bg_text_button));
languageButton.setPadding(V.dp(8), 0, V.dp(8), 0);
languageButton.setCompoundDrawablesRelativeWithIntrinsicBounds(getActivity().getDrawable(R.drawable.ic_fluent_local_language_16_regular), null, null, null);
languageButton.setCompoundDrawableTintList(languageButton.getTextColors());
languageButton.setCompoundDrawablePadding(V.dp(6));
languagePopup=new PopupMenu(getActivity(), languageButton);
languageButton.setOnTouchListener(languagePopup.getDragToOpenListener());
languageButton.setOnClickListener(v->languagePopup.show());
Preferences prefs = AccountSessionManager.getInstance().getAccount(accountID).preferences;
updateLanguage(prefs != null && prefs.postingDefaultLanguage != null && prefs.postingDefaultLanguage.length() > 0
? languageResolver.from(prefs.postingDefaultLanguage)
: languageResolver.getDefault());
Menu languageMenu = languagePopup.getMenu();
for (String recentLanguage : Optional.ofNullable(recentLanguages.get(accountID)).orElse(defaultRecentLanguages)) {
MastodonLanguage l = languageResolver.from(recentLanguage);
languageMenu.add(0, allLanguages.indexOf(l), Menu.NONE, getActivity().getString(R.string.sk_language_name, l.getDefaultName(), l.getLanguageName()));
}
SubMenu allLanguagesMenu = languageMenu.addSubMenu(R.string.sk_available_languages);
for (int i = 0; i < allLanguages.size(); i++) {
MastodonLanguage l = allLanguages.get(i);
allLanguagesMenu.add(0, i, Menu.NONE, getActivity().getString(R.string.sk_language_name, l.getDefaultName(), l.getLanguageName()));
}
languagePopup.setOnMenuItemClickListener(i->{
if (i.hasSubMenu()) return false;
updateLanguage(allLanguages.get(i.getItemId()));
return true;
});
return languageButton;
}
@Override
public boolean onOptionsItemSelected(MenuItem item){
return true;
@@ -698,6 +771,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
req.status=text;
req.visibility=statusVisibility;
req.sensitive=sensitive;
req.language=language;
if(!attachments.isEmpty()){
req.mediaIds=attachments.stream().map(a->a.serverAttachment.id).collect(Collectors.toList());
}
@@ -775,6 +849,14 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
.setCallback(resCallback)
.exec(accountID);
}
if (replyTo == null) {
List<String> newRecentLanguages = new ArrayList<>(Optional.ofNullable(recentLanguages.get(accountID)).orElse(defaultRecentLanguages));
newRecentLanguages.remove(language);
newRecentLanguages.add(0, language);
recentLanguages.put(accountID, newRecentLanguages.stream().limit(4).collect(Collectors.toList()));
GlobalUserPreferences.save();
}
}
private boolean hasDraft(){
@@ -1358,34 +1440,23 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
}
new GetPreferences()
.setCallback(new Callback<>(){
@Override
public void onSuccess(Preferences result){
// Only override the reply visibility if our preference is more private
if (result.postingDefaultVisibility.isLessVisibleThan(statusVisibility)) {
statusVisibility = switch (result.postingDefaultVisibility) {
case PUBLIC -> StatusPrivacy.PUBLIC;
case UNLISTED -> StatusPrivacy.UNLISTED;
case PRIVATE -> StatusPrivacy.PRIVATE;
case DIRECT -> StatusPrivacy.DIRECT;
};
}
Preferences prefs = AccountSessionManager.getInstance().getAccount(accountID).preferences;
if (prefs != null) {
// Only override the reply visibility if our preference is more private
if (prefs.postingDefaultVisibility.isLessVisibleThan(statusVisibility)) {
statusVisibility = switch (prefs.postingDefaultVisibility) {
case PUBLIC -> StatusPrivacy.PUBLIC;
case UNLISTED -> StatusPrivacy.UNLISTED;
case PRIVATE -> StatusPrivacy.PRIVATE;
case DIRECT -> StatusPrivacy.DIRECT;
};
}
// A saved privacy setting from a previous compose session wins over all
if(savedInstanceState !=null){
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
}
updateVisibilityIcon ();
}
@Override
public void onError(ErrorResponse error){
Log.w(TAG, "Unable to get user preferences to set default post privacy");
}
})
.exec(accountID);
// A saved privacy setting from a previous compose session wins over all
if(savedInstanceState !=null){
statusVisibility = (StatusPrivacy) savedInstanceState.getSerializable("visibility");
}
}
}
private void updateVisibilityIcon(){

View File

@@ -302,7 +302,7 @@ public class FollowRequestsListFragment extends BaseRecyclerFragment<FollowReque
RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter = getBindingAdapter();
if (!rel.requested && !rel.followedBy && adapter != null) {
data.remove(item);
adapter.notifyItemRemoved(getBindingAdapterPosition());
adapter.notifyItemRemoved(getLayoutPosition());
} else {
rebind();
}

View File

@@ -11,6 +11,7 @@ import android.os.Build;
import android.os.Bundle;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -31,6 +32,7 @@ import com.squareup.otto.Subscribe;
import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.E;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.GlobalUserPreferences.ColorPreference;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
@@ -48,6 +50,7 @@ import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.updater.GithubSelfUpdater;
import java.util.ArrayList;
import java.util.Objects;
import java.util.function.Consumer;
import androidx.annotation.DrawableRes;
@@ -159,6 +162,10 @@ public class SettingsFragment extends MastodonToolbarFragment{
}
items.add(new TextItem(R.string.sk_settings_contribute, ()->UiUtils.launchWebBrowser(getActivity(), "https://github.com/sk22/megalodon")));
items.add(new TextItem(R.string.settings_clear_cache, this::clearImageCache));
items.add(new TextItem(R.string.sk_clear_recent_languages, ()->UiUtils.showConfirmationAlert(getActivity(), R.string.sk_clear_recent_languages, R.string.sk_confirm_clear_recent_languages, R.string.clear, ()->{
GlobalUserPreferences.recentLanguages.remove(accountID);
GlobalUserPreferences.save();
})));
items.add(new TextItem(R.string.log_out, this::confirmLogOut));
items.add(new FooterItem(getString(R.string.sk_settings_app_version, BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE)));
@@ -236,10 +243,25 @@ public class SettingsFragment extends MastodonToolbarFragment{
restartActivityToApplyNewTheme();
}
private void onColorPreferenceClick(GlobalUserPreferences.ColorPreference color){
GlobalUserPreferences.color=color;
private boolean onColorPreferenceClick(MenuItem item){
ColorPreference pref = null;
int id = item.getItemId();
if (id == R.id.m3_color) pref = ColorPreference.MATERIAL3;
else if (id == R.id.pink_color) pref = ColorPreference.PINK;
else if (id == R.id.purple_color) pref = ColorPreference.PURPLE;
else if (id == R.id.green_color) pref = ColorPreference.GREEN;
else if (id == R.id.blue_color) pref = ColorPreference.BLUE;
else if (id == R.id.brown_color) pref = ColorPreference.BROWN;
else if (id == R.id.red_color) pref = ColorPreference.RED;
else if (id == R.id.yellow_color) pref = ColorPreference.YELLOW;
if (pref == null) return false;
GlobalUserPreferences.color=pref;
GlobalUserPreferences.save();
restartActivityToApplyNewTheme();
return true;
}
private void onTrueBlackThemeChanged(SwitchItem item){
@@ -677,38 +699,7 @@ public class SettingsFragment extends MastodonToolbarFragment{
button=findViewById(R.id.color_picker_button);
popupMenu=new PopupMenu(getActivity(), button, Gravity.CENTER_HORIZONTAL);
popupMenu.inflate(R.menu.color_picker);
popupMenu.setOnMenuItemClickListener(item->{
GlobalUserPreferences.ColorPreference pref;
int id=item.getItemId();
if(id==R.id.pink_color) {
pref = GlobalUserPreferences.ColorPreference.PINK;
onColorPreferenceClick(pref);
}
else if(id==R.id.purple_color) {
pref = GlobalUserPreferences.ColorPreference.PURPLE;
onColorPreferenceClick(pref);
}
else if(id==R.id.green_color) {
pref = GlobalUserPreferences.ColorPreference.GREEN;
onColorPreferenceClick(pref);
}
else if(id==R.id.blue_color) {
pref = GlobalUserPreferences.ColorPreference.BLUE;
onColorPreferenceClick(pref);
}
else if(id==R.id.brown_color) {
pref = GlobalUserPreferences.ColorPreference.BROWN;
onColorPreferenceClick(pref);
}
else if(id==R.id.yellow_color) {
pref = GlobalUserPreferences.ColorPreference.YELLOW;
onColorPreferenceClick(pref);
}
else
return false;
return true;
});
// UiUtils.enablePopupMenuIcons(getActivity(), popupMenu);
popupMenu.setOnMenuItemClickListener(SettingsFragment.this::onColorPreferenceClick);
button.setOnTouchListener(popupMenu.getDragToOpenListener());
button.setOnClickListener(v->popupMenu.show());
}
@@ -717,12 +708,15 @@ public class SettingsFragment extends MastodonToolbarFragment{
public void onBind(ColorPicker item){
icon.setImageResource(R.drawable.ic_fluent_color_24_regular);
button.setText(switch(GlobalUserPreferences.color){
case MATERIAL3 -> R.string.sk_color_theme_material3;
case PINK -> R.string.sk_color_theme_pink;
case PURPLE -> R.string.sk_color_theme_purple;
case GREEN -> R.string.sk_color_theme_green;
case BLUE -> R.string.sk_color_theme_blue;
case BROWN -> R.string.sk_color_theme_brown;
case RED -> R.string.sk_color_theme_red;
case YELLOW -> R.string.sk_color_theme_yellow;
default -> throw new IllegalStateException("Unexpected value: "+GlobalUserPreferences.color);
});
}
}

View File

@@ -5,7 +5,6 @@ import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.style.ImageSpan;
import android.text.style.ReplacementSpan;
import android.view.LayoutInflater;
import android.view.View;
@@ -15,17 +14,14 @@ import android.view.WindowInsets;
import android.widget.LinearLayout;
import android.widget.TextView;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.onboarding.InstanceCatalogSignupFragment;
import org.joinmastodon.android.fragments.onboarding.InstanceChooserLoginFragment;
import org.joinmastodon.android.ui.InterpolatingMotionEffect;
import org.joinmastodon.android.ui.views.SizeListenerFrameLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.PagerAdapter;
import androidx.viewpager2.widget.ViewPager2;
import me.grishka.appkit.Nav;
import me.grishka.appkit.fragments.AppKitFragment;

View File

@@ -177,7 +177,7 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
public void onStatusCountersUpdated(StatusCountersUpdatedEvent ev){
for(Status s:data){
if(s.getContentStatus().id.equals(ev.id)){
s.update(ev);
s.getContentStatus().update(ev);
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder instanceof FooterStatusDisplayItem.Holder footer && footer.getItem().status==s.getContentStatus()){

View File

@@ -23,6 +23,7 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.ListTimelinesFragment;
import org.joinmastodon.android.fragments.ProfileFragment;
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
import org.joinmastodon.android.model.Account;
@@ -286,6 +287,7 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
menu.findItem(R.id.mute).setTitle(getString(relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getDisplayUsername()));
menu.findItem(R.id.block).setTitle(getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getDisplayUsername()));
menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getDisplayUsername()));
menu.findItem(R.id.manage_user_lists).setTitle(getString(R.string.sk_lists_with_user, account.getDisplayUsername())).setVisible(relationship.following);
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
MenuItem manageUserLists=menu.findItem(R.id.manage_user_lists);
if(relationship.following){
@@ -372,6 +374,12 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
})
.wrapProgress(getActivity(), R.string.loading, false)
.exec(accountID);
}else if(id==R.id.manage_user_lists){
final Bundle args=new Bundle();
args.putString("account", accountID);
args.putString("profileAccount", account.id);
args.putString("profileDisplayUsername", account.getDisplayUsername());
Nav.go(getActivity(), ListTimelinesFragment.class, args);
}
return true;
}

View File

@@ -1,8 +1,8 @@
package org.joinmastodon.android.fragments.onboarding;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
@@ -12,19 +12,21 @@ import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import org.joinmastodon.android.MainActivity;
import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
import org.joinmastodon.android.api.requests.accounts.ResendConfirmationEmail;
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
import org.joinmastodon.android.api.session.AccountActivationInfo;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.SettingsFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.ui.AccountSwitcherSheet;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.io.File;
@@ -35,40 +37,50 @@ import me.grishka.appkit.Nav;
import me.grishka.appkit.api.APIRequest;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.fragments.AppKitFragment;
import me.grishka.appkit.fragments.ToolbarFragment;
import me.grishka.appkit.utils.V;
public class AccountActivationFragment extends AppKitFragment{
public class AccountActivationFragment extends ToolbarFragment{
private String accountID;
private Button btn, backBtn;
private View buttonBar;
private Button openEmailBtn, resendBtn;
private View contentView;
private Handler uiHandler=new Handler(Looper.getMainLooper());
private Runnable pollRunnable=this::tryGetAccount;
private APIRequest currentRequest;
private Runnable resendTimer=this::updateResendTimer;
private long lastResendTime;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
accountID=getArguments().getString("account");
setTitle(R.string.confirm_email_title);
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
lastResendTime=session.activationInfo!=null ? session.activationInfo.lastEmailConfirmationResend : 0;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
public View onCreateContentView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
View view=inflater.inflate(R.layout.fragment_onboarding_activation, container, false);
btn=view.findViewById(R.id.btn_next);
btn.setOnClickListener(v->onButtonClick());
btn.setOnLongClickListener(v->{
openEmailBtn=view.findViewById(R.id.btn_next);
openEmailBtn.setOnClickListener(this::onOpenEmailClick);
openEmailBtn.setOnLongClickListener(v->{
Bundle args=new Bundle();
args.putString("account", accountID);
Nav.go(getActivity(), SettingsFragment.class, args);
return true;
});
buttonBar=view.findViewById(R.id.button_bar);
view.findViewById(R.id.btn_back).setOnClickListener(v->onBackButtonClick());
resendBtn=view.findViewById(R.id.btn_resend);
resendBtn.setOnClickListener(this::onResendClick);
TextView text=view.findViewById(R.id.subtitle);
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
text.setText(getString(R.string.confirm_email_subtitle, session.activationInfo!=null ? session.activationInfo.email : "?"));
updateResendTimer();
contentView=view;
return view;
}
@@ -80,14 +92,32 @@ public class AccountActivationFragment extends AppKitFragment{
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLight));
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
}
@Override
protected void onUpdateToolbar(){
super.onUpdateToolbar();
getToolbar().setBackground(null);
getToolbar().setElevation(0);
}
@Override
protected boolean canGoBack(){
return true;
}
@Override
public void onToolbarNavigationClick(){
new AccountSwitcherSheet(getActivity()).show();
}
@Override
public void onApplyWindowInsets(WindowInsets insets){
if(Build.VERSION.SDK_INT>=27){
int inset=insets.getSystemWindowInsetBottom();
buttonBar.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(36)) : 0);
contentView.setPadding(0, 0, 0, inset>0 ? Math.max(inset, V.dp(36)) : 0);
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), 0));
}else{
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
@@ -111,7 +141,7 @@ public class AccountActivationFragment extends AppKitFragment{
}
}
private void onButtonClick(){
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){
@@ -119,12 +149,21 @@ public class AccountActivationFragment extends AppKitFragment{
}
}
private void onBackButtonClick(){
private void onResendClick(View v){
new ResendConfirmationEmail(null)
.setCallback(new Callback<>(){
@Override
public void onSuccess(Object result){
Toast.makeText(getActivity(), R.string.resent_email, Toast.LENGTH_SHORT).show();
AccountSession session=AccountSessionManager.getInstance().getAccount(accountID);
if(session.activationInfo==null){
session.activationInfo=new AccountActivationInfo("?", System.currentTimeMillis());
}else{
session.activationInfo.lastEmailConfirmationResend=System.currentTimeMillis();
}
lastResendTime=session.activationInfo.lastEmailConfirmationResend;
AccountSessionManager.getInstance().writeAccountsFile();
updateResendTimer();
}
@Override
@@ -152,7 +191,7 @@ public class AccountActivationFragment extends AppKitFragment{
AccountSessionManager mgr=AccountSessionManager.getInstance();
AccountSession session=mgr.getAccount(accountID);
mgr.removeAccount(accountID);
mgr.addAccount(mgr.getInstanceInfo(session.domain), session.token, result, session.app, true);
mgr.addAccount(mgr.getInstanceInfo(session.domain), session.token, result, session.app, null);
String newID=mgr.getLastActiveAccountID();
Bundle args=new Bundle();
args.putString("account", newID);
@@ -189,4 +228,25 @@ public class AccountActivationFragment extends AppKitFragment{
})
.exec(accountID);
}
@SuppressLint("DefaultLocale")
private void updateResendTimer(){
long sinceResend=System.currentTimeMillis()-lastResendTime;
if(sinceResend>59_000L){
resendBtn.setText(R.string.resend);
resendBtn.setEnabled(true);
return;
}
int seconds=(int)((60_000L-sinceResend)/1000L);
resendBtn.setText(String.format("%s (%d)", getString(R.string.resend), seconds));
if(resendBtn.isEnabled())
resendBtn.setEnabled(false);
resendBtn.postDelayed(resendTimer, 500);
}
@Override
public void onDestroyView(){
super.onDestroyView();
resendBtn.removeCallbacks(resendTimer);
}
}

View File

@@ -0,0 +1,260 @@
package org.joinmastodon.android.fragments.onboarding;
import android.content.Context;
import android.content.res.ColorStateList;
import android.os.Build;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RadioButton;
import android.widget.Space;
import android.widget.TextView;
import android.widget.Toolbar;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.catalog.CatalogInstance;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.ArrayList;
import java.util.Objects;
import me.grishka.appkit.FragmentStackActivity;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class CustomWelcomeFragment extends InstanceCatalogFragment {
private View headerView;
public CustomWelcomeFragment() {
super(R.layout.fragment_welcome_custom, 1);
}
@Override
public void onAttach(Context context){
super.onAttach(context);
setRefreshEnabled(false);
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
dataLoaded();
}
@Override
protected void onUpdateToolbar(){
super.onUpdateToolbar();
if (!canGoBack()) {
ImageView toolbarLogo=new ImageView(getActivity());
toolbarLogo.setScaleType(ImageView.ScaleType.CENTER);
toolbarLogo.setImageResource(R.drawable.logo);
toolbarLogo.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(getActivity(), android.R.attr.textColorPrimary)));
FrameLayout logoWrap=new FrameLayout(getActivity());
FrameLayout.LayoutParams logoParams=new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER);
logoParams.setMargins(0, V.dp(2), 0, 0);
logoWrap.addView(toolbarLogo, logoParams);
getToolbar().addView(logoWrap, new Toolbar.LayoutParams(Gravity.CENTER));
} else {
setTitle(R.string.add_account);
}
}
@Override
protected void proceedWithAuthOrSignup(Instance instance) {
AccountSessionManager.getInstance().authenticate(getActivity(), instance);
}
@Override
protected void updateFilteredList(){
boolean addFakeInstance = currentSearchQuery.length()>0 && currentSearchQuery.matches("^\\S+\\.[^\\.]+$");
if(addFakeInstance){
fakeInstance.domain=fakeInstance.normalizedDomain=currentSearchQuery;
fakeInstance.description=getString(R.string.loading_instance);
if(filteredData.size()>0 && filteredData.get(0)==fakeInstance){
if(list.findViewHolderForAdapterPosition(1) instanceof InstanceViewHolder ivh){
ivh.rebind();
}
}
if(filteredData.isEmpty()){
filteredData.add(fakeInstance);
adapter.notifyItemInserted(0);
}
}
ArrayList<CatalogInstance> prevData=new ArrayList<>(filteredData);
filteredData.clear();
if(currentSearchQuery.length()>0){
boolean foundExactMatch=false;
for(CatalogInstance inst:data){
if(inst.normalizedDomain.contains(currentSearchQuery)){
filteredData.add(inst);
if(inst.normalizedDomain.equals(currentSearchQuery))
foundExactMatch=true;
}
}
if(!foundExactMatch && addFakeInstance) {
filteredData.add(0, fakeInstance);
adapter.notifyItemChanged(0);
}
}
UiUtils.updateList(prevData, filteredData, list, adapter, Objects::equals);
for(int i=0;i<list.getChildCount();i++){
list.getChildAt(i).invalidateOutline();
}
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorWindowBackground));
list.setItemAnimator(new BetterItemAnimator());
}
@Override
protected void doLoadData(int offset, int count) {}
@Override
protected RecyclerView.Adapter getAdapter(){
headerView=getActivity().getLayoutInflater().inflate(R.layout.header_welcome_custom, list, false);
searchEdit=headerView.findViewById(R.id.search_edit);
searchEdit.setOnEditorActionListener(this::onSearchEnterPressed);
headerView.findViewById(R.id.more).setVisibility(View.GONE);
headerView.findViewById(R.id.visibility).setVisibility(View.GONE);
headerView.findViewById(R.id.separator).setVisibility(View.GONE);
headerView.findViewById(R.id.timestamp).setVisibility(View.GONE);
((TextView) headerView.findViewById(R.id.username)).setText(R.string.sk_app_username);
((TextView) headerView.findViewById(R.id.name)).setText(R.string.sk_app_name);
((ImageView) headerView.findViewById(R.id.avatar)).setImageDrawable(getActivity().getDrawable(R.mipmap.ic_launcher));
((FragmentStackActivity) getActivity()).invalidateSystemBarColors(this);
searchEdit.addTextChangedListener(new TextWatcher(){
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after){}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count){
nextButton.setEnabled(false);
chosenInstance = null;
searchEdit.removeCallbacks(searchDebouncer);
searchEdit.postDelayed(searchDebouncer, 300);
}
@Override
public void afterTextChanged(Editable s){}
});
mergeAdapter=new MergeRecyclerAdapter();
mergeAdapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
mergeAdapter.addAdapter(adapter=new InstancesAdapter());
View spacer = new Space(getActivity());
spacer.setMinimumHeight(V.dp(8));
mergeAdapter.addAdapter(new SingleViewRecyclerAdapter(spacer));
return mergeAdapter;
}
private class InstancesAdapter extends UsableRecyclerView.Adapter<InstanceViewHolder> {
public InstancesAdapter(){
super(imgLoader);
}
@NonNull
@Override
public InstanceViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType){
return new InstanceViewHolder();
}
@Override
public void onBindViewHolder(InstanceViewHolder holder, int position){
holder.bind(filteredData.get(position));
chosenInstance = filteredData.get(position);
if (chosenInstance != fakeInstance) nextButton.setEnabled(true);
super.onBindViewHolder(holder, position);
}
@Override
public int getItemCount(){
return filteredData.size();
}
@Override
public int getItemViewType(int position){
return -1;
}
}
private class InstanceViewHolder extends BindableViewHolder<CatalogInstance> implements UsableRecyclerView.Clickable{
private final TextView title, description, userCount, lang;
private final RadioButton radioButton;
public InstanceViewHolder(){
super(getActivity(), R.layout.item_instance_custom, list);
// itemView.setPadding(V.dp(16), V.dp(16), V.dp(16), V.dp(16));
// TypedValue value = new TypedValue();
// getActivity().getTheme().resolveAttribute(android.R.attr.selectableItemBackground, value, true);
// itemView.setBackground(getActivity().getTheme().getDrawable(R.drawable.bg_search_field));
title=findViewById(R.id.title);
description=findViewById(R.id.description);
userCount=findViewById(R.id.user_count);
lang=findViewById(R.id.lang);
radioButton=findViewById(R.id.radiobtn);
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N){
UiUtils.fixCompoundDrawableTintOnAndroid6(userCount);
UiUtils.fixCompoundDrawableTintOnAndroid6(lang);
}
}
@Override
public void onBind(CatalogInstance item){
title.setText(item.normalizedDomain);
description.setText(item.description);
if (item == fakeInstance) {
userCount.setVisibility(View.GONE);
lang.setVisibility(View.GONE);
} else {
userCount.setVisibility(View.VISIBLE);
lang.setVisibility(View.VISIBLE);
userCount.setText(UiUtils.abbreviateNumber(item.totalUsers));
lang.setText(item.language.toUpperCase());
}
radioButton.setChecked(chosenInstance==item);
radioButton.setVisibility(View.GONE);
}
@Override
public void onClick(){
if(chosenInstance!=null){
int idx=filteredData.indexOf(chosenInstance);
if(idx!=-1){
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(mergeAdapter.getPositionForAdapter(adapter)+idx);
if(holder instanceof InstanceViewHolder ivh){
ivh.radioButton.setChecked(false);
}
}
}
radioButton.setChecked(true);
if(chosenInstance==null)
nextButton.setEnabled(true);
chosenInstance=item;
loadInstanceInfo(chosenInstance.domain, false);
onNextClick(null);
}
}
}

View File

@@ -1,6 +1,7 @@
package org.joinmastodon.android.fragments.onboarding;
import android.app.Activity;
import android.graphics.Paint;
import android.graphics.Rect;
import android.os.Build;
import android.os.Bundle;
@@ -15,6 +16,7 @@ import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.ui.DividerItemDecoration;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.jsoup.Jsoup;
@@ -33,6 +35,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
import me.grishka.appkit.fragments.AppKitFragment;
import me.grishka.appkit.fragments.ToolbarFragment;
import me.grishka.appkit.imageloader.ViewImageLoader;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.BindableViewHolder;
@@ -46,7 +49,7 @@ import okhttp3.Request;
import okhttp3.Response;
import okhttp3.ResponseBody;
public class GoogleMadeMeAddThisFragment extends AppKitFragment{
public class GoogleMadeMeAddThisFragment extends ToolbarFragment{
private UsableRecyclerView list;
private MergeRecyclerAdapter adapter;
private Button btn;
@@ -60,6 +63,7 @@ public class GoogleMadeMeAddThisFragment extends AppKitFragment{
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setRetainInstance(true);
setTitle(R.string.privacy_policy_title);
}
@Override
@@ -82,37 +86,24 @@ public class GoogleMadeMeAddThisFragment extends AppKitFragment{
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view=inflater.inflate(R.layout.fragment_onboarding_rules, container, false);
list=view.findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(getActivity()));
View headerView=inflater.inflate(R.layout.item_list_header, list, false);
TextView title=headerView.findViewById(R.id.title);
TextView subtitle=headerView.findViewById(R.id.subtitle);
headerView.findViewById(R.id.step_counter).setVisibility(View.GONE);
title.setText(R.string.privacy_policy_title);
subtitle.setText(R.string.privacy_policy_subtitle);
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
TextView text=headerView.findViewById(R.id.text);
text.setText(R.string.privacy_policy_subtitle);
adapter=new MergeRecyclerAdapter();
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
adapter.addAdapter(itemsAdapter=new ItemsAdapter());
list.setAdapter(adapter);
list.setSelector(null);
list.addItemDecoration(new RecyclerView.ItemDecoration(){
@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state){
if(parent.getChildViewHolder(view) instanceof ItemViewHolder){
outRect.left=outRect.right=V.dp(18.5f);
outRect.top=V.dp(16);
}
}
});
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorM3SurfaceVariant, 1, 56, 0, DividerItemDecoration.NOT_FIRST));
btn=view.findViewById(R.id.btn_next);
btn.setOnClickListener(v->onButtonClick());
buttonBar=view.findViewById(R.id.button_bar);
view.findViewById(R.id.btn_back).setOnClickListener(v->Nav.finish(this));
return view;
}
@@ -120,7 +111,15 @@ public class GoogleMadeMeAddThisFragment extends AppKitFragment{
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLight));
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
}
@Override
protected void onUpdateToolbar(){
super.onUpdateToolbar();
getToolbar().setBackground(null);
getToolbar().setElevation(0);
}
protected void onButtonClick(){
@@ -192,24 +191,17 @@ public class GoogleMadeMeAddThisFragment extends AppKitFragment{
}
private class ItemViewHolder extends BindableViewHolder<Item> implements UsableRecyclerView.Clickable{
private final TextView domain, title;
private final ImageView favicon;
private final TextView title;
public ItemViewHolder(){
super(getActivity(), R.layout.item_privacy_policy_link, list);
domain=findViewById(R.id.domain);
title=findViewById(R.id.title);
favicon=findViewById(R.id.favicon);
itemView.setOutlineProvider(OutlineProviders.roundedRect(10));
itemView.setClipToOutline(true);
title.setPaintFlags(title.getPaintFlags() | Paint.UNDERLINE_TEXT_FLAG);
}
@Override
public void onBind(Item item){
domain.setText(item.domain);
title.setText(item.title);
ViewImageLoader.load(favicon, null, new UrlImageLoaderRequest(item.faviconUrl));
}
@Override

View File

@@ -84,7 +84,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
isSignup=getArguments().getBoolean("signup");
isSignup=getArguments() != null && getArguments().getBoolean("signup");
}
protected abstract void proceedWithAuthOrSignup(Instance instance);
@@ -187,6 +187,8 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
}
protected void loadInstanceInfo(String _domain, boolean isFromRedirect){
if(TextUtils.isEmpty(_domain))
return;
String domain=normalizeInstanceDomain(_domain);
Instance cachedInstance=instancesCache.get(domain);
if(cachedInstance!=null){
@@ -222,7 +224,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
}
if(Objects.equals(domain, currentSearchQuery) || Objects.equals(currentSearchQuery, redirects.get(domain)) || Objects.equals(currentSearchQuery, redirectsInverse.get(domain))){
boolean found=false;
for(CatalogInstance ci : filteredData){
for(CatalogInstance ci:filteredData){
if(ci.domain.equals(domain) && ci!=fakeInstance){
found=true;
break;

View File

@@ -1,39 +1,52 @@
package org.joinmastodon.android.fragments.onboarding;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Build;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Bundle;
import android.os.LocaleList;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.inputmethod.InputMethodManager;
import android.widget.HorizontalScrollView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.PopupMenu;
import android.widget.RadioButton;
import android.widget.RelativeLayout;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.api.requests.catalog.GetCatalogCategories;
import org.joinmastodon.android.api.requests.catalog.GetCatalogInstances;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.catalog.CatalogCategory;
import org.joinmastodon.android.model.catalog.CatalogInstance;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.DividerItemDecoration;
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.tabs.TabLayout;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.FilterChipView;
import org.parceler.Parcels;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Locale;
import java.util.Random;
import java.util.stream.Collectors;
import androidx.annotation.NonNull;
@@ -42,18 +55,37 @@ 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.fragments.OnBackPressedListener;
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
private View headerView;
public class InstanceCatalogSignupFragment extends InstanceCatalogFragment implements OnBackPressedListener{
private MastodonAPIRequest<?> getCategoriesRequest;
private TabLayout categoriesList;
private String currentCategory="all";
private List<CatalogCategory> categories=new ArrayList<>();
private View topBar;
private List<String> languages=Collections.emptyList();
private PopupMenu langFilterMenu, speedFilterMenu;
private SignupSpeedFilter currentSignupSpeedFilter=SignupSpeedFilter.INSTANT;
private String currentLanguage=null;
private boolean searchQueryMode;
private LinearLayout filtersWrap;
private HorizontalScrollView filtersScroll;
private ImageButton backBtn, clearSearchBtn;
private View focusThing;
private FilterChipView categoryGeneral, categorySpecialInterests;
private List<FilterChipView> regionalFilters;
private CatalogInstance.Region chosenRegion;
private CategoryChoice categoryChoice;
public InstanceCatalogSignupFragment(){
super(R.layout.fragment_onboarding_common, 10);
@@ -63,6 +95,12 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
public void onAttach(Context context){
super.onAttach(context);
setRefreshEnabled(false);
setRetainInstance(true);
}
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
loadData();
}
@@ -75,6 +113,25 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
if(getActivity()==null)
return;
onDataLoaded(sortInstances(result), false);
if(langFilterMenu!=null){
Menu menu=langFilterMenu.getMenu();
menu.clear();
menu.add(0, 0, 0, R.string.server_filter_any_language);
languages=result.stream().map(i->i.language).distinct().filter(s->s.length()>0).sorted().collect(Collectors.toList());
int i=1;
for(String lang:languages){
Locale locale=Locale.forLanguageTag(lang);
String name=locale.getDisplayLanguage(locale);
if(name.equals(lang))
name=lang.toUpperCase();
else
name=name.substring(0, 1).toUpperCase()+name.substring(1);
menu.add(0, i, 0, name);
i++;
}
}
updateFilteredList();
}
@@ -111,14 +168,14 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
}
private void updateCategories(){
categoriesList.removeAllTabs();
for(CatalogCategory cat:categories){
int titleRes=getTitleForCategory(cat.category);
TabLayout.Tab tab=categoriesList.newTab().setText(titleRes!=0 ? getString(titleRes) : cat.category).setCustomView(R.layout.item_instance_category);
ImageView emoji=tab.getCustomView().findViewById(R.id.emoji);
emoji.setImageResource(getEmojiForCategory(cat.category));
categoriesList.addTab(tab);
}
// categoriesList.removeAllTabs();
// for(CatalogCategory cat:categories){
// int titleRes=getTitleForCategory(cat.category);
// TabLayout.Tab tab=categoriesList.newTab().setText(titleRes!=0 ? getString(titleRes) : cat.category).setCustomView(R.layout.item_instance_category);
// ImageView emoji=tab.getCustomView().findViewById(R.id.emoji);
// emoji.setImageResource(getEmojiForCategory(cat.category));
// categoriesList.addTab(tab);
// }
}
@Override
@@ -130,27 +187,77 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
@Override
protected RecyclerView.Adapter getAdapter(){
headerView=getActivity().getLayoutInflater().inflate(R.layout.header_onboarding_instance_catalog, list, false);
searchEdit=headerView.findViewById(R.id.search_edit);
categoriesList=headerView.findViewById(R.id.categories_list);
categoriesList.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener(){
@Override
public void onTabSelected(TabLayout.Tab tab){
CatalogCategory category=categories.get(tab.getPosition());
currentCategory=category.category;
updateFilteredList();
}
View headerView=new View(getActivity());
headerView.setLayoutParams(new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 1));
@Override
public void onTabUnselected(TabLayout.Tab tab){
}
@Override
public void onTabReselected(TabLayout.Tab tab){
mergeAdapter=new MergeRecyclerAdapter();
mergeAdapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
mergeAdapter.addAdapter(adapter=new InstancesAdapter());
return mergeAdapter;
}
@SuppressLint("ClickableViewAccessibility")
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
backBtn=view.findViewById(R.id.btn_back);
backBtn.setOnClickListener(v->{
if(searchQueryMode){
setSearchQueryMode(false);
}else{
Nav.finish(this);
}
});
clearSearchBtn=view.findViewById(R.id.clear);
clearSearchBtn.setOnClickListener(v->searchEdit.setText(""));
nextButton.setEnabled(true);
list.setItemAnimator(new BetterItemAnimator());
setStatusBarColor(0);
topBar=view.findViewById(R.id.top_bar);
LayerDrawable topBg=(LayerDrawable) topBar.getBackground().mutate();
topBar.setBackground(topBg);
Drawable topOverlay=topBg.findDrawableByLayerId(R.id.color_overlay);
topOverlay.setAlpha(0);
LayerDrawable btmBg=(LayerDrawable) buttonBar.getBackground().mutate();
buttonBar.setBackground(btmBg);
Drawable btmOverlay=btmBg.findDrawableByLayerId(R.id.color_overlay);
btmOverlay.setAlpha(0);
list.addOnScrollListener(new RecyclerView.OnScrollListener(){
private boolean isAtTop=true;
private Animator currentPanelsAnim;
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy){
boolean newAtTop=recyclerView.getChildCount()==0 || (recyclerView.getChildAdapterPosition(recyclerView.getChildAt(0))==0 && recyclerView.getChildAt(0).getTop()==recyclerView.getPaddingTop());
if(newAtTop!=isAtTop){
isAtTop=newAtTop;
if(currentPanelsAnim!=null)
currentPanelsAnim.cancel();
AnimatorSet set=new AnimatorSet();
set.playTogether(
ObjectAnimator.ofInt(topOverlay, "alpha", isAtTop ? 0 : 20),
ObjectAnimator.ofInt(btmOverlay, "alpha", isAtTop ? 0 : 20),
ObjectAnimator.ofFloat(topBar, View.TRANSLATION_Z, isAtTop ? 0 : V.dp(3)),
ObjectAnimator.ofFloat(buttonBar, View.TRANSLATION_Z, isAtTop ? 0 : V.dp(3))
);
set.setDuration(150);
set.setInterpolator(CubicBezierInterpolator.DEFAULT);
set.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation){
currentPanelsAnim=null;
}
});
set.start();
currentPanelsAnim=set;
}
}
});
searchEdit=view.findViewById(R.id.search_edit);
searchEdit.setOnEditorActionListener(this::onSearchEnterPressed);
searchEdit.addTextChangedListener(new TextWatcher(){
@Override
@@ -166,42 +273,159 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
@Override
public void afterTextChanged(Editable s){
if((clearSearchBtn.getVisibility()==View.VISIBLE)!=(s.length()>0)){
clearSearchBtn.setVisibility(s.length()>0 ? View.VISIBLE : View.GONE);
}
}
});
searchEdit.setOnFocusChangeListener((v, hasFocus)->{
if(hasFocus && !searchQueryMode){
setSearchQueryMode(true);
}
});
mergeAdapter=new MergeRecyclerAdapter();
mergeAdapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
mergeAdapter.addAdapter(adapter=new InstancesAdapter());
return mergeAdapter;
FilterChipView langFilter=new FilterChipView(getActivity());
langFilter.setDrawableEnd(R.drawable.ic_baseline_arrow_drop_down_18);
if(currentLanguage==null){
langFilter.setText(R.string.server_filter_any_language);
}else{
Locale locale=Locale.forLanguageTag(currentLanguage);
langFilter.setText(locale.getDisplayLanguage(locale));
langFilter.setSelected(true);
}
langFilterMenu=new PopupMenu(getContext(), langFilter);
langFilter.setOnTouchListener(langFilterMenu.getDragToOpenListener());
langFilter.setOnClickListener(v->langFilterMenu.show());
filtersWrap=view.findViewById(R.id.filters_container);
filtersScroll=view.findViewById(R.id.filters_scroll);
filtersWrap.addView(langFilter, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
FilterChipView speedFilter=new FilterChipView(getActivity());
speedFilter.setDrawableEnd(R.drawable.ic_baseline_arrow_drop_down_18);
speedFilterMenu=new PopupMenu(getContext(), speedFilter);
speedFilterMenu.getMenu().add(0, 0, 0, R.string.server_filter_any_signup_speed);
speedFilterMenu.getMenu().add(0, 1, 0, R.string.server_filter_instant_signup);
speedFilterMenu.getMenu().add(0, 2, 0, R.string.server_filter_manual_review);
speedFilter.setOnTouchListener(speedFilterMenu.getDragToOpenListener());
speedFilter.setOnClickListener(v->speedFilterMenu.show());
speedFilter.setText(switch(currentSignupSpeedFilter){
case ANY -> R.string.server_filter_any_signup_speed;
case INSTANT -> R.string.server_filter_instant_signup;
case REVIEWED -> R.string.server_filter_manual_review;
});
speedFilter.setSelected(currentSignupSpeedFilter!=SignupSpeedFilter.ANY);
filtersWrap.addView(speedFilter, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
speedFilterMenu.setOnMenuItemClickListener(item->{
speedFilter.setText(item.getTitle());
speedFilter.setSelected(item.getItemId()>0);
currentSignupSpeedFilter=SignupSpeedFilter.values()[item.getItemId()];
updateFilteredList();
return true;
});
langFilterMenu.setOnMenuItemClickListener(item->{
langFilter.setText(item.getTitle());
langFilter.setSelected(item.getItemId()>0);
currentLanguage=item.getItemId()==0 ? null : languages.get(item.getItemId()-1);
updateFilteredList();
return true;
});
View divider=new View(getActivity());
divider.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Outline));
filtersWrap.addView(divider, new LinearLayout.LayoutParams(V.dp(.5f), ViewGroup.LayoutParams.MATCH_PARENT));
categoryGeneral=new FilterChipView(getActivity());
categoryGeneral.setText(R.string.category_general);
categoryGeneral.setTag(CategoryChoice.GENERAL);
categoryGeneral.setOnClickListener(this::onCategoryFilterClick);
categoryGeneral.setSelected(categoryChoice==CategoryChoice.GENERAL);
filtersWrap.addView(categoryGeneral, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
categorySpecialInterests=new FilterChipView(getActivity());
categorySpecialInterests.setText(R.string.category_special_interests);
categorySpecialInterests.setTag(CategoryChoice.SPECIAL);
categorySpecialInterests.setOnClickListener(this::onCategoryFilterClick);
categorySpecialInterests.setSelected(categoryChoice==CategoryChoice.SPECIAL);
filtersWrap.addView(categorySpecialInterests, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
regionalFilters=Arrays.stream(CatalogInstance.Region.values()).map(r->{
FilterChipView fv=new FilterChipView(getActivity());
fv.setTag(r);
fv.setText(switch(r){
case EUROPE -> R.string.server_filter_region_europe;
case NORTH_AMERICA -> R.string.server_filter_region_north_america;
case SOUTH_AMERICA -> R.string.server_filter_region_south_america;
case AFRICA -> R.string.server_filter_region_africa;
case ASIA -> R.string.server_filter_region_asia;
case OCEANIA -> R.string.server_filter_region_oceania;
});
fv.setSelected(r==chosenRegion);
fv.setOnClickListener(this::onRegionFilterClick);
filtersWrap.addView(fv, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
return fv;
}).collect(Collectors.toList());
focusThing=view.findViewById(R.id.focus_thing);
focusThing.requestFocus();
}
private void onRegionFilterClick(View v){
CatalogInstance.Region r=(CatalogInstance.Region) v.getTag();
if(chosenRegion==r){
chosenRegion=null;
v.setSelected(false);
}else{
if(chosenRegion!=null)
filtersWrap.findViewWithTag(chosenRegion).setSelected(false);
chosenRegion=r;
v.setSelected(true);
}
updateFilteredList();
}
private void onCategoryFilterClick(View v){
CategoryChoice c=(CategoryChoice) v.getTag();
if(categoryChoice==c){
categoryChoice=null;
v.setSelected(false);
}else{
if(categoryChoice!=null)
filtersWrap.findViewWithTag(categoryChoice).setSelected(false);
categoryChoice=c;
v.setSelected(true);
}
updateFilteredList();
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
view.findViewById(R.id.btn_back).setOnClickListener(v->Nav.finish(this));
list.setItemAnimator(new BetterItemAnimator());
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 1, 16, 16, DividerItemDecoration.NOT_FIRST));
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLight));
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLight));
protected void onNextClick(View v){
if(chosenInstance==null){
String lang=Locale.getDefault().getLanguage();
List<CatalogInstance> instances=data.stream().filter(ci->!ci.approvalRequired && ("general".equals(ci.category) || (ci.categories!=null && ci.categories.contains("general"))) && (lang.equals(ci.language) || (ci.languages!=null && ci.languages.contains(lang)))).collect(Collectors.toList());
if(instances.isEmpty()){
instances=data.stream().filter(ci->!ci.approvalRequired && ("general".equals(ci.category) || (ci.categories!=null && ci.categories.contains("general")))).collect(Collectors.toList());
}
if(instances.isEmpty()){
return;
}
chosenInstance=instances.get(new Random().nextInt(instances.size()));
}
super.onNextClick(v);
}
@Override
protected void proceedWithAuthOrSignup(Instance instance){
getActivity().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(contentView.getWindowToken(), 0);
if(isSignup){
if(!instance.registrations){
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.error)
.setMessage(R.string.instance_signup_closed)
.setPositiveButton(R.string.ok, null)
.show();
return;
}
Bundle args=new Bundle();
args.putParcelable("instance", Parcels.wrap(instance));
Nav.go(getActivity(), InstanceRulesFragment.class, args);
}else{
if(!instance.registrations){
new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.error)
.setMessage(R.string.instance_signup_closed)
.setPositiveButton(R.string.ok, null)
.show();
return;
}
Bundle args=new Bundle();
args.putParcelable("instance", Parcels.wrap(instance));
Nav.go(getActivity(), InstanceRulesFragment.class, args);
}
// private String getEmojiForCategory(String category){
@@ -265,11 +489,29 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
protected void updateFilteredList(){
ArrayList<CatalogInstance> prevData=new ArrayList<>(filteredData);
filteredData.clear();
for(CatalogInstance instance:data){
if(currentCategory.equals("all") || instance.categories.contains(currentCategory)){
if(TextUtils.isEmpty(currentSearchQuery) || instance.domain.contains(currentSearchQuery)){
if(instance.domain.equals(currentSearchQuery) || !isSignup || !instance.approvalRequired)
if(searchQueryMode){
if(!TextUtils.isEmpty(currentSearchQuery)){
for(CatalogInstance instance:data){
if(instance.domain.contains(currentSearchQuery)){
filteredData.add(instance);
}
}
}
}else{
for(CatalogInstance instance:data){
if(categoryChoice==null || categoryChoice.matches(instance.category)){
if(chosenRegion==null || instance.region==chosenRegion){
boolean signupSpeedMatches=switch(currentSignupSpeedFilter){
case ANY -> true;
case INSTANT -> !instance.approvalRequired;
case REVIEWED -> instance.approvalRequired;
};
if(signupSpeedMatches){
if(currentLanguage==null || instance.languages.contains(currentLanguage)){
filteredData.add(instance);
}
}
}
}
}
}
@@ -296,8 +538,46 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
}).dispatchUpdatesTo(adapter);
}
@Override
public void onApplyWindowInsets(WindowInsets insets){
topBar.setPadding(0, insets.getSystemWindowInsetTop(), 0, 0);
super.onApplyWindowInsets(insets.replaceSystemWindowInsets(insets.getSystemWindowInsetLeft(), 0, insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()));
}
private class InstancesAdapter extends UsableRecyclerView.Adapter<InstanceCatalogSignupFragment.InstanceViewHolder>{
@Override
public boolean onBackPressed(){
if(searchQueryMode){
setSearchQueryMode(false);
return true;
}
return false;
}
private void setSearchQueryMode(boolean enabled){
searchQueryMode=enabled;
RelativeLayout.LayoutParams lp=(RelativeLayout.LayoutParams) searchEdit.getLayoutParams();
if(searchQueryMode){
filtersScroll.setVisibility(View.GONE);
lp.removeRule(RelativeLayout.END_OF);
backBtn.setScaleX(0.83333333f);
backBtn.setScaleY(0.83333333f);
backBtn.setTranslationX(V.dp(8));
searchEdit.setCompoundDrawableTintList(ColorStateList.valueOf(0));
}else{
filtersScroll.setVisibility(View.VISIBLE);
focusThing.requestFocus();
searchEdit.setText("");
lp.addRule(RelativeLayout.END_OF, R.id.btn_back);
getActivity().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(searchEdit.getWindowToken(), 0);
backBtn.setScaleX(1);
backBtn.setScaleY(1);
backBtn.setTranslationX(0);
searchEdit.setCompoundDrawableTintList(ColorStateList.valueOf(UiUtils.getThemeColor(getActivity(), R.attr.colorM3OnSurfaceVariant)));
}
updateFilteredList();
}
private class InstancesAdapter extends UsableRecyclerView.Adapter<InstanceCatalogSignupFragment.InstanceViewHolder> implements ImageLoaderRecyclerAdapter{
public InstancesAdapter(){
super(imgLoader);
}
@@ -323,32 +603,53 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
public int getItemViewType(int position){
return -1;
}
@Override
public int getImageCountForItem(int position){
return filteredData.get(position).thumbnailRequest!=null ? 1 : 0;
}
@Override
public ImageLoaderRequest getImageRequest(int position, int image){
return filteredData.get(position).thumbnailRequest;
}
}
private class InstanceViewHolder extends BindableViewHolder<CatalogInstance> implements UsableRecyclerView.Clickable{
private final TextView title, description, userCount, lang;
private class InstanceViewHolder extends BindableViewHolder<CatalogInstance> implements UsableRecyclerView.DisableableClickable, ImageLoaderViewHolder{
private final TextView title, description;
private final RadioButton radioButton;
private final ImageView thumbnail;
private boolean enabled;
public InstanceViewHolder(){
super(getActivity(), R.layout.item_instance_catalog, list);
title=findViewById(R.id.title);
description=findViewById(R.id.description);
userCount=findViewById(R.id.user_count);
lang=findViewById(R.id.lang);
radioButton=findViewById(R.id.radiobtn);
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.N){
UiUtils.fixCompoundDrawableTintOnAndroid6(userCount);
UiUtils.fixCompoundDrawableTintOnAndroid6(lang);
}
thumbnail=findViewById(R.id.image);
}
@Override
public void onBind(CatalogInstance item){
title.setText(item.normalizedDomain);
description.setText(item.description);
userCount.setText(UiUtils.abbreviateNumber(item.totalUsers));
lang.setText(item.language.toUpperCase());
radioButton.setChecked(chosenInstance==item);
if(item.thumbnailRequest==null)
thumbnail.setImageDrawable(null);
Instance realInstance=instancesCache.get(item.normalizedDomain);
float alpha;
if(realInstance!=null && !realInstance.registrations){
alpha=0.38f;
description.setText(R.string.not_accepting_new_members);
enabled=false;
}else{
alpha=1f;
description.setText(item.description);
enabled=true;
}
title.setAlpha(alpha);
description.setAlpha(alpha);
radioButton.setAlpha(alpha);
thumbnail.setAlpha(alpha);
}
@Override
@@ -358,10 +659,17 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
if(chosenInstance!=null){
int idx=filteredData.indexOf(chosenInstance);
if(idx!=-1){
RecyclerView.ViewHolder holder=list.findViewHolderForAdapterPosition(mergeAdapter.getPositionForAdapter(adapter)+idx);
if(holder instanceof InstanceCatalogSignupFragment.InstanceViewHolder ivh){
ivh.radioButton.setChecked(false);
boolean found=false;
for(int i=0;i<list.getChildCount();i++){
RecyclerView.ViewHolder holder=list.getChildViewHolder(list.getChildAt(i));
if(holder.getAbsoluteAdapterPosition()==mergeAdapter.getPositionForAdapter(adapter)+idx && holder instanceof InstanceViewHolder ivh){
ivh.radioButton.setChecked(false);
found=true;
break;
}
}
if(!found)
adapter.notifyItemChanged(idx);
}
}
radioButton.setChecked(true);
@@ -370,5 +678,36 @@ public class InstanceCatalogSignupFragment extends InstanceCatalogFragment{
chosenInstance=item;
loadInstanceInfo(chosenInstance.domain, false);
}
@Override
public void setImage(int index, Drawable image){
thumbnail.setImageDrawable(image);
}
@Override
public void clearImage(int index){
setImage(index, null);
}
@Override
public boolean isEnabled(){
return enabled;
}
}
private enum SignupSpeedFilter{
ANY,
INSTANT,
REVIEWED
}
private enum CategoryChoice{
GENERAL,
SPECIAL;
public boolean matches(String category){
boolean isGeneral=(category==null || "general".equals(category));
return (this==GENERAL)==isGeneral;
}
}
}

View File

@@ -1,5 +1,6 @@
package org.joinmastodon.android.fragments.onboarding;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
@@ -22,14 +23,14 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
import me.grishka.appkit.fragments.AppKitFragment;
import me.grishka.appkit.fragments.ToolbarFragment;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.MergeRecyclerAdapter;
import me.grishka.appkit.utils.SingleViewRecyclerAdapter;
import me.grishka.appkit.utils.V;
import me.grishka.appkit.views.UsableRecyclerView;
public class InstanceRulesFragment extends AppKitFragment{
public class InstanceRulesFragment extends ToolbarFragment{
private UsableRecyclerView list;
private MergeRecyclerAdapter adapter;
private Button btn;
@@ -47,31 +48,28 @@ public class InstanceRulesFragment extends AppKitFragment{
super.onAttach(activity);
setNavigationBarColor(UiUtils.getThemeColor(activity, R.attr.colorWindowBackground));
instance=Parcels.unwrap(getArguments().getParcelable("instance"));
setTitle(R.string.instance_rules_title);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
View view=inflater.inflate(R.layout.fragment_onboarding_rules, container, false);
list=view.findViewById(R.id.list);
list.setLayoutManager(new LinearLayoutManager(getActivity()));
View headerView=inflater.inflate(R.layout.item_list_header, list, false);
TextView title=headerView.findViewById(R.id.title);
TextView subtitle=headerView.findViewById(R.id.subtitle);
headerView.findViewById(R.id.step_counter).setVisibility(View.GONE);
title.setText(R.string.instance_rules_title);
subtitle.setText(getString(R.string.instance_rules_subtitle, instance.uri));
View headerView=inflater.inflate(R.layout.item_list_header_simple, list, false);
TextView text=headerView.findViewById(R.id.text);
text.setText(getString(R.string.instance_rules_subtitle, instance.uri));
adapter=new MergeRecyclerAdapter();
adapter.addAdapter(new SingleViewRecyclerAdapter(headerView));
adapter.addAdapter(new ItemsAdapter());
list.setAdapter(adapter);
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorPollVoted, 1, 16, 16, DividerItemDecoration.NOT_FIRST));
list.addItemDecoration(new DividerItemDecoration(getActivity(), R.attr.colorM3SurfaceVariant, 1, 56, 0, DividerItemDecoration.NOT_FIRST));
btn=view.findViewById(R.id.btn_next);
btn.setOnClickListener(v->onButtonClick());
buttonBar=view.findViewById(R.id.button_bar);
view.findViewById(R.id.btn_back).setOnClickListener(v->Nav.finish(this));
return view;
}
@@ -79,7 +77,15 @@ public class InstanceRulesFragment extends AppKitFragment{
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLight));
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
}
@Override
protected void onUpdateToolbar(){
super.onUpdateToolbar();
getToolbar().setBackground(null);
getToolbar().setElevation(0);
}
protected void onButtonClick(){
@@ -119,23 +125,22 @@ public class InstanceRulesFragment extends AppKitFragment{
}
private class ItemViewHolder extends BindableViewHolder<Instance.Rule>{
private final TextView title, subtitle;
private final ImageView checkbox;
private final TextView text, number;
public ItemViewHolder(){
super(getActivity(), R.layout.item_report_choice, list);
title=findViewById(R.id.title);
subtitle=findViewById(R.id.subtitle);
checkbox=findViewById(R.id.checkbox);
subtitle.setVisibility(View.GONE);
super(getActivity(), R.layout.item_server_rule, list);
text=findViewById(R.id.text);
number=findViewById(R.id.number);
}
@SuppressLint("DefaultLocale")
@Override
public void onBind(Instance.Rule item){
if(item.parsedText==null){
item.parsedText=HtmlParser.parseLinks(item.text);
}
title.setText(item.parsedText);
text.setText(item.parsedText);
number.setText(String.format("%d", getAbsoluteAdapterPosition()));
}
}
}

View File

@@ -25,14 +25,15 @@ import org.joinmastodon.android.api.MastodonDetailedErrorResponse;
import org.joinmastodon.android.api.requests.accounts.RegisterAccount;
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
import org.joinmastodon.android.api.requests.oauth.GetOauthToken;
import org.joinmastodon.android.api.session.AccountActivationInfo;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.Application;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Token;
import org.joinmastodon.android.ui.OutlineProviders;
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.FloatingHintEditTextLayout;
import org.parceler.Parcels;
import java.io.File;
@@ -49,30 +50,28 @@ import me.grishka.appkit.Nav;
import me.grishka.appkit.api.APIRequest;
import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.fragments.AppKitFragment;
import me.grishka.appkit.fragments.ToolbarFragment;
import me.grishka.appkit.imageloader.ViewImageLoader;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.V;
public class SignupFragment extends AppKitFragment{
public class SignupFragment extends ToolbarFragment{
private static final int AVATAR_RESULT=198;
private static final String TAG="SignupFragment";
private Instance instance;
private EditText displayName, username, email, password, reason;
private EditText displayName, username, email, password, passwordConfirm, reason;
private FloatingHintEditTextLayout displayNameWrap, usernameWrap, emailWrap, passwordWrap, passwordConfirmWrap, reasonWrap;
private TextView reasonExplain;
private Button btn;
private View buttonBar;
private TextWatcher buttonStateUpdater=new SimpleTextWatcher(e->updateButtonState());
private ImageView avatar;
private APIRequest currentBackgroundRequest;
private Application apiApplication;
private Token apiToken;
private boolean submitAfterGettingToken;
private ProgressDialog progressDialog;
private Uri avatarUri;
private File avatarFile;
private HashSet<EditText> errorFields=new HashSet<>();
@Override
@@ -81,25 +80,30 @@ public class SignupFragment extends AppKitFragment{
setRetainInstance(true);
instance=Parcels.unwrap(getArguments().getParcelable("instance"));
createAppAndGetToken();
setTitle(R.string.signup_title);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
public View onCreateContentView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState){
View view=inflater.inflate(R.layout.fragment_onboarding_signup, container, false);
TextView title=view.findViewById(R.id.title);
TextView domain=view.findViewById(R.id.domain);
displayName=view.findViewById(R.id.display_name);
username=view.findViewById(R.id.username);
email=view.findViewById(R.id.email);
password=view.findViewById(R.id.password);
avatar=view.findViewById(R.id.avatar);
passwordConfirm=view.findViewById(R.id.password_confirm);
reason=view.findViewById(R.id.reason);
reasonExplain=view.findViewById(R.id.reason_explain);
View avaWrap=view.findViewById(R.id.ava_wrap);
title.setText(getString(R.string.signup_title, instance.uri));
displayNameWrap=view.findViewById(R.id.display_name_wrap);
usernameWrap=view.findViewById(R.id.username_wrap);
emailWrap=view.findViewById(R.id.email_wrap);
passwordWrap=view.findViewById(R.id.password_wrap);
passwordConfirmWrap=view.findViewById(R.id.password_confirm_wrap);
reasonWrap=view.findViewById(R.id.reason_wrap);
domain.setText('@'+instance.uri);
username.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@@ -114,23 +118,20 @@ public class SignupFragment extends AppKitFragment{
btn=view.findViewById(R.id.btn_next);
btn.setOnClickListener(v->onButtonClick());
buttonBar=view.findViewById(R.id.button_bar);
view.findViewById(R.id.btn_back).setOnClickListener(v->Nav.finish(this));
updateButtonState();
username.addTextChangedListener(buttonStateUpdater);
email.addTextChangedListener(buttonStateUpdater);
password.addTextChangedListener(buttonStateUpdater);
passwordConfirm.addTextChangedListener(buttonStateUpdater);
reason.addTextChangedListener(buttonStateUpdater);
username.addTextChangedListener(new ErrorClearingListener(username));
email.addTextChangedListener(new ErrorClearingListener(email));
password.addTextChangedListener(new ErrorClearingListener(password));
passwordConfirm.addTextChangedListener(new ErrorClearingListener(passwordConfirm));
reason.addTextChangedListener(new ErrorClearingListener(reason));
avaWrap.setOutlineProvider(OutlineProviders.roundedRect(22));
avaWrap.setClipToOutline(true);
avaWrap.setOnClickListener(v->onAvatarClick());
if(!instance.approvalRequired){
reason.setVisibility(View.GONE);
reasonExplain.setVisibility(View.GONE);
@@ -142,10 +143,23 @@ public class SignupFragment extends AppKitFragment{
@Override
public void onViewCreated(View view, Bundle savedInstanceState){
super.onViewCreated(view, savedInstanceState);
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorBackgroundLight));
setStatusBarColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
view.setBackgroundColor(UiUtils.getThemeColor(getActivity(), R.attr.colorM3Background));
}
@Override
protected void onUpdateToolbar(){
super.onUpdateToolbar();
getToolbar().setBackground(null);
getToolbar().setElevation(0);
}
private void onButtonClick(){
if(!password.getText().equals(passwordConfirm.getText())){
passwordConfirm.setError(getString(R.string.signup_passwords_dont_match));
passwordConfirmWrap.setErrorState();
return;
}
showProgressDialog();
if(currentBackgroundRequest!=null){
submitAfterGettingToken=true;
@@ -160,32 +174,8 @@ public class SignupFragment extends AppKitFragment{
}
}
private void copyAvatar(Runnable onDone){
// Need to copy the avatar from the content provider to somewhere accessible in case the app gets killed between signup and account activation
Activity activity=getActivity();
MastodonAPIController.runInBackground(()->{
String origName=UiUtils.getFileName(avatarUri);
avatarFile=new File(activity.getCacheDir(), System.currentTimeMillis()+origName.substring(origName.lastIndexOf('.')));
try(InputStream in=activity.getContentResolver().openInputStream(avatarUri);
FileOutputStream out=new FileOutputStream(avatarFile)){
byte[] buf=new byte[10240];
int read;
while((read=in.read(buf))>0){
out.write(buf, 0, read);
}
}catch(IOException x){
Log.w(TAG, "copyAvatar: error copying", x);
}
activity.runOnUiThread(onDone);
});
}
private void submit(){
if(avatarUri!=null && (avatarFile==null || !avatarFile.exists())){
copyAvatar(this::actuallySubmit);
}else{
actuallySubmit();
}
actuallySubmit();
}
private void actuallySubmit(){
@@ -204,9 +194,7 @@ public class SignupFragment extends AppKitFragment{
fakeAccount.acct=fakeAccount.username=username;
fakeAccount.id="tmp"+System.currentTimeMillis();
fakeAccount.displayName=displayName.getText().toString();
if(avatarFile!=null)
fakeAccount.avatar=avatarFile.getAbsolutePath();
AccountSessionManager.getInstance().addAccount(instance, result, fakeAccount, apiApplication, false);
AccountSessionManager.getInstance().addAccount(instance, result, fakeAccount, apiApplication, new AccountActivationInfo(email, System.currentTimeMillis()));
Bundle args=new Bundle();
args.putString("account", AccountSessionManager.getInstance().getLastActiveAccountID());
Nav.goClearingStack(getActivity(), AccountActivationFragment.class, args);
@@ -225,6 +213,7 @@ public class SignupFragment extends AppKitFragment{
continue;
}
field.setError(fieldErrors.get(fieldName).stream().map(err->err.description).collect(Collectors.joining("\n")));
getFieldWrapByName(fieldName).setErrorState();
errorFields.add(field);
if(first){
first=false;
@@ -252,6 +241,16 @@ public class SignupFragment extends AppKitFragment{
};
}
private FloatingHintEditTextLayout getFieldWrapByName(String name){
return switch(name){
case "email" -> emailWrap;
case "username" -> usernameWrap;
case "password" -> passwordWrap;
case "reason" -> reasonWrap;
default -> null;
};
}
private void showProgressDialog(){
if(progressDialog==null){
progressDialog=new ProgressDialog(getActivity());
@@ -262,7 +261,7 @@ public class SignupFragment extends AppKitFragment{
}
private void updateButtonState(){
btn.setEnabled(username.length()>0 && email.length()>0 && email.getText().toString().contains("@") && password.length()>=8 && (!instance.approvalRequired || reason.length()>0));
btn.setEnabled(username.length()>0 && email.length()>0 && email.getText().toString().contains("@") && password.length()>=8 && passwordConfirm.length()>=8 && (!instance.approvalRequired || reason.length()>0));
}
private void createAppAndGetToken(){
@@ -324,20 +323,6 @@ public class SignupFragment extends AppKitFragment{
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data){
if(requestCode==AVATAR_RESULT && resultCode==Activity.RESULT_OK){
avatarUri=data.getData();
if(avatarFile!=null && avatarFile.exists())
avatarFile.delete();
ViewImageLoader.load(avatar, getResources().getDrawable(R.drawable.default_avatar), new UrlImageLoaderRequest(avatarUri, V.dp(100), V.dp(100)));
}
}
private void onAvatarClick(){
startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT).setType("image/*").addCategory(Intent.CATEGORY_OPENABLE), AVATAR_RESULT);
}
private class ErrorClearingListener implements TextWatcher{
public final EditText editText;

View File

@@ -1,5 +1,10 @@
package org.joinmastodon.android.model.catalog;
import android.graphics.Region;
import android.text.TextUtils;
import com.google.gson.annotations.SerializedName;
import org.joinmastodon.android.api.AllFieldsAreRequired;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.model.BaseModel;
@@ -7,13 +12,17 @@ import org.joinmastodon.android.model.BaseModel;
import java.net.IDN;
import java.util.List;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.V;
@AllFieldsAreRequired
public class CatalogInstance extends BaseModel{
public String domain;
public String version;
public String description;
public List<String> languages;
public String region;
@SerializedName("region")
private String _region;
public List<String> categories;
public String proxiedThumbnail;
public int totalUsers;
@@ -22,7 +31,9 @@ public class CatalogInstance extends BaseModel{
public String language;
public String category;
public transient Region region;
public transient String normalizedDomain;
public transient UrlImageLoaderRequest thumbnailRequest;
@Override
public void postprocess() throws ObjectValidationException{
@@ -31,6 +42,14 @@ public class CatalogInstance extends BaseModel{
normalizedDomain=IDN.toUnicode(domain);
else
normalizedDomain=domain;
if(!TextUtils.isEmpty(_region)){
try{
region=Region.valueOf(_region.toUpperCase());
}catch(IllegalArgumentException ignore){}
}
if(!TextUtils.isEmpty(proxiedThumbnail)){
thumbnailRequest=new UrlImageLoaderRequest(proxiedThumbnail, 0, V.dp(56));
}
}
@Override
@@ -50,4 +69,13 @@ public class CatalogInstance extends BaseModel{
", category='"+category+'\''+
'}';
}
public enum Region{
EUROPE,
NORTH_AMERICA,
SOUTH_AMERICA,
AFRICA,
ASIA,
OCEANIA
}
}

View File

@@ -2,14 +2,12 @@ package org.joinmastodon.android.ui;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -25,8 +23,7 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.oauth.RevokeOauthToken;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.SplashFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.fragments.onboarding.CustomWelcomeFragment;
import org.joinmastodon.android.ui.utils.UiUtils;
import java.util.List;
@@ -80,7 +77,7 @@ public class AccountSwitcherSheet extends BottomSheet{
holder.avatar.setImageResource(R.drawable.ic_fluent_add_circle_24_filled);
holder.avatar.setImageTintList(ColorStateList.valueOf(UiUtils.getThemeColor(activity, android.R.attr.textColorPrimary)));
adapter.addAdapter(new ClickableSingleViewRecyclerAdapter(holder.itemView, ()->{
Nav.go(activity, SplashFragment.class, null);
Nav.go(activity, CustomWelcomeFragment.class, null);
dismiss();
}));
@@ -243,7 +240,10 @@ public class AccountSwitcherSheet extends BottomSheet{
public WrappedAccount(AccountSession session){
this.session=session;
req=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? session.self.avatar : session.self.avatarStatic, V.dp(50), V.dp(50));
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;
}
}
}

View File

@@ -12,6 +12,8 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Account;
@@ -23,7 +25,9 @@ import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.ProgressBarButton;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
@@ -154,10 +158,18 @@ public class AccountCardStatusDisplayItem extends StatusDisplayItem{
private void onFollowRequestButtonClick(View v) {
itemView.setHasTransientState(true);
UiUtils.handleFollowRequest((Activity) v.getContext(), item.account, item.parentFragment.getAccountID(), item.notification.id , v == acceptButton, relationship, rel -> {
UiUtils.handleFollowRequest((Activity) v.getContext(), item.account, item.parentFragment.getAccountID(), null, v == acceptButton, relationship, rel -> {
itemView.setHasTransientState(false);
item.parentFragment.putRelationship(item.account.id, rel);
rebind();
RecyclerView.Adapter<? extends RecyclerView.ViewHolder> adapter = getBindingAdapter();
if (!rel.requested && !rel.followedBy && adapter != null) {
int index = item.parentFragment.getDisplayItems().indexOf(item);
item.parentFragment.getDisplayItems().remove(index);
item.parentFragment.getDisplayItems().remove(index - 1);
adapter.notifyItemRangeRemoved(getLayoutPosition()-1, 2);
} else {
rebind();
}
});
}

View File

@@ -4,9 +4,14 @@ import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.ScaleAnimation;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
@@ -21,10 +26,8 @@ import org.joinmastodon.android.model.StatusPrivacy;
import org.joinmastodon.android.ui.utils.UiUtils;
import org.parceler.Parcels;
import java.text.DecimalFormat;
import me.grishka.appkit.Nav;
import me.grishka.appkit.utils.BindableViewHolder;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V;
public class FooterStatusDisplayItem extends StatusDisplayItem{
@@ -46,6 +49,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem>{
private final TextView reply, boost, favorite, bookmark;
private final ImageView share;
private static final AnimationSet scaleDown, scaleUp;
private final View.AccessibilityDelegate buttonAccessibilityDelegate=new View.AccessibilityDelegate(){
@Override
@@ -56,6 +60,27 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
};
static {
// 20dp to center in middle of icon, because: (icon width = 24dp) / 2 + (paddingStart = 8dp)
Animation scaleDownAnim = new ScaleAnimation(1, 0.85f, 1, 0.85f, Animation.ABSOLUTE, V.dp(20), Animation.RELATIVE_TO_SELF, 0.5f);
Animation scaleUpAnim = new ScaleAnimation(0.85f, 1, 0.85f, 1, Animation.ABSOLUTE, V.dp(20), Animation.RELATIVE_TO_SELF, 0.5f);
Animation opacityOutAnim = new AlphaAnimation(1, 0.75f);
Animation opacityInAnim = new AlphaAnimation(0.75f, 1);
scaleDown = new AnimationSet(true);
scaleDown.setDuration(350);
scaleDown.setInterpolator(CubicBezierInterpolator.DEFAULT);
scaleDown.setFillAfter(true);
scaleDown.addAnimation(scaleDownAnim);
scaleDown.addAnimation(opacityOutAnim);
scaleUp = new AnimationSet(true);
scaleUp.setDuration(100);
scaleUp.setInterpolator(CubicBezierInterpolator.DEFAULT);
scaleUp.addAnimation(scaleUpAnim);
scaleUp.addAnimation(opacityInAnim);
}
public Holder(Activity activity, ViewGroup parent){
super(activity, R.layout.display_item_footer, parent);
reply=findViewById(R.id.reply);
@@ -74,14 +99,19 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
View favorite=findViewById(R.id.favorite_btn);
View share=findViewById(R.id.share_btn);
View bookmark=findViewById(R.id.bookmark_btn);
reply.setOnTouchListener(this::onButtonTouch);
reply.setOnClickListener(this::onReplyClick);
reply.setAccessibilityDelegate(buttonAccessibilityDelegate);
boost.setOnTouchListener(this::onButtonTouch);
boost.setOnClickListener(this::onBoostClick);
boost.setAccessibilityDelegate(buttonAccessibilityDelegate);
favorite.setOnTouchListener(this::onButtonTouch);
favorite.setOnClickListener(this::onFavoriteClick);
favorite.setAccessibilityDelegate(buttonAccessibilityDelegate);
bookmark.setOnTouchListener(this::onButtonTouch);
bookmark.setOnClickListener(this::onBookmarkClick);
bookmark.setAccessibilityDelegate(buttonAccessibilityDelegate);
share.setOnTouchListener(this::onButtonTouch);
share.setOnClickListener(this::onShareClick);
share.setAccessibilityDelegate(buttonAccessibilityDelegate);
}
@@ -109,30 +139,45 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
}
private void onReplyClick(View v){
v.startAnimation(scaleUp);
Bundle args=new Bundle();
args.putString("account", item.accountID);
args.putParcelable("replyTo", Parcels.wrap(item.status));
Nav.go(item.parentFragment.getActivity(), ComposeFragment.class, args);
}
private boolean onButtonTouch(View v, MotionEvent event){
if (event.getAction() == MotionEvent.ACTION_UP) v.performClick();
else if (event.getAction() == MotionEvent.ACTION_DOWN) v.startAnimation(scaleDown);
else if (event.getAction() == MotionEvent.ACTION_CANCEL) v.startAnimation(scaleUp);
return true;
}
private void onBoostClick(View v){
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged);
boost.setSelected(item.status.reblogged);
bindButton(boost, item.status.reblogsCount);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setReblogged(item.status, !item.status.reblogged, r->{
v.startAnimation(scaleUp);
boost.setSelected(item.status.reblogged);
bindButton(boost, r.reblogsCount);
});
}
private void onFavoriteClick(View v){
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited);
favorite.setSelected(item.status.favourited);
bindButton(favorite, item.status.favouritesCount);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
v.startAnimation(scaleUp);
favorite.setSelected(r.favourited);
bindButton(favorite, r.favouritesCount);
});
}
private void onBookmarkClick(View v){
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked);
bookmark.setSelected(item.status.bookmarked);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
v.startAnimation(scaleUp);
bookmark.setSelected(item.status.bookmarked);
});
}
private void onShareClick(View v){
v.startAnimation(scaleUp);
Intent intent=new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, item.status.url);

View File

@@ -89,10 +89,12 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
button.setBackground(progressBg);
itemView.setSelected(item.isMostVoted);
icon.setSelected(item.poll.ownVotes.contains(item.poll.options.indexOf(item.option)));
icon.setVisibility(item.poll.voted && item.poll.ownVotes.isEmpty() ? View.GONE : View.VISIBLE);
percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f)));
}else{
itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option));
button.setBackgroundResource(R.drawable.bg_poll_option_clickable);
icon.setVisibility(View.VISIBLE);
}
}

View File

@@ -148,6 +148,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
translateWrap.setVisibility(item.textSelectable && item.translateEnabled &&
!item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) &&
item.status.language != null &&
(item.session.preferences == null || !item.status.language.equalsIgnoreCase(item.session.preferences.postingDefaultLanguage))
? View.VISIBLE : View.GONE);
translateButton.setText(item.translated ? R.string.sk_translate_show_original : R.string.sk_translate_post);

View File

@@ -708,6 +708,16 @@ public class UiUtils{
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Brown : R.style.Theme_Mastodon_Dark_Brown;
});
break;
case RED:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack_Red : R.style.Theme_Mastodon_AutoLightDark_Red;
case LIGHT ->
R.style.Theme_Mastodon_Light_Red;
case DARK ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Red : R.style.Theme_Mastodon_Dark_Red;
});
break;
case YELLOW:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO ->
@@ -718,6 +728,16 @@ public class UiUtils{
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Yellow : R.style.Theme_Mastodon_Dark_Yellow;
});
break;
case MATERIAL3:
context.setTheme(switch(GlobalUserPreferences.theme){
case AUTO ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_AutoLightDark_TrueBlack_Material3 : R.style.Theme_Mastodon_AutoLightDark_Material3;
case LIGHT ->
R.style.Theme_Mastodon_Light_Material3;
case DARK ->
GlobalUserPreferences.trueBlackTheme ? R.style.Theme_Mastodon_Dark_TrueBlack_Material3 : R.style.Theme_Mastodon_Dark_Material3;
});
break;
}
}

View File

@@ -0,0 +1,59 @@
package org.joinmastodon.android.ui.views;
import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.widget.Button;
import org.joinmastodon.android.R;
import org.joinmastodon.android.ui.utils.UiUtils;
import androidx.annotation.DrawableRes;
import me.grishka.appkit.utils.V;
public class FilterChipView extends Button{
private boolean currentlySelected;
public FilterChipView(Context context){
this(context, null);
}
public FilterChipView(Context context, AttributeSet attrs){
this(context, attrs, 0);
}
public FilterChipView(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
setCompoundDrawablePadding(V.dp(8));
setBackgroundResource(R.drawable.bg_filter_chip);
setTextAppearance(R.style.m3_label_large);
setTextColor(getResources().getColorStateList(R.color.filter_chip_text, context.getTheme()));
setCompoundDrawableTintList(ColorStateList.valueOf(UiUtils.getThemeColor(context, R.attr.colorM3OnSurface)));
updatePadding();
}
@Override
protected void drawableStateChanged(){
super.drawableStateChanged();
if(currentlySelected==isSelected())
return;
currentlySelected=isSelected();
Drawable start=currentlySelected ? getResources().getDrawable(R.drawable.ic_baseline_check_18, getContext().getTheme()) : null;
Drawable end=getCompoundDrawablesRelative()[2];
setCompoundDrawablesRelativeWithIntrinsicBounds(start, null, end, null);
updatePadding();
}
private void updatePadding(){
int vertical=V.dp(6);
Drawable[] drawables=getCompoundDrawablesRelative();
setPaddingRelative(V.dp(drawables[0]==null ? 16 : 8), vertical, V.dp(drawables[2]==null ? 16 : 8), vertical);
}
public void setDrawableEnd(@DrawableRes int drawable){
setCompoundDrawablesRelativeWithIntrinsicBounds(0, 0, drawable, 0);
updatePadding();
}
}

View File

@@ -5,19 +5,34 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.InsetDrawable;
import android.os.Build;
import android.text.Editable;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.TextView;
import org.joinmastodon.android.R;
import org.joinmastodon.android.ui.utils.SimpleTextWatcher;
import org.joinmastodon.android.ui.utils.UiUtils;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V;
@@ -28,6 +43,10 @@ public class FloatingHintEditTextLayout extends FrameLayout{
private int offsetY;
private boolean hintVisible;
private Animator currentAnim;
private float animProgress;
private RectF tmpRect=new RectF();
private ColorStateList labelColors, origHintColors;
private boolean errorState;
public FloatingHintEditTextLayout(Context context){
this(context, null);
@@ -44,7 +63,9 @@ public class FloatingHintEditTextLayout extends FrameLayout{
TypedArray ta=context.obtainStyledAttributes(attrs, R.styleable.FloatingHintEditTextLayout);
labelTextSize=ta.getDimensionPixelSize(R.styleable.FloatingHintEditTextLayout_android_labelTextSize, V.dp(12));
offsetY=ta.getDimensionPixelOffset(R.styleable.FloatingHintEditTextLayout_editTextOffsetY, 0);
labelColors=ta.getColorStateList(R.styleable.FloatingHintEditTextLayout_labelTextColor);
ta.recycle();
setAddStatesFromChildren(true);
}
@Override
@@ -58,13 +79,15 @@ public class FloatingHintEditTextLayout extends FrameLayout{
label=new TextView(getContext());
label.setTextSize(TypedValue.COMPLEX_UNIT_PX, labelTextSize);
label.setTextColor(edit.getHintTextColors());
// label.setTextColor(labelColors==null ? edit.getHintTextColors() : labelColors);
origHintColors=edit.getHintTextColors();
label.setText(edit.getHint());
label.setSingleLine();
label.setPivotX(0f);
label.setPivotY(0f);
label.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO);
LayoutParams lp=new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.START | Gravity.TOP);
lp.setMarginStart(edit.getPaddingStart());
lp.setMarginStart(edit.getPaddingStart()+((LayoutParams)edit.getLayoutParams()).getMarginStart());
addView(label, lp);
hintVisible=edit.getText().length()==0;
@@ -75,6 +98,11 @@ public class FloatingHintEditTextLayout extends FrameLayout{
}
private void onTextChanged(Editable text){
if(errorState){
errorState=false;
setForeground(getResources().getDrawable(R.drawable.bg_m3_outlined_text_field));
refreshDrawableState();
}
boolean newHintVisible=text.length()==0;
if(newHintVisible==hintVisible)
return;
@@ -83,42 +111,210 @@ public class FloatingHintEditTextLayout extends FrameLayout{
hintVisible=newHintVisible;
label.setAlpha(1);
float scale=edit.getLineHeight()/(float)label.getLineHeight();
float transY=edit.getHeight()/2f-edit.getLineHeight()/2f+(edit.getTop()-label.getTop())-(label.getHeight()/2f-label.getLineHeight()/2f);
AnimatorSet anim=new AnimatorSet();
if(hintVisible){
anim.playTogether(
ObjectAnimator.ofFloat(edit, TRANSLATION_Y, 0),
ObjectAnimator.ofFloat(label, SCALE_X, scale),
ObjectAnimator.ofFloat(label, SCALE_Y, scale),
ObjectAnimator.ofFloat(label, TRANSLATION_Y, transY)
);
edit.setHintTextColor(0);
}else{
label.setScaleX(scale);
label.setScaleY(scale);
label.setTranslationY(transY);
anim.playTogether(
ObjectAnimator.ofFloat(edit, TRANSLATION_Y, offsetY),
ObjectAnimator.ofFloat(label, SCALE_X, 1f),
ObjectAnimator.ofFloat(label, SCALE_Y, 1f),
ObjectAnimator.ofFloat(label, TRANSLATION_Y, 0f)
);
}
anim.setDuration(150);
anim.setInterpolator(CubicBezierInterpolator.DEFAULT);
anim.start();
anim.addListener(new AnimatorListenerAdapter(){
edit.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){
@Override
public void onAnimationEnd(Animator animation){
currentAnim=null;
public boolean onPreDraw(){
edit.getViewTreeObserver().removeOnPreDrawListener(this);
float scale=edit.getLineHeight()/(float)label.getLineHeight();
float transY=edit.getHeight()/2f-edit.getLineHeight()/2f+(edit.getTop()-label.getTop())-(label.getHeight()/2f-label.getLineHeight()/2f);
AnimatorSet anim=new AnimatorSet();
if(hintVisible){
label.setAlpha(0);
edit.setHintTextColor(label.getTextColors());
anim.playTogether(
ObjectAnimator.ofFloat(edit, TRANSLATION_Y, 0),
ObjectAnimator.ofFloat(label, SCALE_X, scale),
ObjectAnimator.ofFloat(label, SCALE_Y, scale),
ObjectAnimator.ofFloat(label, TRANSLATION_Y, transY),
ObjectAnimator.ofFloat(FloatingHintEditTextLayout.this, "animProgress", 0f)
);
edit.setHintTextColor(0);
}else{
label.setScaleX(scale);
label.setScaleY(scale);
label.setTranslationY(transY);
anim.playTogether(
ObjectAnimator.ofFloat(edit, TRANSLATION_Y, offsetY),
ObjectAnimator.ofFloat(label, SCALE_X, 1f),
ObjectAnimator.ofFloat(label, SCALE_Y, 1f),
ObjectAnimator.ofFloat(label, TRANSLATION_Y, 0f),
ObjectAnimator.ofFloat(FloatingHintEditTextLayout.this, "animProgress", 1f)
);
}
anim.setDuration(150);
anim.setInterpolator(CubicBezierInterpolator.DEFAULT);
anim.start();
anim.addListener(new AnimatorListenerAdapter(){
@Override
public void onAnimationEnd(Animator animation){
currentAnim=null;
if(hintVisible){
label.setAlpha(0);
edit.setHintTextColor(origHintColors);
}
}
});
currentAnim=anim;
return true;
}
});
currentAnim=anim;
}
@Keep
public void setAnimProgress(float progress){
animProgress=progress;
invalidate();
}
@Keep
public float getAnimProgress(){
return animProgress;
}
@Override
public void onDrawForeground(Canvas canvas){
if(getForeground()!=null && animProgress>0){
canvas.save();
float width=(label.getWidth()+V.dp(8))*animProgress;
float centerX=label.getLeft()+label.getWidth()/2f;
tmpRect.set(centerX-width/2f, label.getTop(), centerX+width/2f, label.getBottom());
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O)
canvas.clipOutRect(tmpRect);
else
canvas.clipRect(tmpRect, Region.Op.DIFFERENCE);
super.onDrawForeground(canvas);
canvas.restore();
}else{
super.onDrawForeground(canvas);
}
}
@Override
public void setForeground(Drawable foreground){
super.setForeground(new PaddedForegroundDrawable(foreground));
}
@Override
public Drawable getForeground(){
if(super.getForeground() instanceof PaddedForegroundDrawable pfd){
return pfd.wrapped;
}
return null;
}
@Override
protected void drawableStateChanged(){
super.drawableStateChanged();
if(label==null || errorState)
return;
ColorStateList color=labelColors==null ? origHintColors : labelColors;
label.setTextColor(color.getColorForState(getDrawableState(), 0xff00ff00));
}
public void setErrorState(){
if(errorState)
return;
errorState=true;
setForeground(getResources().getDrawable(R.drawable.bg_m3_outlined_text_field_error, getContext().getTheme()));
label.setTextColor(UiUtils.getThemeColor(getContext(), R.attr.colorM3Error));
}
private class PaddedForegroundDrawable extends Drawable{
private final Drawable wrapped;
private PaddedForegroundDrawable(Drawable wrapped){
this.wrapped=wrapped;
wrapped.setCallback(new Callback(){
@Override
public void invalidateDrawable(@NonNull Drawable who){
invalidateSelf();
}
@Override
public void scheduleDrawable(@NonNull Drawable who, @NonNull Runnable what, long when){
scheduleSelf(what, when);
}
@Override
public void unscheduleDrawable(@NonNull Drawable who, @NonNull Runnable what){
unscheduleSelf(what);
}
});
}
@Override
public void draw(@NonNull Canvas canvas){
wrapped.draw(canvas);
}
@Override
public void setAlpha(int alpha){
wrapped.setAlpha(alpha);
}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter){
wrapped.setColorFilter(colorFilter);
}
@Override
public int getOpacity(){
return wrapped.getOpacity();
}
@Override
public boolean setState(@NonNull int[] stateSet){
return wrapped.setState(stateSet);
}
@Override
public int getLayoutDirection(){
return wrapped.getLayoutDirection();
}
@Override
public int getAlpha(){
return wrapped.getAlpha();
}
@Nullable
@Override
public ColorFilter getColorFilter(){
return wrapped.getColorFilter();
}
@Override
public boolean isStateful(){
return wrapped.isStateful();
}
@NonNull
@Override
public int[] getState(){
return wrapped.getState();
}
@NonNull
@Override
public Drawable getCurrent(){
return wrapped.getCurrent();
}
@Override
public void applyTheme(@NonNull Resources.Theme t){
wrapped.applyTheme(t);
}
@Override
public boolean canApplyTheme(){
return wrapped.canApplyTheme();
}
@Override
protected void onBoundsChange(@NonNull Rect bounds){
super.onBoundsChange(bounds);
LayoutParams lp=(LayoutParams) edit.getLayoutParams();
wrapped.setBounds(bounds.left+lp.leftMargin-V.dp(12), bounds.top, bounds.right-lp.rightMargin+V.dp(12), bounds.bottom);
}
}
}

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?android:colorPrimary" android:state_enabled="true"/>
<item android:color="?colorPollVoted"/>
<item android:color="?attr/colorButtonBackgroundPrimaryDarkOnLight" android:state_enabled="true"/>
<item android:color="?colorButtonBackgroundPrimaryDarkOnLightDisabled"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorSecondary" android:state_enabled="true"/>
<item android:color="?colorPollVoted"/>
<item android:color="?colorButtonBackgroundPrimaryLightOnDark" android:state_enabled="true"/>
<item android:color="?colorButtonBackgroundPrimaryLightOnDarkDisabled"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_25" android:state_enabled="true"/>
<item android:color="@color/gray_100"/>
<item android:color="?colorButtonBackgroundSecondaryDarkOnLight" android:state_enabled="true"/>
<item android:color="?colorButtonBackgroundSecondaryDarkOnLightDisabled"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorPollVoted" android:state_enabled="true"/>
<item android:color="?colorSearchHint"/>
<item android:color="?colorButtonBackgroundSecondaryLightOnDark" android:state_enabled="true"/>
<item android:color="?colorButtonBackgroundSecondaryLightOnDarkDisabled"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_50" android:state_enabled="true"/>
<item android:color="?colorTabInactive"/>
<item android:color="?colorButtonTextPrimaryDarkOnLight" android:state_enabled="true"/>
<item android:color="?colorButtonTextPrimaryDarkOnLightDisabled"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_800" android:state_enabled="true"/>
<item android:color="?colorTabInactive"/>
<item android:color="?colorButtonTextPrimaryLightOnDark" android:state_enabled="true"/>
<item android:color="?colorButtonTextPrimaryLightOnDarkDisabled"/>
</selector>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?android:colorPrimary" android:state_enabled="true"/>
<item android:color="?colorTabInactive"/>
<item android:color="?colorButtonTextSecondaryDarkOnLight" android:state_enabled="true"/>
<item android:color="?colorButtonTextSecondaryDarkOnLightDisabled"/>
</selector>

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="?colorM3Primary" android:state_focused="true"/>
<item android:color="?colorM3OnSurfaceVariant"/>
</selector>

View File

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

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:left="12dp" android:top="12dp" android:right="12dp" android:bottom="12dp">
<selector>
<item android:state_focused="true">
<shape>
<stroke android:color="?colorM3Primary" android:width="2dp"/>
<corners android:radius="4dp"/>
</shape>
</item>
<item>
<shape>
<stroke android:color="?colorM3Outline" android:width="1dp"/>
<corners android:radius="4dp"/>
</shape>
</item>
</selector>
</item>
</layer-list>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:left="12dp" android:top="12dp" android:right="12dp" android:bottom="12dp">
<shape>
<stroke android:color="?colorM3Error" android:width="2dp"/>
<corners android:radius="4dp"/>
</shape>
</item>
</layer-list>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="?colorM3Background"/>
</item>
<item android:id="@+id/color_overlay">
<color android:color="?colorM3Primary"/>
</item>
</layer-list>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:width="8dp"/>
<solid android:color="#00000000"/>
</shape>

View File

@@ -0,0 +1,5 @@
<vector android:height="18dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M7,10l5,5 5,-5z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="18dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M9,16.17L4.83,12l-1.42,1.41L9,19 21,7l-1.41,-1.41z"/>
</vector>

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_selected="true" android:drawable="@drawable/ic_fluent_arrow_repeat_all_24_filled"/>
<item android:state_selected="true" android:drawable="@drawable/ic_fluent_arrow_repeat_all_24_very_filled"/>
<item android:state_enabled="true" android:drawable="@drawable/ic_fluent_arrow_repeat_all_24_regular"/>
<item android:drawable="@drawable/ic_fluent_arrow_repeat_all_off_24_regular"/>
</selector>

View File

@@ -0,0 +1,23 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M9,9.123C7.423,9.123 6.125,10.421 6.125,11.994C6.125,12.523 6.269,13.014 6.514,13.434C6.514,13.435 6.513,13.436 6.514,13.438L6.619,13.607L6.623,13.613C6.666,13.679 6.706,13.747 6.744,13.816L7.787,12.775C9.015,11.549 10.977,11.548 12.205,12.775C12.789,13.359 13.077,14.104 13.105,14.863L15.002,14.863C16.579,14.863 17.875,13.567 17.875,11.992C17.875,11.463 17.731,10.972 17.486,10.553L17.486,10.549L17.381,10.379C17.337,10.311 17.295,10.241 17.256,10.17L16.215,11.211C14.986,12.439 13.025,12.44 11.797,11.213C11.218,10.634 10.931,9.885 10.902,9.123L9,9.123z"
android:strokeWidth="3"
android:fillColor="#212121"/>
<path
android:pathData="M20.787,8.06C20.603,7.828 20.319,7.678 20,7.678c-0.552,0 -1,0.447 -1,0.999 0,0.208 0.064,0.401 0.172,0.561C19.695,10.028 20,10.975 20,11.993c0,2.759 -2.238,4.996 -4.999,4.996l-5.586,-0.001 1.294,-1.291 0.084,-0.095c0.281,-0.362 0.279,-0.872 -0.006,-1.231L10.709,14.284 10.614,14.2C10.252,13.92 9.741,13.922 9.382,14.206L9.294,14.284 6.289,17.287 6.206,17.382c-0.281,0.362 -0.279,0.872 0.006,1.231l0.078,0.087 3.005,3.003 0.094,0.083c0.392,0.305 0.96,0.277 1.32,-0.083 0.363,-0.362 0.389,-0.934 0.078,-1.326l-0.078,-0.087 -1.304,-1.303 5.596,0.001 0.241,-0.004C18.996,18.857 22,15.776 22,11.993 22,10.534 21.552,9.178 20.787,8.057Z"
android:fillColor="#212121"/>
<path
android:pathData="M14.712,2.289 L14.625,2.211C14.233,1.901 13.661,1.926 13.298,2.289L13.22,2.376C12.91,2.768 12.936,3.34 13.298,3.702l1.299,1.297 -5.598,0 -0.241,0.004C5.004,5.13 2,8.211 2,11.993c0,1.445 0.438,2.787 1.189,3.898 0.182,0.251 0.477,0.415 0.811,0.415 0.552,0 1,-0.447 1,-0.999C5,15.091 4.931,14.891 4.815,14.729L4.68,14.511C4.248,13.772 4,12.911 4,11.993 4,9.234 6.238,6.998 8.999,6.998L14.595,6.998 13.298,8.295 13.22,8.382c-0.311,0.392 -0.285,0.964 0.078,1.326 0.391,0.39 1.024,0.39 1.414,0L17.718,6.705 17.795,6.618C18.106,6.226 18.08,5.654 17.718,5.292Z"
android:strokeWidth="3"
android:fillColor="#212121"/>
<path
android:pathData="M20.11,5.619L20.11,5.619A1.393,0.037 0,0 1,21.503 5.656L21.503,5.656A1.393,0.037 0,0 1,20.11 5.693L20.11,5.693A1.393,0.037 0,0 1,18.717 5.656L18.717,5.656A1.393,0.037 0,0 1,20.11 5.619z"
android:strokeWidth="52.513"
android:fillColor="#613583"
android:fillType="evenOdd"
android:fillAlpha="0.0156863"/>
</vector>

View File

@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="20dp" android:height="20dp" android:viewportWidth="20" android:viewportHeight="20">
<path android:pathData="M10 18c4.418 0 8-3.582 8-8s-3.582-8-8-8-8 3.582-8 8 3.582 8 8 8zm0-15c0.657 0 1.407 0.59 2.022 1.908 0.217 0.466 0.406 1.002 0.559 1.592H7.419c0.153-0.59 0.342-1.126 0.56-1.592C8.592 3.59 9.342 3 10 3zM7.072 4.485C6.796 5.077 6.565 5.757 6.389 6.5H3.936c0.837-1.446 2.176-2.565 3.778-3.118-0.241 0.33-0.456 0.704-0.642 1.103zM6.192 7.5C6.068 8.288 6 9.13 6 10c0 0.87 0.067 1.712 0.193 2.5H3.46C3.163 11.724 3 10.88 3 10c0-0.88 0.163-1.724 0.46-2.5h2.733zm0.197 6c0.176 0.743 0.407 1.422 0.683 2.015 0.186 0.399 0.401 0.773 0.642 1.103-1.602-0.553-2.941-1.672-3.778-3.118H6.39zm1.03 0h5.162c-0.153 0.59-0.342 1.126-0.56 1.592C11.408 16.41 10.658 17 10 17c-0.657 0-1.407-0.59-2.022-1.908C7.761 14.626 7.572 14.09 7.42 13.5zm5.375-1H7.206C7.073 11.725 7 10.883 7 10s0.074-1.725 0.206-2.5h5.588C12.927 8.275 13 9.117 13 10s-0.073 1.725-0.206 2.5zm0.817 1h2.453c-0.837 1.446-2.176 2.565-3.778 3.118 0.241-0.33 0.456-0.704 0.642-1.103 0.276-0.593 0.507-1.272 0.683-2.015zm2.93-1h-2.734C13.933 11.712 14 10.87 14 10c0-0.87-0.067-1.712-0.193-2.5h2.733C16.837 8.276 17 9.12 17 10c0 0.88-0.163 1.724-0.46 2.5zm-4.255-9.118c1.602 0.553 2.941 1.672 3.778 3.118H13.61c-0.176-0.743-0.407-1.423-0.683-2.015-0.186-0.399-0.401-0.773-0.642-1.103z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6zM20,6l-8,5 -8,-5h16zM20,18L4,18L4,8l8,5 8,-5v10z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M17,7h-4v2h4c1.65,0 3,1.35 3,3s-1.35,3 -3,3h-4v2h4c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5zM11,15L7,15c-1.65,0 -3,-1.35 -3,-3s1.35,-3 3,-3h4L11,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h4v-2zM8,11h8v2L8,13z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M2,17h20v2H2V17zM3.15,12.95L4,11.47l0.85,1.48l1.3,-0.75L5.3,10.72H7v-1.5H5.3l0.85,-1.47L4.85,7L4,8.47L3.15,7l-1.3,0.75L2.7,9.22H1v1.5h1.7L1.85,12.2L3.15,12.95zM9.85,12.2l1.3,0.75L12,11.47l0.85,1.48l1.3,-0.75l-0.85,-1.48H15v-1.5h-1.7l0.85,-1.47L12.85,7L12,8.47L11.15,7l-1.3,0.75l0.85,1.47H9v1.5h1.7L9.85,12.2zM23,9.22h-1.7l0.85,-1.47L20.85,7L20,8.47L19.15,7l-1.3,0.75l0.85,1.47H17v1.5h1.7l-0.85,1.48l1.3,0.75L20,11.47l0.85,1.48l1.3,-0.75l-0.85,-1.48H23V9.22z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#000000"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,6c1.1,0 2,0.9 2,2s-0.9,2 -2,2 -2,-0.9 -2,-2 0.9,-2 2,-2m0,10c2.7,0 5.8,1.29 6,2L6,18c0.23,-0.72 3.31,-2 6,-2m0,-12C9.79,4 8,5.79 8,8s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="100dp"/>
<solid android:color="#000"/>
</shape>

View File

@@ -4,8 +4,7 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="48dp"
android:paddingLeft="20dp"
android:paddingRight="20dp">
android:paddingHorizontal="16dp">
<FrameLayout
android:id="@+id/reply_btn"
@@ -15,10 +14,11 @@
<TextView
android:id="@+id/reply"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_gravity="center"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:drawableStart="@drawable/ic_fluent_chat_multiple_24_regular"
android:drawablePadding="8dp"
android:paddingHorizontal="8dp"
android:drawableTint="?android:textColorSecondary"
android:gravity="center_vertical"
android:textAppearance="@style/m3_label_large"
@@ -38,10 +38,11 @@
<TextView
android:id="@+id/boost"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_gravity="center"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:drawableStart="@drawable/ic_boost"
android:drawablePadding="8dp"
android:paddingHorizontal="8dp"
android:drawableTint="@color/boost_icon"
android:textColor="@color/boost_icon"
android:gravity="center_vertical"
@@ -62,10 +63,11 @@
<TextView
android:id="@+id/favorite"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_gravity="center"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:drawableStart="@drawable/ic_fluent_star_24_selector"
android:drawablePadding="8dp"
android:paddingHorizontal="8dp"
android:drawableTint="@color/favorite_icon"
android:textColor="@color/favorite_icon"
android:gravity="center_vertical"
@@ -103,14 +105,14 @@
<FrameLayout
android:id="@+id/share_btn"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:minWidth="56dp">
android:layout_height="match_parent">
<ImageView
android:id="@+id/share"
android:layout_width="wrap_content"
android:layout_height="24dp"
android:layout_gravity="center"
android:layout_gravity="center_vertical"
android:src="@drawable/ic_fluent_share_24_regular"
android:paddingHorizontal="8dp"
android:tint="?android:textColorSecondary"
android:gravity="center_vertical"/>
</FrameLayout>

View File

@@ -18,7 +18,8 @@
android:layout_marginTop="6dp"
android:layout_marginBottom="8dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:visibility="gone">
<View
android:id="@+id/border_top"
android:layout_width="match_parent"

View File

@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<me.grishka.appkit.views.FragmentRootLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="match_parent"
tools:context=".fragments.onboarding.AccountActivationFragment">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="?colorBackgroundLight">
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
@@ -17,40 +17,67 @@
android:orientation="vertical"
android:clipChildren="false">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_headline_medium"
android:minHeight="36dp"
android:layout_marginTop="32dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="12dp"
android:gravity="center_vertical"
android:text="@string/confirm_email_title"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:textAppearance="@style/m3_title_medium"
android:textColor="?android:textColorSecondary"
android:layout_marginStart="56dp"
android:layout_marginEnd="24dp"
android:layout_marginTop="12dp"
android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurface"
android:text="@string/confirm_email_subtitle"/>
<ImageView
android:layout_width="wrap_content"
android:layout_width="230dp"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_margin="32dp"
android:layout_marginTop="12dp"
android:importantForAccessibility="no"
android:adjustViewBounds="true"
android:src="@drawable/confirm_email_art"/>
</LinearLayout>
</ScrollView>
<include layout="@layout/button_bar_activation" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_gravity="center_horizontal">
</me.grishka.appkit.views.FragmentRootLinearLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_label_large"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/confirm_email_didnt_get"/>
<Button
android:id="@+id/btn_resend"
android:layout_width="wrap_content"
android:layout_height="40dp"
android:text="@string/resend"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:fontFeatureSettings="'tnum'"
style="@style/Widget.Mastodon.M3.Button.Text"/>
</LinearLayout>
<Button
android:id="@+id/btn_next"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:minWidth="145dp"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:text="@string/open_email_app" />
</LinearLayout>

View File

@@ -5,14 +5,103 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:id="@+id/appkit_loader_root"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?colorBackgroundLight">
xmlns:android="http://schemas.android.com/apk/res/android">
<RelativeLayout
android:id="@+id/top_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="8dp"
android:background="@drawable/bg_onboarding_panel">
<EditText
android:id="@+id/search_edit"
android:layout_width="match_parent"
android:layout_height="48dp"
android:elevation="0dp"
android:inputType="textFilter|textUri"
android:layout_toEndOf="@+id/btn_back"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:layout_marginStart="8dp"
android:layout_marginEnd="16dp"
android:textAppearance="@style/m3_body_large"
android:paddingTop="0dp"
android:paddingBottom="0dp"
android:paddingStart="12dp"
android:paddingEnd="40dp"
android:drawableStart="@drawable/ic_m3_search"
android:drawablePadding="8dp"
android:drawableTint="?colorM3OnSurfaceVariant"
android:gravity="center_vertical"
android:textColorHint="?colorM3OnSurfaceVariant"
android:textColor="?colorM3OnSurfaceVariant"
android:background="@drawable/round_rect"
android:backgroundTint="?colorM3SurfaceVariant"
android:hint="@string/search_communities"/>
<View
android:id="@+id/focus_thing"
android:layout_width="1dp"
android:layout_height="1dp"
android:focusable="true"
android:focusableInTouchMode="true"
android:importantForAccessibility="no"/>
<ImageButton
android:id="@+id/btn_back"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="20dp"
android:layout_marginStart="8dp"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:background="?android:selectableItemBackgroundBorderless"
android:tint="?colorM3OnSurface"
android:contentDescription="@string/back"
android:src="@drawable/ic_arrow_back"/>
<ImageButton
android:id="@+id/clear"
android:layout_width="24dp"
android:layout_height="24dp"
android:background="?android:selectableItemBackgroundBorderless"
android:layout_alignEnd="@id/search_edit"
android:layout_alignTop="@id/search_edit"
android:layout_margin="12dp"
android:contentDescription="@string/clear"
android:tint="?colorM3OnSurfaceVariant"
android:visibility="gone"
android:src="@drawable/ic_m3_cancel"/>
<HorizontalScrollView
android:id="@+id/filters_scroll"
android:layout_below="@id/search_edit"
android:layout_width="match_parent"
android:layout_height="48dp"
android:scrollbars="none">
<LinearLayout
android:id="@+id/filters_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:paddingTop="8dp"
android:paddingRight="16dp"
android:paddingBottom="8dp"
android:paddingLeft="16dp"
android:showDividers="middle"
android:divider="@drawable/empty_8dp">
</LinearLayout>
</HorizontalScrollView>
</RelativeLayout>
<FrameLayout
android:id="@+id/appkit_loader_content"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1">
android:layout_weight="1"
android:background="?colorM3Surface">
<include layout="@layout/loading"
android:id="@+id/loading"/>
@@ -33,32 +122,29 @@
android:id="@+id/button_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorBackgroundLight"
android:outlineProvider="bounds"
android:orientation="horizontal"
android:elevation="3dp">
android:orientation="vertical"
android:background="@drawable/bg_onboarding_panel">
<Button
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:minWidth="145dp"
style="?secondaryLargeButtonStyle"
android:text="@string/back"/>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:textAppearance="@style/m3_body_small"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/signup_random_server_explain"/>
<Button
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:minWidth="145dp"
style="?primaryLargeButtonStyle"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:text="@string/next" />
</LinearLayout>

View File

@@ -8,39 +8,24 @@
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="?colorBackgroundLight"/>
android:layout_weight="1"/>
<LinearLayout
android:id="@+id/button_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorBackgroundLight"
android:outlineProvider="bounds"
android:orientation="horizontal"
android:elevation="3dp">
<Button
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:minWidth="145dp"
style="?secondaryLargeButtonStyle"
android:text="@string/back"/>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"/>
android:orientation="horizontal">
<Button
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:minWidth="145dp"
style="?primaryLargeButtonStyle"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:text="@string/i_agree" />
</LinearLayout>

View File

@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<me.grishka.appkit.views.FragmentRootLinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -8,8 +9,7 @@
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="?colorBackgroundLight">
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
@@ -17,68 +17,58 @@
android:orientation="vertical"
android:clipChildren="false">
<TextView
android:id="@+id/title"
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
android:id="@+id/display_name_wrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:textAppearance="@style/m3_headline_medium"
android:minHeight="36dp"
android:layout_marginTop="32dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:gravity="center_vertical"
tools:text="@string/signup_title"/>
android:layout_height="80dp"
android:paddingTop="4dp"
app:labelTextColor="@color/m3_outlined_text_field_label"
android:foreground="@drawable/bg_m3_outlined_text_field">
<FrameLayout
android:id="@+id/ava_wrap"
android:layout_width="88dp"
android:layout_height="88dp"
android:layout_gravity="center_horizontal"
android:layout_marginBottom="24dp">
<ImageView
android:id="@+id/avatar"
<EditText
android:id="@+id/display_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/default_avatar"/>
android:layout_height="56dp"
android:layout_marginStart="56dp"
android:layout_marginEnd="24dp"
android:layout_marginTop="8dp"
android:padding="16dp"
android:background="@null"
android:elevation="0dp"
android:inputType="textPersonName|textCapWords"
android:autofillHints="name"
android:singleLine="true"
android:hint="@string/display_name"/>
<TextView
android:layout_width="match_parent"
android:layout_height="22dp"
android:layout_gravity="bottom"
android:gravity="center"
android:background="@color/gray_800t"
android:textAppearance="@style/m3_label_large"
android:textColor="#eee"
android:text="@string/edit_photo"/>
<View
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="start|top"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:backgroundTint="?colorM3OnSurfaceVariant"
android:background="@drawable/ic_outline_person_24"/>
</FrameLayout>
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
<EditText
android:id="@+id/display_name"
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
android:id="@+id/username_wrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:inputType="textPersonName|textCapWords"
android:autofillHints="name"
android:singleLine="true"
android:hint="@string/display_name"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginBottom="24dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp">
android:layout_height="80dp"
android:paddingTop="4dp"
app:labelTextColor="@color/m3_outlined_text_field_label"
android:foreground="@drawable/bg_m3_outlined_text_field">
<EditText
android:id="@+id/username"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="56dp"
android:layout_marginStart="56dp"
android:layout_marginEnd="24dp"
android:layout_marginTop="8dp"
android:padding="16dp"
android:background="@null"
android:elevation="0dp"
android:inputType="textFilter|textNoSuggestions"
android:autofillHints="username"
android:singleLine="true"
@@ -89,70 +79,152 @@
android:id="@+id/domain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="5dp"
android:layout_gravity="right|center_vertical"
android:layout_marginRight="20dp"
android:paddingLeft="8dp"
android:paddingRight="16dp"
android:textAppearance="@style/m3_title_medium"
android:textAppearance="@style/m3_body_large"
tools:text="\@mastodon.social"/>
</FrameLayout>
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
<EditText
android:id="@+id/email"
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
android:id="@+id/email_wrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="8dp"
android:inputType="textEmailAddress"
android:autofillHints="emailAddress"
android:singleLine="true"
android:hint="@string/email"/>
android:layout_height="80dp"
android:paddingTop="4dp"
app:labelTextColor="@color/m3_outlined_text_field_label"
android:foreground="@drawable/bg_m3_outlined_text_field">
<EditText
android:id="@+id/password"
<EditText
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginStart="56dp"
android:layout_marginEnd="24dp"
android:layout_marginTop="8dp"
android:padding="16dp"
android:background="@null"
android:elevation="0dp"
android:inputType="textEmailAddress"
android:autofillHints="emailAddress"
android:singleLine="true"
android:hint="@string/email"/>
<View
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="start|top"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:backgroundTint="?colorM3OnSurfaceVariant"
android:background="@drawable/ic_outline_email_24"/>
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
android:id="@+id/password_wrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:inputType="textPassword"
android:autofillHints="password"
android:singleLine="true"
android:fontFamily="sans-serif"
android:hint="@string/password"/>
android:layout_height="80dp"
android:paddingTop="4dp"
app:labelTextColor="@color/m3_outlined_text_field_label"
android:foreground="@drawable/bg_m3_outlined_text_field">
<EditText
android:id="@+id/password"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginStart="56dp"
android:layout_marginEnd="24dp"
android:layout_marginTop="8dp"
android:padding="16dp"
android:background="@null"
android:elevation="0dp"
android:inputType="textPassword"
android:autofillHints="password"
android:singleLine="true"
android:fontFamily="sans-serif"
android:hint="@string/password"/>
<View
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_gravity="start|top"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:backgroundTint="?colorM3OnSurfaceVariant"
android:background="@drawable/ic_outline_password_24"/>
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
android:id="@+id/password_confirm_wrap"
android:layout_width="match_parent"
android:layout_height="80dp"
android:paddingTop="4dp"
app:labelTextColor="@color/m3_outlined_text_field_label"
android:foreground="@drawable/bg_m3_outlined_text_field">
<EditText
android:id="@+id/password_confirm"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginStart="56dp"
android:layout_marginEnd="24dp"
android:layout_marginTop="8dp"
android:padding="16dp"
android:background="@null"
android:elevation="0dp"
android:inputType="textPassword"
android:autofillHints="password"
android:singleLine="true"
android:fontFamily="sans-serif"
android:hint="@string/confirm_password"/>
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:textAppearance="@style/m3_body_medium"
android:textColor="?android:textColorSecondary"
android:layout_marginStart="56dp"
android:layout_marginEnd="20dp"
android:textAppearance="@style/m3_body_small"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/password_note"/>
<EditText
android:id="@+id/reason"
<org.joinmastodon.android.ui.views.FloatingHintEditTextLayout
android:id="@+id/reason_wrap"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:inputType="textCapSentences|textMultiLine"
android:hint="@string/signup_reason"/>
android:paddingTop="4dp"
app:labelTextColor="@color/m3_outlined_text_field_label"
android:foreground="@drawable/bg_m3_outlined_text_field">
<EditText
android:id="@+id/reason"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="56dp"
android:layout_marginEnd="24dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="12dp"
android:padding="16dp"
android:background="@null"
android:elevation="0dp"
android:inputType="textCapSentences|textMultiLine"
android:hint="@string/signup_reason"/>
</org.joinmastodon.android.ui.views.FloatingHintEditTextLayout>
<TextView
android:id="@+id/reason_explain"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:textAppearance="@style/m3_body_medium"
android:textColor="?android:textColorSecondary"
android:layout_marginStart="56dp"
android:layout_marginEnd="20dp"
android:textAppearance="@style/m3_body_small"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/signup_reason_note"/>
</LinearLayout>
@@ -163,32 +235,18 @@
android:id="@+id/button_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorBackgroundLight"
android:outlineProvider="bounds"
android:orientation="horizontal"
android:elevation="3dp">
<Button
android:id="@+id/btn_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:minWidth="145dp"
style="?secondaryLargeButtonStyle"
android:text="@string/back"/>
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1"/>
android:orientation="horizontal">
<Button
android:id="@+id/btn_next"
android:layout_width="wrap_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="16dp"
android:minWidth="145dp"
style="?primaryLargeButtonStyle"
style="@style/Widget.Mastodon.M3.Button.Filled"
android:text="@string/next" />
</LinearLayout>

View File

@@ -85,7 +85,7 @@
<LinearLayout
android:id="@+id/posts_btn"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:gravity="center_horizontal"
@@ -112,7 +112,7 @@
<LinearLayout
android:id="@+id/following_btn"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="16dp"
android:padding="4dp"
@@ -140,7 +140,7 @@
<LinearLayout
android:id="@+id/followers_btn"
android:layout_width="wrap_content"
android:layout_height="56dp"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:layout_marginEnd="12dp"
android:padding="4dp"

View File

@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="utf-8"?>
<me.grishka.appkit.views.FragmentRootLinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:id="@+id/appkit_loader_root"
xmlns:android="http://schemas.android.com/apk/res/android"
android:background="?colorBackgroundLight">
<include layout="@layout/appkit_toolbar"/>
<FrameLayout
android:id="@+id/appkit_loader_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<include layout="@layout/loading"
android:id="@+id/loading"/>
<ViewStub android:layout="?errorViewLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/error"
android:visibility="gone"/>
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/content_stub"/>
</FrameLayout>
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="?attr/colorPollVoted"/>
<LinearLayout
android:id="@+id/button_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?colorBackgroundLight"
android:outlineProvider="bounds"
android:orientation="horizontal"
android:elevation="0dp">
<Button
style="?primaryLargeButtonStyle"
android:id="@+id/btn_next"
android:minWidth="145dp"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:layout_weight="1"
android:text="@string/next" />
</LinearLayout>
</me.grishka.appkit.views.FragmentRootLinearLayout>

View File

@@ -1,61 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:layout_marginTop="32dp"
android:layout_marginLeft="19dp"
android:layout_marginRight="19dp"
android:textAppearance="@style/m3_headline_medium"
android:minHeight="36dp"
android:gravity="center_vertical"
android:text="@string/instance_catalog_title"/>
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="19dp"
android:layout_marginRight="19dp"
android:layout_marginBottom="24dp"
android:textAppearance="@style/m3_title_medium"
android:textColor="?android:textColorSecondary"
android:text="@string/instance_catalog_subtitle"/>
<org.joinmastodon.android.ui.tabs.TabLayout
android:id="@+id/categories_list"
android:layout_width="match_parent"
android:layout_height="72dp"
android:background="@drawable/bg_catalog_tabs"
app:tabIndicator="@drawable/mtrl_tabs_default_indicator"
app:tabIndicatorAnimationMode="elastic"
app:tabIndicatorColor="?android:textColorPrimary"
app:tabMinWidth="120dp"
app:tabMaxWidth="120dp"
app:tabMode="scrollable"/>
<EditText
android:id="@+id/search_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textFilter|textNoSuggestions"
android:singleLine="true"
android:imeOptions="actionGo"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="19dp"
android:layout_marginBottom="3dp"
android:drawableStart="@drawable/ic_fluent_search_20_regular"
android:drawablePadding="8dp"
android:drawableTint="?android:textColorSecondary"
android:hint="@string/search_communities"/>
</LinearLayout>

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/display_item_header" />
<TextView
style="@style/m3_headline_small"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginVertical="12dp"
android:text="@string/sk_welcome_title"
/>
<TextView
style="@style/m3_body_large"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:text="@string/sk_welcome_text" />
<View
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:layout_marginTop="16dp"
android:background="?attr/colorPollVoted"/>
<EditText
android:id="@+id/search_edit"
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp"
android:layout_marginHorizontal="16dp"
android:inputType="textFilter|textNoSuggestions"
android:singleLine="true"
android:imeOptions="actionGo"
android:drawableStart="@drawable/ic_fluent_globe_20_regular"
android:drawablePadding="12dp"
android:drawableTint="?android:textColorSecondary"
android:background="@drawable/bg_search_field"
android:paddingHorizontal="16dp"
android:elevation="0dp"
android:hint="@string/sk_example_domain"/>
<ViewStub
android:layout="?errorViewLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/error"
android:visibility="gone" />
</LinearLayout>

View File

@@ -3,73 +3,60 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
android:paddingStart="16dp"
android:paddingEnd="24dp"
android:paddingTop="12dp"
android:paddingBottom="12dp">
<RadioButton
android:id="@+id/radiobtn"
android:layout_width="24dp"
android:layout_width="28dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
android:layout_centerVertical="true"
android:layout_marginStart="-3dp"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true"
android:button="@drawable/ic_round_checkbox"
android:buttonTint="?android:textColorSecondary"
android:buttonTint="@color/m3_radiobutton_tint"
android:background="@null"
android:focusable="false"
android:clickable="false"/>
<ImageView
android:id="@+id/image"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginEnd="16dp"
android:importantForAccessibility="no"
android:layout_toEndOf="@id/radiobtn"
android:scaleType="centerCrop"
tools:src="#0f0"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/radiobtn"
android:layout_toEndOf="@id/image"
android:layout_alignParentTop="true"
android:layout_marginBottom="4dp"
android:textAppearance="@style/m3_title_medium"
android:textAppearance="@style/m3_body_large"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center_vertical"
android:textSize="16sp"
android:minHeight="24dp"
android:textColor="?colorM3OnSurface"
tools:text="mastodon.social"/>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/radiobtn"
android:layout_toEndOf="@id/image"
android:layout_below="@id/title"
android:layout_marginBottom="8dp"
android:textAppearance="@style/m3_body_medium"
android:textColor="?android:textColorSecondary"
android:textColor="?colorM3OnSurfaceVariant"
android:textSize="14sp"
android:lineSpacingExtra="4sp"
tools:text="General-purpose server run by the lead developer of Mastodon"/>
<TextView
android:id="@+id/user_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/radiobtn"
android:layout_below="@id/description"
android:textAppearance="@style/m3_label_medium"
android:textColor="?android:textColorSecondary"
android:drawableStart="@drawable/ic_fluent_people_community_16_regular"
android:drawableTint="?android:textColorSecondary"
android:drawablePadding="8dp"
tools:text="588.8K"/>
<TextView
android:id="@+id/lang"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/user_count"
android:layout_below="@id/description"
android:layout_marginStart="24dp"
android:textAppearance="@style/m3_label_medium"
android:textColor="?android:textColorSecondary"
android:drawableStart="@drawable/ic_fluent_local_language_16_regular"
android:drawableTint="?android:textColorSecondary"
android:drawablePadding="8dp"
tools:text="EN"/>
</RelativeLayout>

View File

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingHorizontal="16dp"
android:paddingVertical="8dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bg_search_field">
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<RadioButton
android:id="@+id/radiobtn"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:button="@drawable/ic_round_checkbox"
android:buttonTint="?android:textColorSecondary"
android:background="@null"
android:focusable="false"
android:clickable="false"/>
<ImageView
android:id="@+id/image"
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_marginEnd="16dp"
android:importantForAccessibility="no"
android:layout_toEndOf="@id/radiobtn"
android:scaleType="centerCrop"
android:visibility="gone"
tools:src="#0f0"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/radiobtn"
android:layout_alignParentTop="true"
android:layout_marginBottom="4dp"
android:textAppearance="@style/m3_title_medium"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center_vertical"
android:textSize="16sp"
android:minHeight="24dp"
tools:text="mastodon.social"/>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/radiobtn"
android:layout_below="@id/title"
android:layout_marginBottom="8dp"
android:textAppearance="@style/m3_body_medium"
android:textColor="?android:textColorSecondary"
android:textSize="14sp"
tools:text="General-purpose server run by the lead developer of Mastodon"/>
<TextView
android:id="@+id/user_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/radiobtn"
android:layout_below="@id/description"
android:textAppearance="@style/m3_label_medium"
android:textColor="?android:textColorSecondary"
android:drawableStart="@drawable/ic_fluent_people_community_16_regular"
android:drawableTint="?android:textColorSecondary"
android:drawablePadding="8dp"
tools:text="588.8K"/>
<TextView
android:id="@+id/lang"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toEndOf="@id/user_count"
android:layout_below="@id/description"
android:layout_marginStart="24dp"
android:textAppearance="@style/m3_label_medium"
android:textColor="?android:textColorSecondary"
android:drawableStart="@drawable/ic_fluent_local_language_16_regular"
android:drawableTint="?android:textColorSecondary"
android:drawablePadding="8dp"
tools:text="EN"/>
</RelativeLayout>
</FrameLayout>
</FrameLayout>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurface"
android:paddingStart="56dp"
android:paddingTop="12dp"
android:paddingEnd="24dp"
android:paddingBottom="12dp">
</TextView>

View File

@@ -1,44 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<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="wrap_content"
android:padding="16dp"
android:elevation="3dp"
android:background="?colorBackgroundLightest"
android:foreground="?android:selectableItemBackground">
android:paddingTop="12dp"
android:paddingEnd="24dp"
android:paddingBottom="12dp"
android:paddingStart="16dp"
android:textSize="16sp"
android:textColor="?colorM3Primary"
android:drawableStart="@drawable/ic_outline_link_24"
android:drawablePadding="16dp"
android:drawableTint="?colorM3Primary"
tools:text="Privacy Policy - example.social">
<ImageView
android:id="@+id/favicon"
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_marginTop="2dp"
android:importantForAccessibility="no"
tools:src="#0f0"/>
<TextView
android:id="@+id/domain"
android:layout_width="match_parent"
android:layout_height="20dp"
android:layout_toEndOf="@id/favicon"
android:layout_marginStart="4dp"
android:singleLine="true"
android:ellipsize="end"
android:textAppearance="@style/m3_title_small"
android:textColor="?android:textColorPrimary"
android:gravity="center_vertical"
tools:text="joinmastodon.org"/>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="24dp"
android:layout_below="@id/domain"
android:layout_marginTop="6dp"
android:textAppearance="@style/m3_title_medium"
android:singleLine="true"
android:ellipsize="end"
android:gravity="center_vertical"
tools:text="Mastodon for Android privacy policy"/>
</RelativeLayout>
</TextView>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingEnd="24dp"
android:paddingBottom="12dp"
android:paddingStart="16dp"
android:baselineAligned="false">
<TextView
android:id="@+id/number"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="16dp"
android:textColor="?colorM3Primary"
android:fontFamily="sans-serif-condensed"
android:textStyle="bold"
android:textSize="22dp"
android:gravity="center"
android:includeFontPadding="false"
tools:text="1"/>
<org.joinmastodon.android.ui.views.LinkedTextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:textAppearance="@style/m3_body_large"
tools:text="No discrimination, including (but not limited to) racism, sexism, homophobia or transphobia."/>
</LinearLayout>

View File

@@ -1,9 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/m3_color" android:title="@string/sk_color_theme_material3"/>
<item android:id="@+id/pink_color" android:title="@string/sk_color_theme_pink"/>
<item android:id="@+id/purple_color" android:title="@string/sk_color_theme_purple"/>
<item android:id="@+id/green_color" android:title="@string/sk_color_theme_green"/>
<item android:id="@+id/blue_color" android:title="@string/sk_color_theme_blue"/>
<item android:id="@+id/brown_color" android:title="@string/sk_color_theme_brown"/>
<item android:id="@+id/red_color" android:title="@string/sk_color_theme_red"/>
<item android:id="@+id/yellow_color" android:title="@string/sk_color_theme_yellow"/>
</menu>

View File

@@ -38,4 +38,13 @@
<string name="sk_settings_always_reveal_content_warnings">Mostra sempre els avisos de contingut</string>
<string name="sk_settings_contribute">Contribueix a Megalodon</string>
<string name="sk_settings_show_federated_timeline">Mostra la línia de temps federada</string>
<string name="sk_notification_type_status">Publicacions</string>
<string name="sk_notify_posts">Notificacions de publicacions</string>
<string name="sk_settings_color_picker">Color de tema</string>
<string name="sk_color_theme_pink">Rosa</string>
<string name="sk_color_theme_purple">Lila</string>
<string name="sk_color_theme_green">Verd</string>
<string name="sk_color_theme_blue">Blau</string>
<string name="sk_color_theme_brown">Marró</string>
<string name="sk_color_theme_yellow">Groc</string>
</resources>

View File

@@ -48,4 +48,15 @@
<string name="sk_notification_type_status">Beiträge</string>
<string name="sk_color_theme_blue">Blau</string>
<string name="sk_poll_allow_multiple">Mehrfachantworten erlauben</string>
<string name="sk_translated_using">Übersetzt mit %s</string>
<string name="sk_post_language">Sprache: %s</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_confirm_clear_recent_languages">Sicher, dass du die Liste der zuletzt verwendeten Sprachen leeren willst\?</string>
<string name="sk_translate_post">Übersetzen</string>
<string name="sk_translate_show_original">Original anzeigen</string>
<string name="sk_available_languages">Verfügbare Sprachen</string>
<string name="sk_clear_recent_languages">Zuletzt verwendete Sprachen leeren</string>
<string name="sk_welcome_title">Willkommen!</string>
<string name="sk_example_domain">beispiel.social</string>
<string name="sk_welcome_text">Der Hai sagt Hi! Um anzufangen, bitte gib den Domain-Namen deiner Heim-Instanz unten ein.</string>
</resources>

View File

@@ -2,28 +2,28 @@
<resources>
<string name="sk_pinned_posts">Anclado</string>
<string name="sk_delete_and_redraft">Eliminar y editar</string>
<string name="sk_confirm_delete_and_redraft_title">Eliminar y editar post</string>
<string name="sk_confirm_delete_and_redraft">Seguro que quiere eliminar y volver a editar este post\?</string>
<string name="sk_pin_post">Fijar en perfil</string>
<string name="sk_confirm_pin_post_title">Fijar post en perfil</string>
<string name="sk_confirm_pin_post">Desea fijar el post en su perfil\?</string>
<string name="sk_pinning">Fijando post</string>
<string name="sk_unpin_post">Quitar del perfil</string>
<string name="sk_confirm_unpin_post_title">Quitar post del perfil</string>
<string name="sk_confirm_unpin_post">Está seguro que quiere quitar el post\?</string>
<string name="sk_confirm_delete_and_redraft_title">Eliminar y editar publicación</string>
<string name="sk_confirm_delete_and_redraft">¿Confirma que quiere eliminar y volver a editar esta publicación\?</string>
<string name="sk_pin_post">Anclar en perfil</string>
<string name="sk_confirm_pin_post_title">Anclar publicación en perfil</string>
<string name="sk_confirm_pin_post">¿Quiere anclar la publicación en su perfil\?</string>
<string name="sk_pinning">Anclando publicación</string>
<string name="sk_unpin_post">Desanclar del perfil</string>
<string name="sk_confirm_unpin_post_title">Desanclar publicación del perfil</string>
<string name="sk_confirm_unpin_post">¿Confirma que quiere desanclar esta publicación\?</string>
<string name="sk_app_name">Megalodon</string>
<string name="sk_unpinning">Quitando post</string>
<string name="sk_unpinning">Desanclando publicación</string>
<string name="sk_image_description">Descripción de la imagen</string>
<string name="sk_visibility_unlisted">Sin listar</string>
<string name="sk_visibility_unlisted">Descatalogada</string>
<string name="sk_settings_show_replies">Mostrar respuestas</string>
<string name="sk_settings_show_boosts">Mostrar boosts</string>
<string name="sk_settings_load_new_posts">Cargar nuevos posts automáticamente</string>
<string name="sk_settings_show_interaction_counts">Mostrar contadores de interacciones</string>
<string name="sk_mark_media_as_sensitive">Marcar medio como sensible</string>
<string name="sk_settings_show_boosts">Mostrar impulsos</string>
<string name="sk_settings_load_new_posts">Cargar publicaciones nuevas automáticamente</string>
<string name="sk_settings_show_interaction_counts">Mostrar recuentos de interacciones</string>
<string name="sk_mark_media_as_sensitive">Marcar medio como delicado</string>
<string name="sk_user_post_notifications_on">Activadas las notificaciones de posts para %s</string>
<string name="sk_user_post_notifications_off">Desactivadas las notificaciones de posts para %s</string>
<string name="sk_federated_timeline">Federación</string>
<string name="sk_federated_timeline_info_banner">Estos son los posts más recientes de las personas de tu federación.</string>
<string name="sk_federated_timeline_info_banner">Estas son las publicaciones más recientes de las personas de su federación.</string>
<string name="sk_update_available">Megalodon %s está listo para descargar.</string>
<string name="sk_update_ready">Megalodon %s se ha descargado y está listo para instalarse.</string>
<string name="sk_check_for_update">Buscar actualizaciones</string>
@@ -36,6 +36,28 @@
<string name="sk_settings_always_reveal_content_warnings">Mostrar siempre advertencias de contenido</string>
<string name="sk_disable_marquee">Desactivar desplazamiento de texto en barras del título</string>
<string name="sk_settings_contribute">Contribuir a Megalodon</string>
<string name="sk_settings_show_federated_timeline">Mostrar el timeline federado</string>
<string name="sk_settings_show_federated_timeline">Mostrar cronología federada</string>
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
<string name="sk_notification_type_status">Publicaciones</string>
<string name="sk_notify_posts">Publicar notificaciones</string>
<string name="sk_settings_color_picker">Colores para los temas</string>
<string name="sk_color_theme_pink">Rosa</string>
<string name="sk_color_theme_purple">Violeta</string>
<string name="sk_color_theme_green">Verde</string>
<string name="sk_color_theme_blue">Azul</string>
<string name="sk_color_theme_brown">Marrón</string>
<string name="sk_color_theme_yellow">Amarillo</string>
<string name="sk_poll_allow_multiple">Permitir respuesta múltiple</string>
<string name="sk_translate_post">Traducir</string>
<string name="sk_translate_show_original">Mostrar original</string>
<string name="sk_translated_using">Traducido mediante %s</string>
<string name="sk_post_language">Idioma: %s</string>
<string name="sk_available_languages">Idiomas disponibles</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_confirm_clear_recent_languages">¿Confirma que quiere vaciar sus idiomas usados recientemente\?</string>
<string name="sk_clear_recent_languages">Vaciar idiomas usados recientemente</string>
<string name="sk_welcome_text">¡El tiburón te saluda! Para empezar, introduzca a continuación el nombre del dominio de su instancia de origen.</string>
<string name="sk_example_domain">example.social</string>
<string name="sk_welcome_title">¡Bienvenidos!</string>
<string name="sk_color_theme_material3">Sistema</string>
</resources>

View File

@@ -38,4 +38,26 @@
<string name="sk_settings_show_interaction_counts">Afficher le nombre d\'interactions</string>
<string name="sk_federated_timeline">Fédération</string>
<string name="sk_federated_timeline_info_banner">Ce sont les messages les plus récents des membres de votre fédération.</string>
<string name="sk_notification_type_status">Messages</string>
<string name="sk_notify_posts">Notifications des messages</string>
<string name="sk_color_theme_pink">Rose</string>
<string name="sk_color_theme_purple">Violet</string>
<string name="sk_color_theme_green">Vert</string>
<string name="sk_color_theme_blue">Bleu</string>
<string name="sk_color_theme_brown">Marron</string>
<string name="sk_color_theme_yellow">Jaune</string>
<string name="sk_settings_color_picker">Couleur d\'accentuation</string>
<string name="sk_poll_allow_multiple">Autoriser plusieurs choix</string>
<string name="sk_translate_post">Traduire</string>
<string name="sk_translate_show_original">Afficher l\'original</string>
<string name="sk_translated_using">Traduit en utilisant %s</string>
<string name="sk_post_language">Langue : %s</string>
<string name="sk_available_languages">Langues disponibles</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_confirm_clear_recent_languages">Êtes-vous sûr de vouloir effacer vos langues récemment utilisées \?</string>
<string name="sk_clear_recent_languages">Effacer les langues récemment utilisées</string>
<string name="sk_example_domain">exemple.social</string>
<string name="sk_welcome_title">Bienvenue !</string>
<string name="sk_welcome_text">Le requin vous salue ! Pour commencer, veuillez entrer le nom de domaine de votre instance personnelle ci-dessous.</string>
<string name="sk_color_theme_material3">Système</string>
</resources>

View File

@@ -38,4 +38,13 @@
<string name="sk_settings_always_reveal_content_warnings">Selalu ungkap peringatan konten</string>
<string name="sk_disable_marquee">Nonaktifkan teks bergulir dalam bilah judul</string>
<string name="sk_settings_show_federated_timeline">Tampilkan lini masa federasi</string>
<string name="sk_notification_type_status">Kiriman</string>
<string name="sk_notify_posts">Notifikasi kiriman</string>
<string name="sk_settings_color_picker">Warna tema</string>
<string name="sk_color_theme_pink">Merah muda</string>
<string name="sk_color_theme_purple">Ungu</string>
<string name="sk_color_theme_green">Hijau</string>
<string name="sk_color_theme_blue">Biru</string>
<string name="sk_color_theme_brown">Cokelat</string>
<string name="sk_color_theme_yellow">Kuning</string>
</resources>

View File

@@ -1,3 +1,63 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>
<string name="sk_notification_type_status">Post</string>
<string name="sk_notify_posts">Notifiche post</string>
<string name="sk_settings_color_picker">Colore del tema</string>
<string name="sk_color_theme_pink">Rosa</string>
<string name="sk_color_theme_purple">Viola</string>
<string name="sk_color_theme_green">Verde</string>
<string name="sk_color_theme_blue">Blu</string>
<string name="sk_color_theme_brown">Marrone</string>
<string name="sk_color_theme_yellow">Giallo</string>
<string name="sk_app_name">Megalodon</string>
<string name="sk_pinned_posts">Fissati</string>
<string name="sk_delete_and_redraft">Elimina e riscrivi</string>
<string name="sk_user_post_notifications_on">Attivate notifiche per i post di %s</string>
<string name="sk_user_post_notifications_off">Disattivate notifiche per i post di %s</string>
<string name="sk_confirm_delete_and_redraft_title">Elimina e riscrivi post</string>
<string name="sk_confirm_delete_and_redraft">Sei sicuro di voler eliminare e riscrivere questo post\?</string>
<string name="sk_pin_post">Fissa sul profilo</string>
<string name="sk_confirm_pin_post_title">Fissa post sul profilo</string>
<string name="sk_confirm_pin_post">Vuoi fissare questo post al tuo profilo\?</string>
<string name="sk_pinning">Fissando il post…</string>
<string name="sk_unpin_post">Togli dal profilo</string>
<string name="sk_follow_requests">Richieste di seguirti</string>
<string name="sk_accept_follow_request">Accetta richiesta di seguirti</string>
<string name="sk_confirm_unpin_post_title">Togli post dal profilo</string>
<string name="sk_confirm_unpin_post">Sei sicuro di voler togliere questo post\?</string>
<string name="sk_unpinning">Togliendo il post…</string>
<string name="sk_image_description">Descrizione immagine</string>
<string name="sk_visibility_unlisted">Non in elenco</string>
<string name="sk_settings_show_replies">Mostra risposte</string>
<string name="sk_settings_show_boosts">Mostra boost</string>
<string name="sk_settings_load_new_posts">Carica automaticamente nuovi post</string>
<string name="sk_settings_show_interaction_counts">Mostra conteggi interazioni</string>
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
<string name="sk_mark_media_as_sensitive">Segnala media come sensibile</string>
<string name="sk_federated_timeline">Federata</string>
<string name="sk_federated_timeline_info_banner">Questi sono i post più recenti dalle persone nella tua federazione.</string>
<string name="sk_update_available">Megalodon %s è pronto da scaricare.</string>
<string name="sk_update_ready">Megalodon %s è scaricato e pronto da installare.</string>
<string name="sk_check_for_update">Verifica aggiornamenti</string>
<string name="sk_no_update_available">Non ci sono aggiornamenti disponibili</string>
<string name="sk_list_timelines">Liste</string>
<string name="sk_settings_always_reveal_content_warnings">Apri sempre contenuti segnalati come sensibili</string>
<string name="sk_lists_with_user">Liste con %s</string>
<string name="sk_settings_contribute">Contribuisci a Megalodon</string>
<string name="sk_settings_show_federated_timeline">Mostra timeline federata</string>
<string name="sk_disable_marquee">Disabilita scorrimento titoli</string>
<string name="sk_reject_follow_request">Rifiuta richiesta di seguirti</string>
<string name="sk_translate_post">Traduci</string>
<string name="sk_translate_show_original">Mostra originale</string>
<string name="sk_translated_using">Tradotto con</string>
<string name="sk_post_language">Lingua: %s</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_confirm_clear_recent_languages">Sei sicuro di voler cancellare le lingue usate di recente\?</string>
<string name="sk_clear_recent_languages">Cancella lingue usate di recente</string>
<string name="sk_welcome_title">Benvenuto!</string>
<string name="sk_example_domain">example.social</string>
<string name="sk_poll_allow_multiple">Consenti scelte multiple</string>
<string name="sk_available_languages">Lingue disponibili</string>
<string name="sk_welcome_text">Lo squalo ti saluta! Per iniziare inserisci il dominio dell\'istanza a cui sei iscritto.</string>
<string name="sk_color_theme_material3">Sistema</string>
</resources>

View File

@@ -1,35 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sk_pinned_posts">고정됨</string>
<string name="sk_delete_and_redraft">삭제하고 다시 쓰기</string>
<string name="sk_confirm_delete_and_redraft_title">게시물 삭제하고 다시 쓰기</string>
<string name="sk_confirm_delete_and_redraft">정말로 이 게시물을 삭제하고 다시 쓰시겠습니까?</string>
<string name="sk_pin_post">고정</string>
<string name="sk_confirm_pin_post_title">게시물 고정</string>
<string name="sk_confirm_pin_post">정말로 이 게시물을 고정하시겠습니까?</string>
<string name="sk_pinning">고정 중…</string>
<string name="sk_unpin_post">고정 해제</string>
<string name="sk_confirm_unpin_post_title">게시물 고정 해제</string>
<string name="sk_confirm_unpin_post">정말로 이 게시물을 고정 해제하시겠습니까?</string>
<string name="sk_unpinning">고정 해제 중…</string>
<string name="sk_image_description">이미지 설명</string>
<string name="sk_visibility_unlisted">타임라인에 비표시</string>
<string name="sk_settings_show_replies">답장 표시</string>
<string name="sk_settings_show_boosts">리블로그 표시</string>
<string name="sk_settings_load_new_posts">자동으로 새 포스트 불러오기</string>
<string name="sk_settings_show_interaction_counts">상호 작용 수 표시</string>
<string name="sk_mark_media_as_sensitive">미디어를 민감함으로 설정하기</string>
<string name="sk_user_post_notifications_on">%s의 게시물 알림 켜기</string>
<string name="sk_user_post_notifications_off">%s의 게시물 알림 끄기</string>
<string name="sk_federated_timeline">연합</string>
<string name="sk_federated_timeline_info_banner">당신이 속한 연합에 존재하는 사람들이 공유한 최신 게시물들입니다.</string>
<string name="sk_check_for_update">업데이트 확인</string>
<string name="sk_no_update_available">사용 가능한 업데이트 없음</string>
<string name="sk_list_timelines">리스트</string>
<string name="sk_follow_requests">팔로우 요청</string>
<string name="sk_accept_follow_request">팔로우 요청 허가</string>
<string name="sk_reject_follow_request">팔로우 요청 거부</string>
<string name="sk_lists_with_user">%s 님이 포함된 리스트</string>
<string name="sk_settings_always_reveal_content_warnings">열람주의 을 항상 펼치기</string>
<string name="sk_disable_marquee">제목 표시줄의 텍스트 스크롤 비활성화</string>
<string name="sk_pinned_posts">고정됨</string>
<string name="sk_delete_and_redraft">삭제하고 다시 쓰기</string>
<string name="sk_confirm_delete_and_redraft_title">게시물 삭제하고 다시 쓰기</string>
<string name="sk_confirm_delete_and_redraft">정말로 이 게시물을 삭제하고 다시 쓰시겠습니까?</string>
<string name="sk_pin_post">고정</string>
<string name="sk_confirm_pin_post_title">게시물 고정</string>
<string name="sk_confirm_pin_post">정말로 이 게시물을 고정하시겠습니까?</string>
<string name="sk_pinning">고정 중…</string>
<string name="sk_unpin_post">고정 해제</string>
<string name="sk_confirm_unpin_post_title">게시물 고정 해제</string>
<string name="sk_confirm_unpin_post">정말로 이 게시물을 고정 해제하시겠습니까?</string>
<string name="sk_unpinning">고정 해제 중…</string>
<string name="sk_image_description">이미지 설명</string>
<string name="sk_visibility_unlisted">타임라인에 비표시</string>
<string name="sk_settings_show_replies">답장 표시</string>
<string name="sk_settings_show_boosts">리블로그 표시</string>
<string name="sk_settings_load_new_posts">자동으로 새 게시물 불러오기</string>
<string name="sk_settings_show_interaction_counts">반응 수 표시</string>
<string name="sk_mark_media_as_sensitive">미디어를 민감함으로 설정하기</string>
<string name="sk_user_post_notifications_on">%s의 게시물 알림 켜기</string>
<string name="sk_user_post_notifications_off">%s의 게시물 알림 끄기</string>
<string name="sk_federated_timeline">연합</string>
<string name="sk_federated_timeline_info_banner">당신이 속한 연합에 존재하는 사람들이 공유한 최신 게시물들입니다.</string>
<string name="sk_check_for_update">업데이트 확인</string>
<string name="sk_no_update_available">사용 가능한 업데이트 없음</string>
<string name="sk_list_timelines">리스트</string>
<string name="sk_follow_requests">팔로우 요청</string>
<string name="sk_accept_follow_request">팔로우 요청 허가</string>
<string name="sk_reject_follow_request">팔로우 요청 거부</string>
<string name="sk_lists_with_user">%s 님이 포함된 리스트</string>
<string name="sk_settings_always_reveal_content_warnings">열람주의 게시물을 항상 펼치기</string>
<string name="sk_disable_marquee">제목 표시줄의 텍스트 스크롤 비활성화</string>
<string name="sk_app_name">Megalodon</string>
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
<string name="sk_update_available">Megalodon %s 버전을 다운로드할 수 있습니다.</string>
<string name="sk_update_ready">Megalodon %s 버전을 다운로드하였으며 설치할 수 있습니다.</string>
<string name="sk_settings_show_federated_timeline">연합 타임라인 표시</string>
<string name="sk_notification_type_status">게시물</string>
<string name="sk_notify_posts">게시물 알림</string>
<string name="sk_settings_color_picker">테마 색상</string>
<string name="sk_color_theme_pink">분홍색</string>
<string name="sk_color_theme_purple">보라색</string>
<string name="sk_color_theme_green">초록색</string>
<string name="sk_color_theme_blue">파란색</string>
<string name="sk_color_theme_brown">갈색</string>
<string name="sk_color_theme_yellow">노란색</string>
<string name="sk_settings_contribute">Megalodon에 기여</string>
<string name="sk_poll_allow_multiple">다중 선택 허용</string>
<string name="sk_translate_post">번역하기</string>
<string name="sk_translate_show_original">원본 보기</string>
<string name="sk_post_language">언어: %s</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_translated_using">%s에서 번역함</string>
<string name="sk_available_languages">모든 언어</string>
<string name="sk_clear_recent_languages">최근 사용한 언어 지우기</string>
<string name="sk_confirm_clear_recent_languages">정말로 최근 사용한 언어를 지우시겠습니까\?</string>
<string name="sk_example_domain">example.social</string>
<string name="sk_welcome_title">환영합니다!</string>
<string name="sk_welcome_text">상어가 당신을 맞이합니다! 시작하기 위해, 아래에 사용하시는 인스턴스의 도메인 이름을 입력해주세요.</string>
</resources>

View File

@@ -17,4 +17,7 @@
<style name="Theme.Mastodon.AutoLightDark.Yellow" parent="Theme.Mastodon.Dark.Yellow"/>
<style name="Theme.Mastodon.AutoLightDark.TrueBlack.Yellow" parent="Theme.Mastodon.Dark.TrueBlack.Yellow"/>
<style name="Theme.Mastodon.AutoLightDark.Material3" parent="Theme.Mastodon.Dark.Material3"/>
<style name="Theme.Mastodon.AutoLightDark.TrueBlack.Material3" parent="Theme.Mastodon.Dark.TrueBlack.Material3"/>
</resources>

View File

@@ -1,41 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sk_delete_and_redraft">Usuń i zmodyfikuj</string>
<string name="sk_pin_post">Przypomnij do profilu</string>
<string name="sk_confirm_pin_post_title">Przypomnij post na profilu</string>
<string name="sk_confirm_pin_post">Czy chcesz przypiąć ten post na swoim profilu\?</string>
<string name="sk_pinning">Przypinanie postu…</string>
<string name="sk_unpin_post">Odepnij post z profilu</string>
<string name="sk_confirm_unpin_post_title">Odepnij post z profilu</string>
<string name="sk_unpinning">Odpinanie postu…</string>
<string name="sk_pin_post">Przypnij do profilu</string>
<string name="sk_confirm_pin_post_title">Przypnij wpis do profilu</string>
<string name="sk_confirm_pin_post">Czy chcesz przypiąć ten wpis do swojego profilu\?</string>
<string name="sk_pinning">Przypinanie wpisu…</string>
<string name="sk_unpin_post">Odepnij z profilu</string>
<string name="sk_confirm_unpin_post_title">Odepnij wpis z profilu</string>
<string name="sk_unpinning">Odpinanie wpisu…</string>
<string name="sk_settings_show_replies">Pokaż odpowiedzi</string>
<string name="sk_settings_show_boosts">Pokaż podbicia</string>
<string name="sk_settings_load_new_posts">Automatycznie wczytuj nowe posty</string>
<string name="sk_settings_load_new_posts">Automatycznie wczytuj nowe wpisy</string>
<string name="sk_settings_show_interaction_counts">Pokaż dane ilości interakcji</string>
<string name="sk_mark_media_as_sensitive">Oznacz jako wrażliwe</string>
<string name="sk_user_post_notifications_on">Włączono powiadomienia dla postu %s</string>
<string name="sk_user_post_notifications_off">Wyłączono powiadomienia dla postu %s</string>
<string name="sk_federated_timeline">Znana sieć fediverse</string>
<string name="sk_federated_timeline_info_banner">To są najnowsze post ze znanej sieci fediverse dla twojego serwera.</string>
<string name="sk_federated_timeline">fediwersum</string>
<string name="sk_federated_timeline_info_banner">To są najnowsze post ze znanej sieci fediwersum dla twojego serwera.</string>
<string name="sk_update_available">Megalodon %s jest dostępny do pobrania.</string>
<string name="sk_update_ready">Megalodon %s został pobrany i jest gotowy do instalacji.</string>
<string name="sk_check_for_update">Szukaj uaktualnień</string>
<string name="sk_no_update_available">Brak dostępnych uaktualnień</string>
<string name="sk_check_for_update">Sprawdź dostępność aktualizacji</string>
<string name="sk_no_update_available">Brak dostępnych aktualizacji</string>
<string name="sk_app_name">Megalodon</string>
<string name="sk_pinned_posts">Przypięte</string>
<string name="sk_confirm_delete_and_redraft">Jesteś pewnien, że chcesz usunąć zmodyfikowany post\?</string>
<string name="sk_confirm_unpin_post">Jesteś pewien, że chcesz odpiąć ten post\?</string>
<string name="sk_image_description">Opis obrazka</string>
<string name="sk_confirm_delete_and_redraft_title">Usuń i zmodyfikuj post</string>
<string name="sk_confirm_delete_and_redraft">Jesteś pewnien, że chcesz usunąć zmodyfikowany wpis\?</string>
<string name="sk_confirm_unpin_post">Jesteś pewien, że chcesz odpiąć ten wpis\?</string>
<string name="sk_image_description">Opis zdjęcia</string>
<string name="sk_confirm_delete_and_redraft_title">Usuń i zmodyfikuj wpis</string>
<string name="sk_list_timelines">Listy</string>
<string name="sk_follow_requests">Prośby o obserwowanie</string>
<string name="sk_accept_follow_request">Zaakceptuj prośby o obserwowanie</string>
<string name="sk_reject_follow_request">Odrzuć prośby o obserwowanie</string>
<string name="sk_follow_requests">Prośby o obserwację</string>
<string name="sk_accept_follow_request">Zaakceptuj prośby o obserwację</string>
<string name="sk_reject_follow_request">Odrzuć prośby o obserwację</string>
<string name="sk_lists_with_user">Listy z %s</string>
<string name="sk_settings_always_reveal_content_warnings">Zawsze odkrywaj ostrzeżenia o zawartości</string>
<string name="sk_disable_marquee">Wyłącz tekst przewijany w paskach tytułowych</string>
<string name="sk_settings_contribute">Wspomóż Megalodon</string>
<string name="sk_settings_show_federated_timeline">Pokaż oś czasu znanej sieci Fediverse</string>
<string name="sk_settings_show_federated_timeline">Pokaż globalną oś czasu</string>
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
<string name="sk_visibility_unlisted">Nienotowany</string>
<string name="sk_visibility_unlisted">Niewidoczny</string>
<string name="sk_notification_type_status">Wpisy</string>
<string name="sk_notify_posts">Powiadomienia wpisów</string>
<string name="sk_settings_color_picker">Motyw</string>
<string name="sk_color_theme_pink">Różowy</string>
<string name="sk_color_theme_purple">Fioletowy</string>
<string name="sk_color_theme_green">Zielony</string>
<string name="sk_color_theme_blue">Niebieski</string>
<string name="sk_color_theme_brown">Brązowy</string>
<string name="sk_color_theme_yellow">Żółty</string>
<string name="sk_poll_allow_multiple">Pozwalaj na wybieranie wielu opcji</string>
<string name="sk_translate_post">Przetłumacz</string>
<string name="sk_translate_show_original">Pokaż oryginał</string>
<string name="sk_translated_using">Przetłumaczono przy użyciu %s</string>
<string name="sk_post_language">Język: %s</string>
<string name="sk_available_languages">Dostępne języki</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_confirm_clear_recent_languages">Czy na pewno chcesz wyczyścić ostatnio użyte języki\?</string>
<string name="sk_clear_recent_languages">Wyczyść ostatnio użyte języki</string>
<string name="sk_example_domain">przykład.social</string>
<string name="sk_welcome_title">Witaj!</string>
<string name="sk_welcome_text">Rekin się kłania! Aby zacząć, wpisz adres swojej instancji poniżej.</string>
</resources>

View File

@@ -38,4 +38,21 @@
<string name="sk_settings_show_federated_timeline">Mostre a linha do tempo federada</string>
<string name="sk_visibility_unlisted">Não-listado</string>
<string name="sk_settings_show_interaction_counts">Mostrar contagens de interação</string>
<string name="sk_color_theme_purple">Roxo</string>
<string name="sk_color_theme_green">Verde</string>
<string name="sk_color_theme_blue">Azul</string>
<string name="sk_color_theme_brown">Marrom</string>
<string name="sk_color_theme_yellow">Amarelo</string>
<string name="sk_color_theme_pink">Rosa</string>
<string name="sk_notification_type_status">Postagens</string>
<string name="sk_settings_color_picker">Cor do tema</string>
<string name="sk_translate_post">Traduzir</string>
<string name="sk_translate_show_original">Mostrar original</string>
<string name="sk_translated_using">Traduzido usando %s</string>
<string name="sk_post_language">Idioma: %s</string>
<string name="sk_available_languages">Idiomas disponíveis</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_confirm_clear_recent_languages">Tem certeza de que deseja limpar os idiomas usados recentemente\?</string>
<string name="sk_clear_recent_languages">Limpar idiomas usados recentemente</string>
<string name="sk_notify_posts">Notificações de posts</string>
</resources>

View File

@@ -15,4 +15,42 @@
<string name="sk_visibility_unlisted">Скрытый</string>
<string name="sk_mark_media_as_sensitive">Отметить медиафайл как деликатный</string>
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
<string name="sk_notification_type_status">Публикации</string>
<string name="sk_notify_posts">Отправляет публикацию</string>
<string name="sk_settings_color_picker">Цветовая схема</string>
<string name="sk_color_theme_pink">Розовый</string>
<string name="sk_color_theme_purple">Фиолетовый</string>
<string name="sk_color_theme_brown">Коричневый</string>
<string name="sk_color_theme_yellow">Жёлтый</string>
<string name="sk_translate_show_original">Показать оригинальную публикацию</string>
<string name="sk_translated_using">Переведено через %s</string>
<string name="sk_available_languages">Доступные языки</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_welcome_title">Добро пожаловать!</string>
<string name="sk_example_domain">example.social</string>
<string name="sk_settings_load_new_posts">Автоматически загружать новые публикации</string>
<string name="sk_settings_show_replies">Показывать ответы на публикации</string>
<string name="sk_federated_timeline">Федерация</string>
<string name="sk_update_available">Megalodon %s готов к скачиванию.</string>
<string name="sk_update_ready">Megalodon %s скачан и готов к установке новой версии.</string>
<string name="sk_check_for_update">Проверить обновления</string>
<string name="sk_follow_requests">Запросы на подписку</string>
<string name="sk_lists_with_user">Списки с %s</string>
<string name="sk_confirm_unpin_post">Вы точно хотите открепить эту публикацию от профиля\?</string>
<string name="sk_unpinning">Открепление публикации…</string>
<string name="sk_federated_timeline_info_banner">Это самые последние публикации людей из вашей федерации.</string>
<string name="sk_no_update_available">Обновление отсутствует</string>
<string name="sk_list_timelines">Списки</string>
<string name="sk_accept_follow_request">Принять запрос на подписку</string>
<string name="sk_reject_follow_request">Отклонить заявку на подписку</string>
<string name="sk_settings_always_reveal_content_warnings">Всегда раскрывать предупреждения о непристойном контенте</string>
<string name="sk_settings_contribute">Внести свой код в Megalodon</string>
<string name="sk_settings_show_federated_timeline">Показывать федеративную временную шкалу</string>
<string name="sk_color_theme_green">Зелёный</string>
<string name="sk_color_theme_blue">Синий</string>
<string name="sk_translate_post">Перевести</string>
<string name="sk_post_language">Язык: %s</string>
<string name="sk_clear_recent_languages">Очистить недавно использованные языки</string>
<string name="sk_confirm_clear_recent_languages">Вы точно хотите очистить недавно использованные языки\?</string>
<string name="sk_welcome_text">Акула приветствует вас! Чтобы начать, пожалуйста, введите домен своего домашнего сервера (инстанса) ниже.</string>
</resources>

View File

@@ -1,3 +1,62 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
</resources>
<string name="sk_notify_posts">Сповіщення про пости</string>
<string name="sk_settings_color_picker">Колірна тема</string>
<string name="sk_color_theme_purple">Фіолетовий</string>
<string name="sk_color_theme_green">Зелений</string>
<string name="sk_color_theme_blue">Синий</string>
<string name="sk_color_theme_brown">Коричневий</string>
<string name="sk_color_theme_yellow">Жовтий</string>
<string name="sk_poll_allow_multiple">Дозволити кілька виборів</string>
<string name="sk_translate_post">Перекласти</string>
<string name="sk_translate_show_original">Показати оригінал</string>
<string name="sk_translated_using">Перекладено через %s</string>
<string name="sk_post_language">Мова: %s</string>
<string name="sk_available_languages">Доступні мови</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_clear_recent_languages">Очистити нещодавно використані мови</string>
<string name="sk_settings_always_reveal_content_warnings">Завжди відкривати вміст</string>
<string name="sk_notification_type_status">Пости</string>
<string name="sk_color_theme_pink">Рожевий</string>
<string name="sk_confirm_clear_recent_languages">Ви впевнені, що хочете очистити нещодавно використані мови\?</string>
<string name="sk_app_name">Megalodon</string>
<string name="sk_pinned_posts">Закріплене</string>
<string name="sk_delete_and_redraft">Видалити та переробити</string>
<string name="sk_confirm_delete_and_redraft_title">Видалити та переробити пост</string>
<string name="sk_confirm_delete_and_redraft">Ви впевнені, що хочете видалити та переробити цей пост\?</string>
<string name="sk_pin_post">Закріпити у профіль</string>
<string name="sk_confirm_pin_post_title">Закріпити пост у профіль</string>
<string name="sk_confirm_pin_post">Чи хочете ви закріпити цей пост у ваш профіль\?</string>
<string name="sk_pinning">Закріпляємо пост…</string>
<string name="sk_unpin_post">Відкріпити з профілю</string>
<string name="sk_confirm_unpin_post_title">Відкріпити пост з профілю</string>
<string name="sk_confirm_unpin_post">Ви впевнені, що хочете відкріпити цей пост\?</string>
<string name="sk_unpinning">Відкріпляємо пост…</string>
<string name="sk_image_description">Опис зображення</string>
<string name="sk_visibility_unlisted">Не у списку</string>
<string name="sk_settings_show_replies">Показувати відповіді</string>
<string name="sk_settings_load_new_posts">Автоматично завантажувати нові пости</string>
<string name="sk_settings_show_interaction_counts">Показати кількість взаємодій</string>
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
<string name="sk_follow_requests">Запити на підписку</string>
<string name="sk_accept_follow_request">Прийняти запит на підписку</string>
<string name="sk_reject_follow_request">Відхилити запит на підписку</string>
<string name="sk_lists_with_user">Списки з %s</string>
<string name="sk_disable_marquee">Вимкнути прокручування тексту у рядках заголовка</string>
<string name="sk_settings_contribute">Допомогти у розробці Megalodon</string>
<string name="sk_mark_media_as_sensitive">Помітити медіа як чутливу</string>
<string name="sk_settings_show_boosts">Показувати бусти</string>
<string name="sk_user_post_notifications_on">Увімкнено сповіщення про пости для %s</string>
<string name="sk_user_post_notifications_off">Вимкнено сповіщення про пости для %s</string>
<string name="sk_federated_timeline">Федерація</string>
<string name="sk_federated_timeline_info_banner">Це найновіші публікації людей у вашій федерації.</string>
<string name="sk_update_available">Megalodon %s готовий до завантаження.</string>
<string name="sk_update_ready">Megalodon %s завантажений й готовий до встановлення.</string>
<string name="sk_check_for_update">Перевірити оновлення</string>
<string name="sk_no_update_available">Немає доступних оновлень</string>
<string name="sk_list_timelines">Списки</string>
<string name="sk_settings_show_federated_timeline">Показувати федеративну стрічку</string>
<string name="sk_example_domain">example.social</string>
<string name="sk_welcome_title">Вітаємо!</string>
<string name="sk_welcome_text">Акулка вас вітає! Щоб розпочати, введіть нижче доменне ім’я вашого інстансу.</string>
</resources>

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.Mastodon.Toolbar" parent="android:Widget.Material.Toolbar">
<item name="android:contentInsetStartWithNavigation">0dp</item>
<item name="android:titleMarginEnd">0dp</item>
<item name="android:titleMarginStart">0dp</item>
</style>
</resources>

View File

@@ -2,6 +2,35 @@
<resources>
<!-- M3 dynamic colors -->
<color name="m3_navigation_bar_bg">@android:color/system_neutral1_50</color>
<color name="m3_gray_900">@android:color/system_neutral1_900</color>
<color name="m3_gray_800t">@android:color/system_neutral1_800</color>
<color name="m3_gray_800">@android:color/system_neutral1_800</color>
<color name="m3_gray_700">@android:color/system_neutral1_700</color>
<color name="m3_gray_600">@android:color/system_neutral1_600</color>
<color name="m3_gray_500">@android:color/system_neutral1_500</color>
<color name="m3_gray_400">@android:color/system_neutral1_400</color>
<color name="m3_gray_300">@android:color/system_neutral1_300</color>
<color name="m3_gray_200">@android:color/system_neutral1_200</color>
<color name="m3_gray_100">@android:color/system_neutral1_100</color>
<color name="m3_gray_50t">@android:color/system_neutral1_50</color>
<color name="m3_gray_50">@android:color/system_neutral1_50</color>
<color name="m3_gray_25">@android:color/system_neutral1_10</color>
<color name="m3_primary_25">@android:color/system_accent1_10</color>
<color name="m3_primary_50">@android:color/system_accent1_50</color>
<color name="m3_primary_100">@android:color/system_accent1_100</color>
<color name="m3_primary_200">@android:color/system_accent1_200</color>
<color name="m3_primary_300">@android:color/system_accent1_300</color>
<color name="m3_primary_400">@android:color/system_accent1_400</color>
<color name="m3_primary_500">@android:color/system_accent1_500</color>
<color name="m3_primary_600">@android:color/system_accent1_600</color>
<color name="m3_primary_700">@android:color/system_accent1_700</color>
<color name="m3_primary_800">@android:color/system_accent1_800</color>
<color name="m3_primary_900">@android:color/system_accent1_900</color>
<!-- light theme -->
<color name="m3_sys_light_primary">@android:color/system_accent1_600</color>
<color name="m3_sys_light_on_primary">#FFF</color>

View File

@@ -38,4 +38,13 @@
<string name="sk_settings_show_federated_timeline">显示联邦时间轴</string>
<string name="sk_follow_requests">关注请求</string>
<string name="sk_settings_always_reveal_content_warnings">总是显示内容警告</string>
<string name="sk_settings_color_picker">主题色</string>
<string name="sk_color_theme_pink"></string>
<string name="sk_color_theme_purple"></string>
<string name="sk_color_theme_green">绿</string>
<string name="sk_color_theme_blue"></string>
<string name="sk_color_theme_brown"></string>
<string name="sk_color_theme_yellow"></string>
<string name="sk_notification_type_status">嘟文</string>
<string name="sk_notify_posts">嘟文通知</string>
</resources>

View File

@@ -17,6 +17,26 @@
<attr name="colorTabInactive" format="color"/>
<attr name="colorAccentLightest" format="color"/>
<attr name="profileHeaderBackground" format="color"/>
<attr name="colorButtonBackgroundPrimaryDarkOnLight" format="color"/>
<attr name="colorButtonBackgroundPrimaryDarkOnLightDisabled" format="color"/>
<attr name="colorButtonTextPrimaryDarkOnLight" format="color"/>
<attr name="colorButtonTextPrimaryDarkOnLightDisabled" format="color"/>
<attr name="colorButtonBackgroundPrimaryLightOnDark" format="color"/>
<attr name="colorButtonBackgroundPrimaryLightOnDarkDisabled" format="color"/>
<attr name="colorButtonTextPrimaryLightOnDark" format="color"/>
<attr name="colorButtonTextPrimaryLightOnDarkDisabled" format="color"/>
<attr name="colorButtonBackgroundSecondaryDarkOnLight" format="color"/>
<attr name="colorButtonBackgroundSecondaryDarkOnLightDisabled" format="color"/>
<attr name="colorButtonTextSecondaryDarkOnLight" format="color"/>
<attr name="colorButtonTextSecondaryDarkOnLightDisabled" format="color"/>
<attr name="colorButtonBackgroundSecondaryLightOnDark" format="color"/>
<attr name="colorButtonBackgroundSecondaryLightOnDarkDisabled" format="color"/>
<attr name="colorButtonTextSecondaryLightOnDark" format="color"/>
<attr name="colorButtonTextSecondaryLightOnDarkDisabled" format="color"/>
<attr name="colorM3Primary" format="color"/>
<attr name="colorM3OnPrimary" format="color"/>
@@ -39,6 +59,10 @@
<attr name="colorM3Outline" format="color"/>
<attr name="colorM3DisabledBackground" format="color"/>
<attr name="colorM3PressedOverlay" format="color"/>
<attr name="colorM3Error" format="color"/>
<attr name="colorM3OnError" format="color"/>
<attr name="colorM3ErrorContainer" format="color"/>
<attr name="colorM3OnErrorContainer" format="color"/>
<attr name="primaryLargeButtonStyle" format="reference"/>
<attr name="secondaryLargeButtonStyle" format="reference"/>
@@ -50,5 +74,6 @@
<declare-styleable name="FloatingHintEditTextLayout">
<attr name="editTextOffsetY" format="dimension"/>
<attr name="android:labelTextSize" format="dimension"/>
<attr name="labelTextColor" format="color"/>
</declare-styleable>
</resources>

View File

@@ -5,12 +5,13 @@
<color name="fluent_default_icon_tint">?android:textColorPrimary</color>
<color name="gray_900">#121029</color>
<color name="gray_800t">#cc2b2938</color>
<color name="gray_800">#2b2938</color>
<color name="gray_700">#353454</color>
<color name="gray_600">#464666</color>
<color name="gray_500">#696685</color>
<color name="gray_900">#110c10</color>
<color name="gray_800t">#cc191417</color>
<color name="gray_800">#191417</color>
<color name="gray_700">#231f22</color>
<color name="gray_600">#3b373a</color>
<color name="gray_500">#625d60</color>
<color name="gray_400">#9998b3</color>
<color name="gray_300">#d1d1de</color>
<color name="gray_200">#e6e6ed</color>
@@ -31,6 +32,13 @@
<color name="primary_800">#ae218a</color>
<color name="primary_900">#6d1556</color>
<!-- <color name="original_gray_900">#121029</color> -->
<!-- <color name="original_gray_800t">#cc2b2938</color> -->
<!-- <color name="original_gray_800">#2b2938</color> -->
<!-- <color name="original_gray_700">#353454</color> -->
<!-- <color name="original_gray_600">#464666</color> -->
<!-- <color name="original_gray_500">#696685</color> -->
<color name="original_primary_25">#fafaff</color>
<color name="original_primary_50">#f4f3ff</color>
<color name="original_primary_100">#ebebff</color>
@@ -91,13 +99,6 @@
<color name="yellow_primary_800">#3c2f00</color>
<color name="yellow_primary_900">#231b00</color>
<color name="custom_gray_900">#000000</color>
<color name="custom_gray_800t">#cc171717</color>
<color name="custom_gray_800">#171717</color>
<color name="custom_gray_700">#191919</color>
<color name="custom_gray_600">#212121</color>
<color name="custom_gray_500">#242424</color>
<color name="green_gray_400">#a2b095</color>
<color name="green_gray_300">#bdcbaf</color>
<color name="green_gray_200">#d9e7ca</color>
@@ -199,6 +200,33 @@
<color name="shortcut_icon_foreground">@color/primary_700</color>
<!-- M3 dynamic colors -->
<color name="m3_navigation_bar_bg">@color/gray_50</color>
<color name="m3_gray_900">@color/gray_900</color>
<color name="m3_gray_800t">@color/gray_800t</color>
<color name="m3_gray_800">@color/gray_800</color>
<color name="m3_gray_700">@color/gray_700</color>
<color name="m3_gray_600">@color/gray_600</color>
<color name="m3_gray_500">@color/gray_500</color>
<color name="m3_gray_400">@color/gray_400</color>
<color name="m3_gray_300">@color/gray_300</color>
<color name="m3_gray_200">@color/gray_200</color>
<color name="m3_gray_100">@color/gray_100</color>
<color name="m3_gray_50t">@color/gray_50t</color>
<color name="m3_gray_50">@color/gray_50</color>
<color name="m3_gray_25">@color/gray_25</color>
<color name="m3_primary_25">@color/primary_25</color>
<color name="m3_primary_50">@color/primary_50</color>
<color name="m3_primary_100">@color/primary_100</color>
<color name="m3_primary_200">@color/primary_200</color>
<color name="m3_primary_300">@color/primary_300</color>
<color name="m3_primary_400">@color/primary_400</color>
<color name="m3_primary_500">@color/primary_500</color>
<color name="m3_primary_600">@color/primary_600</color>
<color name="m3_primary_700">@color/primary_700</color>
<color name="m3_primary_800">@color/primary_800</color>
<color name="m3_primary_900">@color/primary_900</color>
<!-- light theme -->
<color name="m3_sys_light_primary">#6750A4</color>

View File

@@ -179,15 +179,16 @@
<string name="back">Back</string>
<string name="instance_catalog_title">Mastodon is made of users on different servers.</string>
<string name="instance_catalog_subtitle">Pick a server based on your interests, region, or a general purpose one. You can still connect with everyone, regardless of server.</string>
<string name="search_communities">Search servers or enter URL</string>
<string name="instance_rules_title">Some ground rules</string>
<string name="instance_rules_subtitle">Take a minute to review the rules set and enforced by %s admins.</string>
<string name="signup_title">Let\'s get you set up on %s</string>
<string name="search_communities">Server name or URL</string>
<string name="instance_rules_title">Server Rules</string>
<string name="instance_rules_subtitle">By continuing, you agree to follow by the following rules set and enforced by the %s moderators.</string>
<string name="signup_title">Create Account</string>
<string name="edit_photo">edit</string>
<string name="display_name">display name</string>
<string name="username">username</string>
<string name="email">email</string>
<string name="password">password</string>
<string name="display_name">Name</string>
<string name="username">Username</string>
<string name="email">Email</string>
<string name="password">Password</string>
<string name="confirm_password">Confirm password</string>
<string name="password_note">Include capital letters, special characters, and numbers to increase your password strength.</string>
<string name="category_academia">Academia</string>
<string name="category_activism">Activism</string>
@@ -202,8 +203,10 @@
<string name="category_music">Music</string>
<string name="category_regional">Regional</string>
<string name="category_tech">Tech</string>
<string name="confirm_email_title">One last thing</string>
<string name="confirm_email_subtitle">Tap the link we emailed to you to verify your account.</string>
<string name="confirm_email_title">Check Your Inbox</string>
<!-- %s is the email address -->
<string name="confirm_email_subtitle">Tap the link we sent you to verify %s. We\'ll wait right here.</string>
<string name="confirm_email_didnt_get">Didn\'t get a link?</string>
<string name="resend">Resend</string>
<string name="open_email_app">Open email app</string>
<string name="resent_email">Confirmation email sent</string>
@@ -291,7 +294,7 @@
<string name="open_in_browser">Open in browser</string>
<string name="hide_boosts_from_user">Hide reblogs from %s</string>
<string name="show_boosts_from_user">Show reblogs from %s</string>
<string name="signup_reason">why do you want to join?</string>
<string name="signup_reason">Why do you want to join?</string>
<string name="signup_reason_note">This will help us review your application.</string>
<string name="clear">Clear</string>
<string name="profile_header">Header image</string>
@@ -385,7 +388,7 @@
<!-- %s is file size -->
<string name="download_update">Download (%s)</string>
<string name="install_update">Install</string>
<string name="privacy_policy_title">Mastodon and your privacy</string>
<string name="privacy_policy_title">Your Privacy</string>
<string name="privacy_policy_subtitle">Although the Mastodon app does not collect any data, the server you sign up through may have a different policy. Take a minute to review and agree to the Mastodon app privacy policy and your server\'s privacy policy.</string>
<string name="i_agree">I Agree</string>
<string name="empty_list">This list is empty</string>
@@ -405,4 +408,18 @@
<string name="welcome_page2_text">Your handle might be @gothgirl654@example.social, but you can still follow, reblog, and chat with @fallout5ever@example.online.</string>
<string name="welcome_page3_title">How do I pick a server?</string>
<string name="welcome_page3_text">Different people choose different servers for any number of reasons. art.example is a great place for artists, while glasgow.example might be a good pick for Scots.\n\nYou cant go wrong with any of our recommend servers, so regardless of which one you pick (or if you enter your own in the server search bar), youll never miss a beat anywhere.</string>
<string name="signup_random_server_explain">We\'ll pick a server based on your language if you continue without making a selection.</string>
<string name="server_filter_any_language">Any Language</string>
<string name="server_filter_instant_signup">Instant Sign-up</string>
<string name="server_filter_manual_review">Manual Review</string>
<string name="server_filter_any_signup_speed">Any Sign-up Speed</string>
<string name="server_filter_region_europe">Europe</string>
<string name="server_filter_region_north_america">North America</string>
<string name="server_filter_region_south_america">South America</string>
<string name="server_filter_region_africa">Africa</string>
<string name="server_filter_region_asia">Asia</string>
<string name="server_filter_region_oceania">Oceania</string>
<string name="not_accepting_new_members">Not accepting new members</string>
<string name="category_special_interests">Special Interests</string>
<string name="signup_passwords_dont_match">Passwords don\'t match</string>
</resources>

View File

@@ -1,54 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="sk_app_name">Megalodon</string>
<string name="sk_pinned_posts">Pinned</string>
<string name="sk_delete_and_redraft">Delete and re-draft</string>
<string name="sk_confirm_delete_and_redraft_title">Delete and re-draft Post</string>
<string name="sk_confirm_delete_and_redraft">Are you sure you want to delete and re-draft this post?</string>
<string name="sk_pin_post">Pin to profile</string>
<string name="sk_confirm_pin_post_title">Pin post to profile</string>
<string name="sk_confirm_pin_post">Do you want to pin this post to your profile?</string>
<string name="sk_pinning">Pinning post…</string>
<string name="sk_unpin_post">Unpin from profile</string>
<string name="sk_confirm_unpin_post_title">Unpin post from profile</string>
<string name="sk_confirm_unpin_post">Are you sure you want to unpin this post?</string>
<string name="sk_unpinning">Unpinning post…</string>
<string name="sk_image_description">Image description</string>
<string name="sk_visibility_unlisted">Unlisted</string>
<string name="sk_settings_show_replies">Show replies</string>
<string name="sk_settings_show_boosts">Show boosts</string>
<string name="sk_settings_load_new_posts">Automatically load new posts</string>
<string name="sk_settings_show_interaction_counts">Show interaction counts</string>
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
<string name="sk_mark_media_as_sensitive">Mark media as sensitive</string>
<string name="sk_user_post_notifications_on">Turned on post notifications for %s</string>
<string name="sk_user_post_notifications_off">Turned off post notifications for %s</string>
<string name="sk_federated_timeline">Federation</string>
<string name="sk_federated_timeline_info_banner">These are the most recent posts by the people in your federation.</string>
<string name="sk_update_available">Megalodon %s is ready to download.</string>
<string name="sk_update_ready">Megalodon %s is downloaded and ready to install.</string>
<string name="sk_check_for_update">Check for update</string>
<string name="sk_no_update_available">No update available</string>
<string name="sk_list_timelines">Lists</string>
<string name="sk_follow_requests">Follow requests</string>
<string name="sk_accept_follow_request">Accept follow request</string>
<string name="sk_reject_follow_request">Reject follow request</string>
<string name="sk_lists_with_user">Lists with %s</string>
<string name="sk_settings_always_reveal_content_warnings">Always reveal content warnings</string>
<string name="sk_disable_marquee">Disable scrolling text in title bars</string>
<string name="sk_settings_contribute">Contribute to Megalodon</string>
<string name="sk_settings_show_federated_timeline">Show federated timeline</string>
<string name="sk_notification_type_status">Posts</string>
<string name="sk_notify_posts">Post notifications</string>
<string name="sk_settings_color_picker">Color theme</string>
<string name="sk_color_theme_pink">Pink</string>
<string name="sk_color_theme_purple">Purple</string>
<string name="sk_color_theme_green">Green</string>
<string name="sk_color_theme_blue">Blue</string>
<string name="sk_color_theme_brown">Brown</string>
<string name="sk_color_theme_yellow">Yellow</string>
<string name="sk_poll_allow_multiple">Allow multiple choices</string>
<string name="sk_translate_post">Translate</string>
<string name="sk_translate_show_original">Show original</string>
<string name="sk_translated_using">Translated using %s</string>
<string name="sk_app_name">Megalodon</string>
<string name="sk_pinned_posts">Pinned</string>
<string name="sk_delete_and_redraft">Delete and re-draft</string>
<string name="sk_confirm_delete_and_redraft_title">Delete and re-draft Post</string>
<string name="sk_confirm_delete_and_redraft">Are you sure you want to delete and re-draft this post?</string>
<string name="sk_pin_post">Pin to profile</string>
<string name="sk_confirm_pin_post_title">Pin post to profile</string>
<string name="sk_confirm_pin_post">Do you want to pin this post to your profile?</string>
<string name="sk_pinning">Pinning post…</string>
<string name="sk_unpin_post">Unpin from profile</string>
<string name="sk_confirm_unpin_post_title">Unpin post from profile</string>
<string name="sk_confirm_unpin_post">Are you sure you want to unpin this post?</string>
<string name="sk_unpinning">Unpinning post…</string>
<string name="sk_image_description">Image description</string>
<string name="sk_visibility_unlisted">Unlisted</string>
<string name="sk_settings_show_replies">Show replies</string>
<string name="sk_settings_show_boosts">Show boosts</string>
<string name="sk_settings_load_new_posts">Automatically load new posts</string>
<string name="sk_settings_show_interaction_counts">Show interaction counts</string>
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
<string name="sk_mark_media_as_sensitive">Mark media as sensitive</string>
<string name="sk_user_post_notifications_on">Turned on post notifications for %s</string>
<string name="sk_user_post_notifications_off">Turned off post notifications for %s</string>
<string name="sk_federated_timeline">Federation</string>
<string name="sk_federated_timeline_info_banner">These are the most recent posts by the people in your federation.</string>
<string name="sk_update_available">Megalodon %s is ready to download.</string>
<string name="sk_update_ready">Megalodon %s is downloaded and ready to install.</string>
<string name="sk_check_for_update">Check for update</string>
<string name="sk_no_update_available">No update available</string>
<string name="sk_list_timelines">Lists</string>
<string name="sk_follow_requests">Follow requests</string>
<string name="sk_accept_follow_request">Accept follow request</string>
<string name="sk_reject_follow_request">Reject follow request</string>
<string name="sk_lists_with_user">Lists with %s</string>
<string name="sk_settings_always_reveal_content_warnings">Always reveal content warnings</string>
<string name="sk_disable_marquee">Disable scrolling text in title bars</string>
<string name="sk_settings_contribute">Contribute to Megalodon</string>
<string name="sk_settings_show_federated_timeline">Show federated timeline</string>
<string name="sk_notification_type_status">Posts</string>
<string name="sk_notify_posts">Post notifications</string>
<string name="sk_settings_color_picker">Color theme</string>
<string name="sk_color_theme_material3">System</string>
<string name="sk_color_theme_pink">Pink</string>
<string name="sk_color_theme_purple">Purple</string>
<string name="sk_color_theme_green">Green</string>
<string name="sk_color_theme_blue">Blue</string>
<string name="sk_color_theme_brown">Brown</string>
<string name="sk_color_theme_red">Red</string>
<string name="sk_color_theme_yellow">Yellow</string>
<string name="sk_poll_allow_multiple">Allow multiple choices</string>
<string name="sk_translate_post">Translate</string>
<string name="sk_translate_show_original">Show original</string>
<string name="sk_translated_using">Translated using %s</string>
<string name="sk_post_language">Language: %s</string>
<string name="sk_available_languages">Available languages</string>
<string name="sk_language_name">%s (%s)</string>
<string name="sk_clear_recent_languages">Clear recently used languages</string>
<string name="sk_confirm_clear_recent_languages">Are you sure you want to clear your recently used languages?</string>
<string name="sk_welcome_title">Welcome!</string>
<string name="sk_welcome_text">The shark salutes you! To get started, please enter your home instances domain name below.</string>
<string name="sk_example_domain">example.social</string>
<string name="sk_app_username" translatable="false">\@megalodon</string>
</resources>

View File

@@ -38,6 +38,27 @@
<item name="colorAccentLightest">@color/primary_100</item>
<item name="profileHeaderBackground">@color/gray_500</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/gray_400</item>
<item name="buttonBackground">@drawable/bg_button_primary_dark_on_light</item>
<item name="android:editTextBackground">@drawable/bg_edittext_light</item>
@@ -68,6 +89,10 @@
<item name="colorM3Outline">@color/m3_sys_light_outline</item>
<item name="colorM3DisabledBackground">#1F1F1F1F</item>
<item name="colorM3PressedOverlay">@color/m3_sys_light_on_primary</item>
<item name="colorM3Error">#B3261E</item>
<item name="colorM3OnError">#FFF</item>
<item name="colorM3ErrorContainer">#F9DEDC</item>
<item name="colorM3OnErrorContainer">#410E0B</item>
</style>
@@ -111,6 +136,27 @@
<item name="colorSearchField">@color/gray_700</item>
<item name="colorSearchHint">@color/gray_300</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/gray_400</item>
<item name="buttonBackground">@drawable/bg_button_primary_light_on_dark</item>
<item name="android:editTextBackground">@drawable/bg_edittext_dark</item>
@@ -141,6 +187,10 @@
<item name="colorM3Outline">@color/m3_sys_dark_outline</item>
<item name="colorM3DisabledBackground">#1FE3E3E3</item>
<item name="colorM3PressedOverlay">@color/m3_sys_dark_primary</item>
<item name="colorM3Error">#F2B8B5</item>
<item name="colorM3OnError">#601410</item>
<item name="colorM3ErrorContainer">#8C1D18</item>
<item name="colorM3OnErrorContainer">#F9DEDC</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack">
@@ -157,6 +207,7 @@
<item name="colorWindowBackground">@color/black</item>
<item name="colorM3Background">#000</item>
<!-- <item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_900</item>-->
</style>
<style name="Theme.Mastodon.AutoLightDark" parent="Theme.Mastodon.Light"/>
@@ -164,37 +215,37 @@
<style name="Theme.Mastodon.Light.CustomBase" parent="Theme.Mastodon.Light">
<!-- needed to disable scrim on API 29+ -->
<item name="android:colorPrimary">@color/custom_gray_800</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_500</item>
<item name="colorDarkIcon">@color/custom_gray_900</item>
<item name="colorSearchHint">@color/custom_gray_600</item>
<item name="profileHeaderBackground">@color/custom_gray_500</item>
<item name="android:colorPrimary">@color/gray_800</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_500</item>
<item name="colorDarkIcon">@color/gray_900</item>
<item name="colorSearchHint">@color/gray_600</item>
<item name="profileHeaderBackground">@color/gray_500</item>
</style>
<style name="Theme.Mastodon.Dark.CustomBase" parent="Theme.Mastodon.Dark">
<!-- needed to disable scrim on API 29+ -->
<item name="android:colorBackground">@color/custom_gray_700</item>
<item name="colorButtonText">@color/custom_gray_800</item>
<item name="colorBackgroundLight">@color/custom_gray_700</item>
<item name="colorBackgroundLightest">@color/custom_gray_900</item>
<item name="colorBackgroundPopup">@color/custom_gray_900</item>
<item name="android:colorBackground">@color/gray_700</item>
<item name="colorButtonText">@color/gray_800</item>
<item name="colorBackgroundLight">@color/gray_700</item>
<item name="colorBackgroundLightest">@color/gray_900</item>
<item name="colorBackgroundPopup">@color/gray_900</item>
<item name="colorDarkIcon">@color/gray_25</item>
<item name="colorWindowBackground">@color/custom_gray_800</item>
<item name="android:statusBarColor">@color/custom_gray_800</item>
<item name="android:navigationBarColor">@color/custom_gray_800</item>
<item name="colorPollVoted">@color/custom_gray_600</item>
<item name="colorWindowBackground">@color/gray_800</item>
<item name="android:statusBarColor">@color/gray_800</item>
<item name="android:navigationBarColor">@color/gray_800</item>
<item name="colorPollVoted">@color/gray_600</item>
<item name="profileHeaderBackground">?colorWindowBackground</item>
<item name="android:actionBarTheme">@style/Theme.Mastodon.Toolbar.Dark.CustomBase</item>
<!-- TODO dark colors -->
<item name="colorSearchField">@color/custom_gray_700</item>
<item name="colorSearchField">@color/gray_700</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack.CustomBase">
<item name="colorPollVoted">@color/custom_gray_800</item>
<item name="colorSearchField">@color/custom_gray_900</item>
<item name="colorBackgroundPopup">@color/custom_gray_900</item>
<item name="colorPollVoted">@color/gray_800</item>
<item name="colorSearchField">@color/gray_900</item>
<item name="colorBackgroundPopup">@color/gray_900</item>
<item name="android:navigationBarColor">@color/black</item>
<item name="android:colorBackground">@color/black</item>
<item name="android:statusBarColor">@color/black</item>
@@ -205,6 +256,166 @@
<item name="colorBackgroundLightest">@color/black</item>
</style>
<style name="Theme.Mastodon.Light.Material3" parent="Theme.Mastodon.Light">
<!-- needed to disable scrim on API 29+ -->
<item name="android:colorPrimary">@color/m3_gray_800</item>
<item name="android:textColorPrimary">@color/m3_gray_800</item>
<item name="android:textColorSecondary">@color/m3_gray_500</item>
<item name="colorDarkIcon">@color/m3_gray_900</item>
<item name="colorSearchHint">@color/m3_gray_700</item>
<item name="profileHeaderBackground">@color/m3_gray_500</item>
<item name="android:colorAccent">@color/m3_primary_700</item>
<item name="android:colorBackground">@color/m3_gray_50</item>
<item name="colorButtonText">@color/m3_gray_50</item>
<item name="colorBackgroundLight">@color/m3_gray_50</item>
<item name="colorBackgroundLightest">@color/m3_gray_25</item>
<item name="android:statusBarColor">@color/m3_gray_50</item>
<item name="android:navigationBarColor">@color/m3_navigation_bar_bg</item>
<item name="android:actionBarTheme">@style/Theme.Mastodon.Toolbar.M3</item>
<item name="android:alertDialogTheme">@style/Theme.Mastodon.Dialog.Alert.M3</item>
<item name="colorPollMostVoted">@color/m3_primary_500</item>
<item name="colorPollVoted">@color/m3_gray_200</item>
<item name="colorAccentLight">@color/m3_primary_600</item>
<item name="colorSearchField">@color/m3_gray_100</item>
<item name="colorTabInactive">@color/m3_gray_400</item>
<item name="colorAccentLightest">@color/m3_primary_100</item>
<item name="colorSecondary">@color/m3_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/m3_gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/m3_gray_200</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/m3_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/m3_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/m3_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/m3_gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/m3_gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/m3_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/m3_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/m3_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/m3_gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/m3_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/m3_gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/m3_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/m3_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/m3_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.Material3" parent="Theme.Mastodon.Dark">
<!-- needed to disable scrim on API 29+ -->
<item name="android:colorBackground">@color/m3_gray_800</item>
<item name="colorButtonText">@color/m3_gray_800</item>
<item name="colorBackgroundLight">@color/m3_gray_800</item>
<item name="colorBackgroundLightest">@color/m3_gray_900</item>
<item name="colorBackgroundPopup">@color/m3_gray_900</item>
<item name="colorDarkIcon">@color/gray_25</item>
<item name="colorWindowBackground">@color/m3_gray_900</item>
<item name="android:statusBarColor">@color/m3_gray_900</item>
<item name="android:navigationBarColor">@color/m3_gray_900</item>
<item name="colorPollVoted">@color/m3_gray_700</item>
<item name="profileHeaderBackground">?colorWindowBackground</item>
<item name="android:actionBarTheme">@style/Theme.Mastodon.Toolbar.Dark.Material3</item>
<item name="android:colorAccent">@color/m3_primary_400</item>
<item name="android:colorPrimary">@color/m3_gray_50</item>
<item name="android:textColorPrimary">@color/m3_gray_50</item>
<item name="android:textColorSecondary">@color/m3_gray_400</item>
<item name="android:alertDialogTheme">@style/Theme.Mastodon.Dialog.Alert.Dark.M3</item>
<item name="colorPollMostVoted">@color/m3_primary_700</item>
<item name="colorAccentLight">@color/m3_primary_600</item>
<item name="colorAccentLightest">@color/m3_primary_800</item>
<item name="colorTabInactive">@color/m3_gray_400</item>
<item name="colorSearchHint">@color/m3_gray_300</item>
<item name="colorSecondary">@color/m3_gray_50</item>
<!-- TODO dark colors -->
<item name="colorSearchField">@color/m3_gray_700</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/m3_gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/m3_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/m3_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/m3_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/m3_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/m3_gray_700</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/m3_gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/m3_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/m3_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/m3_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/m3_gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/m3_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/m3_gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/m3_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/m3_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/m3_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack.Material3" parent="Theme.Mastodon.Dark.Material3">
<item name="android:colorAccent">@color/m3_primary_400</item>
<item name="colorPollMostVoted">@color/m3_primary_700</item>
<item name="colorAccentLight">@color/m3_primary_600</item>
<item name="colorAccentLightest">@color/m3_primary_800</item>
<item name="colorSecondary">@color/m3_gray_50</item>
<item name="colorPollVoted">@color/m3_gray_800</item>
<item name="colorSearchField">@color/m3_gray_900</item>
<item name="colorBackgroundPopup">@color/m3_gray_900</item>
<item name="android:navigationBarColor">@color/black</item>
<item name="android:colorBackground">@color/black</item>
<item name="android:statusBarColor">@color/black</item>
<item name="android:actionBarTheme">@style/Theme.Mastodon.Toolbar.Dark.TrueBlack</item>
<item name="colorBackgroundLight">@color/black</item>
<item name="colorWindowBackground">@color/black</item>
<item name="colorButtonText">@color/black</item>
<item name="colorBackgroundLightest">@color/black</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/m3_gray_900</item>
</style>
<style name="Theme.Mastodon.AutoLightDark.Material3" parent="Theme.Mastodon.Light.Material3"/>
<style name="Theme.Mastodon.AutoLightDark.TrueBlack.Material3" parent="Theme.Mastodon.Light.Material3"/>
<style name="Theme.Mastodon.Dialog.Alert.Dark.M3" parent="android:Theme.Material.Dialog.Alert">
<item name="android:windowTitleStyle">@style/alert_title</item>
<item name="android:dialogPreferredPadding">24dp</item>
<item name="android:windowBackground">@drawable/bg_alert</item>
<item name="android:buttonBarButtonStyle">@style/Widget.Mastodon.ButtonBarButton</item>
<!-- colors -->
<item name="android:colorAccent">@color/m3_primary_600</item>
<item name="android:colorPrimary">@color/m3_gray_50</item>
<item name="android:colorBackground">@color/gray_700</item>
<item name="android:textColorPrimary">@color/m3_gray_50</item>
<item name="android:textColorSecondary">@color/m3_gray_400</item>
</style>
<style name="Theme.Mastodon.Dialog.Alert.M3" parent="android:Theme.Material.Light.Dialog.Alert">
<item name="android:windowTitleStyle">@style/alert_title</item>
<item name="android:dialogPreferredPadding">24dp</item>
<item name="android:windowBackground">@drawable/bg_alert</item>
<item name="android:buttonBarButtonStyle">@style/Widget.Mastodon.ButtonBarButton</item>
<!-- colors -->
<item name="android:colorAccent">@color/m3_primary_700</item>
<item name="android:colorPrimary">@color/gray_800</item>
<item name="android:colorBackground">@color/m3_gray_100</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_500</item>
</style>
<style name="Theme.Mastodon.Toolbar.M3" parent="android:ThemeOverlay.Material.ActionBar">
<item name="android:colorPrimary">@color/m3_gray_50</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_800</item>
</style>
<style name="Theme.Mastodon.Light.Green" parent="Theme.Mastodon.Light.CustomBase">
<item name="android:colorAccent">@color/green_primary_700</item>
<item name="android:colorBackground">@color/green_gray_100</item>
@@ -222,6 +433,27 @@
<item name="colorTabInactive">@color/green_gray_400</item>
<item name="colorAccentLightest">@color/green_primary_100</item>
<item name="colorSecondary">@color/green_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/green_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/green_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/green_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/green_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/green_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/green_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/green_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/green_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/green_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/green_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/green_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.Green" parent="Theme.Mastodon.Dark.CustomBase">
@@ -236,6 +468,27 @@
<item name="colorTabInactive">@color/green_gray_400</item>
<item name="colorSearchHint">@color/green_gray_300</item>
<item name="colorSecondary">@color/green_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/green_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/green_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/green_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/green_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/green_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/green_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/green_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/green_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/green_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/green_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/green_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack.Green" parent="Theme.Mastodon.Dark.Green">
@@ -245,9 +498,9 @@
<item name="colorAccentLightest">@color/green_primary_800</item>
<item name="colorSecondary">@color/green_gray_50</item>
<item name="colorPollVoted">@color/custom_gray_800</item>
<item name="colorSearchField">@color/custom_gray_900</item>
<item name="colorBackgroundPopup">@color/custom_gray_900</item>
<item name="colorPollVoted">@color/gray_800</item>
<item name="colorSearchField">@color/gray_900</item>
<item name="colorBackgroundPopup">@color/gray_900</item>
<item name="android:navigationBarColor">@color/black</item>
<item name="android:colorBackground">@color/black</item>
<item name="android:statusBarColor">@color/black</item>
@@ -270,7 +523,7 @@
<!-- colors -->
<item name="android:colorAccent">@color/green_primary_600</item>
<item name="android:colorPrimary">@color/green_gray_50</item>
<item name="android:colorBackground">@color/custom_gray_700</item>
<item name="android:colorBackground">@color/gray_700</item>
<item name="android:textColorPrimary">@color/green_gray_50</item>
<item name="android:textColorSecondary">@color/green_gray_400</item>
</style>
@@ -283,16 +536,16 @@
<!-- colors -->
<item name="android:colorAccent">@color/green_primary_700</item>
<item name="android:colorPrimary">@color/custom_gray_800</item>
<item name="android:colorPrimary">@color/gray_800</item>
<item name="android:colorBackground">@color/green_gray_100</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_500</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_500</item>
</style>
<style name="Theme.Mastodon.Toolbar.Green" parent="android:ThemeOverlay.Material.ActionBar">
<item name="android:colorPrimary">@color/green_gray_50</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_800</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_800</item>
</style>
@@ -313,6 +566,27 @@
<item name="colorTabInactive">@color/blue_gray_400</item>
<item name="colorAccentLightest">@color/blue_primary_100</item>
<item name="colorSecondary">@color/blue_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/blue_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/blue_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/blue_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/blue_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/blue_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/blue_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/blue_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/blue_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/blue_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/blue_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/blue_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.Blue" parent="Theme.Mastodon.Dark.CustomBase">
@@ -327,6 +601,27 @@
<item name="colorTabInactive">@color/blue_gray_400</item>
<item name="colorSearchHint">@color/blue_gray_300</item>
<item name="colorSecondary">@color/blue_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/blue_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/blue_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/blue_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/blue_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/blue_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/blue_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/blue_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/blue_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/blue_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/blue_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/blue_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack.Blue" parent="Theme.Mastodon.Dark.Blue">
@@ -336,9 +631,9 @@
<item name="colorAccentLightest">@color/blue_primary_800</item>
<item name="colorSecondary">@color/blue_gray_50</item>
<item name="colorPollVoted">@color/custom_gray_800</item>
<item name="colorSearchField">@color/custom_gray_900</item>
<item name="colorBackgroundPopup">@color/custom_gray_900</item>
<item name="colorPollVoted">@color/gray_800</item>
<item name="colorSearchField">@color/gray_900</item>
<item name="colorBackgroundPopup">@color/gray_900</item>
<item name="android:navigationBarColor">@color/black</item>
<item name="android:colorBackground">@color/black</item>
<item name="android:statusBarColor">@color/black</item>
@@ -361,7 +656,7 @@
<!-- colors -->
<item name="android:colorAccent">@color/blue_primary_600</item>
<item name="android:colorPrimary">@color/blue_gray_50</item>
<item name="android:colorBackground">@color/custom_gray_700</item>
<item name="android:colorBackground">@color/gray_700</item>
<item name="android:textColorPrimary">@color/blue_gray_50</item>
<item name="android:textColorSecondary">@color/blue_gray_400</item>
</style>
@@ -374,16 +669,16 @@
<!-- colors -->
<item name="android:colorAccent">@color/blue_primary_700</item>
<item name="android:colorPrimary">@color/custom_gray_800</item>
<item name="android:colorPrimary">@color/gray_800</item>
<item name="android:colorBackground">@color/blue_gray_100</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_500</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_500</item>
</style>
<style name="Theme.Mastodon.Toolbar.Blue" parent="android:ThemeOverlay.Material.ActionBar">
<item name="android:colorPrimary">@color/blue_gray_50</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_800</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_800</item>
</style>
<style name="Theme.Mastodon.Light.Brown" parent="Theme.Mastodon.Light.CustomBase">
@@ -403,6 +698,27 @@
<item name="colorTabInactive">@color/brown_gray_400</item>
<item name="colorAccentLightest">@color/brown_primary_100</item>
<item name="colorSecondary">@color/brown_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/brown_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/brown_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/brown_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/brown_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/brown_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/brown_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/brown_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/brown_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/brown_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/brown_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/brown_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.Brown" parent="Theme.Mastodon.Dark.CustomBase">
@@ -417,6 +733,27 @@
<item name="colorTabInactive">@color/brown_gray_400</item>
<item name="colorSearchHint">@color/brown_gray_300</item>
<item name="colorSecondary">@color/brown_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/brown_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/brown_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/brown_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/brown_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/brown_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/brown_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/brown_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/brown_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/brown_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/brown_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/brown_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack.Brown" parent="Theme.Mastodon.Dark.Brown">
@@ -426,9 +763,9 @@
<item name="colorAccentLightest">@color/brown_primary_800</item>
<item name="colorSecondary">@color/brown_gray_50</item>
<item name="colorPollVoted">@color/custom_gray_800</item>
<item name="colorSearchField">@color/custom_gray_900</item>
<item name="colorBackgroundPopup">@color/custom_gray_900</item>
<item name="colorPollVoted">@color/gray_800</item>
<item name="colorSearchField">@color/gray_900</item>
<item name="colorBackgroundPopup">@color/gray_900</item>
<item name="android:navigationBarColor">@color/black</item>
<item name="android:colorBackground">@color/black</item>
<item name="android:statusBarColor">@color/black</item>
@@ -451,7 +788,7 @@
<!-- colors -->
<item name="android:colorAccent">@color/brown_primary_600</item>
<item name="android:colorPrimary">@color/brown_gray_50</item>
<item name="android:colorBackground">@color/custom_gray_700</item>
<item name="android:colorBackground">@color/gray_700</item>
<item name="android:textColorPrimary">@color/brown_gray_50</item>
<item name="android:textColorSecondary">@color/brown_gray_400</item>
</style>
@@ -464,16 +801,16 @@
<!-- colors -->
<item name="android:colorAccent">@color/brown_primary_700</item>
<item name="android:colorPrimary">@color/custom_gray_800</item>
<item name="android:colorPrimary">@color/gray_800</item>
<item name="android:colorBackground">@color/brown_gray_100</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_500</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_500</item>
</style>
<style name="Theme.Mastodon.Toolbar.Brown" parent="android:ThemeOverlay.Material.ActionBar">
<item name="android:colorPrimary">@color/brown_gray_50</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_800</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_800</item>
</style>
@@ -494,6 +831,27 @@
<item name="colorTabInactive">@color/yellow_gray_400</item>
<item name="colorAccentLightest">@color/yellow_primary_100</item>
<item name="colorSecondary">@color/yellow_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/yellow_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/yellow_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/yellow_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/yellow_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/yellow_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/yellow_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/yellow_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/yellow_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/yellow_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/yellow_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/yellow_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.Yellow" parent="Theme.Mastodon.Dark.CustomBase">
@@ -508,6 +866,27 @@
<item name="colorTabInactive">@color/yellow_gray_400</item>
<item name="colorSearchHint">@color/yellow_gray_300</item>
<item name="colorSecondary">@color/yellow_gray_50</item>
<!-- colors for button_bg|text_primary|secondary_dark|light_on_light|dark.xml -->
<item name="colorButtonBackgroundPrimaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonBackgroundPrimaryDarkOnLightDisabled">@color/yellow_gray_300</item>
<item name="colorButtonTextPrimaryDarkOnLight">@color/yellow_gray_50</item>
<item name="colorButtonTextPrimaryDarkOnLightDisabled">@color/yellow_gray_400</item>
<item name="colorButtonBackgroundPrimaryLightOnDark">@color/yellow_gray_100</item>
<item name="colorButtonBackgroundPrimaryLightOnDarkDisabled">@color/gray_500</item>
<item name="colorButtonTextPrimaryLightOnDark">@color/gray_800</item>
<item name="colorButtonTextPrimaryLightOnDarkDisabled">@color/yellow_gray_400</item>
<item name="colorButtonBackgroundSecondaryDarkOnLight">@color/yellow_gray_25</item>
<item name="colorButtonBackgroundSecondaryDarkOnLightDisabled">@color/yellow_gray_100</item>
<item name="colorButtonTextSecondaryDarkOnLight">@color/gray_800</item>
<item name="colorButtonTextSecondaryDarkOnLightDisabled">@color/yellow_gray_400</item>
<item name="colorButtonBackgroundSecondaryLightOnDark">@color/gray_600</item>
<item name="colorButtonBackgroundSecondaryLightOnDarkDisabled">@color/yellow_gray_300</item>
<item name="colorButtonTextSecondaryLightOnDark">@color/yellow_gray_50</item>
<item name="colorButtonTextSecondaryLightOnDarkDisabled">@color/yellow_gray_400</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack.Yellow" parent="Theme.Mastodon.Dark.Yellow">
@@ -517,9 +896,9 @@
<item name="colorAccentLightest">@color/yellow_primary_800</item>
<item name="colorSecondary">@color/yellow_gray_50</item>
<item name="colorPollVoted">@color/custom_gray_800</item>
<item name="colorSearchField">@color/custom_gray_900</item>
<item name="colorBackgroundPopup">@color/custom_gray_900</item>
<item name="colorPollVoted">@color/gray_800</item>
<item name="colorSearchField">@color/gray_900</item>
<item name="colorBackgroundPopup">@color/gray_900</item>
<item name="android:navigationBarColor">@color/black</item>
<item name="android:colorBackground">@color/black</item>
<item name="android:statusBarColor">@color/black</item>
@@ -542,7 +921,7 @@
<!-- colors -->
<item name="android:colorAccent">@color/yellow_primary_600</item>
<item name="android:colorPrimary">@color/yellow_gray_50</item>
<item name="android:colorBackground">@color/custom_gray_700</item>
<item name="android:colorBackground">@color/gray_700</item>
<item name="android:textColorPrimary">@color/yellow_gray_50</item>
<item name="android:textColorSecondary">@color/yellow_gray_400</item>
</style>
@@ -555,24 +934,50 @@
<!-- colors -->
<item name="android:colorAccent">@color/yellow_primary_700</item>
<item name="android:colorPrimary">@color/custom_gray_800</item>
<item name="android:colorPrimary">@color/gray_800</item>
<item name="android:colorBackground">@color/yellow_gray_100</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_500</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_500</item>
</style>
<style name="Theme.Mastodon.Toolbar.Yellow" parent="android:ThemeOverlay.Material.ActionBar">
<item name="android:colorPrimary">@color/yellow_gray_50</item>
<item name="android:textColorPrimary">@color/custom_gray_800</item>
<item name="android:textColorSecondary">@color/custom_gray_800</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_800</item>
</style>
<style name="Theme.Mastodon.Dark.Red" parent="Theme.Mastodon.Dark">
<item name="android:colorAccent">@color/error_400</item>
<item name="colorPollMostVoted">@color/error_700</item>
<item name="colorAccentLight">@color/error_600</item>
<item name="colorAccentLightest">@color/error_800</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack.Red" parent="Theme.Mastodon.Dark.TrueBlack">
<item name="android:colorAccent">@color/error_400</item>
<item name="colorPollMostVoted">@color/error_700</item>
<item name="colorAccentLight">@color/error_600</item>
<item name="colorAccentLightest">@color/error_800</item>
</style>
<style name="Theme.Mastodon.Light.Red" parent="Theme.Mastodon.Light">
<item name="android:colorAccent">@color/error_700</item>
<item name="colorPollMostVoted">@color/error_800</item>
<item name="colorAccentLight">@color/error_600</item>
<item name="colorAccentLightest">@color/error_800</item>
</style>
<style name="Theme.Mastodon.AutoLightDark.Red" parent="Theme.Mastodon.Light.Red"/>
<style name="Theme.Mastodon.AutoLightDark.TrueBlack.Red" parent="Theme.Mastodon.Light.Red"/>
<style name="Theme.Mastodon.Dark.Original" parent="Theme.Mastodon.Dark">
<item name="android:colorAccent">@color/original_primary_400</item>
<item name="colorPollMostVoted">@color/original_primary_700</item>
<item name="colorAccentLight">@color/original_primary_600</item>
<item name="colorAccentLightest">@color/original_primary_800</item>
<item name="android:alertDialogTheme">@style/Theme.Mastodon.Dialog.Alert.Dark.Original</item>
</style>
<style name="Theme.Mastodon.Dark.TrueBlack.Original" parent="Theme.Mastodon.Dark.TrueBlack">
@@ -580,6 +985,7 @@
<item name="colorPollMostVoted">@color/original_primary_700</item>
<item name="colorAccentLight">@color/original_primary_600</item>
<item name="colorAccentLightest">@color/original_primary_800</item>
<item name="android:alertDialogTheme">@style/Theme.Mastodon.Dialog.Alert.Dark.Original</item>
</style>
<style name="Theme.Mastodon.Light.Original" parent="Theme.Mastodon.Light">
@@ -587,17 +993,45 @@
<item name="colorPollMostVoted">@color/original_primary_700</item>
<item name="colorAccentLight">@color/original_primary_600</item>
<item name="colorAccentLightest">@color/original_primary_800</item>
<item name="android:alertDialogTheme">@style/Theme.Mastodon.Dialog.Alert.Original</item>
</style>
<style name="Theme.Mastodon.AutoLightDark.Original" parent="Theme.Mastodon.Light.Original"/>
<style name="Theme.Mastodon.AutoLightDark.TrueBlack.Original" parent="Theme.Mastodon.Light.Original"/>
<style name="Theme.Mastodon.Dialog.Alert.Dark.Original" parent="android:Theme.Material.Dialog.Alert">
<item name="android:windowTitleStyle">@style/alert_title</item>
<item name="android:dialogPreferredPadding">24dp</item>
<item name="android:windowBackground">@drawable/bg_alert</item>
<item name="android:buttonBarButtonStyle">@style/Widget.Mastodon.ButtonBarButton</item>
<!-- colors -->
<item name="android:colorAccent">@color/original_primary_600</item>
<item name="android:colorPrimary">@color/gray_50</item>
<item name="android:colorBackground">@color/gray_700</item>
<item name="android:textColorPrimary">@color/gray_50</item>
<item name="android:textColorSecondary">@color/gray_400</item>
</style>
<style name="Theme.Mastodon.Dialog.Alert.Original" parent="android:Theme.Material.Light.Dialog.Alert">
<item name="android:windowTitleStyle">@style/alert_title</item>
<item name="android:dialogPreferredPadding">24dp</item>
<item name="android:windowBackground">@drawable/bg_alert</item>
<item name="android:buttonBarButtonStyle">@style/Widget.Mastodon.ButtonBarButton</item>
<!-- colors -->
<item name="android:colorAccent">@color/original_primary_700</item>
<item name="android:colorPrimary">@color/gray_800</item>
<item name="android:colorBackground">@color/gray_100</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_500</item>
</style>
<style name="Theme.Mastodon.Toolbar" parent="android:ThemeOverlay.Material.ActionBar">
<item name="android:colorPrimary">@color/gray_50</item>
<item name="android:toolbarStyle">@style/Widget.Mastodon.Toolbar</item>
<item name="android:textColorPrimary">@color/gray_800</item>
<item name="android:textColorSecondary">@color/gray_800</item>
<item name="android:toolbarStyle">@style/Widget.Mastodon.Toolbar</item>
</style>
<style name="Theme.Mastodon.Toolbar.Dark" parent="android:ThemeOverlay.Material.Dark.ActionBar">
@@ -607,18 +1041,18 @@
<item name="android:toolbarStyle">@style/Widget.Mastodon.Toolbar</item>
</style>
<style name="Widget.Mastodon.Toolbar" parent="android:Widget.Material.Toolbar">
<item name="android:contentInsetStartWithNavigation">0dp</item>
<item name="android:titleMarginEnd">0dp</item>
<item name="android:titleMarginStart">0dp</item>
</style>
<style name="Theme.Mastodon.Toolbar.Dark.CustomBase" parent="android:ThemeOverlay.Material.Dark.ActionBar">
<item name="android:colorPrimary">@color/custom_gray_800</item>
<item name="android:colorPrimary">@color/gray_800</item>
<item name="android:textColorPrimary">@color/gray_50</item>
<item name="android:textColorSecondary">@color/gray_50</item>
</style>
<style name="Theme.Mastodon.Toolbar.Dark.Material3" parent="android:ThemeOverlay.Material.Dark.ActionBar">
<item name="android:colorPrimary">@color/m3_gray_900</item>
<item name="android:textColorPrimary">@color/m3_gray_50</item>
<item name="android:textColorSecondary">@color/m3_gray_50</item>
</style>
<style name="Theme.Mastodon.Toolbar.Dark.TrueBlack" parent="android:ThemeOverlay.Material.Dark.ActionBar">
<item name="android:colorPrimary">@color/black</item>
</style>
@@ -779,6 +1213,12 @@
<item name="android:lineSpacingExtra">4dp</item>
</style>
<style name="m3_body_small">
<item name="android:textSize">12dp</item>
<item name="android:textColor">?android:textColorSecondary</item>
<item name="android:lineSpacingExtra">2dp</item>
</style>
<style name="m3_title_medium">
<item name="android:fontFamily">sans-serif-medium</item>
<item name="android:textSize">16dp</item>

View File

@@ -0,0 +1,6 @@
- Sprachauswahl hinzugefügt
- Übersetz-Funktion hinzugefügt
- Semantik bei Umfragen verbessert (Radio-Buttons, Checkboxen)
- Mehrfachauswahl als Option bei Umfragen
- Neuer Anmelde-Bildschirm
- Fehlerbehebungen

View File

@@ -9,3 +9,7 @@ Megalodon ist eine modifizierte Version der <a href="https://github.com/mastodon
- <b>Hashtags folgen</b>: Bringt neue Beiträge bestimmter Hashtags direkt in deine Home-Timeline.
- <b>Folgeanfragen beantworten</b>: Folgeanfragen lassen sich nun direkt über die Benachrichtigungen-Liste oder über die Folgeanfragen-Liste akzeptieren oder ablehnen.
- <b>Beiträge löschen und neu erstellen</b>: Das beliebte Feature, das das Bearbeiten von Beiträgen ohne tatsächliche Bearbeit-Funktion möglich gemacht hat.
- <b>Sprachauswahl</b>: Wähle mühelos die Sprache für jeden deiner Beiträge, damit diese richtig gefiltert und übersetzt werden können.
- <b>Übersetzung</b>: Beiträge können nun direkt in Megalodon übersetzt werden aber nur, wenn deine Instanz dies auch unterstützt.
- <b>Sichtbarkeits-Indikator</b>: Beim Öffnen oder Antworten auf einen Beitrag zeigt ein Symbol die Sichtbarkeit des Beitrags an.
- <b>Farb-Schemata</b>: Wem das Standard-Pink nicht gefällt (der Hai verurteilt dich stillschweigend), dem verschaffen die Farb-Schemata von Moshidon Abhilfe.

View File

@@ -1,4 +1,6 @@
- Add language selector
- Add translate function
- Improve semantics for voting on polls (radio buttons and checkboxes)
- Add option to allow voting for multiple options on polls
- Add translate function
- Bugfixes
- New login screen
- Bugfixes

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