Compare commits

...

88 Commits

Author SHA1 Message Date
sk
cd3de97d55 Merge remote-tracking branch 'upstream/l10n_master' 2023-10-07 23:47:36 +02:00
sk
4853a25710 bump version 2023-10-07 23:47:01 +02:00
SomeTr
eba9a1da7b Translated using Weblate (Ukrainian)
Currently translated at 100.0% (18 of 18 strings)

Translation: Megalodon/metadata
Translate-URL: https://translate.codeberg.org/projects/megalodon/metadata/uk/
2023-10-07 21:46:18 +00:00
SomeTr
068c62b060 Translated using Weblate (Ukrainian)
Currently translated at 98.9% (385 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-07 21:46:18 +00:00
David Lapshin
5d7f06eba0 Translated using Weblate (Russian)
Currently translated at 97.6% (380 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-10-07 21:46:18 +00:00
Linerly
fed9dec33a Translated using Weblate (Indonesian)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-07 21:46:18 +00:00
Choukajohn
7973914a5f Translated using Weblate (French)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-07 21:46:18 +00:00
kallekn
35efb3f047 Translated using Weblate (Finnish)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-10-07 21:46:18 +00:00
sk
0a4ed50904 i think i fixed the offset issue 2023-10-07 23:45:33 +02:00
sk
002c66174a fix type filter, wrong max id, refactor max id 2023-10-07 23:32:10 +02:00
Eugen Rochko
22aac3d943 New translations strings.xml (Finnish) 2023-10-07 22:49:20 +02:00
sk
872f47305a Revert "temporary fix for pre-release users"
This reverts commit 2314871246.
2023-10-07 22:38:42 +02:00
sk
75d5332411 don't add existing posts to timeline 2023-10-07 22:38:30 +02:00
sk
035da8a517 update blocks and languages 2023-10-07 22:17:36 +02:00
sk
4c2c877d41 bump version 2023-10-07 22:11:35 +02:00
sk
0cc8cddfc3 support recently used emoji
closes sk22#832
2023-10-07 22:10:52 +02:00
sk
4428ef7ac2 display recent languages
closes sk22#654
2023-10-07 19:47:49 +02:00
sk
44912b7982 display timestamp in notification header
closes sk22#668
2023-10-07 19:17:45 +02:00
sk
c930db6068 refactor filtering
hopefully also fixes sk22#816
2023-10-07 18:25:37 +02:00
sk
d96d4dd581 unselect add button on bind
closes sk22#830
2023-10-07 17:52:39 +02:00
sk
67e3a5bb47 fix warning not clickable if main status 2023-10-07 17:50:24 +02:00
sk22
b0a5aa93e1 Translated using Weblate (German)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/de/
2023-10-07 15:39:39 +00:00
sk22
0bc1459898 Translated using Weblate (English)
Currently translated at 100.0% (389 of 389 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/en/
2023-10-07 15:39:38 +00:00
sk
fae25e93a5 Merge remote-tracking branch 'weblate/main' 2023-10-07 17:29:18 +02:00
kallekn
c0c121050c Translated using Weblate (Finnish)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fi/
2023-10-07 15:29:11 +00:00
teknopata
afe572ca7f Translated using Weblate (Basque)
Currently translated at 78.6% (305 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/eu/
2023-10-07 15:29:11 +00:00
sk
8cb4db5fcf Merge remote-tracking branch 'weblate/main' 2023-10-07 17:28:51 +02:00
sk
de235ec7cc use upstream filtering for warn item 2023-10-07 17:21:20 +02:00
sk
140c2a7b9d remove status filter predicate from thread 2023-10-07 17:04:55 +02:00
sk
c833513344 use same filtering function everywhere 2023-10-07 17:02:03 +02:00
sk
1e95536208 fix issue with loading more 2023-10-07 17:00:16 +02:00
sk
b58fda9795 remove unused method 2023-10-07 16:12:35 +02:00
sk
3135aef398 fix wrong overflow button style 2023-10-07 16:03:30 +02:00
sk
c83dc51322 re-add ripple to filter warning 2023-10-07 15:43:16 +02:00
sk
9cfaed89e6 fix filter warning background color
closes sk22#823
2023-10-07 15:26:10 +02:00
sk
5374ac766c prettier visibility toggle animation
maybe fix sk22#845
2023-10-07 15:21:06 +02:00
sk
98596e77f2 fix interaction button colors
closes sk22#841
2023-10-07 12:44:39 +02:00
sk
54aa89c7f8 OOPS 2023-10-07 12:44:33 +02:00
sk
f59157b160 fix text not selectable
closes sk22#824
2023-10-07 12:33:14 +02:00
sk
6b38db9607 add heart symbol to extended footer 2023-10-07 12:08:37 +02:00
Eugen Rochko
53afc120f3 New translations strings.xml (Chinese Traditional) 2023-10-07 03:46:12 +02:00
sk
c10cdfd795 fix color inheritance issue 2023-10-06 18:44:15 +02:00
sk
c2184e7bd8 don't dismiss when restarting activity 2023-10-06 18:00:59 +02:00
sk
baf756e163 allow using heart as fav icon ❤️
closes sk22#81
2023-10-06 17:53:43 +02:00
sk
efc67fd7e8 remove inset poll styles
closes sk22#801
2023-10-06 17:26:59 +02:00
sk
43e737425a fix null reference 2023-10-06 17:20:49 +02:00
sk
b5b3cb42a1 re-implement missing "translate opened only" 2023-10-06 17:09:57 +02:00
sk
f72f7cb831 hide username wrap in edit mode
closes sk22#828
2023-10-06 17:02:52 +02:00
sk
f86d60be23 fix color palette dialog title 2023-10-06 17:00:09 +02:00
sk
7c8624bd53 fix alpha animations
closes sk22#839
2023-10-06 16:55:02 +02:00
Eugen Rochko
a75ce70615 New translations strings.xml (Finnish) 2023-10-06 16:38:40 +02:00
sk
331548b38d fix crash 2023-10-06 16:20:16 +02:00
sk
8b8f192dfa fix posts/bubble banner not disappearing
closes sk22#833
2023-10-06 16:17:18 +02:00
sk
061b2ee3de per-account color palette preference 2023-10-06 16:13:38 +02:00
sk
5ea2864bd5 Merge remote-tracking branch 'upstream/master' 2023-10-06 15:17:49 +02:00
LucasGGamerM
ee2b4b6a1f fix(hashtag-fragment): fix crash when opening some hashtags (#842) 2023-10-06 15:04:02 +02:00
LucasGGamerM
697f801c1a fix(hashtags): fix crash when hashtag is null (#844) 2023-10-06 15:03:25 +02:00
sk
ebb49c44fe refactor code 2023-10-06 15:01:46 +02:00
LucasGGamerM
bc4619e6b1 fix(translations): fix crash when status language is null 2023-10-06 15:01:46 +02:00
Eugen Rochko
4a3b948760 New translations strings.xml (Finnish) 2023-10-05 22:23:12 +02:00
Eugen Rochko
f81283c892 New translations strings.xml (Italian) 2023-10-05 21:19:39 +02:00
Eugen Rochko
7eae879037 New translations strings.xml (Russian) 2023-10-05 16:06:00 +02:00
Eugen Rochko
1b0ce5d893 New translations strings.xml (Swedish) 2023-10-05 12:02:19 +02:00
butterflyoffire
5d26ea85e9 Translated using Weblate (Arabic)
Currently translated at 80.1% (311 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ar/
2023-10-05 07:53:14 +00:00
ihor_ck
6efe263dd8 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/uk/
2023-10-05 07:53:14 +00:00
David Lapshin
0379347f2d Translated using Weblate (Russian)
Currently translated at 87.1% (338 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ru/
2023-10-05 07:53:14 +00:00
alextecplayz
1299b2ad42 Translated using Weblate (Romanian)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/ro/
2023-10-05 07:53:14 +00:00
Linerly
f3b3bcaa0a Translated using Weblate (Indonesian)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/id/
2023-10-05 07:53:14 +00:00
Choukajohn
b1bec870c5 Translated using Weblate (French)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-05 07:53:13 +00:00
butterflyoffire
36e05a6d14 Translated using Weblate (French)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/fr/
2023-10-05 07:53:13 +00:00
gallegonovato
2e11f78e9d Translated using Weblate (Spanish)
Currently translated at 100.0% (388 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/es/
2023-10-05 07:53:13 +00:00
poesty
9fcfbe5593 Translated using Weblate (Chinese (Simplified))
Currently translated at 99.7% (387 of 388 strings)

Translation: Megalodon/values
Translate-URL: https://translate.codeberg.org/projects/megalodon/values/zh_Hans/
2023-10-05 07:53:12 +00:00
Eugen Rochko
c17745368d New translations strings.xml (Italian) 2023-10-04 22:24:20 +02:00
Eugen Rochko
e78b518654 New translations strings.xml (Ukrainian) 2023-10-04 18:44:26 +02:00
Eugen Rochko
55a8634be2 New translations strings.xml (Japanese) 2023-10-04 16:52:54 +02:00
Eugen Rochko
ac891eea53 New translations strings.xml (Icelandic) 2023-10-04 15:28:52 +02:00
Eugen Rochko
74fa2a3081 New translations strings.xml (Thai) 2023-10-03 21:27:27 +02:00
Grishka
6c1c5b7759 Merge branch 'l10n_master' 2023-10-03 03:53:50 +03:00
Grishka
1f4152b588 Fix #705 and improve handling of unknown attachment dimensions 2023-10-03 02:52:07 +03:00
Grishka
70386ea1b2 Update appkit to finally fix that ViewPager2 crash 2023-10-03 02:11:04 +03:00
Eugen Rochko
cbce90c461 New translations strings.xml (Sinhala) 2023-10-02 21:16:49 +02:00
Eugen Rochko
74ae3bf706 New translations strings.xml (Armenian) 2023-10-02 07:26:27 +02:00
Grishka
1feccdc26d Fixes 2023-10-01 23:11:33 +03:00
Eugen Rochko
c38c2a425b New translations strings.xml (Indonesian) 2023-10-01 17:30:46 +02:00
Eugen Rochko
f43352b790 New translations strings.xml (Indonesian) 2023-10-01 16:30:51 +02:00
Grishka
c5b52b2781 Fix default server not loading sometimes 2023-10-01 12:17:21 +03:00
Grishka
b91840fb95 Another attempt to fix ZoomPanView crash 2023-10-01 07:16:21 +03:00
Eugen Rochko
e40841c128 New translations strings.xml (Portuguese, Brazilian) 2023-09-30 20:26:54 +02:00
116 changed files with 899 additions and 530 deletions

View File

@@ -15,8 +15,8 @@ android {
applicationId "org.joinmastodon.android.sk" applicationId "org.joinmastodon.android.sk"
minSdk 23 minSdk 23
targetSdk 33 targetSdk 33
versionCode 100 versionCode 102
versionName "2.1.4+fork.100" versionName "2.1.6+fork.102"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
resourceConfigurations += ['ar-rSA', 'ar-rDZ', 'be-rBY', 'bn-rBD', 'bs-rBA', 'ca-rES', 'cs-rCZ', 'da-rDK', 'de-rDE', 'el-rGR', 'es-rES', 'eu-rES', 'fa-rIR', 'fi-rFI', 'fil-rPH', 'fr-rFR', 'ga-rIE', 'gd-rGB', 'gl-rES', 'hi-rIN', 'hr-rHR', 'hu-rHU', 'hy-rAM', 'ig-rNG', 'in-rID', 'is-rIS', 'it-rIT', 'iw-rIL', 'ja-rJP', 'kab', 'ko-rKR', 'my-rMM', 'nl-rNL', 'no-rNO', 'oc-rFR', 'pl-rPL', 'pt-rBR', 'pt-rPT', 'ro-rRO', 'ru-rRU', 'si-rLK', 'sl-rSI', 'sv-rSE', 'th-rTH', 'tr-rTR', 'uk-rUA', 'ur-rIN', 'vi-rVN', 'zh-rCN', 'zh-rTW'] resourceConfigurations += ['ar-rSA', 'ar-rDZ', 'be-rBY', 'bn-rBD', 'bs-rBA', 'ca-rES', 'cs-rCZ', 'da-rDK', 'de-rDE', 'el-rGR', 'es-rES', 'eu-rES', 'fa-rIR', 'fi-rFI', 'fil-rPH', 'fr-rFR', 'ga-rIE', 'gd-rGB', 'gl-rES', 'hi-rIN', 'hr-rHR', 'hu-rHU', 'hy-rAM', 'ig-rNG', 'in-rID', 'is-rIS', 'it-rIT', 'iw-rIL', 'ja-rJP', 'kab', 'ko-rKR', 'my-rMM', 'nl-rNL', 'no-rNO', 'oc-rFR', 'pl-rPL', 'pt-rBR', 'pt-rPT', 'ro-rRO', 'ru-rRU', 'si-rLK', 'sl-rSI', 'sv-rSE', 'th-rTH', 'tr-rTR', 'uk-rUA', 'ur-rIN', 'vi-rVN', 'zh-rCN', 'zh-rTW']
} }
@@ -70,7 +70,7 @@ dependencies {
implementation 'me.grishka.litex:viewpager:1.0.0' implementation 'me.grishka.litex:viewpager:1.0.0'
implementation 'me.grishka.litex:viewpager2:1.0.0' implementation 'me.grishka.litex:viewpager2:1.0.0'
implementation 'me.grishka.litex:palette:1.0.0' implementation 'me.grishka.litex:palette:1.0.0'
implementation 'me.grishka.appkit:appkit:1.2.9' implementation 'me.grishka.appkit:appkit:1.2.14'
implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.google.code.gson:gson:2.9.0'
implementation 'org.jsoup:jsoup:1.14.3' implementation 'org.jsoup:jsoup:1.14.3'
implementation 'com.squareup:otto:1.3.8' implementation 'com.squareup:otto:1.3.8'

View File

@@ -1,56 +1,43 @@
13bells.com 13bells.com
1611.social 1611.social
4aem.com 4aem.com
5dollah.click
adachi.party adachi.party
anime.website adtension.com
annihilation.social annihilation.social
anon-kenkai.com anon-kenkai.com
asbestos.cafe asbestos.cafe
bae.st bae.st
bajax.us
banepo.st banepo.st
baraag.net
bassam.social bassam.social
battlepenguin.video
beefyboys.win beefyboys.win
beepboop.ga
berserker.town
bikeshed.party
boks.moe
boymoder.biz boymoder.biz
brainsoap.net brainsoap.net
breastmilk.club breastmilk.club
brighteon.social brighteon.social
bungle.online cachapa.xyz
canary.fedinuke.example.com
catgirl.life
cawfee.club cawfee.club
childlove.space
clew.lol clew.lol
clubcyberia.co clubcyberia.co
collapsitarian.io
comfyboy.club
contrapointsfan.club contrapointsfan.club
crucible.world
cum.camp cum.camp
cum.salon cum.salon
darknight-coffee.org
decayable.ink decayable.ink
dembased.xyz dembased.xyz
desupost.soy
detroitriotcity.com detroitriotcity.com
eatthebugs.social djsumdog.com
eientei.org eientei.org
elementality.org
eveningzoo.club eveningzoo.club
firedragonstudios.com
firefaithfellowship.com
fluf.club fluf.club
foxfam.club
freak.university freak.university
freeatlantis.com freeatlantis.com
freedomstrike.org
freesoftwareextremist.com
freespeech.group
freespeechextremist.com freespeechextremist.com
freetalklive.com
froth.zone froth.zone
fulltermprivacy.com
gameliberty.club gameliberty.club
gearlandia.haus gearlandia.haus
genderheretics.xyz genderheretics.xyz
@@ -59,42 +46,34 @@ gleasonator.com
glee.li glee.li
glindr.org glindr.org
goyim.app goyim.app
goyslop.cafe h5q.net
haeder.net haeder.net
handholding.io handholding.io
hitchhiker.social hitchhiker.social
hunk.city
iddqd.social iddqd.social
intkos.link
justicewarrior.social
kawa-kun.com
kitsunemimi.club kitsunemimi.club
kiwifarms.cc kiwifarms.cc
kompost.cz
kurosawa.moe kurosawa.moe
kyaruc.moe
leafposter.club leafposter.club
leftychan.net
lewdieheaven.com lewdieheaven.com
liberdon.com liberdon.com
ligma.pro ligma.pro
lolicon.rocks lolicon.rocks
lolison.network
lolison.top lolison.top
lovingexpressions.net lovingexpressions.net
mahodou.moe
makemysarcophagus.com makemysarcophagus.com
maladaptive.art
marsey.moe marsey.moe
masochi.st
mastinator.com mastinator.com
merovingian.club merovingian.club
midwaytrades.com midwaytrades.com
mirr0r.city mirr0r.city
moa.st morale.ch
mouse.services mouse.services
mugicha.club mugicha.club
narrativerry.xyz narrativerry.xyz
natehiggers.online natehiggers.online
neckbeard.xyz
needs.vodka needs.vodka
neenster.org neenster.org
nicecrew.digital nicecrew.digital
@@ -103,18 +82,18 @@ noagendasocial.com
noagendasocial.nl noagendasocial.nl
noagendatube.com noagendatube.com
nobodyhasthe.biz nobodyhasthe.biz
nukem.biz norwoodzero.net
obo.sh nyanide.com
onionfarms.org onionfarms.org
pawlicker.com pawlicker.com
pawoo.net pawoo.net
pedo.school pedo.school
peervideo.club
piazza.today piazza.today
pibvt.net pibvt.net
pieville.net pieville.net
pisskey.io pisskey.io
plagu.ee plagu.ee
pmth.us
poa.st poa.st
poast.org poast.org
poast.tv poast.tv
@@ -123,17 +102,18 @@ prospeech.space
quodverum.com quodverum.com
r18.social r18.social
rakket.app rakket.app
rapemeat.express
rapemeat.solutions rapemeat.solutions
rdrama.cc rayci.st
rebelbase.site rebelbase.site
retardedniggers.forsale
rojogato.com
ryona.agency ryona.agency
sad.cab
schwartzwelt.xyz schwartzwelt.xyz
seal.cafe seal.cafe
shaw.app
shigusegubu.club shigusegubu.club
shitpost.cloud shitpost.cloud
shota.house shortstacksran.ch
silliness.observer silliness.observer
skinheads.eu skinheads.eu
skinheads.io skinheads.io
@@ -148,23 +128,20 @@ sneed.social
sonichu.com sonichu.com
spinster.xyz spinster.xyz
springbo.cc springbo.cc
starnix.network
strelizia.net strelizia.net
syspxl.xyz
tastingtraffic.net tastingtraffic.net
teci.world teci.world
theapex.social theapex.social
thechimp.zone
thenobody.club
thepostearthdestination.com thepostearthdestination.com
tkammer.de tkammer.de
trumpislovetrumpis.life trumpislovetrumpis.life
truthsocial.co.in truthsocial.co.in
urchan.org usualsuspects.lol
varishangout.net varishangout.net
whinge.house vtuberfan.social
whinge.town
wideboys.org
wolfgirl.bar wolfgirl.bar
xn--p1abe3d.xn--80asehdb xn--p1abe3d.xn--80asehdb
yggdrasil.social yggdrasil.social
youjo.love youjo.love
zztails.gay

View File

@@ -32,7 +32,6 @@ public class ExternalShareActivity extends FragmentStackActivity{
UiUtils.setUserPreferredTheme(this); UiUtils.setUserPreferredTheme(this);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if(savedInstanceState==null){ if(savedInstanceState==null){
Optional<String> text = Optional.ofNullable(getIntent().getStringExtra(Intent.EXTRA_TEXT)); Optional<String> text = Optional.ofNullable(getIntent().getStringExtra(Intent.EXTRA_TEXT));
Optional<Pair<String, Optional<String>>> fediHandle = text.flatMap(UiUtils::parseFediverseHandle); Optional<Pair<String, Optional<String>>> fediHandle = text.flatMap(UiUtils::parseFediverseHandle);
boolean isFediUrl = text.map(UiUtils::looksLikeFediverseUrl).orElse(false); boolean isFediUrl = text.map(UiUtils::looksLikeFediverseUrl).orElse(false);

View File

@@ -57,7 +57,6 @@ public class GlobalUserPreferences{
public static boolean allowRemoteLoading; public static boolean allowRemoteLoading;
public static boolean forwardReportDefault; public static boolean forwardReportDefault;
public static AutoRevealMode autoRevealEqualSpoilers; public static AutoRevealMode autoRevealEqualSpoilers;
public static ColorPreference color;
public static boolean disableM3PillActiveIndicator; public static boolean disableM3PillActiveIndicator;
public static boolean showNavigationLabels; public static boolean showNavigationLabels;
public static boolean displayPronounsInTimelines, displayPronounsInThreads, displayPronounsInUserListings; public static boolean displayPronounsInTimelines, displayPronounsInThreads, displayPronounsInUserListings;
@@ -133,14 +132,8 @@ public class GlobalUserPreferences{
.apply(); .apply();
} }
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;
}
if(prefs.getInt("migrationLevel", 0) < 61) migrateToUpstreamVersion61(); if(prefs.getInt("migrationLevel", 0) < 61) migrateToUpstreamVersion61();
if(prefs.getInt("migrationLevel", 0) < 101) migrateToVersion101();
} }
public static void save(){ public static void save(){
@@ -171,7 +164,6 @@ public class GlobalUserPreferences{
.putBoolean("spectatorMode", spectatorMode) .putBoolean("spectatorMode", spectatorMode)
.putBoolean("autoHideFab", autoHideFab) .putBoolean("autoHideFab", autoHideFab)
.putBoolean("compactReblogReplyLine", compactReblogReplyLine) .putBoolean("compactReblogReplyLine", compactReblogReplyLine)
.putString("color", color.name())
.putBoolean("allowRemoteLoading", allowRemoteLoading) .putBoolean("allowRemoteLoading", allowRemoteLoading)
.putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name()) .putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name())
.putBoolean("forwardReportDefault", forwardReportDefault) .putBoolean("forwardReportDefault", forwardReportDefault)
@@ -185,6 +177,16 @@ public class GlobalUserPreferences{
.apply(); .apply();
} }
private static void migrateToVersion101(){
Log.d(TAG, "Migrating preferences to version 101!! (copy current theme to local preferences)");
AccountSessionManager asm=AccountSessionManager.getInstance();
for(AccountSession session : asm.getLoggedInAccounts()){
String accountID=session.getID();
AccountLocalPreferences localPrefs=session.getLocalPreferences();
}
}
private static void migrateToUpstreamVersion61(){ private static void migrateToUpstreamVersion61(){
Log.d(TAG, "Migrating preferences to upstream version 61!!"); Log.d(TAG, "Migrating preferences to upstream version 61!!");
@@ -235,30 +237,6 @@ public class GlobalUserPreferences{
prefs.edit().putInt("migrationLevel", 61).apply(); prefs.edit().putInt("migrationLevel", 61).apply();
} }
public enum ColorPreference{
MATERIAL3,
PINK,
PURPLE,
GREEN,
BLUE,
BROWN,
RED,
YELLOW;
public @StringRes int getName() {
return switch(this){
case MATERIAL3 -> R.string.sk_color_palette_material3;
case PINK -> R.string.sk_color_palette_pink;
case PURPLE -> R.string.sk_color_palette_purple;
case GREEN -> R.string.sk_color_palette_green;
case BLUE -> R.string.sk_color_palette_blue;
case BROWN -> R.string.sk_color_palette_brown;
case RED -> R.string.sk_color_palette_red;
case YELLOW -> R.string.sk_color_palette_yellow;
};
}
}
public enum ThemePreference{ public enum ThemePreference{
AUTO, AUTO,
LIGHT, LIGHT,

View File

@@ -39,7 +39,8 @@ import me.grishka.appkit.api.ErrorResponse;
public class MainActivity extends FragmentStackActivity implements ProvidesAssistContent { public class MainActivity extends FragmentStackActivity implements ProvidesAssistContent {
@Override @Override
protected void onCreate(@Nullable Bundle savedInstanceState){ protected void onCreate(@Nullable Bundle savedInstanceState){
UiUtils.setUserPreferredTheme(this); AccountSession session=getCurrentSession();
UiUtils.setUserPreferredTheme(this, session);
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
if(savedInstanceState==null){ if(savedInstanceState==null){
@@ -217,6 +218,36 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
if (fragment != null) callFragmentToProvideAssistContent(fragment, assistContent); if (fragment != null) callFragmentToProvideAssistContent(fragment, assistContent);
} }
public AccountSession getCurrentSession(){
AccountSession session;
Bundle args=new Bundle();
Intent intent=getIntent();
if(intent.hasExtra("fromExternalShare")) {
return AccountSessionManager.getInstance()
.getAccount(intent.getStringExtra("account"));
}
boolean fromNotification = intent.getBooleanExtra("fromNotification", false);
boolean hasNotification = intent.hasExtra("notification");
if(fromNotification){
String accountID=intent.getStringExtra("accountID");
try{
session=AccountSessionManager.getInstance().getAccount(accountID);
if(!hasNotification) args.putString("tab", "notifications");
}catch(IllegalStateException x){
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
}else{
session=AccountSessionManager.getInstance().getLastActiveAccount();
}
return session;
}
public void restartActivity(){
finish();
startActivity(new Intent(this, MainActivity.class));
}
public void restartHomeFragment(){ public void restartHomeFragment(){
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){ if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
showFragmentClearingBackStack(new CustomWelcomeFragment()); showFragmentClearingBackStack(new CustomWelcomeFragment());

View File

@@ -74,7 +74,6 @@ public class CacheController{
result.add(status); result.add(status);
}while(cursor.moveToNext()); }while(cursor.moveToNext());
String _newMaxID=newMaxID; String _newMaxID=newMaxID;
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.HOME);
uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true))); uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
return; return;
} }
@@ -86,9 +85,7 @@ public class CacheController{
.setCallback(new Callback<>(){ .setCallback(new Callback<>(){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
ArrayList<Status> filtered=new ArrayList<>(result); callback.onSuccess(new CacheablePaginatedResponse<>(result, result.isEmpty() ? null : result.get(result.size()-1).id, false));
AccountSessionManager.get(accountID).filterStatuses(filtered, FilterContext.HOME);
callback.onSuccess(new CacheablePaginatedResponse<>(filtered, result.isEmpty() ? null : result.get(result.size()-1).id, false));
putHomeTimeline(result, maxID==null); putHomeTimeline(result, maxID==null);
} }

View File

@@ -97,7 +97,7 @@ public class PushSubscriptionManager{
deviceToken=getPrefs().getString("deviceToken", null); deviceToken=getPrefs().getString("deviceToken", null);
int tokenVersion=getPrefs().getInt("version", 0); int tokenVersion=getPrefs().getInt("version", 0);
if(!TextUtils.isEmpty(deviceToken) && tokenVersion==BuildConfig.VERSION_CODE){ if(!TextUtils.isEmpty(deviceToken) && tokenVersion==BuildConfig.VERSION_CODE){
registerAllAccountsForPush(true); // TODO: revert this before release registerAllAccountsForPush(false);
return; return;
} }
Log.i(TAG, "tryRegisterFCM: no token found or app was updated. Trying to get push token..."); Log.i(TAG, "tryRegisterFCM: no token found or app was updated. Trying to get push token...");

View File

@@ -13,7 +13,7 @@ import okhttp3.MultipartBody;
import okhttp3.RequestBody; import okhttp3.RequestBody;
public class PleromaMarkNotificationsRead extends MastodonAPIRequest<List<Notification>> { public class PleromaMarkNotificationsRead extends MastodonAPIRequest<List<Notification>> {
private String maxID; private final String maxID;
public PleromaMarkNotificationsRead(String maxID) { public PleromaMarkNotificationsRead(String maxID) {
super(HttpMethod.POST, "/pleroma/notifications/read", new TypeToken<>(){}); super(HttpMethod.POST, "/pleroma/notifications/read", new TypeToken<>(){});
this.maxID = maxID; this.maxID = maxID;

View File

@@ -6,9 +6,13 @@ import static org.joinmastodon.android.api.MastodonAPIController.gson;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import androidx.annotation.StringRes;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import org.joinmastodon.android.R;
import org.joinmastodon.android.model.ContentType; import org.joinmastodon.android.model.ContentType;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.TimelineDefinition; import org.joinmastodon.android.model.TimelineDefinition;
import java.lang.reflect.Type; import java.lang.reflect.Type;
@@ -36,12 +40,15 @@ public class AccountLocalPreferences{
public String publishButtonText; public String publishButtonText;
public String timelineReplyVisibility; // akkoma-only public String timelineReplyVisibility; // akkoma-only
public boolean keepOnlyLatestNotification; public boolean keepOnlyLatestNotification;
public boolean emojiReactionsEnabled; public boolean emojiReactionsEnabled;
public ShowEmojiReactions showEmojiReactions; public ShowEmojiReactions showEmojiReactions;
public ColorPreference color;
public boolean likeIcon;
public ArrayList<Emoji> recentCustomEmoji;
private final static Type recentLanguagesType = new TypeToken<ArrayList<String>>() {}.getType(); private final static Type recentLanguagesType=new TypeToken<ArrayList<String>>() {}.getType();
private final static Type timelinesType = new TypeToken<ArrayList<TimelineDefinition>>() {}.getType(); private final static Type timelinesType=new TypeToken<ArrayList<TimelineDefinition>>() {}.getType();
private final static Type recentCustomEmojiType=new TypeToken<ArrayList<Emoji>>() {}.getType();
public AccountLocalPreferences(SharedPreferences prefs, AccountSession session){ public AccountLocalPreferences(SharedPreferences prefs, AccountSession session){
this.prefs=prefs; this.prefs=prefs;
@@ -66,6 +73,9 @@ public class AccountLocalPreferences{
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false); keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma()); emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma());
showEmojiReactions=ShowEmojiReactions.valueOf(prefs.getString("showEmojiReactions", ShowEmojiReactions.HIDE_EMPTY.name())); showEmojiReactions=ShowEmojiReactions.valueOf(prefs.getString("showEmojiReactions", ShowEmojiReactions.HIDE_EMPTY.name()));
color=ColorPreference.valueOf(prefs.getString("color", ColorPreference.MATERIAL3.name()));
likeIcon=prefs.getBoolean("likeIcon", false);
recentCustomEmoji=fromJson(prefs.getString("recentCustomEmoji", null), recentCustomEmojiType, new ArrayList<>());
} }
public long getNotificationsPauseEndTime(){ public long getNotificationsPauseEndTime(){
@@ -99,9 +109,36 @@ public class AccountLocalPreferences{
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification) .putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
.putBoolean("emojiReactionsEnabled", emojiReactionsEnabled) .putBoolean("emojiReactionsEnabled", emojiReactionsEnabled)
.putString("showEmojiReactions", showEmojiReactions.name()) .putString("showEmojiReactions", showEmojiReactions.name())
.putString("color", color.name())
.putBoolean("likeIcon", likeIcon)
.putString("recentCustomEmoji", gson.toJson(recentCustomEmoji))
.apply(); .apply();
} }
public enum ColorPreference{
MATERIAL3,
PINK,
PURPLE,
GREEN,
BLUE,
BROWN,
RED,
YELLOW;
public @StringRes int getName() {
return switch(this){
case MATERIAL3 -> R.string.sk_color_palette_material3;
case PINK -> R.string.sk_color_palette_pink;
case PURPLE -> R.string.sk_color_palette_purple;
case GREEN -> R.string.sk_color_palette_green;
case BLUE -> R.string.sk_color_palette_blue;
case BROWN -> R.string.sk_color_palette_brown;
case RED -> R.string.sk_color_palette_red;
case YELLOW -> R.string.sk_color_palette_yellow;
};
}
}
public enum ShowEmojiReactions{ public enum ShowEmojiReactions{
HIDE_EMPTY, HIDE_EMPTY,
ONLY_OPENED, ONLY_OPENED,

View File

@@ -40,7 +40,6 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.Callback;
import me.grishka.appkit.api.ErrorResponse; import me.grishka.appkit.api.ErrorResponse;
@@ -255,52 +254,62 @@ public class AccountSession{
filterStatusContainingObjects(objects, extractor, context, null); filterStatusContainingObjects(objects, extractor, context, null);
} }
public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context, Account profile){ private boolean statusIsOnOwnProfile(Status s, Account profile){
Predicate<Status> statusIsOnOwnProfile = (s) -> self != null && profile != null && s.account != null return self != null && profile != null && s.account != null
&& Objects.equals(self.id, profile.id) && Objects.equals(self.id, s.account.id); && Objects.equals(self.id, profile.id) && Objects.equals(self.id, s.account.id);
}
if(getLocalPreferences().serverSideFiltersSupported){ private boolean isFilteredType(Status s){
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them return (!localPreferences.showReplies && s.inReplyToId != null)
objects.removeIf(o->{ || (!localPreferences.showBoosts && s.reblog != null);
}
public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context, Account profile){
if(!localPreferences.serverSideFiltersSupported) for(T obj:objects){
Status s=extractor.apply(obj);
if(s!=null && s.filtered!=null){
localPreferences.serverSideFiltersSupported=true;
localPreferences.save();
}
}
List<T> removeUs=new ArrayList<>();
for(int i=0; i<objects.size(); i++){
T o=objects.get(i);
if(filterStatusContainingObject(o, extractor, context, profile)){
Status s=extractor.apply(o); Status s=extractor.apply(o);
removeUs.add(o);
if(s!=null && s.hasGapAfter && i > 0){
Status prev=extractor.apply(objects.get(i - 1));
if(prev!=null) prev.hasGapAfter=true;
}
}
}
objects.removeAll(removeUs);
}
public <T> boolean filterStatusContainingObject(T object, Function<T, Status> extractor, FilterContext context, Account profile){
Status s=extractor.apply(object);
if(s==null) if(s==null)
return false; return false;
if(s.filtered==null)
return false;
// don't hide own posts in own profile // don't hide own posts in own profile
if (statusIsOnOwnProfile.test(s)) if(statusIsOnOwnProfile(s, profile))
return false; return false;
for(FilterResult filter:s.filtered){ if(isFilteredType(s) && (context == FilterContext.HOME || context == FilterContext.PUBLIC))
return true;
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
if(localPreferences.serverSideFiltersSupported){
for(FilterResult filter : s.filtered){
if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE) if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE)
return true; return true;
} }
return false; }else if(wordFilters!=null){
}); for(LegacyFilter filter : wordFilters){
return;
}
if(wordFilters==null)
return;
for(T obj:objects){
Status s=extractor.apply(obj);
if(s!=null && s.filtered!=null){
getLocalPreferences().serverSideFiltersSupported=true;
getLocalPreferences().save();
return;
}
}
objects.removeIf(o->{
Status s=extractor.apply(o);
if(s==null)
return false;
// don't hide own posts in own profile
if (statusIsOnOwnProfile.test(s))
return false;
for(LegacyFilter filter:wordFilters){
if(filter.context.contains(context) && filter.matches(s) && filter.isActive()) if(filter.context.contains(context) && filter.matches(s) && filter.isActive())
return true; return true;
} }
}
return false; return false;
});
} }
public void updateAccountInfo(){ public void updateAccountInfo(){

View File

@@ -9,19 +9,16 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses; import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.RemoveAccountPostsEvent; import org.joinmastodon.android.events.RemoveAccountPostsEvent;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusUnpinnedEvent; import org.joinmastodon.android.events.StatusUnpinnedEvent;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import org.parceler.Parcels; import org.parceler.Parcels;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import me.grishka.appkit.api.SimpleCallback; import me.grishka.appkit.api.SimpleCallback;
@@ -55,15 +52,14 @@ public class AccountTimelineFragment extends StatusListFragment{
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int offset, int count){
currentRequest=new GetAccountStatuses(user.id, offset>0 ? getMaxID() : null, null, count, filter) currentRequest=new GetAccountStatuses(user.id, getMaxID(), null, count, filter)
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
if(getActivity()==null) return; if(getActivity()==null) return;
AccountSessionManager asm = AccountSessionManager.getInstance(); boolean more=applyMaxID(result);
boolean empty=result.isEmpty();
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext(), user); AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext(), user);
onDataLoaded(result, !empty); onDataLoaded(result, more);
} }
}) })
.exec(accountID); .exec(accountID);

View File

@@ -97,7 +97,7 @@ public class AnnouncementsFragment extends BaseStatusListFragment<Announcement>
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Announcement> result){ public void onSuccess(List<Announcement> result){
if (getActivity() == null) return; if(getActivity()==null) return;
// get unread items first // get unread items first
List<Announcement> data = result.stream().filter(a -> !a.read).collect(toList()); List<Announcement> data = result.stream().filter(a -> !a.read).collect(toList());

View File

@@ -9,7 +9,6 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.WindowInsets; import android.view.WindowInsets;
@@ -90,6 +89,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
protected Rect tmpRect=new Rect(); protected Rect tmpRect=new Rect();
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView); protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
protected boolean currentlyScrolling; protected boolean currentlyScrolling;
protected String maxID;
public BaseStatusListFragment(){ public BaseStatusListFragment(){
super(20); super(20);
@@ -156,6 +156,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
} }
protected String getMaxID(){ protected String getMaxID(){
if(refreshing) return null;
if(maxID!=null) return maxID;
if(!preloadedData.isEmpty()) if(!preloadedData.isEmpty())
return preloadedData.get(preloadedData.size()-1).getID(); return preloadedData.get(preloadedData.size()-1).getID();
else if(!data.isEmpty()) else if(!data.isEmpty())
@@ -164,6 +166,12 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
return null; return null;
} }
protected boolean applyMaxID(List<Status> result){
boolean empty=result.isEmpty();
if(!empty) maxID=result.get(result.size()-1).id;
return !empty;
}
protected abstract List<StatusDisplayItem> buildDisplayItems(T s); protected abstract List<StatusDisplayItem> buildDisplayItems(T s);
protected abstract void addAccountToKnown(T s); protected abstract void addAccountToKnown(T s);
@@ -559,12 +567,12 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
// to do this if the media grid is not bound, tho - so, doing it ourselves here // to do this if the media grid is not bound, tho - so, doing it ourselves here
status.sensitiveRevealed = !status.sensitiveRevealed; status.sensitiveRevealed = !status.sensitiveRevealed;
} }
holder.rebind(); if(holder.getItem().hasVisibilityToggle) holder.animateVisibilityToggle(false);
} }
public void onSensitiveRevealed(MediaGridStatusDisplayItem.Holder holder) { public void onSensitiveRevealed(MediaGridStatusDisplayItem.Holder holder) {
HeaderStatusDisplayItem.Holder header = findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class); HeaderStatusDisplayItem.Holder header = findHolderOfType(holder.getItemID(), HeaderStatusDisplayItem.Holder.class);
if(header != null) header.rebind(); if(header != null && header.getItem().hasVisibilityToggle) header.animateVisibilityToggle(true);
} }
protected void toggleSpoiler(Status status, String itemID){ protected void toggleSpoiler(Status status, String itemID){
@@ -846,7 +854,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
if(getContext()==null) return; if(getContext()==null) return;
super.onDataLoaded(d, more); super.onDataLoaded(d, more);
// more available, but the page isn't even full yet? seems wrong, let's load some more // more available, but the page isn't even full yet? seems wrong, let's load some more
if(more && d.size() < itemsPerPage){ if(more && data.size() < itemsPerPage){
preloader.onScrolledToLastItem(); preloader.onScrolledToLastItem();
} }
} }

View File

@@ -28,7 +28,7 @@ public class BookmarkedStatusListFragment extends StatusListFragment{
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(HeaderPaginationList<Status> result){ public void onSuccess(HeaderPaginationList<Status> result){
if (getActivity() == null) return; if(getActivity()==null) return;
if(result.nextPageUri!=null) if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id"); nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else else

View File

@@ -162,7 +162,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
private int charCount, charLimit, trimmedCharCount; private int charCount, charLimit, trimmedCharCount;
private Button publishButton, languageButton, scheduleTimeBtn; private Button publishButton, languageButton, scheduleTimeBtn;
private PopupMenu languagePopup, contentTypePopup, visibilityPopup, draftOptionsPopup; private PopupMenu contentTypePopup, visibilityPopup, draftOptionsPopup;
private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, draftsBtn, scheduleDraftDismiss, contentTypeBtn; private ImageButton mediaBtn, pollBtn, emojiBtn, spoilerBtn, draftsBtn, scheduleDraftDismiss, contentTypeBtn;
private View sensitiveBtn; private View sensitiveBtn;
private TextView replyText; private TextView replyText;
@@ -294,7 +294,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
@Override @Override
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){ public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
creatingView=true; creatingView=true;
emojiKeyboard=new CustomEmojiPopupKeyboard(getActivity(), customEmojis, instanceDomain); emojiKeyboard=new CustomEmojiPopupKeyboard(getActivity(), accountID, customEmojis, instanceDomain);
emojiKeyboard.setListener(new CustomEmojiPopupKeyboard.Listener(){ emojiKeyboard.setListener(new CustomEmojiPopupKeyboard.Listener(){
@Override @Override
public void onEmojiSelected(Emoji emoji){ public void onEmojiSelected(Emoji emoji){

View File

@@ -26,12 +26,12 @@ import android.widget.ImageView;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController; import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Attachment; import org.joinmastodon.android.model.Attachment;
import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.photoviewer.PhotoViewer; import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
import org.joinmastodon.android.ui.utils.ColorPalette; import org.joinmastodon.android.ui.utils.ColorPalette;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.FixedAspectRatioImageView;
import java.util.Collections; import java.util.Collections;
@@ -54,16 +54,16 @@ public class ComposeImageDescriptionFragment extends MastodonToolbarFragment imp
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
accountID=getArguments().getString("account");
attachmentID=getArguments().getString("attachment");
setHasOptionsMenu(true); setHasOptionsMenu(true);
} }
@Override @Override
public void onAttach(Activity activity){ public void onAttach(Activity activity){
super.onAttach(activity); super.onAttach(activity);
accountID=getArguments().getString("account");
attachmentID=getArguments().getString("attachment");
themeWrapper=new ContextThemeWrapper(activity, R.style.Theme_Mastodon_Dark); themeWrapper=new ContextThemeWrapper(activity, R.style.Theme_Mastodon_Dark);
ColorPalette.palettes.get(GlobalUserPreferences.color).apply(themeWrapper, GlobalUserPreferences.ThemePreference.DARK); ColorPalette.palettes.get(AccountSessionManager.get(accountID).getLocalPreferences().color).apply(themeWrapper, GlobalUserPreferences.ThemePreference.DARK);
setTitle(R.string.add_alt_text); setTitle(R.string.add_alt_text);
} }

View File

@@ -169,7 +169,7 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
} }
private void updateOptionsMenu() { private void updateOptionsMenu() {
if (getActivity() == null) return; if(getActivity()==null) return;
optionsMenu.clear(); optionsMenu.clear();
timelineByMenuItem.clear(); timelineByMenuItem.clear();

View File

@@ -27,7 +27,7 @@ public class FavoritedStatusListFragment extends StatusListFragment{
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(HeaderPaginationList<Status> result){ public void onSuccess(HeaderPaginationList<Status> result){
if (getActivity() == null) return; if(getActivity()==null) return;
if(result.nextPageUri!=null) if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id"); nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else else

View File

@@ -83,7 +83,7 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(HeaderPaginationList<Account> result){ public void onSuccess(HeaderPaginationList<Account> result){
if (getActivity() == null) return; if(getActivity()==null) return;
if(result.nextPageUri!=null) if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id"); nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else else

View File

@@ -56,7 +56,7 @@ public class FollowedHashtagsFragment extends MastodonRecyclerFragment<Hashtag>
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(HeaderPaginationList<Hashtag> result){ public void onSuccess(HeaderPaginationList<Hashtag> result){
if (getActivity() == null) return; if(getActivity()==null) return;
if(result.nextPageUri!=null) if(result.nextPageUri!=null)
nextMaxID=result.nextPageUri.getQueryParameter("max_id"); nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else else

View File

@@ -21,6 +21,7 @@ import org.joinmastodon.android.api.MastodonErrorResponse;
import org.joinmastodon.android.api.requests.tags.GetTag; import org.joinmastodon.android.api.requests.tags.GetTag;
import org.joinmastodon.android.api.requests.tags.SetTagFollowed; import org.joinmastodon.android.api.requests.tags.SetTagFollowed;
import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline; import org.joinmastodon.android.api.requests.timelines.GetHashtagTimeline;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Hashtag; import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
@@ -85,16 +86,19 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
@Override @Override
protected TimelineDefinition makeTimelineDefinition() { protected TimelineDefinition makeTimelineDefinition() {
return TimelineDefinition.ofHashtag(hashtag); return TimelineDefinition.ofHashtag(hashtagName);
} }
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int offset, int count){
currentRequest=new GetHashtagTimeline(hashtagName, offset==0 ? null : getMaxID(), null, count, any, all, none, localOnly, getLocalPrefs().timelineReplyVisibility) currentRequest=new GetHashtagTimeline(hashtagName, getMaxID(), null, count, any, all, none, localOnly, getLocalPrefs().timelineReplyVisibility)
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
onDataLoaded(result, !result.isEmpty()); if(getActivity()==null) return;
boolean more=applyMaxID(result);
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
onDataLoaded(result, more);
} }
}) })
.exec(accountID); .exec(accountID);
@@ -217,8 +221,6 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
followMenuItem=optionsMenu.findItem(R.id.follow_hashtag); followMenuItem=optionsMenu.findItem(R.id.follow_hashtag);
pinMenuItem=optionsMenu.findItem(R.id.pin); pinMenuItem=optionsMenu.findItem(R.id.pin);
followMenuItem.setVisible(toolbarContentVisible); followMenuItem.setVisible(toolbarContentVisible);
followMenuItem.setTitle(getString(hashtag.following ? R.string.unfollow_user : R.string.follow_user, "#"+hashtagName));
followMenuItem.setIcon(hashtag.following ? R.drawable.ic_fluent_person_delete_24_filled : R.drawable.ic_fluent_person_add_24_regular);
pinMenuItem.setShowAsAction(toolbarContentVisible ? MenuItem.SHOW_AS_ACTION_NEVER : MenuItem.SHOW_AS_ACTION_ALWAYS); pinMenuItem.setShowAsAction(toolbarContentVisible ? MenuItem.SHOW_AS_ACTION_NEVER : MenuItem.SHOW_AS_ACTION_ALWAYS);
super.updatePinButton(pinMenuItem); super.updatePinButton(pinMenuItem);
if(toolbarContentVisible){ if(toolbarContentVisible){
@@ -260,7 +262,7 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
} }
private void updateHeader(){ private void updateHeader(){
if(hashtag==null) if(hashtag==null || getActivity()==null)
return; return;
if(hashtag.history!=null && !hashtag.history.isEmpty()){ if(hashtag.history!=null && !hashtag.history.isEmpty()){

View File

@@ -287,7 +287,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
new GetAnnouncements(false).setCallback(new Callback<>() { new GetAnnouncements(false).setCallback(new Callback<>() {
@Override @Override
public void onSuccess(List<Announcement> result) { public void onSuccess(List<Announcement> result) {
if (getActivity() == null) return; if(getActivity()==null) return;
if (result.stream().anyMatch(a -> !a.read)) { if (result.stream().anyMatch(a -> !a.read)) {
announcementsBadged = true; announcementsBadged = true;
announcements.setVisible(false); announcements.setVisible(false);
@@ -381,7 +381,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
} }
private void updateOverflowMenu() { private void updateOverflowMenu() {
if (getActivity() == null) return; if(getActivity()==null) return;
Menu m = overflowPopup.getMenu(); Menu m = overflowPopup.getMenu();
m.clear(); m.clear();
overflowPopup.inflate(R.menu.home_overflow); overflowPopup.inflate(R.menu.home_overflow);

View File

@@ -11,7 +11,6 @@ import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.requests.markers.SaveMarkers; import org.joinmastodon.android.api.requests.markers.SaveMarkers;
import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline; import org.joinmastodon.android.api.requests.timelines.GetHomeTimeline;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.CacheablePaginatedResponse; import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterContext;
@@ -20,6 +19,7 @@ import org.joinmastodon.android.model.TimelineMarkers;
import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem; import org.joinmastodon.android.ui.displayitems.GapStatusDisplayItem;
import org.joinmastodon.android.ui.displayitems.StatusDisplayItem; import org.joinmastodon.android.ui.displayitems.StatusDisplayItem;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@@ -49,16 +49,6 @@ public class HomeTimelineFragment extends StatusListFragment {
loadData(); loadData();
} }
private boolean typeFilterPredicate(Status s) {
AccountLocalPreferences lp=getLocalPrefs();
return (lp.showReplies || s.inReplyToId == null) &&
(lp.showBoosts || s.reblog == null);
}
private List<Status> filterPosts(List<Status> items) {
return items.stream().filter(this::typeFilterPredicate).collect(Collectors.toList());
}
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int offset, int count){
AccountSessionManager.getInstance() AccountSessionManager.getInstance()
@@ -66,10 +56,11 @@ public class HomeTimelineFragment extends StatusListFragment {
.getHomeTimeline(offset>0 ? maxID : null, count, refreshing, new SimpleCallback<>(this){ .getHomeTimeline(offset>0 ? maxID : null, count, refreshing, new SimpleCallback<>(this){
@Override @Override
public void onSuccess(CacheablePaginatedResponse<List<Status>> result){ public void onSuccess(CacheablePaginatedResponse<List<Status>> result){
if (getActivity() == null) return; if(getActivity()==null) return;
List<Status> filteredItems = filterPosts(result.items); boolean empty=result.items.isEmpty();
maxID=result.maxID; maxID=result.maxID;
onDataLoaded(filteredItems, !result.items.isEmpty()); AccountSessionManager.get(accountID).filterStatuses(result.items, getFilterContext());
onDataLoaded(result.items, !empty);
if(result.isFromCache()) if(result.isFromCache())
loadNewPosts(); loadNewPosts();
} }
@@ -142,23 +133,26 @@ public class HomeTimelineFragment extends StatusListFragment {
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
currentRequest=null; currentRequest=null;
dataLoading=false; dataLoading=false;
result = filterPosts(result);
if(result.isEmpty() || getActivity()==null) if(result.isEmpty() || getActivity()==null)
return; return;
Status last=result.get(result.size()-1); Status last=result.get(result.size()-1);
List<Status> toAdd; List<Status> toAdd;
if(!data.isEmpty() && last.id.equals(data.get(0).id)){ // This part intersects with the existing one if(!data.isEmpty() && last.id.equals(data.get(0).id)){ // This part intersects with the existing one
toAdd=result.subList(0, result.size()-1); // Remove the already known last post toAdd=new ArrayList<>(result.subList(0, result.size()-1)); // Remove the already known last post
}else{ }else{
result.get(result.size()-1).hasGapAfter=true; result.get(result.size()-1).hasGapAfter=true;
toAdd=result; toAdd=result;
} }
List<String> existingIds=data.stream().map(Status::getID).collect(Collectors.toList());
toAdd.removeIf(s->existingIds.contains(s.getID()));
List<Status> toAddUnfiltered=new ArrayList<>(toAdd);
AccountSessionManager.get(accountID).filterStatuses(toAdd, getFilterContext()); AccountSessionManager.get(accountID).filterStatuses(toAdd, getFilterContext());
if(!toAdd.isEmpty()){ if(!toAdd.isEmpty()){
prependItems(toAdd, true); prependItems(toAdd, true);
if (parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton(); if(parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton();
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAdd, false);
} }
if(toAddUnfiltered.isEmpty())
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAddUnfiltered, false);
} }
@Override @Override

View File

@@ -16,6 +16,7 @@ import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.lists.GetList; import org.joinmastodon.android.api.requests.lists.GetList;
import org.joinmastodon.android.api.requests.lists.UpdateList; import org.joinmastodon.android.api.requests.lists.UpdateList;
import org.joinmastodon.android.api.requests.timelines.GetListTimeline; import org.joinmastodon.android.api.requests.timelines.GetListTimeline;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.ListDeletedEvent; import org.joinmastodon.android.events.ListDeletedEvent;
import org.joinmastodon.android.events.ListUpdatedCreatedEvent; import org.joinmastodon.android.events.ListUpdatedCreatedEvent;
import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterContext;
@@ -25,10 +26,8 @@ import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.M3AlertDialogBuilder; import org.joinmastodon.android.ui.M3AlertDialogBuilder;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.ui.views.ListEditor; import org.joinmastodon.android.ui.views.ListEditor;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import me.grishka.appkit.Nav; import me.grishka.appkit.Nav;
import me.grishka.appkit.api.Callback; import me.grishka.appkit.api.Callback;
@@ -63,7 +62,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
new GetList(listID).setCallback(new Callback<>() { new GetList(listID).setCallback(new Callback<>() {
@Override @Override
public void onSuccess(ListTimeline listTimeline) { public void onSuccess(ListTimeline listTimeline) {
if (getActivity() == null) return; if(getActivity()==null) return;
// TODO: save updated info // TODO: save updated info
if (!listTimeline.title.equals(listTitle)) setTitle(listTimeline.title); if (!listTimeline.title.equals(listTitle)) setTitle(listTimeline.title);
if (listTimeline.repliesPolicy != null && !listTimeline.repliesPolicy.equals(repliesPolicy)) { if (listTimeline.repliesPolicy != null && !listTimeline.repliesPolicy.equals(repliesPolicy)) {
@@ -101,7 +100,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
new UpdateList(listID, newTitle, editor.isExclusive(), editor.getRepliesPolicy()).setCallback(new Callback<>() { new UpdateList(listID, newTitle, editor.isExclusive(), editor.getRepliesPolicy()).setCallback(new Callback<>() {
@Override @Override
public void onSuccess(ListTimeline list) { public void onSuccess(ListTimeline list) {
if (getActivity() == null) return; if(getActivity()==null) return;
setTitle(list.title); setTitle(list.title);
listTitle = list.title; listTitle = list.title;
repliesPolicy = list.repliesPolicy; repliesPolicy = list.repliesPolicy;
@@ -134,13 +133,14 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
@Override @Override
protected void doLoadData(int offset, int count) { protected void doLoadData(int offset, int count) {
currentRequest=new GetListTimeline(listID, offset==0 ? null : getMaxID(), null, count, null, getLocalPrefs().timelineReplyVisibility) currentRequest=new GetListTimeline(listID, getMaxID(), null, count, null, getLocalPrefs().timelineReplyVisibility)
.setCallback(new SimpleCallback<>(this) { .setCallback(new SimpleCallback<>(this) {
@Override @Override
public void onSuccess(List<Status> result) { public void onSuccess(List<Status> result) {
if (getActivity() == null) return; if(getActivity()==null) return;
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList()); boolean more=applyMaxID(result);
onDataLoaded(result, !result.isEmpty()); AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
onDataLoaded(result, more);
} }
}) })
.exec(accountID); .exec(accountID);

View File

@@ -140,7 +140,7 @@ public class ListsFragment extends MastodonRecyclerFragment<ListTimeline> implem
.setCallback(new SimpleCallback<>(this) { .setCallback(new SimpleCallback<>(this) {
@Override @Override
public void onSuccess(List<ListTimeline> lists) { public void onSuccess(List<ListTimeline> lists) {
if (getActivity() == null) return; if(getActivity()==null) return;
for (ListTimeline l : lists) userInListBefore.put(l.id, true); for (ListTimeline l : lists) userInListBefore.put(l.id, true);
userInList.putAll(userInListBefore); userInList.putAll(userInListBefore);
if (profileAccountId == null || !lists.isEmpty()) onDataLoaded(lists, false); if (profileAccountId == null || !lists.isEmpty()) onDataLoaded(lists, false);
@@ -149,7 +149,7 @@ public class ListsFragment extends MastodonRecyclerFragment<ListTimeline> implem
currentRequest=new GetLists().setCallback(new SimpleCallback<>(ListsFragment.this) { currentRequest=new GetLists().setCallback(new SimpleCallback<>(ListsFragment.this) {
@Override @Override
public void onSuccess(List<ListTimeline> allLists) { public void onSuccess(List<ListTimeline> allLists) {
if (getActivity() == null) return; if(getActivity()==null) return;
List<ListTimeline> newLists = new ArrayList<>(); List<ListTimeline> newLists = new ArrayList<>();
for (ListTimeline l : allLists) { for (ListTimeline l : allLists) {
if (lists.stream().noneMatch(e -> e.id.equals(l.id))) newLists.add(l); if (lists.stream().noneMatch(e -> e.id.equals(l.id))) newLists.add(l);

View File

@@ -254,7 +254,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
new GetFollowRequests(null, 1).setCallback(new Callback<>() { new GetFollowRequests(null, 1).setCallback(new Callback<>() {
@Override @Override
public void onSuccess(HeaderPaginationList<Account> accounts) { public void onSuccess(HeaderPaginationList<Account> accounts) {
if (getActivity() == null) return; if(getActivity()==null) return;
getToolbar().getMenu().findItem(R.id.follow_requests).setVisible(!accounts.isEmpty()); getToolbar().getMenu().findItem(R.id.follow_requests).setVisible(!accounts.isEmpty());
} }

View File

@@ -134,6 +134,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
return; return;
maxID=result.maxID; maxID=result.maxID;
onDataLoaded(result.items.stream().filter(n->n.type!=null).collect(Collectors.toList()), !result.items.isEmpty()); onDataLoaded(result.items.stream().filter(n->n.type!=null).collect(Collectors.toList()), !result.items.isEmpty());
if(bannerHelper!=null) bannerHelper.onBannerBecameVisible();
reloadingFromCache=false; reloadingFromCache=false;
if (getParentFragment() instanceof NotificationsFragment nf) { if (getParentFragment() instanceof NotificationsFragment nf) {
nf.updateMarkAllReadButton(); nf.updateMarkAllReadButton();

View File

@@ -5,6 +5,7 @@ import android.os.Bundle;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses; import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
@@ -35,6 +36,8 @@ public class PinnedPostsListFragment extends StatusListFragment{
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
if(getActivity()==null) return;
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
onDataLoaded(result, false); onDataLoaded(result, false);
} }
}).exec(accountID); }).exec(accountID);

View File

@@ -133,6 +133,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private ImageView avatar; private ImageView avatar;
private CoverImageView cover; private CoverImageView cover;
private View avatarBorder; private View avatarBorder;
private View usernameWrap;
private TextView name, username, bio, followersCount, followersLabel, followingCount, followingLabel; private TextView name, username, bio, followersCount, followersLabel, followingCount, followingLabel;
private ImageView lockIcon, botIcon; private ImageView lockIcon, botIcon;
private ProgressBarButton actionButton, notifyButton; private ProgressBarButton actionButton, notifyButton;
@@ -233,6 +234,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
cover=content.findViewById(R.id.cover); cover=content.findViewById(R.id.cover);
avatarBorder=content.findViewById(R.id.avatar_border); avatarBorder=content.findViewById(R.id.avatar_border);
name=content.findViewById(R.id.name); name=content.findViewById(R.id.name);
usernameWrap=content.findViewById(R.id.username_wrap);
username=content.findViewById(R.id.username); username=content.findViewById(R.id.username);
lockIcon=content.findViewById(R.id.lock_icon); lockIcon=content.findViewById(R.id.lock_icon);
botIcon=content.findViewById(R.id.bot_icon); botIcon=content.findViewById(R.id.bot_icon);
@@ -480,7 +482,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(Account result){ public void onSuccess(Account result){
if (getActivity() == null) return; if(getActivity()==null) return;
onAccountLoaded(result); onAccountLoaded(result);
} }
}) })
@@ -892,7 +894,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
} }
private void updateRelationship(){ private void updateRelationship(){
if (getActivity() == null) return; if(getActivity()==null) return;
invalidateOptionsMenu(); invalidateOptionsMenu();
actionButton.setVisibility(View.VISIBLE); actionButton.setVisibility(View.VISIBLE);
notifyButton.setVisibility(relationship.following ? View.VISIBLE : View.GONE); notifyButton.setVisibility(relationship.following ? View.VISIBLE : View.GONE);
@@ -1114,7 +1116,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
name.setVisibility(View.GONE); name.setVisibility(View.GONE);
rolesView.setVisibility(View.GONE); rolesView.setVisibility(View.GONE);
username.setVisibility(View.GONE); usernameWrap.setVisibility(View.GONE);
bio.setVisibility(View.GONE); bio.setVisibility(View.GONE);
countersLayout.setVisibility(View.GONE); countersLayout.setVisibility(View.GONE);
@@ -1163,7 +1165,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
bioEditWrap.setVisibility(View.GONE); bioEditWrap.setVisibility(View.GONE);
name.setVisibility(View.VISIBLE); name.setVisibility(View.VISIBLE);
rolesView.setVisibility(View.VISIBLE); rolesView.setVisibility(View.VISIBLE);
username.setVisibility(View.VISIBLE); usernameWrap.setVisibility(View.VISIBLE);
bio.setVisibility(View.VISIBLE); bio.setVisibility(View.VISIBLE);
countersLayout.setVisibility(View.VISIBLE); countersLayout.setVisibility(View.VISIBLE);
refreshLayout.setEnabled(true); refreshLayout.setEnabled(true);
@@ -1189,7 +1191,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
savingEdits=false; savingEdits=false;
account=result; account=result;
AccountSessionManager.getInstance().updateAccountInfo(accountID, account); AccountSessionManager.getInstance().updateAccountInfo(accountID, account);
if (getActivity() == null) return; if(getActivity()==null) return;
exitEditMode(); exitEditMode();
setActionProgressVisible(false); setActionProgressVisible(false);
} }

View File

@@ -129,7 +129,7 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
nextMaxID=result.nextPageUri.getQueryParameter("max_id"); nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else else
nextMaxID=null; nextMaxID=null;
if (getActivity() == null) return; if(getActivity()==null) return;
onDataLoaded(result, nextMaxID!=null); onDataLoaded(result, nextMaxID!=null);
} }
}) })

View File

@@ -47,13 +47,12 @@ public class SplashFragment extends AppKitFragment{
private ProgressBarButton defaultServerButton; private ProgressBarButton defaultServerButton;
private ProgressBar defaultServerProgress; private ProgressBar defaultServerProgress;
private String chosenDefaultServer=DEFAULT_SERVER; private String chosenDefaultServer=DEFAULT_SERVER;
private boolean loadingDefaultServer; private boolean loadingDefaultServer, loadedDefaultServer;
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
motionEffect=new InterpolatingMotionEffect(MastodonApp.context); motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
loadAndChooseDefaultServer();
} }
@Nullable @Nullable
@@ -101,6 +100,8 @@ public class SplashFragment extends AppKitFragment{
}); });
} }
}); });
if(!loadedDefaultServer && !loadingDefaultServer)
loadAndChooseDefaultServer();
return contentView; return contentView;
} }
@@ -239,6 +240,7 @@ public class SplashFragment extends AppKitFragment{
private void setChosenDefaultServer(String domain){ private void setChosenDefaultServer(String domain){
chosenDefaultServer=domain; chosenDefaultServer=domain;
loadingDefaultServer=false; loadingDefaultServer=false;
loadedDefaultServer=true;
if(defaultServerButton!=null && getActivity()!=null){ if(defaultServerButton!=null && getActivity()!=null){
defaultServerButton.setTextVisible(true); defaultServerButton.setTextVisible(true);
defaultServerProgress.setVisibility(View.GONE); defaultServerProgress.setVisibility(View.GONE);

View File

@@ -48,8 +48,8 @@ public class StatusEditHistoryFragment extends StatusListFragment{
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
if(getActivity()==null) return;
Collections.sort(result, Comparator.comparing((Status s)->s.createdAt).reversed()); Collections.sort(result, Comparator.comparing((Status s)->s.createdAt).reversed());
if (getActivity() == null) return;
onDataLoaded(result, false); onDataLoaded(result, false);
} }
}) })

View File

@@ -42,10 +42,12 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
boolean isMainThreadStatus = this instanceof ThreadFragment t && s.id.equals(t.mainStatus.id); boolean isMainThreadStatus = this instanceof ThreadFragment t && s.id.equals(t.mainStatus.id);
int flags = 0; int flags = 0;
AccountLocalPreferences lp=getLocalPrefs(); AccountLocalPreferences lp=getLocalPrefs();
if (GlobalUserPreferences.spectatorMode) if(GlobalUserPreferences.spectatorMode)
flags |= StatusDisplayItem.FLAG_NO_FOOTER; flags |= StatusDisplayItem.FLAG_NO_FOOTER;
if (!lp.emojiReactionsEnabled || lp.showEmojiReactions==ONLY_OPENED) if(!lp.emojiReactionsEnabled || lp.showEmojiReactions==ONLY_OPENED)
flags |= StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS; flags |= StatusDisplayItem.FLAG_NO_EMOJI_REACTIONS;
if(GlobalUserPreferences.translateButtonOpenedOnly)
flags |= StatusDisplayItem.FLAG_NO_TRANSLATE;
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, getFilterContext(), isMainThreadStatus ? 0 : flags); return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, getFilterContext(), isMainThreadStatus ? 0 : flags);
} }

View File

@@ -13,8 +13,8 @@ import org.joinmastodon.android.GlobalUserPreferences.AutoRevealMode;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.statuses.GetStatusByID; import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
import org.joinmastodon.android.api.requests.statuses.GetStatusContext; import org.joinmastodon.android.api.requests.statuses.GetStatusContext;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusCountersUpdatedEvent; import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.events.StatusCreatedEvent;
import org.joinmastodon.android.events.StatusUpdatedEvent; import org.joinmastodon.android.events.StatusUpdatedEvent;
import org.joinmastodon.android.model.Account; import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterContext;
@@ -31,7 +31,6 @@ import org.joinmastodon.android.ui.displayitems.WarningFilteredStatusDisplayItem
import org.joinmastodon.android.ui.text.HtmlParser; import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.UiUtils; import org.joinmastodon.android.ui.utils.UiUtils;
import org.joinmastodon.android.utils.ProvidesAssistContent; import org.joinmastodon.android.utils.ProvidesAssistContent;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import org.parceler.Parcels; import org.parceler.Parcels;
import java.util.ArrayDeque; import java.util.ArrayDeque;
@@ -195,8 +194,8 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
// TODO: figure out how this code works // TODO: figure out how this code works
if (isInstanceAkkoma()) sortStatusContext(mainStatus, result); if (isInstanceAkkoma()) sortStatusContext(mainStatus, result);
result.descendants=filterStatuses(result.descendants); filterStatuses(result.descendants);
result.ancestors=filterStatuses(result.ancestors); filterStatuses(result.ancestors);
restoreStatusStates(result.descendants, oldData); restoreStatusStates(result.descendants, oldData);
restoreStatusStates(result.ancestors, oldData); restoreStatusStates(result.ancestors, oldData);
@@ -332,11 +331,8 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
private List<Status> filterStatuses(List<Status> statuses){ private void filterStatuses(List<Status> statuses){
StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,getFilterContext()); AccountSessionManager.get(accountID).filterStatuses(statuses, getFilterContext());
return statuses.stream()
.filter(statusFilterPredicate)
.collect(Collectors.toList());
} }
@Override @Override

View File

@@ -83,7 +83,7 @@ public abstract class BaseAccountListFragment extends MastodonRecyclerFragment<A
for(Relationship rel:result){ for(Relationship rel:result){
relationships.put(rel.id, rel); relationships.put(rel.id, rel);
} }
if (getActivity() == null) return; if(getActivity()==null) return;
if(list==null) if(list==null)
return; return;
for(int i=0;i<list.getChildCount();i++){ for(int i=0;i<list.getChildCount();i++){

View File

@@ -133,7 +133,7 @@ public abstract class PaginatedAccountListFragment<T> extends BaseAccountListFra
nextMaxID=result.nextPageUri.getQueryParameter("max_id"); nextMaxID=result.nextPageUri.getQueryParameter("max_id");
else else
nextMaxID=null; nextMaxID=null;
if (getActivity() == null) return; if(getActivity()==null) return;
List<AccountViewModel> items = result.stream() List<AccountViewModel> items = result.stream()
.filter(a -> d.size() > 1000 || d.stream() .filter(a -> d.size() > 1000 || d.stream()
.noneMatch(i -> i.account.url.equals(a.url))) .noneMatch(i -> i.account.url.equals(a.url)))

View File

@@ -6,21 +6,19 @@ import android.os.Bundle;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import org.joinmastodon.android.api.requests.timelines.GetBubbleTimeline; import org.joinmastodon.android.api.requests.timelines.GetBubbleTimeline;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.StatusListFragment; import org.joinmastodon.android.fragments.StatusListFragment;
import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper; import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
import org.joinmastodon.android.utils.StatusFilterPredicate;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import me.grishka.appkit.api.SimpleCallback; import me.grishka.appkit.api.SimpleCallback;
import me.grishka.appkit.utils.MergeRecyclerAdapter; import me.grishka.appkit.utils.MergeRecyclerAdapter;
public class BubbleTimelineFragment extends StatusListFragment { public class BubbleTimelineFragment extends StatusListFragment {
private DiscoverInfoBannerHelper bannerHelper; private DiscoverInfoBannerHelper bannerHelper;
private String maxID;
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
@@ -36,15 +34,15 @@ public class BubbleTimelineFragment extends StatusListFragment {
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int offset, int count){
currentRequest=new GetBubbleTimeline(refreshing ? null : maxID, count, getLocalPrefs().timelineReplyVisibility) currentRequest=new GetBubbleTimeline(getMaxID(), count, getLocalPrefs().timelineReplyVisibility)
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
if(!result.isEmpty()) if(getActivity()==null) return;
maxID=result.get(result.size()-1).id; boolean more=applyMaxID(result);
if (getActivity() == null) return; AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList()); onDataLoaded(result, more);
onDataLoaded(result, !result.isEmpty()); bannerHelper.onBannerBecameVisible();
} }
}) })
.exec(accountID); .exec(accountID);

View File

@@ -77,7 +77,7 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<FollowSuggestion> result){ public void onSuccess(List<FollowSuggestion> result){
if (getActivity() == null) return; if(getActivity()==null) return;
onDataLoaded(result.stream().map(fs->new AccountWrapper(fs.account)).collect(Collectors.toList()), false); onDataLoaded(result.stream().map(fs->new AccountWrapper(fs.account)).collect(Collectors.toList()), false);
loadRelationships(); loadRelationships();
} }
@@ -112,7 +112,7 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
public void onSuccess(List<Relationship> result){ public void onSuccess(List<Relationship> result){
relationshipsRequest=null; relationshipsRequest=null;
relationships=result.stream().collect(Collectors.toMap(rel->rel.id, Function.identity())); relationships=result.stream().collect(Collectors.toMap(rel->rel.id, Function.identity()));
if (getActivity() == null) return; if(getActivity()==null) return;
if(list==null) if(list==null)
return; return;
for(int i=0;i<list.getChildCount();i++){ for(int i=0;i<list.getChildCount();i++){

View File

@@ -4,6 +4,7 @@ import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import org.joinmastodon.android.api.requests.trends.GetTrendingStatuses; import org.joinmastodon.android.api.requests.trends.GetTrendingStatuses;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.StatusListFragment; import org.joinmastodon.android.fragments.StatusListFragment;
import org.joinmastodon.android.model.FilterContext; import org.joinmastodon.android.model.FilterContext;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
@@ -17,6 +18,7 @@ import me.grishka.appkit.utils.MergeRecyclerAdapter;
public class DiscoverPostsFragment extends StatusListFragment{ public class DiscoverPostsFragment extends StatusListFragment{
private DiscoverInfoBannerHelper bannerHelper; private DiscoverInfoBannerHelper bannerHelper;
private int offset;
@Override @Override
public void onCreate(Bundle savedInstanceState){ public void onCreate(Bundle savedInstanceState){
@@ -25,12 +27,17 @@ public class DiscoverPostsFragment extends StatusListFragment{
} }
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int o, int count){
if(refreshing) offset=0;
currentRequest=new GetTrendingStatuses(offset, count) currentRequest=new GetTrendingStatuses(offset, count)
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
onDataLoaded(result, !result.isEmpty()); if(getActivity()==null) return;
boolean empty=result.isEmpty();
offset+=result.size();
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
onDataLoaded(result, !empty);
bannerHelper.onBannerBecameVisible(); bannerHelper.onBannerBecameVisible();
} }
}).exec(accountID); }).exec(accountID);

View File

@@ -29,15 +29,14 @@ public class FederatedTimelineFragment extends StatusListFragment{
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int offset, int count){
currentRequest=new GetPublicTimeline(false, false, refreshing ? null : maxID, count, getLocalPrefs().timelineReplyVisibility) currentRequest=new GetPublicTimeline(false, false, getMaxID(), count, getLocalPrefs().timelineReplyVisibility)
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
if(!result.isEmpty()) if(getActivity()==null) return;
maxID=result.get(result.size()-1).id; boolean more=applyMaxID(result);
boolean empty=result.isEmpty(); AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.PUBLIC); onDataLoaded(result, more);
onDataLoaded(result, !empty);
bannerHelper.onBannerBecameVisible(); bannerHelper.onBannerBecameVisible();
} }
}) })

View File

@@ -2,7 +2,6 @@ package org.joinmastodon.android.fragments.discover;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import android.view.View;
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline; import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
@@ -30,15 +29,14 @@ public class LocalTimelineFragment extends StatusListFragment{
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int offset, int count){
currentRequest=new GetPublicTimeline(true, false, refreshing ? null : maxID, count, getLocalPrefs().timelineReplyVisibility) currentRequest=new GetPublicTimeline(true, false, getMaxID(), count, getLocalPrefs().timelineReplyVisibility)
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
if(!result.isEmpty()) if(getActivity()==null) return;
maxID=result.get(result.size()-1).id; boolean more=applyMaxID(result);
boolean empty=result.isEmpty(); AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.PUBLIC); onDataLoaded(result, more);
onDataLoaded(result, !empty);
bannerHelper.onBannerBecameVisible(); bannerHelper.onBannerBecameVisible();
} }
}) })

View File

@@ -83,10 +83,11 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
@Override @Override
protected void doLoadData(int offset, int count){ protected void doLoadData(int offset, int count){
currentRequest=new GetAccountStatuses(reportAccount.id, offset>0 ? getMaxID() : null, null, count, GetAccountStatuses.Filter.OWN_POSTS_AND_REPLIES) currentRequest=new GetAccountStatuses(reportAccount.id, getMaxID(), null, count, GetAccountStatuses.Filter.OWN_POSTS_AND_REPLIES)
.setCallback(new SimpleCallback<>(this){ .setCallback(new SimpleCallback<>(this){
@Override @Override
public void onSuccess(List<Status> result){ public void onSuccess(List<Status> result){
if(getActivity()==null) return;
for(Status s:result){ for(Status s:result){
s.sensitive=true; s.sensitive=true;
} }

View File

@@ -17,6 +17,7 @@ import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.MastodonApp; import org.joinmastodon.android.MastodonApp;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountLocalPreferences; import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference;
import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent; import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
@@ -37,7 +38,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
private CheckableListItem<Void> revealCWsItem, hideSensitiveMediaItem, interactionCountsItem, emojiInNamesItem; private CheckableListItem<Void> revealCWsItem, hideSensitiveMediaItem, interactionCountsItem, emojiInNamesItem;
// MEGALODON // MEGALODON
private CheckableListItem<Void> trueBlackModeItem, marqueeItem, disableSwipeItem, reduceMotionItem, altIndicatorItem, noAltIndicatorItem, collapsePostsItem, spectatorModeItem, hideFabItem, translateOpenedItem, disablePillItem, showNavigationLabelsItem; private CheckableListItem<Void> trueBlackModeItem, marqueeItem, disableSwipeItem, reduceMotionItem, altIndicatorItem, noAltIndicatorItem, collapsePostsItem, spectatorModeItem, hideFabItem, translateOpenedItem, disablePillItem, showNavigationLabelsItem, likeIconItem;
private ListItem<Void> colorItem, publishTextItem, autoRevealCWsItem; private ListItem<Void> colorItem, publishTextItem, autoRevealCWsItem;
private CheckableListItem<Void> pronounsInUserListingsItem, pronounsInTimelinesItem, pronounsInThreadsItem; private CheckableListItem<Void> pronounsInUserListingsItem, pronounsInTimelinesItem, pronounsInThreadsItem;
@@ -69,6 +70,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
hideFabItem=new CheckableListItem<>(R.string.sk_settings_hide_fab, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.autoHideFab, R.drawable.ic_fluent_edit_24_regular, ()->toggleCheckableItem(hideFabItem)), hideFabItem=new CheckableListItem<>(R.string.sk_settings_hide_fab, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.autoHideFab, R.drawable.ic_fluent_edit_24_regular, ()->toggleCheckableItem(hideFabItem)),
translateOpenedItem=new CheckableListItem<>(R.string.sk_settings_translate_only_opened, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.translateButtonOpenedOnly, R.drawable.ic_fluent_translate_24_regular, ()->toggleCheckableItem(translateOpenedItem)), translateOpenedItem=new CheckableListItem<>(R.string.sk_settings_translate_only_opened, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.translateButtonOpenedOnly, R.drawable.ic_fluent_translate_24_regular, ()->toggleCheckableItem(translateOpenedItem)),
disablePillItem=new CheckableListItem<>(R.string.sk_disable_pill_shaped_active_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableM3PillActiveIndicator, R.drawable.ic_fluent_pill_24_regular, ()->toggleCheckableItem(disablePillItem)), disablePillItem=new CheckableListItem<>(R.string.sk_disable_pill_shaped_active_indicator, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.disableM3PillActiveIndicator, R.drawable.ic_fluent_pill_24_regular, ()->toggleCheckableItem(disablePillItem)),
likeIconItem=new CheckableListItem<>(R.string.sk_settings_like_icon, 0, CheckableListItem.Style.SWITCH, lp.likeIcon, R.drawable.ic_fluent_heart_24_regular, ()->toggleCheckableItem(likeIconItem)),
showNavigationLabelsItem=new CheckableListItem<>(R.string.sk_settings_show_labels_in_navigation_bar, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNavigationLabels, R.drawable.ic_fluent_tag_24_regular, ()->toggleCheckableItem(showNavigationLabelsItem), true), showNavigationLabelsItem=new CheckableListItem<>(R.string.sk_settings_show_labels_in_navigation_bar, 0, CheckableListItem.Style.SWITCH, GlobalUserPreferences.showNavigationLabels, R.drawable.ic_fluent_tag_24_regular, ()->toggleCheckableItem(showNavigationLabelsItem), true),
pronounsInTimelinesItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_timelines, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInTimelines, 0, ()->toggleCheckableItem(pronounsInTimelinesItem)), pronounsInTimelinesItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_timelines, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInTimelines, 0, ()->toggleCheckableItem(pronounsInTimelinesItem)),
pronounsInThreadsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_threads, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInThreads, 0, ()->toggleCheckableItem(pronounsInThreadsItem)), pronounsInThreadsItem=new CheckableListItem<>(R.string.sk_settings_display_pronouns_in_threads, 0, CheckableListItem.Style.CHECKBOX, GlobalUserPreferences.displayPronounsInThreads, 0, ()->toggleCheckableItem(pronounsInThreadsItem)),
@@ -96,12 +98,14 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
boolean restartPlease= boolean restartPlease=
GlobalUserPreferences.disableM3PillActiveIndicator!=disablePillItem.checked || GlobalUserPreferences.disableM3PillActiveIndicator!=disablePillItem.checked ||
GlobalUserPreferences.showNavigationLabels!=showNavigationLabelsItem.checked; GlobalUserPreferences.showNavigationLabels!=showNavigationLabelsItem.checked ||
lp.likeIcon!=likeIconItem.checked;
lp.revealCWs=revealCWsItem.checked; lp.revealCWs=revealCWsItem.checked;
lp.hideSensitiveMedia=hideSensitiveMediaItem.checked; lp.hideSensitiveMedia=hideSensitiveMediaItem.checked;
lp.showInteractionCounts=interactionCountsItem.checked; lp.showInteractionCounts=interactionCountsItem.checked;
lp.customEmojiInNames=emojiInNamesItem.checked; lp.customEmojiInNames=emojiInNamesItem.checked;
lp.likeIcon=likeIconItem.checked;
lp.save(); lp.save();
GlobalUserPreferences.toolbarMarquee=marqueeItem.checked; GlobalUserPreferences.toolbarMarquee=marqueeItem.checked;
GlobalUserPreferences.reduceMotion=reduceMotionItem.checked; GlobalUserPreferences.reduceMotion=reduceMotionItem.checked;
@@ -131,7 +135,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
} }
private @StringRes int getColorPaletteValue(){ private @StringRes int getColorPaletteValue(){
return switch(GlobalUserPreferences.color){ return switch(AccountSessionManager.get(accountID).getLocalPreferences().color){
case MATERIAL3 -> R.string.sk_color_palette_material3; case MATERIAL3 -> R.string.sk_color_palette_material3;
case PINK -> R.string.sk_color_palette_pink; case PINK -> R.string.sk_color_palette_pink;
case PURPLE -> R.string.sk_color_palette_purple; case PURPLE -> R.string.sk_color_palette_purple;
@@ -196,18 +200,18 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
} }
private void onColorClick(){ private void onColorClick(){
int selected=GlobalUserPreferences.color.ordinal(); int selected=lp.color.ordinal();
int[] newSelected={selected}; int[] newSelected={selected};
String[] names=Arrays.stream(GlobalUserPreferences.ColorPreference.values()).map(GlobalUserPreferences.ColorPreference::getName).map(this::getString).toArray(String[]::new); String[] names=Arrays.stream(ColorPreference.values()).map(ColorPreference::getName).map(this::getString).toArray(String[]::new);
new M3AlertDialogBuilder(getActivity()) new M3AlertDialogBuilder(getActivity())
.setTitle(R.string.settings_theme) .setTitle(R.string.sk_settings_color_palette)
.setSingleChoiceItems(names, .setSingleChoiceItems(names,
selected, (dlg, item)->newSelected[0]=item) selected, (dlg, item)->newSelected[0]=item)
.setPositiveButton(R.string.ok, (dlg, item)->{ .setPositiveButton(R.string.ok, (dlg, item)->{
GlobalUserPreferences.ColorPreference pref=GlobalUserPreferences.ColorPreference.values()[newSelected[0]]; ColorPreference pref=ColorPreference.values()[newSelected[0]];
if(pref!=GlobalUserPreferences.color){ if(pref!=lp.color){
GlobalUserPreferences.ColorPreference prev=GlobalUserPreferences.color; ColorPreference prev=lp.color;
GlobalUserPreferences.color=pref; lp.color=pref;
GlobalUserPreferences.save(); GlobalUserPreferences.save();
colorItem.subtitleRes=getColorPaletteValue(); colorItem.subtitleRes=getColorPaletteValue();
rebindItem(colorItem); rebindItem(colorItem);
@@ -257,17 +261,17 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
.show(); .show();
} }
private void maybeApplyNewThemeRightNow(GlobalUserPreferences.ThemePreference prevTheme, GlobalUserPreferences.ColorPreference prevColor, Boolean prevTrueBlack){ private void maybeApplyNewThemeRightNow(GlobalUserPreferences.ThemePreference prevTheme, ColorPreference prevColor, Boolean prevTrueBlack){
if(prevTheme==null) prevTheme=GlobalUserPreferences.theme; if(prevTheme==null) prevTheme=GlobalUserPreferences.theme;
if(prevTrueBlack==null) prevTrueBlack=GlobalUserPreferences.trueBlackTheme; if(prevTrueBlack==null) prevTrueBlack=GlobalUserPreferences.trueBlackTheme;
if(prevColor==null) prevColor=GlobalUserPreferences.color; if(prevColor==null) prevColor=lp.color;
boolean isCurrentDark=prevTheme==GlobalUserPreferences.ThemePreference.DARK || boolean isCurrentDark=prevTheme==GlobalUserPreferences.ThemePreference.DARK ||
(prevTheme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive()); (prevTheme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive());
boolean isNewDark=GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.DARK || boolean isNewDark=GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.DARK ||
(GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive()); (GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive());
boolean isNewBlack=GlobalUserPreferences.trueBlackTheme; boolean isNewBlack=GlobalUserPreferences.trueBlackTheme;
if(isCurrentDark!=isNewDark || prevColor!=GlobalUserPreferences.color || (isNewDark && prevTrueBlack!=isNewBlack)){ if(isCurrentDark!=isNewDark || prevColor!=lp.color || (isNewDark && prevTrueBlack!=isNewBlack)){
restartActivityToApplyNewTheme(); restartActivityToApplyNewTheme();
} }
} }

View File

@@ -163,7 +163,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername())) .setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
.setPositiveButton(R.string.log_out, (dialog, which)->account.logOut(getActivity(), ()->{ .setPositiveButton(R.string.log_out, (dialog, which)->account.logOut(getActivity(), ()->{
loggedOut=true; loggedOut=true;
((MainActivity)getActivity()).restartHomeFragment(); ((MainActivity)getActivity()).restartActivity();
})) }))
.setNegativeButton(R.string.cancel, null) .setNegativeButton(R.string.cancel, null)
.show(); .show();

View File

@@ -68,6 +68,14 @@ public class Attachment extends BaseModel{
return 1080; return 1080;
} }
public boolean hasKnownDimensions(){
return meta!=null && (
(meta.height>0 && meta.width>0)
|| (meta.original!=null && meta.original.height>0 && meta.original.width>0)
|| (meta.small!=null && meta.small.height>0 && meta.small.width>0)
);
}
public double getDuration(){ public double getDuration(){
if(meta==null) if(meta==null)
return 0; return 0;

View File

@@ -147,8 +147,7 @@ public class AccountSwitcherSheet extends BottomSheet{
private void logOut(String accountID){ private void logOut(String accountID){
AccountSessionManager.get(accountID).logOut(activity, ()->{ AccountSessionManager.get(accountID).logOut(activity, ()->{
dismiss(); ((MainActivity)activity).restartActivity();
((MainActivity)activity).restartHomeFragment();
}); });
} }
@@ -317,14 +316,14 @@ public class AccountSwitcherSheet extends BottomSheet{
@Override @Override
public void onClick(){ public void onClick(){
setOnDismissListener(null); setOnDismissListener(null);
dismiss();
if (onClick != null) { if (onClick != null) {
dismiss();
onClick.accept(item.getID(), false); onClick.accept(item.getID(), false);
return; return;
} }
if(AccountSessionManager.getInstance().tryGetAccount(item.getID())!=null){ if(AccountSessionManager.getInstance().tryGetAccount(item.getID())!=null){
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID()); AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
((MainActivity)activity).restartHomeFragment(); ((MainActivity)activity).restartActivity();
} }
} }

File diff suppressed because one or more lines are too long

View File

@@ -170,12 +170,14 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
@Override @Override
public void onBind(EmojiReactionsStatusDisplayItem item) { public void onBind(EmojiReactionsStatusDisplayItem item) {
if(emojiKeyboard != null) root.removeView(emojiKeyboard.getView()); if(emojiKeyboard != null) root.removeView(emojiKeyboard.getView());
addButton.setSelected(false);
AccountSession session=item.parentFragment.getSession(); AccountSession session=item.parentFragment.getSession();
item.status.reactions.forEach(r->r.request=r.getUrl(item.playGifs)!=null item.status.reactions.forEach(r->r.request=r.getUrl(item.playGifs)!=null
? new UrlImageLoaderRequest(r.getUrl(item.playGifs), V.sp(24), V.sp(24)) ? new UrlImageLoaderRequest(r.getUrl(item.playGifs), V.sp(24), V.sp(24))
: null); : null);
emojiKeyboard=new CustomEmojiPopupKeyboard( emojiKeyboard=new CustomEmojiPopupKeyboard(
(Activity) item.parentFragment.getContext(), (Activity) item.parentFragment.getContext(),
item.accountID,
AccountSessionManager.getInstance().getCustomEmojis(session.domain), AccountSessionManager.getInstance().getCustomEmojis(session.domain),
session.domain, true); session.domain, true);
emojiKeyboard.setListener(this); emojiKeyboard.setListener(this);

View File

@@ -14,6 +14,8 @@ import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.fragments.StatusEditHistoryFragment; import org.joinmastodon.android.fragments.StatusEditHistoryFragment;
import org.joinmastodon.android.fragments.account_list.StatusFavoritesListFragment; import org.joinmastodon.android.fragments.account_list.StatusFavoritesListFragment;
@@ -74,6 +76,9 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
@Override @Override
public void onBind(ExtendedFooterStatusDisplayItem item){ public void onBind(ExtendedFooterStatusDisplayItem item){
Status s=item.status; Status s=item.status;
AccountSession session=AccountSessionManager.get(item.accountID);
boolean like=session!=null && session.getLocalPreferences().likeIcon;
favorites.setCompoundDrawablesRelativeWithIntrinsicBounds(like ? R.drawable.ic_fluent_heart_20_regular : R.drawable.ic_fluent_star_20_regular, 0, 0, 0);
favorites.setText(context.getResources().getQuantityString(R.plurals.x_favorites, (int)(s.favouritesCount%1000), s.favouritesCount)); favorites.setText(context.getResources().getQuantityString(R.plurals.x_favorites, (int)(s.favouritesCount%1000), s.favouritesCount));
reblogs.setText(context.getResources().getQuantityString(R.plurals.x_reblogs, (int) (s.reblogsCount % 1000), s.reblogsCount)); reblogs.setText(context.getResources().getQuantityString(R.plurals.x_reblogs, (int) (s.reblogsCount % 1000), s.reblogsCount));
reblogs.setVisibility(s.visibility != StatusPrivacy.DIRECT ? View.VISIBLE : View.GONE); reblogs.setVisibility(s.visibility != StatusPrivacy.DIRECT ? View.VISIBLE : View.GONE);

View File

@@ -1,12 +1,10 @@
package org.joinmastodon.android.ui.displayitems; package org.joinmastodon.android.ui.displayitems;
import static org.joinmastodon.android.ui.utils.UiUtils.opacityIn;
import static org.joinmastodon.android.ui.utils.UiUtils.opacityOut;
import android.app.Activity; import android.app.Activity;
import android.app.Dialog; import android.app.Dialog;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
@@ -17,6 +15,7 @@ import android.view.ViewGroup;
import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.Button; import android.widget.Button;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
@@ -57,13 +56,14 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem>{ public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem>{
private final TextView replies, boosts, favorites; private final TextView replies, boosts, favorites;
private final View reply, boost, favorite, share, bookmark; private final View reply, boost, favorite, share, bookmark;
private final ImageView favIcon;
private View touchingView = null; private View touchingView = null;
private boolean longClickPerformed = false; private boolean longClickPerformed = false;
private final Runnable longClickRunnable = () -> { private final Runnable longClickRunnable = () -> {
longClickPerformed = touchingView != null && touchingView.performLongClick(); longClickPerformed = touchingView != null && touchingView.performLongClick();
if (longClickPerformed && touchingView != null) { if (longClickPerformed && touchingView != null) {
touchingView.startAnimation(opacityIn); UiUtils.opacityIn(touchingView);
touchingView.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start(); touchingView.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start();
} }
}; };
@@ -89,6 +89,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
favorite=findViewById(R.id.favorite_btn); favorite=findViewById(R.id.favorite_btn);
share=findViewById(R.id.share_btn); share=findViewById(R.id.share_btn);
bookmark=findViewById(R.id.bookmark_btn); bookmark=findViewById(R.id.bookmark_btn);
favIcon=findViewById(R.id.favorite_icon);
reply.setOnTouchListener(this::onButtonTouch); reply.setOnTouchListener(this::onButtonTouch);
reply.setOnClickListener(this::onReplyClick); reply.setOnClickListener(this::onReplyClick);
@@ -132,6 +133,16 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
boolean condenseBottom = !item.isMainStatus && item.hasDescendantNeighbor && boolean condenseBottom = !item.isMainStatus && item.hasDescendantNeighbor &&
!nextIsWarning; !nextIsWarning;
AccountSession session=AccountSessionManager.get(item.accountID);
boolean like=session!=null && session.getLocalPreferences().likeIcon;
ColorStateList color=item.parentFragment.getResources().getColorStateList(
like ? R.color.like_icon : R.color.favorite_icon, item.parentFragment.getContext().getTheme()
);
favIcon.setImageResource(like ? R.drawable.ic_fluent_heart_24_selector : R.drawable.ic_fluent_star_24_selector);
favIcon.setImageTintList(color);
favorites.setTextColor(color);
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) itemView.getLayoutParams(); ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) itemView.getLayoutParams();
params.setMargins(params.leftMargin, params.topMargin, params.rightMargin, params.setMargins(params.leftMargin, params.topMargin, params.rightMargin,
condenseBottom ? V.dp(-5) : 0); condenseBottom ? V.dp(-5) : 0);
@@ -160,7 +171,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
if (!longClickPerformed) v.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start(); if (!longClickPerformed) v.animate().scaleX(1).scaleY(1).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(150).start();
if (disabled) return true; if (disabled) return true;
if (action == MotionEvent.ACTION_UP && !longClickPerformed) v.performClick(); if (action == MotionEvent.ACTION_UP && !longClickPerformed) v.performClick();
else if (!longClickPerformed) v.startAnimation(opacityIn); else if (!longClickPerformed) UiUtils.opacityIn(v);
} else if (action == MotionEvent.ACTION_DOWN) { } else if (action == MotionEvent.ACTION_DOWN) {
longClickPerformed = false; longClickPerformed = false;
touchingView = v; touchingView = v;
@@ -168,13 +179,13 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
v.animate().scaleX(0.85f).scaleY(0.85f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(75).start(); v.animate().scaleX(0.85f).scaleY(0.85f).setInterpolator(CubicBezierInterpolator.DEFAULT).setDuration(75).start();
if (disabled) return true; if (disabled) return true;
v.postDelayed(longClickRunnable, ViewConfiguration.getLongPressTimeout()); v.postDelayed(longClickRunnable, ViewConfiguration.getLongPressTimeout());
v.startAnimation(opacityOut); UiUtils.opacityOut(v);
} }
return true; return true;
} }
private void onReplyClick(View v){ private void onReplyClick(View v){
v.startAnimation(opacityIn); UiUtils.opacityIn(v);
Bundle args=new Bundle(); Bundle args=new Bundle();
args.putString("account", item.accountID); args.putString("account", item.accountID);
args.putParcelable("replyTo", Parcels.wrap(item.status)); args.putParcelable("replyTo", Parcels.wrap(item.status));
@@ -198,7 +209,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
private void onBoostClick(View v){ private void onBoostClick(View v){
if (GlobalUserPreferences.confirmBoost) { if (GlobalUserPreferences.confirmBoost) {
v.startAnimation(opacityIn); UiUtils.opacityIn(v);
onBoostLongClick(v); onBoostLongClick(v);
return; return;
} }
@@ -207,7 +218,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
} }
private void boostConsumer(View v, Status r) { private void boostConsumer(View v, Status r) {
v.startAnimation(opacityIn); UiUtils.opacityIn(v);
bindText(boosts, r.reblogsCount); bindText(boosts, r.reblogsCount);
} }
@@ -218,7 +229,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
AccountSession session = AccountSessionManager.getInstance().getAccount(item.accountID); AccountSession session = AccountSessionManager.getInstance().getAccount(item.accountID);
Consumer<StatusPrivacy> doReblog = (visibility) -> { Consumer<StatusPrivacy> doReblog = (visibility) -> {
v.startAnimation(opacityOut); UiUtils.opacityOut(v);
session.getStatusInteractionController() session.getStatusInteractionController()
.setReblogged(item.status, !item.status.reblogged, visibility, r->boostConsumer(v, r)); .setReblogged(item.status, !item.status.reblogged, visibility, r->boostConsumer(v, r));
dialog.dismiss(); dialog.dismiss();
@@ -271,7 +282,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
menu.findViewById(R.id.quote).setOnClickListener(c->{ menu.findViewById(R.id.quote).setOnClickListener(c->{
dialog.dismiss(); dialog.dismiss();
v.startAnimation(opacityIn); UiUtils.opacityIn(v);
Bundle args=new Bundle(); Bundle args=new Bundle();
args.putString("account", item.accountID); args.putString("account", item.accountID);
AccountSession accountSession=AccountSessionManager.getInstance().getAccount(item.accountID); AccountSession accountSession=AccountSessionManager.getInstance().getAccount(item.accountID);
@@ -296,7 +307,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
private void onFavoriteClick(View v){ private void onFavoriteClick(View v){
favorite.setSelected(!item.status.favourited); favorite.setSelected(!item.status.favourited);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{ AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
v.startAnimation(opacityIn); UiUtils.opacityIn(v);
bindText(favorites, r.favouritesCount); bindText(favorites, r.favouritesCount);
}); });
} }
@@ -318,7 +329,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
private void onBookmarkClick(View v){ private void onBookmarkClick(View v){
bookmark.setSelected(!item.status.bookmarked); bookmark.setSelected(!item.status.bookmarked);
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{ AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setBookmarked(item.status, !item.status.bookmarked, r->{
v.startAnimation(opacityIn); UiUtils.opacityIn(v);
}); });
} }
@@ -337,7 +348,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
} }
private void onShareClick(View v){ private void onShareClick(View v){
v.startAnimation(opacityIn); UiUtils.opacityIn(v);
Intent intent=new Intent(Intent.ACTION_SEND); Intent intent=new Intent(Intent.ACTION_SEND);
intent.setType("text/plain"); intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, item.status.url); intent.putExtra(Intent.EXTRA_TEXT, item.status.url);

View File

@@ -72,7 +72,7 @@ public class GapStatusDisplayItem extends StatusDisplayItem{
private void onViewClick(View v){ private void onViewClick(View v){
if(item.loading) return; if(item.loading) return;
boolean isTop=v==top; boolean isTop=v==top;
(isTop ? textTop : textBottom).startAnimation(UiUtils.opacityOut); UiUtils.opacityOut(isTop ? textTop : textBottom);
V.setVisibilityAnimated((isTop ? progressTop : progressBottom), View.VISIBLE); V.setVisibilityAnimated((isTop ? progressTop : progressBottom), View.VISIBLE);
item.parentFragment.onGapClick(this, isTop); item.parentFragment.onGapClick(this, isTop);
} }

View File

@@ -66,6 +66,7 @@ import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder; import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest; import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
public class HeaderStatusDisplayItem extends StatusDisplayItem{ public class HeaderStatusDisplayItem extends StatusDisplayItem{
@@ -76,7 +77,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper(); private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
private SpannableStringBuilder parsedName; private SpannableStringBuilder parsedName;
public final Status status; public final Status status;
private boolean hasVisibilityToggle; public boolean hasVisibilityToggle;
boolean needBottomPadding; boolean needBottomPadding;
private CharSequence extraText; private CharSequence extraText;
private Notification notification; private Notification notification;
@@ -294,17 +295,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
UiUtils.enablePopupMenuIcons(activity, optionsMenu); UiUtils.enablePopupMenuIcons(activity, optionsMenu);
} }
private void populateAccountsMenu(Menu menu) {
List<AccountSession> sessions=AccountSessionManager.getInstance().getLoggedInAccounts();
sessions.stream().filter(s -> !s.getID().equals(item.accountID)).forEach(s -> {
String username = "@"+s.self.username+"@"+s.domain;
menu.add(username).setOnMenuItemClickListener(c->{
UiUtils.openURL(item.parentFragment.getActivity(), s.getID(), item.status.url, false);
return true;
});
});
}
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
@Override @Override
public void onBind(HeaderStatusDisplayItem item){ public void onBind(HeaderStatusDisplayItem item){
@@ -331,23 +321,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
botIcon.setColorFilter(username.getCurrentTextColor()); botIcon.setColorFilter(username.getCurrentTextColor());
deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE); deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE);
visibility.setVisibility(item.hasVisibilityToggle ? View.VISIBLE : View.GONE);
if (item.hasVisibilityToggle){ if (item.hasVisibilityToggle){
boolean hidden = !item.status.sensitiveRevealed || (item.status.hasSpoiler() && !item.status.spoilerRevealed); boolean visible = item.status.sensitiveRevealed && (!item.status.hasSpoiler() || item.status.spoilerRevealed);
visibility.setAlpha(visible ? 1 : 0f);
// doing this because V.setVisibilityAnimated ignores changes between INVISIBLE and GONE visibility.setScaleY(visible ? 1 : 0.8f);
int newVis=hidden ? View.INVISIBLE : View.VISIBLE; visibility.setScaleX(visible ? 1 : 0.8f);
if(newVis==View.INVISIBLE && visibility.getVisibility()==View.GONE) visibility.setEnabled(visible);
visibility.setVisibility(newVis);
else
V.setVisibilityAnimated(visibility, newVis);
visibility.setEnabled(!hidden);
visibility.setContentDescription(item.parentFragment.getString(item.status.sensitiveRevealed ? R.string.spoiler_hide : R.string.spoiler_show));
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.O){
visibility.setTooltipText(visibility.getContentDescription());
}
} else {
visibility.setVisibility(View.GONE);
} }
itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), item.needBottomPadding ? V.dp(16) : 0); itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), item.needBottomPadding ? V.dp(16) : 0);
if(TextUtils.isEmpty(item.extraText)){ if(TextUtils.isEmpty(item.extraText)){
@@ -412,6 +392,16 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
item.inset ? V.dp(10) : V.dp(4), itemView.getPaddingBottom()); item.inset ? V.dp(10) : V.dp(4), itemView.getPaddingBottom());
} }
public void animateVisibilityToggle(boolean visible){
visibility.animate()
.alpha(visible ? 1 : 0)
.scaleX(visible ? 1 : 0.8f)
.scaleY(visible ? 1 : 0.8f)
.setInterpolator(CubicBezierInterpolator.DEFAULT)
.start();
visibility.setEnabled(visible);
}
@Override @Override
public void setImage(int index, Drawable drawable){ public void setImage(int index, Drawable drawable){
if(index>0){ if(index>0){

View File

@@ -46,11 +46,13 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
private final String accountID; private final String accountID;
private final CustomEmojiHelper emojiHelper=new CustomEmojiHelper(); private final CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
private final CharSequence text; private final CharSequence text;
private final CharSequence timestamp;
public NotificationHeaderStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Notification notification, String accountID){ public NotificationHeaderStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Notification notification, String accountID){
super(parentID, parentFragment); super(parentID, parentFragment);
this.notification=notification; this.notification=notification;
this.accountID=accountID; this.accountID=accountID;
this.timestamp=notification.createdAt==null ? null : UiUtils.formatRelativeTimestamp(context, notification.createdAt);
if(notification.type==Notification.Type.POLL){ if(notification.type==Notification.Type.POLL){
text=parentFragment.getString(R.string.poll_ended); text=parentFragment.getString(R.string.poll_ended);
@@ -112,7 +114,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder<NotificationHeaderStatusDisplayItem> implements ImageLoaderViewHolder{ public static class Holder extends StatusDisplayItem.Holder<NotificationHeaderStatusDisplayItem> implements ImageLoaderViewHolder{
private final ImageView icon, avatar; private final ImageView icon, avatar;
private final TextView text; private final TextView text, timestamp;
private final int selectableItemBackground; private final int selectableItemBackground;
public Holder(Activity activity, ViewGroup parent){ public Holder(Activity activity, ViewGroup parent){
@@ -120,6 +122,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
icon=findViewById(R.id.icon); icon=findViewById(R.id.icon);
avatar=findViewById(R.id.avatar); avatar=findViewById(R.id.avatar);
text=findViewById(R.id.text); text=findViewById(R.id.text);
timestamp=findViewById(R.id.timestamp);
avatar.setOutlineProvider(OutlineProviders.roundedRect(8)); avatar.setOutlineProvider(OutlineProviders.roundedRect(8));
avatar.setClipToOutline(true); avatar.setClipToOutline(true);
@@ -152,6 +155,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
@Override @Override
public void onBind(NotificationHeaderStatusDisplayItem item){ public void onBind(NotificationHeaderStatusDisplayItem item){
text.setText(item.text); text.setText(item.text);
timestamp.setText(item.timestamp);
avatar.setVisibility(item.notification.type==Notification.Type.POLL ? View.GONE : View.VISIBLE); avatar.setVisibility(item.notification.type==Notification.Type.POLL ? View.GONE : View.VISIBLE);
icon.setImageResource(switch(item.notification.type){ icon.setImageResource(switch(item.notification.type){
case FAVORITE -> R.drawable.ic_fluent_star_24_filled; case FAVORITE -> R.drawable.ic_fluent_star_24_filled;

View File

@@ -68,7 +68,7 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
private final TextView text, percent; private final TextView text, percent;
private final View button; private final View button;
private final ImageView icon; private final ImageView icon;
private final Drawable progressBg, progressBgInset; private final Drawable progressBg;
public Holder(Activity activity, ViewGroup parent){ public Holder(Activity activity, ViewGroup parent){
super(activity, R.layout.display_item_poll_option, parent); super(activity, R.layout.display_item_poll_option, parent);
@@ -77,7 +77,6 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
icon=findViewById(R.id.icon); icon=findViewById(R.id.icon);
button=findViewById(R.id.button); button=findViewById(R.id.button);
progressBg=activity.getResources().getDrawable(R.drawable.bg_poll_option_voted, activity.getTheme()).mutate(); progressBg=activity.getResources().getDrawable(R.drawable.bg_poll_option_voted, activity.getTheme()).mutate();
progressBgInset=activity.getResources().getDrawable(R.drawable.bg_poll_option_voted_inset, activity.getTheme()).mutate();
itemView.setOnClickListener(this::onButtonClick); itemView.setOnClickListener(this::onButtonClick);
button.setOutlineProvider(OutlineProviders.roundedRect(20)); button.setOutlineProvider(OutlineProviders.roundedRect(20));
button.setClipToOutline(true); button.setClipToOutline(true);
@@ -93,23 +92,18 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
item.showResults ? R.drawable.ic_poll_option_button : R.drawable.ic_fluent_radio_button_24_selector item.showResults ? R.drawable.ic_poll_option_button : R.drawable.ic_fluent_radio_button_24_selector
)); ));
if(item.showResults){ if(item.showResults){
Drawable bg=item.inset ? progressBgInset : progressBg; Drawable bg=progressBg;
bg.setLevel(Math.round(10000f*item.votesFraction)); bg.setLevel(Math.round(10000f*item.votesFraction));
button.setBackground(bg); button.setBackground(bg);
itemView.setSelected(item.poll.ownVotes!=null && item.poll.ownVotes.contains(item.optionIndex)); itemView.setSelected(item.poll.ownVotes!=null && item.poll.ownVotes.contains(item.optionIndex));
percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f))); percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f)));
}else{ }else{
itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option)); itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option));
button.setBackgroundResource(item.inset ? R.drawable.bg_poll_option_clickable_inset : R.drawable.bg_poll_option_clickable); button.setBackgroundResource(R.drawable.bg_poll_option_clickable);
} }
if(item.inset){
text.setTextColor(itemView.getContext().getColorStateList(R.color.poll_option_text_inset));
percent.setTextColor(itemView.getContext().getColorStateList(R.color.poll_option_text_inset));
}else{
text.setTextColor(UiUtils.getThemeColor(itemView.getContext(), android.R.attr.textColorPrimary)); text.setTextColor(UiUtils.getThemeColor(itemView.getContext(), android.R.attr.textColorPrimary));
percent.setTextColor(UiUtils.getThemeColor(itemView.getContext(), R.attr.colorM3OnSecondaryContainer)); percent.setTextColor(UiUtils.getThemeColor(itemView.getContext(), R.attr.colorM3OnSecondaryContainer));
} }
}
@Override @Override
public void setImage(int index, Drawable image){ public void setImage(int index, Drawable image){

View File

@@ -204,11 +204,12 @@ public abstract class StatusDisplayItem{
items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null, null, scheduledStatus)); items.add(header=new HeaderStatusDisplayItem(parentID, statusForContent.account, statusForContent.createdAt, fragment, accountID, statusForContent, null, null, scheduledStatus));
} }
boolean filtered=false; LegacyFilter applyingFilter=null;
if(status.filtered!=null){ if(status.filtered!=null){
for(FilterResult filter:status.filtered){ for(FilterResult filter:status.filtered){
if(filter.filter.isActive()){ LegacyFilter f=filter.filter;
filtered=true; if(f.isActive() && filterContext != null && f.context.contains(filterContext)){
applyingFilter=f;
break; break;
} }
} }
@@ -315,14 +316,7 @@ public abstract class StatusDisplayItem{
} }
} }
LegacyFilter applyingFilter = null; return applyingFilter==null ? items :
if (!statusForContent.filterRevealed) {
StatusFilterPredicate predicate = new StatusFilterPredicate(accountID, filterContext, FilterAction.WARN);
statusForContent.filterRevealed = predicate.test(status);
applyingFilter = predicate.getApplyingFilter();
}
return statusForContent.filterRevealed ? items :
new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items, applyingFilter))); new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items, applyingFilter)));
} }

View File

@@ -1,7 +1,5 @@
package org.joinmastodon.android.ui.displayitems; package org.joinmastodon.android.ui.displayitems;
import static org.joinmastodon.android.ui.utils.UiUtils.opacityIn;
import android.app.Activity; import android.app.Activity;
import android.graphics.drawable.Animatable; import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
@@ -16,6 +14,7 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.BaseStatusListFragment; import org.joinmastodon.android.fragments.BaseStatusListFragment;
import org.joinmastodon.android.model.Status; import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.model.Translation; import org.joinmastodon.android.model.Translation;
@@ -29,6 +28,7 @@ import java.util.Locale;
import me.grishka.appkit.imageloader.ImageLoaderViewHolder; import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
import me.grishka.appkit.imageloader.MovieDrawable; import me.grishka.appkit.imageloader.MovieDrawable;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest; import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.utils.CubicBezierInterpolator;
import me.grishka.appkit.utils.V; import me.grishka.appkit.utils.V;
public class TextStatusDisplayItem extends StatusDisplayItem{ public class TextStatusDisplayItem extends StatusDisplayItem{
@@ -112,7 +112,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
}else{ }else{
text.setText(item.text); text.setText(item.text);
} }
text.setTextIsSelectable(item.textSelectable); text.setTextIsSelectable(false);
if(item.textSelectable) itemView.post(() -> text.setTextIsSelectable(true));
text.setInvalidateOnEveryFrame(false); text.setInvalidateOnEveryFrame(false);
itemView.setClickable(false); itemView.setClickable(false);
itemView.setPadding(itemView.getPaddingLeft(), item.reduceTopPadding ? V.dp(6) : V.dp(12), itemView.getPaddingRight(), itemView.getPaddingBottom()); itemView.setPadding(itemView.getPaddingLeft(), item.reduceTopPadding ? V.dp(6) : V.dp(12), itemView.getPaddingRight(), itemView.getPaddingBottom());
@@ -200,17 +201,20 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
translationProgress=findViewById(R.id.translation_progress); translationProgress=findViewById(R.id.translation_progress);
translationButton.setOnClickListener(v->item.parentFragment.togglePostTranslation(item.status, item.parentID)); translationButton.setOnClickListener(v->item.parentFragment.togglePostTranslation(item.status, item.parentID));
} }
if(translationButton!=null) translationButton.animate().cancel();
if(item.status.translationState==Status.TranslationState.HIDDEN){ if(item.status.translationState==Status.TranslationState.HIDDEN){
if(updateText) text.setText(item.text); if(updateText) text.setText(item.text);
if(translationFooter==null) return; if(translationFooter==null) return;
translationFooter.setVisibility(translateEnabled ? View.VISIBLE : View.GONE); translationFooter.setVisibility(translateEnabled ? View.VISIBLE : View.GONE);
translationProgress.setVisibility(View.GONE); translationProgress.setVisibility(View.GONE);
Translation existingTrans=item.status.getContentStatus().translation; Translation existingTrans=item.status.getContentStatus().translation;
String lang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null; String existingTransLang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null;
String displayLang=Locale.forLanguageTag(lang!=null ? lang : item.status.getContentStatus().language).getDisplayLanguage(); String lang=existingTransLang!=null ? existingTransLang : item.status.getContentStatus().language;
String displayLang=Locale.forLanguageTag(lang != null ? lang
: AccountSessionManager.get(item.parentFragment.getAccountID()).preferences.postingDefaultLanguage).getDisplayLanguage();
translationButton.setText(item.parentFragment.getString(R.string.translate_post, !displayLang.isBlank() ? displayLang : lang)); translationButton.setText(item.parentFragment.getString(R.string.translate_post, !displayLang.isBlank() ? displayLang : lang));
translationButton.setEnabled(true); translationButton.setClickable(true);
translationButton.setAlpha(1); translationButton.animate().alpha(1).setDuration(100).start();
translationInfo.setVisibility(View.GONE); translationInfo.setVisibility(View.GONE);
UiUtils.beginLayoutTransition((ViewGroup) translationButtonWrap); UiUtils.beginLayoutTransition((ViewGroup) translationButtonWrap);
}else{ }else{
@@ -218,8 +222,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
if(item.status.translationState==Status.TranslationState.SHOWN){ if(item.status.translationState==Status.TranslationState.SHOWN){
translationProgress.setVisibility(View.GONE); translationProgress.setVisibility(View.GONE);
translationButton.setText(R.string.translation_show_original); translationButton.setText(R.string.translation_show_original);
translationButton.setEnabled(true); translationButton.setClickable(true);
translationButton.setAlpha(1); translationButton.animate().alpha(1).setDuration(200).start();
translationInfo.setVisibility(View.VISIBLE); translationInfo.setVisibility(View.VISIBLE);
translationButton.setVisibility(View.VISIBLE); translationButton.setVisibility(View.VISIBLE);
String displayLang=Locale.forLanguageTag(item.status.translation.detectedSourceLanguage).getDisplayLanguage(); String displayLang=Locale.forLanguageTag(item.status.translation.detectedSourceLanguage).getDisplayLanguage();
@@ -233,8 +237,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
} }
}else{ // LOADING }else{ // LOADING
translationProgress.setVisibility(View.VISIBLE); translationProgress.setVisibility(View.VISIBLE);
translationButton.setEnabled(false); translationButton.setClickable(false);
translationButton.startAnimation(opacityIn); translationButton.animate().alpha(UiUtils.ALPHA_PRESSED).setStartDelay(50).setDuration(300).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
translationInfo.setVisibility(View.INVISIBLE); translationInfo.setVisibility(View.INVISIBLE);
UiUtils.beginLayoutTransition((ViewGroup) translationButton.getParent()); UiUtils.beginLayoutTransition((ViewGroup) translationButton.getParent());
} }

View File

@@ -31,13 +31,11 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
} }
public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{ public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{
public final View warningWrap;
public final TextView text; public final TextView text;
public List<StatusDisplayItem> filteredItems; public List<StatusDisplayItem> filteredItems;
public Holder(Context context, ViewGroup parent) { public Holder(Context context, ViewGroup parent) {
super(context, R.layout.display_item_filter_warning, parent); super(context, R.layout.display_item_filter_warning, parent);
warningWrap=findViewById(R.id.warning_wrap);
text=findViewById(R.id.text); text=findViewById(R.id.text);
} }
@@ -45,11 +43,7 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
public void onBind(WarningFilteredStatusDisplayItem item) { public void onBind(WarningFilteredStatusDisplayItem item) {
filteredItems = item.filteredItems; filteredItems = item.filteredItems;
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.applyingFilter.title)); text.setText(item.parentFragment.getString(R.string.sk_filtered, item.applyingFilter.title));
} itemView.setOnClickListener(v->item.parentFragment.onWarningClick(this));
@Override
public void onClick() {
item.parentFragment.onWarningClick(this);
} }
} }
} }

View File

@@ -66,6 +66,10 @@ public class BlurhashCrossfadeDrawable extends Drawable{
public void setImageDrawable(Drawable imageDrawable){ public void setImageDrawable(Drawable imageDrawable){
this.imageDrawable=imageDrawable; this.imageDrawable=imageDrawable;
if(imageDrawable!=null){
width=imageDrawable.getIntrinsicWidth();
height=imageDrawable.getIntrinsicHeight();
}
invalidateSelf(); invalidateSelf();
} }
@@ -99,11 +103,15 @@ public class BlurhashCrossfadeDrawable extends Drawable{
@Override @Override
public int getIntrinsicWidth(){ public int getIntrinsicWidth(){
if(width==0)
return imageDrawable==null ? 1920 : imageDrawable.getIntrinsicWidth();
return width; return width;
} }
@Override @Override
public int getIntrinsicHeight(){ public int getIntrinsicHeight(){
if(height==0)
return imageDrawable==null ? 1080 : imageDrawable.getIntrinsicHeight();
return height; return height;
} }

View File

@@ -734,9 +734,18 @@ public class PhotoViewer implements ZoomPanView.Listener{
public void onBind(Attachment item){ public void onBind(Attachment item){
super.onBind(item); super.onBind(item);
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) imageView.getLayoutParams(); FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) imageView.getLayoutParams();
Drawable currentDrawable=listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition());
if(item.hasKnownDimensions()){
params.width=item.getWidth(); params.width=item.getWidth();
params.height=item.getHeight(); params.height=item.getHeight();
ViewImageLoader.load(this, listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition()), new UrlImageLoaderRequest(item.url), false); }else if(currentDrawable!=null){
params.width=currentDrawable.getIntrinsicWidth();
params.height=currentDrawable.getIntrinsicHeight();
}else{
params.width=1920;
params.height=1080;
}
ViewImageLoader.load(this, currentDrawable, new UrlImageLoaderRequest(item.url), false);
} }
@Override @Override
@@ -778,9 +787,18 @@ public class PhotoViewer implements ZoomPanView.Listener{
super.onBind(item); super.onBind(item);
playerReady=false; playerReady=false;
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) wrap.getLayoutParams(); FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) wrap.getLayoutParams();
Drawable currentDrawable=listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition());
if(item.hasKnownDimensions()){
params.width=item.getWidth(); params.width=item.getWidth();
params.height=item.getHeight(); params.height=item.getHeight();
wrap.setBackground(listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition())); }else if(currentDrawable!=null){
params.width=currentDrawable.getIntrinsicWidth();
params.height=currentDrawable.getIntrinsicHeight();
}else{
params.width=1920;
params.height=1080;
}
wrap.setBackground(currentDrawable);
progressBar.setVisibility(item.type==Attachment.Type.VIDEO ? View.VISIBLE : View.GONE); progressBar.setVisibility(item.type==Attachment.Type.VIDEO ? View.VISIBLE : View.GONE);
if(itemView.isAttachedToWindow()){ if(itemView.isAttachedToWindow()){
reset(); reset();
@@ -841,7 +859,9 @@ public class PhotoViewer implements ZoomPanView.Listener{
@Override @Override
public boolean onError(MediaPlayer mp, int what, int extra){ public boolean onError(MediaPlayer mp, int what, int extra){
Log.e(TAG, "video player onError() called with: mp = ["+mp+"], what = ["+what+"], extra = ["+extra+"]"); Log.e(TAG, "video player onError() called with: mp = ["+mp+"], what = ["+what+"], extra = ["+extra+"]");
return false; Toast.makeText(activity, R.string.error_playing_video, Toast.LENGTH_SHORT).show();
onStartSwipeToDismissTransition(0f);
return true;
} }
public void prepareAndStartPlayer(){ public void prepareAndStartPlayer(){
@@ -862,6 +882,8 @@ public class PhotoViewer implements ZoomPanView.Listener{
player.prepareAsync(); player.prepareAsync();
}catch(IOException x){ }catch(IOException x){
Log.w(TAG, "Error initializing gif player", x); Log.w(TAG, "Error initializing gif player", x);
Toast.makeText(activity, R.string.error_playing_video, Toast.LENGTH_SHORT).show();
onStartSwipeToDismissTransition(0f);
} }
} }

View File

@@ -119,8 +119,10 @@ public class ZoomPanView extends FrameLayout implements ScaleGestureDetector.OnS
int width=right-left; int width=right-left;
int height=bottom-top; int height=bottom-top;
if(width==0 || height==0) if(width==0 || height==0 || child.getWidth()==0 || child.getWidth()==0){
matrix.reset();
return; return;
}
float scale=Math.min(width/(float)child.getWidth(), height/(float)child.getHeight()); float scale=Math.min(width/(float)child.getWidth(), height/(float)child.getHeight());
minScale=scale; minScale=scale;

View File

@@ -1,8 +1,8 @@
package org.joinmastodon.android.ui.utils; package org.joinmastodon.android.ui.utils;
import static org.joinmastodon.android.GlobalUserPreferences.ColorPreference;
import static org.joinmastodon.android.GlobalUserPreferences.ThemePreference; import static org.joinmastodon.android.GlobalUserPreferences.ThemePreference;
import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme; import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme;
import static org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference.*;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
@@ -11,20 +11,21 @@ import androidx.annotation.StyleRes;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import java.util.Map; import java.util.Map;
public class ColorPalette { public class ColorPalette {
public static final Map<GlobalUserPreferences.ColorPreference, ColorPalette> palettes = Map.of( public static final Map<AccountLocalPreferences.ColorPreference, ColorPalette> palettes = Map.of(
ColorPreference.MATERIAL3, new ColorPalette(R.style.ColorPalette_Material3) MATERIAL3, new ColorPalette(R.style.ColorPalette_Material3)
.dark(R.style.ColorPalette_Material3_Dark, R.style.ColorPalette_Material3_AutoLightDark), .dark(R.style.ColorPalette_Material3_Dark, R.style.ColorPalette_Material3_AutoLightDark),
ColorPreference.PINK, new ColorPalette(R.style.ColorPalette_Pink), PINK, new ColorPalette(R.style.ColorPalette_Pink),
ColorPreference.PURPLE, new ColorPalette(R.style.ColorPalette_Purple), PURPLE, new ColorPalette(R.style.ColorPalette_Purple),
ColorPreference.GREEN, new ColorPalette(R.style.ColorPalette_Green), GREEN, new ColorPalette(R.style.ColorPalette_Green),
ColorPreference.BLUE, new ColorPalette(R.style.ColorPalette_Blue), BLUE, new ColorPalette(R.style.ColorPalette_Blue),
ColorPreference.BROWN, new ColorPalette(R.style.ColorPalette_Brown), BROWN, new ColorPalette(R.style.ColorPalette_Brown),
ColorPreference.RED, new ColorPalette(R.style.ColorPalette_Red), RED, new ColorPalette(R.style.ColorPalette_Red),
ColorPreference.YELLOW, new ColorPalette(R.style.ColorPalette_Yellow) YELLOW, new ColorPalette(R.style.ColorPalette_Yellow)
); );
private @StyleRes int base; private @StyleRes int base;

View File

@@ -28,6 +28,7 @@ public class MediaAttachmentViewController{
private final Context context; private final Context context;
private boolean didClear; private boolean didClear;
private Status status; private Status status;
private Attachment attachment;
public MediaAttachmentViewController(Context context, MediaGridStatusDisplayItem.GridItemType type){ public MediaAttachmentViewController(Context context, MediaGridStatusDisplayItem.GridItemType type){
view=context.getSystemService(LayoutInflater.class).inflate(switch(type){ view=context.getSystemService(LayoutInflater.class).inflate(switch(type){
@@ -54,6 +55,7 @@ public class MediaAttachmentViewController{
public void bind(Attachment attachment, Status status){ public void bind(Attachment attachment, Status status){
this.status=status; this.status=status;
this.attachment=attachment;
crossfadeDrawable.setSize(attachment.getWidth(), attachment.getHeight()); crossfadeDrawable.setSize(attachment.getWidth(), attachment.getHeight());
crossfadeDrawable.setBlurhashDrawable(attachment.blurhashPlaceholder); crossfadeDrawable.setBlurhashDrawable(attachment.blurhashPlaceholder);
crossfadeDrawable.setCrossfadeAlpha(0f); crossfadeDrawable.setCrossfadeAlpha(0f);
@@ -76,6 +78,11 @@ public class MediaAttachmentViewController{
crossfadeDrawable.setImageDrawable(drawable); crossfadeDrawable.setImageDrawable(drawable);
if(didClear) if(didClear)
crossfadeDrawable.animateAlpha(0f); crossfadeDrawable.animateAlpha(0f);
// Make sure the image is not stretched if the server returned wrong dimensions
if(drawable!=null && (drawable.getIntrinsicWidth()!=attachment.getWidth() || drawable.getIntrinsicHeight()!=attachment.getHeight())){
photo.setImageDrawable(null);
photo.setImageDrawable(crossfadeDrawable);
}
} }
public void clearImage(){ public void clearImage(){

View File

@@ -1,6 +1,7 @@
package org.joinmastodon.android.ui.utils; package org.joinmastodon.android.ui.utils;
import static android.view.Menu.NONE; import static android.view.Menu.NONE;
import static org.joinmastodon.android.GlobalUserPreferences.ThemePreference.*;
import static org.joinmastodon.android.GlobalUserPreferences.theme; import static org.joinmastodon.android.GlobalUserPreferences.theme;
import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme; import static org.joinmastodon.android.GlobalUserPreferences.trueBlackTheme;
@@ -53,9 +54,8 @@ import android.view.MenuItem;
import android.view.SubMenu; import android.view.SubMenu;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets; import android.view.WindowInsets;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import android.widget.Button; import android.widget.Button;
import android.widget.ImageView; import android.widget.ImageView;
@@ -85,6 +85,7 @@ import org.joinmastodon.android.api.requests.statuses.CreateStatus;
import org.joinmastodon.android.api.requests.statuses.DeleteStatus; import org.joinmastodon.android.api.requests.statuses.DeleteStatus;
import org.joinmastodon.android.api.requests.statuses.GetStatusByID; import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
import org.joinmastodon.android.api.requests.statuses.SetStatusPinned; import org.joinmastodon.android.api.requests.statuses.SetStatusPinned;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent; import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
@@ -176,17 +177,6 @@ public class UiUtils {
public static int MAX_WIDTH, SCROLL_TO_TOP_DELTA; public static int MAX_WIDTH, SCROLL_TO_TOP_DELTA;
public static final float ALPHA_PRESSED=0.55f; public static final float ALPHA_PRESSED=0.55f;
public static final Animation opacityOut, opacityIn;
static {
opacityOut = new AlphaAnimation(1, ALPHA_PRESSED);
opacityOut.setDuration(300);
opacityOut.setInterpolator(CubicBezierInterpolator.DEFAULT);
opacityOut.setFillAfter(true);
opacityIn = new AlphaAnimation(ALPHA_PRESSED, 1);
opacityIn.setDuration(400);
opacityIn.setInterpolator(CubicBezierInterpolator.DEFAULT);
}
private UiUtils() { private UiUtils() {
} }
@@ -973,14 +963,20 @@ public class UiUtils {
} }
public static void setUserPreferredTheme(Context context) { public static void setUserPreferredTheme(Context context) {
context.setTheme(switch (theme) { setUserPreferredTheme(context, null);
}
public static void setUserPreferredTheme(Context context, @Nullable AccountSession session) {
context.setTheme(switch(theme) {
case LIGHT -> R.style.Theme_Mastodon_Light; case LIGHT -> R.style.Theme_Mastodon_Light;
case DARK -> R.style.Theme_Mastodon_Dark; case DARK -> R.style.Theme_Mastodon_Dark;
default -> R.style.Theme_Mastodon_AutoLightDark; default -> R.style.Theme_Mastodon_AutoLightDark;
}); });
ColorPalette palette = ColorPalette.palettes.get(GlobalUserPreferences.color); AccountLocalPreferences prefs=session != null ? session.getLocalPreferences() : null;
if (palette != null) palette.apply(context); AccountLocalPreferences.ColorPreference color=prefs != null ? prefs.color : AccountLocalPreferences.ColorPreference.MATERIAL3;
ColorPalette palette = ColorPalette.palettes.get(color);
if (palette != null) palette.apply(context, theme);
Resources res = context.getResources(); Resources res = context.getResources();
MAX_WIDTH = (int) res.getDimension(R.dimen.layout_max_width); MAX_WIDTH = (int) res.getDimension(R.dimen.layout_max_width);
@@ -997,9 +993,9 @@ public class UiUtils {
} }
public static boolean isDarkTheme() { public static boolean isDarkTheme() {
if (theme == GlobalUserPreferences.ThemePreference.AUTO) if (theme == AUTO)
return (MastodonApp.context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES; return (MastodonApp.context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;
return theme == GlobalUserPreferences.ThemePreference.DARK; return theme == DARK;
} }
public static Optional<Pair<String, Optional<String>>> parseFediverseHandle(String maybeFediHandle) { public static Optional<Pair<String, Optional<String>>> parseFediverseHandle(String maybeFediHandle) {
@@ -1740,4 +1736,16 @@ public class UiUtils {
.filter(Objects::nonNull) .filter(Objects::nonNull)
.findFirst(); .findFirst();
} }
public static void opacityIn(View v){
v.animate().alpha(1).setDuration(400).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
}
public static void opacityOut(View v){
opacityOut(v, ALPHA_PRESSED).start();
}
public static ViewPropertyAnimator opacityOut(View v, float alpha){
return v.animate().alpha(alpha).setDuration(300).setInterpolator(CubicBezierInterpolator.DEFAULT);
}
} }

View File

@@ -18,6 +18,7 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences; import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R; import org.joinmastodon.android.R;
import org.joinmastodon.android.api.MastodonAPIController; import org.joinmastodon.android.api.MastodonAPIController;
import org.joinmastodon.android.api.session.AccountLocalPreferences;
import org.joinmastodon.android.api.session.AccountSession; import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager; import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.ui.DividerItemDecoration; import org.joinmastodon.android.ui.DividerItemDecoration;
@@ -66,7 +67,7 @@ public class ComposeLanguageAlertViewController{
.collect(Collectors.toList()); .collect(Collectors.toList());
if(!TextUtils.isEmpty(preferred)){ if(!TextUtils.isEmpty(preferred)){
MastodonLanguage lang = resolver.fromOrFallback(preferred); MastodonLanguage lang=resolver.fromOrFallback(preferred);
specialLocales.add(new SpecialLocaleInfo( specialLocales.add(new SpecialLocaleInfo(
lang, lang,
lang.getDisplayName(context), lang.getDisplayName(context),
@@ -75,7 +76,7 @@ public class ComposeLanguageAlertViewController{
} }
if(!Locale.getDefault().getLanguage().equals(preferred)){ if(!Locale.getDefault().getLanguage().equals(preferred)){
MastodonLanguage lang = resolver.getDefault(); MastodonLanguage lang=resolver.getDefault();
specialLocales.add(new SpecialLocaleInfo( specialLocales.add(new SpecialLocaleInfo(
lang, lang,
lang.getDisplayName(context), lang.getDisplayName(context),
@@ -91,9 +92,19 @@ public class ComposeLanguageAlertViewController{
detectLanguage(detected, postText); detectLanguage(detected, postText);
} }
if (session!=null && session.getLocalPreferences().bottomEncoding) { AccountLocalPreferences lp=session==null ? null : session.getLocalPreferences();
if(lp!=null){
for(String tag : lp.recentLanguages){
if(specialLocales.stream().anyMatch(l->l.language!=null && l.language.languageTag!=null
&& l.language.languageTag.equals(tag))) continue;
resolver.from(tag).ifPresent(lang->specialLocales.add(new SpecialLocaleInfo(
lang, lang.getDisplayName(context), null
)));
}
if(lp.bottomEncoding) {
specialLocales.add(new SpecialLocaleInfo(null, "\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48", "bottom")); specialLocales.add(new SpecialLocaleInfo(null, "\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48", "bottom"));
} }
}
if(previouslySelected!=null){ if(previouslySelected!=null){
if(previouslySelected.index!=-1 && ((previouslySelected.index<specialLocales.size() && Objects.equals(previouslySelected.language, specialLocales.get(previouslySelected.index).language)) || if(previouslySelected.index!=-1 && ((previouslySelected.index<specialLocales.size() && Objects.equals(previouslySelected.language, specialLocales.get(previouslySelected.index).language)) ||
@@ -323,7 +334,7 @@ public class ComposeLanguageAlertViewController{
public void onClick(){ public void onClick(){
selectItem(getAbsoluteAdapterPosition()); selectItem(getAbsoluteAdapterPosition());
selectedLocale=item.language; selectedLocale=item.language;
selectedEncoding = item.title.equals("bottom") ? "bottom" : null; selectedEncoding=item.title != null && item.title.equals("bottom") ? "bottom" : null;
} }
@Override @Override

File diff suppressed because one or more lines are too long

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"> <selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/favorite_selected" android:state_selected="true"/> <item android:color="@color/favorite_selected" android:state_selected="true"/>
<item android:color="?android:textColorSecondary"/> <item android:color="?colorM3OnSurfaceVariant"/>
</selector> </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="@color/like_selected" android:state_selected="true"/>
<item android:color="?android:textColorSecondary"/>
</selector>

View File

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

View File

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

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="?colorM3SurfaceVariant"/>
</item>
<item android:drawable="?android:selectableItemBackground"/>
</layer-list>

View File

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

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="?colorM3Surface"/>
<corners android:radius="20dp"/>
</shape>
</item>
<item>
<scale android:scaleGravity="start|fill_vertical" android:scaleWidth="100%">
<shape>
<solid android:color="@color/poll_option_progress_inset"/>
<corners android:radius="20dp"/>
</shape>
</scale>
</item>
<item>
<shape>
<stroke android:width="1dp" android:color="?colorM3Outline"/>
<corners android:radius="20dp"/>
</shape>
</item>
</layer-list>

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.496 16.803l6.245-6.304c1.684-1.71 1.679-4.474-0.017-6.187-1.663-1.68-4.328-1.723-6.026-0.121-0.037 0.034-0.073 0.07-0.109 0.106L9.993 4.9 9.388 4.29c-0.033-0.034-0.066-0.067-0.1-0.099-1.702-1.614-4.372-1.59-6.027 0.083-1.688 1.705-1.68 4.476 0.016 6.189l6.277 6.34c0.26 0.263 0.682 0.263 0.942 0zM11.3 5c1.296-1.309 3.402-1.308 4.713 0.016 1.312 1.325 1.314 3.461 0.016 4.78v0.002l-6.004 6.06-6.038-6.099C2.674 8.433 2.673 6.29 3.972 4.977 5.265 3.671 7.37 3.673 8.678 4.994l0.96 0.97c0.196 0.198 0.515 0.198 0.711 0L11.3 5z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

@@ -0,0 +1,3 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="24" android:viewportHeight="24">
<path android:pathData="M12.82 5.58L12 6.401l-0.824-0.824c-2.1-2.099-5.502-2.099-7.601 0-2.1 2.1-2.1 5.503 0 7.602l7.895 7.895c0.293 0.293 0.768 0.293 1.06 0l7.902-7.897c2.094-2.106 2.098-5.5-0.001-7.599-2.103-2.103-5.508-2.103-7.611 0z" android:fillColor="@color/fluent_default_icon_tint"/>
</vector>

View File

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

View File

@@ -3,8 +3,7 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/warning_wrap" android:background="@drawable/bg_filter_warning">
android:background="@drawable/bg_timeline_gap">
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"

View File

@@ -36,7 +36,7 @@
android:layout_marginStart="16dp" android:layout_marginStart="16dp"
android:duplicateParentState="true" android:duplicateParentState="true"
android:src="@drawable/ic_fluent_chat_multiple_24_selector_text" android:src="@drawable/ic_fluent_chat_multiple_24_selector_text"
android:tint="?android:textColorSecondary" android:tint="?colorM3OnSurfaceVariant"
android:gravity="center_vertical" /> android:gravity="center_vertical" />
<TextView <TextView
android:id="@+id/reply" android:id="@+id/reply"
@@ -47,6 +47,7 @@
android:minWidth="16dp" android:minWidth="16dp"
android:gravity="center_vertical" android:gravity="center_vertical"
android:textAppearance="@style/m3_label_large" android:textAppearance="@style/m3_label_large"
android:textColor="?colorM3OnSurfaceVariant"
android:maxLines="1" android:maxLines="1"
android:ellipsize="end" android:ellipsize="end"
tools:text="123" tools:text="123"
@@ -62,7 +63,6 @@
android:id="@+id/boost_btn" android:id="@+id/boost_btn"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="match_parent" android:layout_height="match_parent"
android:foregroundTint="@color/boost_icon"
android:paddingVertical="12dp"> android:paddingVertical="12dp">
<ImageView <ImageView
android:layout_width="24sp" android:layout_width="24sp"
@@ -101,6 +101,7 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:paddingVertical="12dp"> android:paddingVertical="12dp">
<ImageView <ImageView
android:id="@+id/favorite_icon"
android:layout_width="24sp" android:layout_width="24sp"
android:layout_height="24sp" android:layout_height="24sp"
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
@@ -160,7 +161,7 @@
android:layout_gravity="center_vertical" android:layout_gravity="center_vertical"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:src="@drawable/ic_fluent_share_24_regular" android:src="@drawable/ic_fluent_share_24_regular"
android:tint="?android:textColorSecondary" android:tint="?colorM3OnSurfaceVariant"
android:gravity="center_vertical"/> android:gravity="center_vertical"/>
</FrameLayout> </FrameLayout>

View File

@@ -43,6 +43,8 @@
android:layout_height="48dp" android:layout_height="48dp"
android:background="?android:actionBarItemBackground" android:background="?android:actionBarItemBackground"
android:scaleType="center" android:scaleType="center"
android:contentDescription="@string/spoiler_hide"
android:tooltipText="@string/spoiler_hide"
android:src="@drawable/ic_fluent_eye_24_regular" android:src="@drawable/ic_fluent_eye_24_regular"
android:tint="?colorM3OnSurfaceVariant" android:tint="?colorM3OnSurfaceVariant"
android:visibility="gone" /> android:visibility="gone" />

View File

@@ -22,14 +22,42 @@
android:layout_height="32dp" android:layout_height="32dp"
android:layout_marginStart="12dp"/> android:layout_marginStart="12dp"/>
<org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView <TextView
android:id="@+id/text" android:id="@+id/text"
android:layout_width="match_parent" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="8dp" android:layout_marginStart="8dp"
android:textAppearance="@style/m3_body_large" android:textAppearance="@style/m3_body_large"
android:textColor="?colorM3OnSurface" android:textColor="?colorM3OnSurface"
android:singleLine="true" android:singleLine="true"
android:ellipsize="end"
tools:text="Notification text"/> tools:text="Notification text"/>
<TextView
android:id="@+id/separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="4sp"
android:importantForAccessibility="no"
android:singleLine="true"
android:textAppearance="@style/m3_body_medium"
android:textColor="?colorM3OnSurfaceVariant"
android:text="@string/sk_separator"/>
<TextView
android:id="@+id/timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="56sp"
android:textAppearance="@style/m3_body_medium"
android:textColor="?colorM3OnSurfaceVariant"
android:maxLines="1"
tools:text="42m ago"/>
</org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout>
</LinearLayout> </LinearLayout>

View File

@@ -132,7 +132,7 @@
android:layout_marginTop="-4dp" android:layout_marginTop="-4dp"
android:layout_marginStart="-12dp" android:layout_marginStart="-12dp"
android:background="@drawable/bg_tabbar_badge" android:background="@drawable/bg_tabbar_badge"
android:textColor="?colorM3OnPrimary" android:textColor="?colorM3OnError"
android:gravity="center" android:gravity="center"
android:includeFontPadding="false" android:includeFontPadding="false"
android:textAppearance="@style/m3_label_small" android:textAppearance="@style/m3_label_small"

View File

@@ -316,4 +316,10 @@
<string name="sk_federated_timeline_info_banner">هذه هي أحدث المنشورات للأعضاء في فديراليتك.</string> <string name="sk_federated_timeline_info_banner">هذه هي أحدث المنشورات للأعضاء في فديراليتك.</string>
<string name="sk_bubble_timeline_info_banner">هذه هي أحدث المنشورات على الشبكة والتي انتقاها مُدراء خادمكم.</string> <string name="sk_bubble_timeline_info_banner">هذه هي أحدث المنشورات على الشبكة والتي انتقاها مُدراء خادمكم.</string>
<string name="sk_schedule_or_draft">برمجة أو تحرير مُسودّة</string> <string name="sk_schedule_or_draft">برمجة أو تحرير مُسودّة</string>
<string name="sk_settings_color_palette">لوحة الألوان</string>
<string name="sk_blocked_accounts">الحسابات المحظورة</string>
<string name="sk_instance_info_unavailable">معلومات مثيل الخادم غير متوفرة في الحين</string>
<string name="sk_muted_accounts">الحسابات المكتومة</string>
<string name="sk_settings_continues_playback_summary">السماح للوسائط المشغَّلَة بالفعل بالاستمرار في التشغيل، مع تراكب التشغيل الجديد</string>
<string name="sk_settings_continues_playback">تراكُب صوتي</string>
</resources> </resources>

View File

@@ -359,7 +359,7 @@
<string name="sk_search_suicide_message">Wenn du auf ein Zeichen wartest, keinen Suizid zu begehen das hier ist es. Bitte ziehe in Erwägung, eine Suizid-Hotline zu kontaktieren, wenn du Hilfe brauchst.</string> <string name="sk_search_suicide_message">Wenn du auf ein Zeichen wartest, keinen Suizid zu begehen das hier ist es. Bitte ziehe in Erwägung, eine Suizid-Hotline zu kontaktieren, wenn du Hilfe brauchst.</string>
<string name="sk_settings_show_emoji_reactions_hide_empty">Leere Emoji-Reaktionen verbergen</string> <string name="sk_settings_show_emoji_reactions_hide_empty">Leere Emoji-Reaktionen verbergen</string>
<string name="sk_settings_show_emoji_reactions_always">Hinzufügen-Button immer anzeigen</string> <string name="sk_settings_show_emoji_reactions_always">Hinzufügen-Button immer anzeigen</string>
<string name="sk_enter_emoji_hint">Emoji zum Reagieren eintippen</string> <string name="sk_enter_emoji_hint">Emoji eintippen oder suchen</string>
<string name="sk_duration_indefinite">Unbestimmt</string> <string name="sk_duration_indefinite">Unbestimmt</string>
<string name="sk_duration_minutes_5">5 Minuten</string> <string name="sk_duration_minutes_5">5 Minuten</string>
<string name="sk_duration_minutes_30">30 Minuten</string> <string name="sk_duration_minutes_30">30 Minuten</string>
@@ -385,4 +385,25 @@
<string name="sk_suicide_helplines_url">https://findahelpline.com</string> <string name="sk_suicide_helplines_url">https://findahelpline.com</string>
<string name="sk_load_missing_posts_below">Ältere Beiträge laden</string> <string name="sk_load_missing_posts_below">Ältere Beiträge laden</string>
<string name="sk_load_missing_posts_above">Neuere Beiträge laden</string> <string name="sk_load_missing_posts_above">Neuere Beiträge laden</string>
<plurals name="sk_time_seconds">
<item quantity="one">%d Sekunde</item>
<item quantity="other">%d Sekunden</item>
</plurals>
<plurals name="sk_time_hours">
<item quantity="one">%d Stunde</item>
<item quantity="other">%d Stunden</item>
</plurals>
<string name="sk_settings_like_icon">Herz als Favorisieren-Symbol verwenden</string>
<string name="sk_blocked_accounts">Blockierte Konten</string>
<plurals name="sk_time_days">
<item quantity="one">%d Tag</item>
<item quantity="other">%d Tage</item>
</plurals>
<string name="sk_muted_accounts">Stummgeschaltete Konten</string>
<string name="sk_trending_posts_info_banner">Diese Beiträge sind im Fediverse gerade beliebt.</string>
<plurals name="sk_time_minutes">
<item quantity="one">%d Minute</item>
<item quantity="other">%d Minuten</item>
</plurals>
<string name="sk_trending_links_info_banner">Über diese Nachrichten wird im Fediverse gerade gesprochen.</string>
</resources> </resources>

View File

@@ -367,7 +367,7 @@
<item quantity="other">%1$,d usuarios reaccionaron con %2$s</item> <item quantity="other">%1$,d usuarios reaccionaron con %2$s</item>
</plurals> </plurals>
<string name="sk_enter_emoji_toast">Por favor, introduce un emoticono</string> <string name="sk_enter_emoji_toast">Por favor, introduce un emoticono</string>
<string name="sk_enter_emoji_hint">Escribe para reaccionar con un emoticono</string> <string name="sk_enter_emoji_hint">Escribe un emoticono o busca un emoticono personalizado</string>
<string name="sk_settings_emoji_reactions">Activar reacciones con emoticonos</string> <string name="sk_settings_emoji_reactions">Activar reacciones con emoticonos</string>
<string name="sk_settings_emoji_reactions_explanation">Muestra las reacciones con emoticonos a las publicaciones y te permite añadir las tuyas. Varias instancias del Fediverso lo soportan, pero Mastodon no.</string> <string name="sk_settings_emoji_reactions_explanation">Muestra las reacciones con emoticonos a las publicaciones y te permite añadir las tuyas. Varias instancias del Fediverso lo soportan, pero Mastodon no.</string>
<string name="sk_settings_emoji_reactions_in_lists_explanation">Las reacciones con los emoticonos deben mostrarse en las líneas de tiempo. Si esta opción está desactivada, las reacciones con los emoticonos solo se mostrarán al ver un hilo.</string> <string name="sk_settings_emoji_reactions_in_lists_explanation">Las reacciones con los emoticonos deben mostrarse en las líneas de tiempo. Si esta opción está desactivada, las reacciones con los emoticonos solo se mostrarán al ver un hilo.</string>
@@ -400,4 +400,6 @@
<string name="sk_load_missing_posts_above">Cargar publicaciones más recientes</string> <string name="sk_load_missing_posts_above">Cargar publicaciones más recientes</string>
<string name="sk_trending_posts_info_banner">Estos son los posts que ganan popularidad en tu servidor.</string> <string name="sk_trending_posts_info_banner">Estos son los posts que ganan popularidad en tu servidor.</string>
<string name="sk_trending_links_info_banner">Estas son las noticias de las que se habla en tu servidor.</string> <string name="sk_trending_links_info_banner">Estas son las noticias de las que se habla en tu servidor.</string>
<string name="sk_blocked_accounts">Cuentas bloqueadas</string>
<string name="sk_muted_accounts">Cuentas silenciadas</string>
</resources> </resources>

View File

@@ -283,7 +283,26 @@
<string name="sk_settings_content_types_explanation">Markdown bezalako eduki-mota ezartzea ahalbidetzen du bidalketa bat sortzerakoan. Gogoan izan instantzia guztiek ez dutela hau baimentzen.</string> <string name="sk_settings_content_types_explanation">Markdown bezalako eduki-mota ezartzea ahalbidetzen du bidalketa bat sortzerakoan. Gogoan izan instantzia guztiek ez dutela hau baimentzen.</string>
<string name="sk_settings_default_content_type">Eduki-mota lehenetsia</string> <string name="sk_settings_default_content_type">Eduki-mota lehenetsia</string>
<string name="sk_settings_confirm_before_reblog">Berretsi bultzatu aurretik</string> <string name="sk_settings_confirm_before_reblog">Berretsi bultzatu aurretik</string>
<string name="sk_reacted_with">%s bezala erreakzionatuta</string> <string name="sk_reacted_with">%1$s-(e)k honela erreakzionatu du: %2$s</string>
<string name="sk_reacted">erreakzionatuta</string> <string name="sk_reacted">%s-(e)k erreakzionatu du</string>
<string name="sk_timeline_bubble">Burbuila</string> <string name="sk_timeline_bubble">Burbuila</string>
<string name="sk_edit_timeline_tags_hint">Sartu traolak…</string>
<string name="sk_add_timeline">Gehitu denbora-lerroa</string>
<string name="sk_edit_timeline_tags_explanation">Jakin eragiketa hauek zerbitzariak kudeatzen dituela. Litekeena da konbinazioetarako euskarririk ez izatea.</string>
<string name="sk_settings_unifiedpush_no_distributor_body">Banatzaile bat instalatu behar duzu UnifiedPush jakinarazpenek funtzionatzeko. Informazio gehiago: https://unifiedpush.org/</string>
<string name="sk_icon_feed">Jarioa</string>
<string name="sk_edit_timeline_tag_main">Traola hau duten tootak…</string>
<string name="sk_icon_verified">Egiaztatua</string>
<string name="sk_hashtag_timeline_local_only_switch">Erakutsi toot lokalak soilik\?</string>
<string name="sk_icon_umbrella">Euritakoa</string>
<string name="sk_settings_unifiedpush_no_distributor">Ez da banatzailerik aurkitu</string>
<string name="sk_edit_timeline_tag_any">...edo hauetako edozein</string>
<string name="sk_edit_timeline_tag_all">...eta hauek guztiak</string>
<string name="sk_icon_diamond">Diamantea</string>
<string name="sk_edit_timeline_tag_hint">Sartu traola…</string>
<string name="sk_edit_timeline_tag_none">...baina hauetako bat ere ez</string>
<string name="sk_settings_unifiedpush_choose">Aukeratu banatzaile bat</string>
<string name="sk_icon_recycle_bin">Zakarrontzia</string>
<string name="sk_trending_links_info_banner">Hauek dira zure zerbitzarian komentatzen ari diren albisteak</string>
<string name="sk_add_timeline_tag_error_empty">Traola ezin da hutsik egon</string>
</resources> </resources>

View File

@@ -9,7 +9,7 @@
<string name="preparing_auth">Valmistellaan todennusta…</string> <string name="preparing_auth">Valmistellaan todennusta…</string>
<string name="finishing_auth">Viimeistellään todennusta…</string> <string name="finishing_auth">Viimeistellään todennusta…</string>
<string name="user_boosted">%s tehosti</string> <string name="user_boosted">%s tehosti</string>
<string name="in_reply_to">Vastauksessa %s</string> <string name="in_reply_to">Vastaus käyttäjälle %s</string>
<string name="notifications">Ilmoitukset</string> <string name="notifications">Ilmoitukset</string>
<string name="user_followed_you">%s seurasi sinua</string> <string name="user_followed_you">%s seurasi sinua</string>
<string name="user_sent_follow_request">%s lähetti sinulle seurauspyynnön</string> <string name="user_sent_follow_request">%s lähetti sinulle seurauspyynnön</string>
@@ -228,7 +228,7 @@
<string name="button_reblog">Tehosta</string> <string name="button_reblog">Tehosta</string>
<string name="button_favorite">Suosikki</string> <string name="button_favorite">Suosikki</string>
<string name="button_share">Jaa</string> <string name="button_share">Jaa</string>
<string name="media_no_description">Kuva ilma kuvausta</string> <string name="media_no_description">Kuva ilman kuvausta</string>
<string name="add_media">Lisää mediatiedosto</string> <string name="add_media">Lisää mediatiedosto</string>
<string name="add_poll">Lisää kysely</string> <string name="add_poll">Lisää kysely</string>
<string name="emoji">Emoji</string> <string name="emoji">Emoji</string>
@@ -240,8 +240,8 @@
<string name="followed_user">Seuraat nyt käyttäjää %s</string> <string name="followed_user">Seuraat nyt käyttäjää %s</string>
<string name="following_user_requested">Käyttäjän %s seuraamista pyydetty</string> <string name="following_user_requested">Käyttäjän %s seuraamista pyydetty</string>
<string name="open_in_browser">Avaa selaimessa</string> <string name="open_in_browser">Avaa selaimessa</string>
<string name="hide_boosts_from_user">Piilota käyttäjän @%s tehostukset</string> <string name="hide_boosts_from_user">Piilota käyttäjän %s tehostukset</string>
<string name="show_boosts_from_user">Näytä tehostukset käyttäjältä @%s</string> <string name="show_boosts_from_user">Näytä tehostukset käyttäjältä %s</string>
<string name="signup_reason">Miksi haluat liittyä?</string> <string name="signup_reason">Miksi haluat liittyä?</string>
<string name="signup_reason_note">Tämä auttaa meitä arvioimaan hakemustasi.</string> <string name="signup_reason_note">Tämä auttaa meitä arvioimaan hakemustasi.</string>
<string name="clear">Tyhjennä</string> <string name="clear">Tyhjennä</string>
@@ -270,11 +270,11 @@
<string name="manually_approves_followers">Hyväksyy seuraajat käsin</string> <string name="manually_approves_followers">Hyväksyy seuraajat käsin</string>
<!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators --> <!-- translators: %,d is a valid placeholder, it formats the number with locale-dependent grouping separators -->
<plurals name="x_followers"> <plurals name="x_followers">
<item quantity="one">%d seuraaja</item> <item quantity="one">%,d seuraaja</item>
<item quantity="other">%d seuraajaa</item> <item quantity="other">%,d seuraajaa</item>
</plurals> </plurals>
<plurals name="x_following"> <plurals name="x_following">
<item quantity="one">%d seurattu</item> <item quantity="one">%,d seurattu</item>
<item quantity="other">%d seurattua</item> <item quantity="other">%d seurattua</item>
</plurals> </plurals>
<plurals name="x_favorites"> <plurals name="x_favorites">
@@ -351,7 +351,7 @@
<string name="server_filter_region_asia">Aasia</string> <string name="server_filter_region_asia">Aasia</string>
<string name="server_filter_region_oceania">Oseania</string> <string name="server_filter_region_oceania">Oseania</string>
<string name="not_accepting_new_members">Ei hyväksy uusia jäseniä</string> <string name="not_accepting_new_members">Ei hyväksy uusia jäseniä</string>
<string name="category_special_interests">Erityiset Kiinnostukset</string> <string name="category_special_interests">Erityiset kiinnostuksen kohteet</string>
<string name="signup_passwords_dont_match">Salasanat eivät täsmää</string> <string name="signup_passwords_dont_match">Salasanat eivät täsmää</string>
<string name="pick_server_for_me">Valitse minulle</string> <string name="pick_server_for_me">Valitse minulle</string>
<string name="profile_add_row">Lisää rivi</string> <string name="profile_add_row">Lisää rivi</string>
@@ -385,7 +385,7 @@
<string name="signup_or_login">tai</string> <string name="signup_or_login">tai</string>
<string name="learn_more">Lue lisää</string> <string name="learn_more">Lue lisää</string>
<string name="welcome_to_mastodon">Tervetuloa Mastodoniin</string> <string name="welcome_to_mastodon">Tervetuloa Mastodoniin</string>
<string name="welcome_paragraph1">Mastodon on hajautettu sosiaalinen verkosto, joka tarkoittaa sitä, ettei sitä hallitse mikään yksittäinen yritys. Se koostuu monista itsenäisesti ylläpidetyistä palvelimista, jotka on liitetty yhteen.</string> <string name="welcome_paragraph1">Mastodon on hajautettu sosiaalinen verkosto, mikä tarkoittaa sitä, ettei sitä hallitse mikään yksittäinen yritys. Se koostuu monista itsenäisesti ylläpidetyistä palvelimista, jotka on liitetty yhteen.</string>
<string name="what_are_servers">Mitä palvelimet ovat?</string> <string name="what_are_servers">Mitä palvelimet ovat?</string>
<string name="welcome_paragraph2">Jokainen Mastodon tili isännöi palvelimella - kullakin on omat arvot, säännöt, &amp; ylläpitäjät. Riippumatta siitä, minkä valitset, voit seurata ja olla vuorovaikutuksessa ihmisten kanssa millä tahansa palvelimella.</string> <string name="welcome_paragraph2">Jokainen Mastodon tili isännöi palvelimella - kullakin on omat arvot, säännöt, &amp; ylläpitäjät. Riippumatta siitä, minkä valitset, voit seurata ja olla vuorovaikutuksessa ihmisten kanssa millä tahansa palvelimella.</string>
<string name="opening_link">Avataan linkki…</string> <string name="opening_link">Avataan linkki…</string>
@@ -583,11 +583,14 @@
<string name="time_hours_ago_short">%dh sitten</string> <string name="time_hours_ago_short">%dh sitten</string>
<string name="time_days_ago_short">%dd sitten</string> <string name="time_days_ago_short">%dd sitten</string>
<!-- %s is the name of the post language --> <!-- %s is the name of the post language -->
<string name="translate_post">Käännetty kielestä %s</string> <string name="translate_post">Käännä kielestä %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service --> <!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Käännetty kielestä %1$s käyttäen %2$s</string> <string name="post_translated">Käännetty kielestä %1$s käyttäen %2$s</string>
<string name="translation_show_original">Näytä alkuperäinen</string> <string name="translation_show_original">Näytä alkuperäinen</string>
<string name="translation_failed">Käännös epäonnistui. Ehkä järjestelmänvalvoja ei ole ottanut käyttöön käännöksiä tällä palvelimella tai tällä palvelimella on käynnissä vanhempi versio Mastodonista, jossa käännöksiä ei vielä tueta.</string> <string name="translation_failed">Käännös epäonnistui. Ehkä järjestelmänvalvoja ei ole ottanut käyttöön käännöksiä tällä palvelimella tai tällä palvelimella on käynnissä vanhempi versio Mastodonista, jossa käännöksiä ei vielä tueta.</string>
<string name="settings_privacy">Yksityisyys ja tavoittavuus</string>
<string name="settings_discoverable">Nosta profiili ja julkaisut esille löytämisalgoritmeissa</string>
<string name="settings_indexable">Sisällytä julkiset julkaisut hakutuloksiin</string>
<plurals name="x_participants"> <plurals name="x_participants">
<item quantity="one">%d osallistuja</item> <item quantity="one">%d osallistuja</item>
<item quantity="other">%d osallistujaa</item> <item quantity="other">%d osallistujaa</item>
@@ -596,4 +599,5 @@
<item quantity="one">%,d viesti tänään</item> <item quantity="one">%,d viesti tänään</item>
<item quantity="other">%,d viestiä tänään</item> <item quantity="other">%,d viestiä tänään</item>
</plurals> </plurals>
<string name="error_playing_video">Virhe videon toistossa</string>
</resources> </resources>

View File

@@ -8,8 +8,8 @@
<string name="sk_settings_emoji_reactions_in_lists_explanation">Näytetäänkö emojireaktiot aikajanoissa. Jos tämä on pois käytöstä, emojireaktiot näkyvät vain lankaa katsottaessa.</string> <string name="sk_settings_emoji_reactions_in_lists_explanation">Näytetäänkö emojireaktiot aikajanoissa. Jos tämä on pois käytöstä, emojireaktiot näkyvät vain lankaa katsottaessa.</string>
<string name="sk_button_react">Reagoi emojilla</string> <string name="sk_button_react">Reagoi emojilla</string>
<string name="sk_again_for_system_keyboard">Järjestelmän näppäimistö seuraavalla painalluksella</string> <string name="sk_again_for_system_keyboard">Järjestelmän näppäimistö seuraavalla painalluksella</string>
<string name="sk_enter_emoji_toast">Tähän tarvitaan emoji</string> <string name="sk_enter_emoji_toast">Lisää emoji</string>
<string name="sk_enter_emoji_hint">Kirjoita vastataksesi emojilla</string> <string name="sk_enter_emoji_hint">Lisää emoji tai etsi</string>
<string name="sk_mute_label">Kesto</string> <string name="sk_mute_label">Kesto</string>
<string name="sk_duration_indefinite">Loputon</string> <string name="sk_duration_indefinite">Loputon</string>
<string name="sk_duration_minutes_5">5 minuuttia</string> <string name="sk_duration_minutes_5">5 minuuttia</string>
@@ -42,7 +42,7 @@
<string name="sk_settings_auto_reveal_equal_spoilers">Avaa automaattisesti samat sisältövaroitukset vastauksissa</string> <string name="sk_settings_auto_reveal_equal_spoilers">Avaa automaattisesti samat sisältövaroitukset vastauksissa</string>
<string name="sk_settings_auto_reveal_nobody">Ei koskaan</string> <string name="sk_settings_auto_reveal_nobody">Ei koskaan</string>
<string name="sk_settings_auto_reveal_author">Saman tilin vastauksissa</string> <string name="sk_settings_auto_reveal_author">Saman tilin vastauksissa</string>
<string name="sk_settings_auto_reveal_anyone">Kaikkien vastauksissa</string> <string name="sk_settings_auto_reveal_anyone">Kaikkien vastaukset</string>
<string name="sk_settings_translate_only_opened">Käännä vain avatut viestit</string> <string name="sk_settings_translate_only_opened">Käännä vain avatut viestit</string>
<string name="sk_translate_show_original">Näytä alkuperäinen</string> <string name="sk_translate_show_original">Näytä alkuperäinen</string>
<string name="sk_available_languages">Käytettävissä olevat kielet</string> <string name="sk_available_languages">Käytettävissä olevat kielet</string>
@@ -69,7 +69,7 @@
<string name="sk_settings_allow_remote_loading">Hae tietoa etäinstansseista</string> <string name="sk_settings_allow_remote_loading">Hae tietoa etäinstansseista</string>
<string name="sk_forward_report_to">Lähetä edelleen kohteeseen %s</string> <string name="sk_forward_report_to">Lähetä edelleen kohteeseen %s</string>
<string name="sk_unsent_posts">Julkaisemattomat viestit</string> <string name="sk_unsent_posts">Julkaisemattomat viestit</string>
<string name="sk_settings_prefix_replies_always">Vastauksissa kaikille</string> <string name="sk_settings_prefix_replies_always">Vastaus kenelle tahansa</string>
<string name="sk_settings_prefix_replies_never">Ei koskaan</string> <string name="sk_settings_prefix_replies_never">Ei koskaan</string>
<string name="sk_confirm_save_draft">Tallenna luonnos\?</string> <string name="sk_confirm_save_draft">Tallenna luonnos\?</string>
<string name="sk_confirm_save_changes">Tallenna muutokset\?</string> <string name="sk_confirm_save_changes">Tallenna muutokset\?</string>
@@ -97,7 +97,7 @@
<string name="sk_settings_about_instance">Tietoja instanssista</string> <string name="sk_settings_about_instance">Tietoja instanssista</string>
<string name="sk_settings_single_notification">Näytä vain yksi ilmoitus</string> <string name="sk_settings_single_notification">Näytä vain yksi ilmoitus</string>
<string name="sk_create">Luo</string> <string name="sk_create">Luo</string>
<string name="sk_in_reply">Vastauksena</string> <string name="sk_in_reply">Vastaus</string>
<string name="sk_delete_list_confirm">Oletko varma että haluat poistaa listan \"%s\"\?</string> <string name="sk_delete_list_confirm">Oletko varma että haluat poistaa listan \"%s\"\?</string>
<string name="sk_remove_follower">Poista seuraajista</string> <string name="sk_remove_follower">Poista seuraajista</string>
<string name="sk_icon_cat">Kissa</string> <string name="sk_icon_cat">Kissa</string>
@@ -132,7 +132,7 @@
<string name="sk_settings_reply_visibility">Vastauksen näkyvyys</string> <string name="sk_settings_reply_visibility">Vastauksen näkyvyys</string>
<string name="sk_settings_reply_visibility_all">Kaikki vastaukset</string> <string name="sk_settings_reply_visibility_all">Kaikki vastaukset</string>
<string name="sk_show_thread">Näytä lanka</string> <string name="sk_show_thread">Näytä lanka</string>
<string name="sk_reply_line_above_avatar">\"Vastauksena\" -rivi käyttäjäkuvakkeen yläpuolella</string> <string name="sk_reply_line_above_avatar">\"Vastaus\" -rivi käyttäjäkuvakkeen yläpuolella</string>
<string name="sk_compact_reblog_reply_line">Tiivistetty tehostus/vastaus-rivi</string> <string name="sk_compact_reblog_reply_line">Tiivistetty tehostus/vastaus-rivi</string>
<plurals name="sk_users_reacted_with"> <plurals name="sk_users_reacted_with">
<item quantity="one">Yksi käyttäjä reagoi näin: %2$s</item> <item quantity="one">Yksi käyttäjä reagoi näin: %2$s</item>
@@ -282,7 +282,7 @@
<string name="sk_unfinished_attachments">Korjataanko liitteet\?</string> <string name="sk_unfinished_attachments">Korjataanko liitteet\?</string>
<string name="sk_content_type_bbcode">BBCode</string> <string name="sk_content_type_bbcode">BBCode</string>
<string name="sk_content_type_mfm">MFM</string> <string name="sk_content_type_mfm">MFM</string>
<string name="sk_settings_prefix_replies_to_others">Vain vastauksissa muille</string> <string name="sk_settings_prefix_replies_to_others">Vastaukset muille</string>
<string name="sk_exclusive_list">Erillinen lista</string> <string name="sk_exclusive_list">Erillinen lista</string>
<string name="sk_list_exclusive_switch">Tee listasta erillinen</string> <string name="sk_list_exclusive_switch">Tee listasta erillinen</string>
<string name="sk_list_exclusive_switch_explanation">Erillisen listan jäsenet eivät näy kotiaikajanallasi jos instanssisi tukee tätä.</string> <string name="sk_list_exclusive_switch_explanation">Erillisen listan jäsenet eivät näy kotiaikajanallasi jos instanssisi tukee tätä.</string>
@@ -359,7 +359,7 @@
<string name="sk_scheduled_too_soon">Julkaisu on ajastettava vähintään 10 minuuttia tulevaisuuteen.</string> <string name="sk_scheduled_too_soon">Julkaisu on ajastettava vähintään 10 minuuttia tulevaisuuteen.</string>
<string name="sk_confirm_unpin_post">Oletko varma että haluat irrottaa tämän viestin\?</string> <string name="sk_confirm_unpin_post">Oletko varma että haluat irrottaa tämän viestin\?</string>
<string name="sk_settings_unifiedpush_no_distributor_body">On asennettava jakelijaohjelma jotta UnifiedPush-ilmoitukset toimivat. Lisätietoja: https://unifiedpush.org/</string> <string name="sk_settings_unifiedpush_no_distributor_body">On asennettava jakelijaohjelma jotta UnifiedPush-ilmoitukset toimivat. Lisätietoja: https://unifiedpush.org/</string>
<string name="sk_settings_emoji_reactions_explanation">Näyttää viestien emojireaktiot ja mahdollistaa vuorovaikutuksen niiden kanssa. Jotkin Mastodonin muokatut versiot tukevat tätä, mutta Mastodon ei.</string> <string name="sk_settings_emoji_reactions_explanation">Näyttää viestien emojireaktiot ja mahdollistaa omien lisäämisen. Jotkin Mastodonin muokatut versiot tukevat tätä, mutta Mastodon ei.</string>
<string name="sk_recent_searches_placeholder">Hae kirjoittamalla tähän</string> <string name="sk_recent_searches_placeholder">Hae kirjoittamalla tähän</string>
<string name="sk_alt_text_missing">Selitys puuttuu vähintään yhdestä liitteestä.</string> <string name="sk_alt_text_missing">Selitys puuttuu vähintään yhdestä liitteestä.</string>
<string name="sk_pinned_timeline">Kiinnitetty kotinäyttöön</string> <string name="sk_pinned_timeline">Kiinnitetty kotinäyttöön</string>
@@ -375,4 +375,38 @@
<string name="sk_settings_support_local_only">Palvelin tukee paikallista julkaisemista</string> <string name="sk_settings_support_local_only">Palvelin tukee paikallista julkaisemista</string>
<string name="sk_settings_continues_playback_summary">Anna mediatoiston jatkua lisäten uusi raita</string> <string name="sk_settings_continues_playback_summary">Anna mediatoiston jatkua lisäten uusi raita</string>
<string name="sk_quoting_user">Lainaus %s</string> <string name="sk_quoting_user">Lainaus %s</string>
<plurals name="sk_time_seconds">
<item quantity="one">%d sekunti</item>
<item quantity="other">%d sekuntia</item>
</plurals>
<string name="sk_settings_show_emoji_reactions_only_opened">Vain kun julkaisu on avattu</string>
<plurals name="sk_time_hours">
<item quantity="one">%d tunti</item>
<item quantity="other">%d tuntia</item>
</plurals>
<string name="sk_settings_show_emoji_reactions_hide_empty">Piilota tyhjät emojireaktiot</string>
<string name="sk_settings_show_emoji_reactions">Näytä emojireaktiot aikajanoissa</string>
<string name="sk_blocked_accounts">Estetyt tilit</string>
<string name="sk_suicide_search_terms">Itsemurha</string>
<string name="sk_load_missing_posts_above">Lataa uudempia julkaisuja</string>
<plurals name="sk_time_days">
<item quantity="one">%d päivä</item>
<item quantity="other">%d päivää</item>
</plurals>
<string name="sk_settings_show_emoji_reactions_always">Näytä lisäyspainike aina</string>
<string name="sk_search_suicide_hotlines">Löydä kriisipuhelin</string>
<string name="sk_muted_accounts">Hiljennetyt tilit</string>
<string name="sk_do_not_show_again">Älä näytä toista kertaa</string>
<string name="sk_suicide_helplines_url">https://mieli.fi/tukea-ja-apua/kriisipuhelin/</string>
<string name="sk_trending_posts_info_banner">Nämä julkaisut ovat saamassa vetoa Fediversumissa.</string>
<string name="sk_load_missing_posts_below">Lataa vanhempia julkaisuja</string>
<string name="sk_search_suicide_title">Jos tarvitset apua…</string>
<plurals name="sk_time_minutes">
<item quantity="one">%d minuutti</item>
<item quantity="other">%d minuuttia</item>
</plurals>
<string name="sk_search_suicide_message">Jos haluat merkin siitä, että elämää kannattaa jatkaa, tämä on se. Jos olet hädässä, voit ottaa yhteyttä paikalliseen kriisipuhelimeen.</string>
<string name="sk_trending_links_info_banner">Näistä uutisjutuista keskustellaan Fediversumissa.</string>
<string name="sk_post_contains_media">Julkaisussa on mediaa</string>
<string name="sk_settings_like_icon">Käytä sydäntä suosikkikuvakkeena</string>
</resources> </resources>

View File

@@ -372,7 +372,7 @@
</plurals> </plurals>
<string name="sk_button_react">Réagissez avec des emojis</string> <string name="sk_button_react">Réagissez avec des emojis</string>
<string name="sk_again_for_system_keyboard">Appuyez à nouveau pour le clavier système</string> <string name="sk_again_for_system_keyboard">Appuyez à nouveau pour le clavier système</string>
<string name="sk_enter_emoji_hint">Tapez pour réagir avec un emoji</string> <string name="sk_enter_emoji_hint">Tapez un emoji ou effectuez une recherche</string>
<string name="sk_enter_emoji_toast">Veuillez saisir un emoji</string> <string name="sk_enter_emoji_toast">Veuillez saisir un emoji</string>
<plurals name="sk_posts_count_label"> <plurals name="sk_posts_count_label">
<item quantity="one">message</item> <item quantity="one">message</item>
@@ -393,12 +393,15 @@
<string name="sk_suicide_search_terms">Suicide</string> <string name="sk_suicide_search_terms">Suicide</string>
<string name="sk_search_suicide_title">Dans le cas où vous seriez en détresse…</string> <string name="sk_search_suicide_title">Dans le cas où vous seriez en détresse…</string>
<string name="sk_search_suicide_message">Si vous cherchez un signe pour ne pas vous suicider, le voici. Si vous êtes en détresse et/ou avez des pensées suicidaires, si vous voulez aider une personne en souffrance, vous pouvez contacter une ligne d\'assistance de prévention du suicide.</string> <string name="sk_search_suicide_message">Si vous cherchez un signe pour ne pas vous suicider, le voici. Si vous êtes en détresse et/ou avez des pensées suicidaires, si vous voulez aider une personne en souffrance, vous pouvez contacter une ligne d\'assistance de prévention du suicide.</string>
<string name="sk_trending_links_info_banner">Ce sont les actualités dont on parle sur votre serveur.</string> <string name="sk_trending_links_info_banner">Ces actualités font parler delles dans tout le Fediverse.</string>
<string name="sk_load_missing_posts_above">Charger les messages les plus récents</string> <string name="sk_load_missing_posts_above">Charger les messages les plus récents</string>
<string name="sk_load_missing_posts_below">Charger les anciens messages</string> <string name="sk_load_missing_posts_below">Charger les anciens messages</string>
<string name="sk_time_seconds">%d secondes</string> <string name="sk_time_seconds">%d secondes</string>
<string name="sk_time_minutes">%d minutes</string> <string name="sk_time_minutes">%d minutes</string>
<string name="sk_time_hours">%d heures</string> <string name="sk_time_hours">%d heures</string>
<string name="sk_time_days">%d jours</string> <string name="sk_time_days">%d jours</string>
<string name="sk_trending_posts_info_banner">Ce sont les publications qui gagnent du terrain sur votre serveur.</string> <string name="sk_trending_posts_info_banner">Ces publications gagnent actuellement du terrain sur le Fediverse.</string>
<string name="sk_blocked_accounts">Comptes bloqués</string>
<string name="sk_muted_accounts">Comptes silenciés</string>
<string name="sk_settings_like_icon">Utiliser le cœur comme icône pour les favoris</string>
</resources> </resources>

View File

@@ -13,6 +13,7 @@
<string name="user_sent_follow_request">%s հետեւելու հարցում է ուղարկել</string> <string name="user_sent_follow_request">%s հետեւելու հարցում է ուղարկել</string>
<string name="user_favorited">%s-ը հավանեց ձեր գրառումը</string> <string name="user_favorited">%s-ը հավանեց ձեր գրառումը</string>
<string name="notification_boosted">%s տարածեց ձեր գրառումը</string> <string name="notification_boosted">%s տարածեց ձեր գրառումը</string>
<string name="poll_ended">Տեսեք ձեր քվեարկած հարցման արդյունքները</string>
<string name="share_toot_title">Տարածել</string> <string name="share_toot_title">Տարածել</string>
<string name="settings">Կարգավորումներ</string> <string name="settings">Կարգավորումներ</string>
<string name="publish">Հրապարակել</string> <string name="publish">Հրապարակել</string>
@@ -102,6 +103,7 @@
<string name="deleting">Ջնջում…</string> <string name="deleting">Ջնջում…</string>
<string name="play">Նվագարկել</string> <string name="play">Նվագարկել</string>
<string name="pause">Դադար տալ</string> <string name="pause">Դադար տալ</string>
<string name="log_out">Ելք</string>
<string name="add_account">Ավելացնել հաշիվ</string> <string name="add_account">Ավելացնել հաշիվ</string>
<string name="search_hint">Որոնել</string> <string name="search_hint">Որոնել</string>
<string name="hashtags">Պիտակներ</string> <string name="hashtags">Պիտակներ</string>

View File

@@ -554,5 +554,18 @@
<string name="time_hours_ago_short">%dj yang lalu</string> <string name="time_hours_ago_short">%dj yang lalu</string>
<string name="time_days_ago_short">%dh yang lalu</string> <string name="time_days_ago_short">%dh yang lalu</string>
<!-- %s is the name of the post language --> <!-- %s is the name of the post language -->
<string name="translate_post">Terjemahkan dari bahasa %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service --> <!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Diterjemahkan dari bahasa %1$s menggunakan %2$s</string>
<string name="translation_show_original">Tampilkan yang asli</string>
<string name="translation_failed">Terjemahan gagal. Administrator mungkin belum mengaktifkan terjemahan di server ini atau server ini menjalankan Mastodon versi lama yang belum mendukung terjemahan.</string>
<string name="settings_privacy">Privasi dan jangkauan</string>
<string name="settings_discoverable">Fiturkan profil dan kiriman dalam algoritma penjelajahan</string>
<string name="settings_indexable">Sertakan kiriman publik dalam hasil pencarian</string>
<plurals name="x_participants">
<item quantity="other">%,d peserta</item>
</plurals>
<plurals name="x_posts_today">
<item quantity="other">%,d kiriman hari ini</item>
</plurals>
</resources> </resources>

View File

@@ -366,7 +366,7 @@
<item quantity="other">%1$,d pengguna bereaksi dengan %2$s</item> <item quantity="other">%1$,d pengguna bereaksi dengan %2$s</item>
</plurals> </plurals>
<string name="sk_enter_emoji_toast">Silakan ketik emoji</string> <string name="sk_enter_emoji_toast">Silakan ketik emoji</string>
<string name="sk_enter_emoji_hint">Ketik untuk bereaksi dengan sebuah emoji</string> <string name="sk_enter_emoji_hint">Ketik emoji atau cari</string>
<string name="sk_settings_emoji_reactions">Aktifkan reaksi emoji</string> <string name="sk_settings_emoji_reactions">Aktifkan reaksi emoji</string>
<string name="sk_settings_emoji_reactions_explanation">Menampilkan reaksi emoji di kiriman dan memungkinkan Anda untuk menambahkan sendiri. Banyak server Fediverse yang mendukung ini, tetapi Mastodon tidak mendukungnya.</string> <string name="sk_settings_emoji_reactions_explanation">Menampilkan reaksi emoji di kiriman dan memungkinkan Anda untuk menambahkan sendiri. Banyak server Fediverse yang mendukung ini, tetapi Mastodon tidak mendukungnya.</string>
<string name="sk_settings_emoji_reactions_in_lists_explanation">"Menentukan apakah reaksi emoji ditampilkan di lini masa. Jika opsi ini mati, reaksi emoji hanya akan ditampilkan ketika melihat sebuah utas."</string> <string name="sk_settings_emoji_reactions_in_lists_explanation">"Menentukan apakah reaksi emoji ditampilkan di lini masa. Jika opsi ini mati, reaksi emoji hanya akan ditampilkan ketika melihat sebuah utas."</string>
@@ -387,11 +387,14 @@
<string name="sk_search_suicide_hotlines">Temukan hotline</string> <string name="sk_search_suicide_hotlines">Temukan hotline</string>
<string name="sk_do_not_show_again">Jangan tampilkan lagi</string> <string name="sk_do_not_show_again">Jangan tampilkan lagi</string>
<string name="sk_suicide_helplines_url">https://findahelpline.com/id</string> <string name="sk_suicide_helplines_url">https://findahelpline.com/id</string>
<string name="sk_trending_posts_info_banner">Di bawah adalah kiriman yang mendapatkan daya tarik di server Anda.</string> <string name="sk_trending_posts_info_banner">Kiriman berikut mendapatkan daya tarik di Fediverse.</string>
<string name="sk_load_missing_posts_below">Muat kiriman lama</string> <string name="sk_load_missing_posts_below">Muat kiriman lama</string>
<string name="sk_search_suicide_title">Jika Anda dalam kesulitan…</string> <string name="sk_search_suicide_title">Jika Anda dalam kesulitan…</string>
<string name="sk_time_minutes">%d menit</string> <string name="sk_time_minutes">%d menit</string>
<string name="sk_search_suicide_message">Jika Anda mencari tanda untuk tidak melakukan bunuh diri, ini adalah tanda itu. Tolong pertimbangkan untuk menghubungi hotline bunuh diri lokal jika Anda dalam kesulitan.</string> <string name="sk_search_suicide_message">Jika Anda mencari tanda untuk tidak melakukan bunuh diri, ini adalah tanda itu. Tolong pertimbangkan untuk menghubungi hotline bunuh diri lokal jika Anda dalam kesulitan.</string>
<string name="sk_trending_links_info_banner">Di bawah adalah berita yang dibicarakan di server Anda.</string> <string name="sk_trending_links_info_banner">Berita berikut sedang dibicarakan di Fediverse.</string>
<string name="sk_post_contains_media">Kiriman berisi media</string> <string name="sk_post_contains_media">Kiriman berisi media</string>
<string name="sk_blocked_accounts">Akun yang diblokir</string>
<string name="sk_muted_accounts">Akun yang dibisukan</string>
<string name="sk_settings_like_icon">Gunakam hati sebagai ikon favorit</string>
</resources> </resources>

View File

@@ -599,4 +599,5 @@
<item quantity="one">%,d færsla í dag</item> <item quantity="one">%,d færsla í dag</item>
<item quantity="other">%,d færslur í dag</item> <item quantity="other">%,d færslur í dag</item>
</plurals> </plurals>
<string name="error_playing_video">Villa við að spila myndskeið</string>
</resources> </resources>

View File

@@ -588,6 +588,8 @@
<string name="post_translated">Tradotto da %1$s utilizzando %2$s</string> <string name="post_translated">Tradotto da %1$s utilizzando %2$s</string>
<string name="translation_show_original">Mostra originale</string> <string name="translation_show_original">Mostra originale</string>
<string name="translation_failed">Traduzione fallita. Forse l\'amministratore non ha abilitato le traduzioni su questo server, o su questo server è in esecuzione una versione precedente di Mastodon in cui le traduzioni non sono ancora supportate.</string> <string name="translation_failed">Traduzione fallita. Forse l\'amministratore non ha abilitato le traduzioni su questo server, o su questo server è in esecuzione una versione precedente di Mastodon in cui le traduzioni non sono ancora supportate.</string>
<string name="settings_privacy">Privacy e copertura</string>
<string name="settings_discoverable">Include il profilo e i post negli algoritmi di scoperta</string>
<string name="settings_indexable">Includi i post pubblici nei risultati di ricerca</string> <string name="settings_indexable">Includi i post pubblici nei risultati di ricerca</string>
<plurals name="x_participants"> <plurals name="x_participants">
<item quantity="one">%,d participante</item> <item quantity="one">%,d participante</item>
@@ -597,4 +599,5 @@
<item quantity="one">%,d post oggi</item> <item quantity="one">%,d post oggi</item>
<item quantity="other">%,d post oggi</item> <item quantity="other">%,d post oggi</item>
</plurals> </plurals>
<string name="error_playing_video">Errore nella riproduzione del video</string>
</resources> </resources>

View File

@@ -568,4 +568,5 @@
<plurals name="x_posts_today"> <plurals name="x_posts_today">
<item quantity="other">今日の投稿 %,d 件</item> <item quantity="other">今日の投稿 %,d 件</item>
</plurals> </plurals>
<string name="error_playing_video">動画再生に失敗しました</string>
</resources> </resources>

View File

@@ -572,5 +572,15 @@
<string name="time_hours_ago_short">%dh atrás</string> <string name="time_hours_ago_short">%dh atrás</string>
<string name="time_days_ago_short">%dd atrás</string> <string name="time_days_ago_short">%dd atrás</string>
<!-- %s is the name of the post language --> <!-- %s is the name of the post language -->
<string name="translate_post">Traduzido de %s</string>
<!-- %1$s is the language, %2$s is the name of the translation service --> <!-- %1$s is the language, %2$s is the name of the translation service -->
<string name="post_translated">Traduzido de %1$s usando %2$s</string>
<string name="translation_show_original">Mostrar original</string>
<string name="translation_failed">A tradução falhou. Talvez o administrador não tenha habilitado as traduções neste servidor ou este servidor esteja executando uma versão mais antiga do Mastodon onde as traduções ainda não são suportadas.</string>
<string name="settings_privacy">Privacidade e alcance</string>
<string name="settings_indexable">Incluir publicações públicas nos resultados de pesquisa</string>
<plurals name="x_participants">
<item quantity="one">%,d participante</item>
<item quantity="other">%,d participantes</item>
</plurals>
</resources> </resources>

View File

@@ -379,7 +379,7 @@
<string name="sk_time_days">%d zile</string> <string name="sk_time_days">%d zile</string>
<string name="sk_settings_show_emoji_reactions_always">Afișați mereu butonul adăugare</string> <string name="sk_settings_show_emoji_reactions_always">Afișați mereu butonul adăugare</string>
<string name="sk_search_suicide_hotlines">Găsiți o linie de asistență telefonică</string> <string name="sk_search_suicide_hotlines">Găsiți o linie de asistență telefonică</string>
<string name="sk_enter_emoji_hint">Scrieți pentru a reacționa cu un emoji</string> <string name="sk_enter_emoji_hint">Scrieți un emoji sau căutați emoji personalizat</string>
<string name="sk_do_not_show_again">Nu mai afișați din nou</string> <string name="sk_do_not_show_again">Nu mai afișați din nou</string>
<string name="sk_suicide_helplines_url">http://www.antisuicid.com/</string> <string name="sk_suicide_helplines_url">http://www.antisuicid.com/</string>
<string name="sk_enter_emoji_toast">Vă rugăm scrieți un emoji</string> <string name="sk_enter_emoji_toast">Vă rugăm scrieți un emoji</string>
@@ -397,4 +397,6 @@
<string name="sk_search_suicide_message">Dacă sunteți în căutarea unui semn pentru a nu vă sinucide, acesta este. Vă rugăm să luați în considerare posibilitatea de a apela la o linie telefonică locală de urgență pentru suicid dacă vă aflați în dificultate.</string> <string name="sk_search_suicide_message">Dacă sunteți în căutarea unui semn pentru a nu vă sinucide, acesta este. Vă rugăm să luați în considerare posibilitatea de a apela la o linie telefonică locală de urgență pentru suicid dacă vă aflați în dificultate.</string>
<string name="sk_trending_links_info_banner">Acestea sunt știrile despre care se vorbește pe serverul tău.</string> <string name="sk_trending_links_info_banner">Acestea sunt știrile despre care se vorbește pe serverul tău.</string>
<string name="sk_post_contains_media">Postare conține media</string> <string name="sk_post_contains_media">Postare conține media</string>
<string name="sk_blocked_accounts">Conturi blocate</string>
<string name="sk_muted_accounts">Conturi amuțite</string>
</resources> </resources>

View File

@@ -661,4 +661,5 @@
<item quantity="many">%,d постов сегодня</item> <item quantity="many">%,d постов сегодня</item>
<item quantity="other">%,d постов сегодня</item> <item quantity="other">%,d постов сегодня</item>
</plurals> </plurals>
<string name="error_playing_video">Ошибка воспроизведения видео</string>
</resources> </resources>

View File

@@ -250,7 +250,7 @@
<string name="sk_settings_server_version">Версия сервера: %s</string> <string name="sk_settings_server_version">Версия сервера: %s</string>
<string name="sk_notify_poll_results">Итоги голосования</string> <string name="sk_notify_poll_results">Итоги голосования</string>
<string name="sk_settings_local_only_explanation">Для работы этой функции ваш инстанс должен поддерживать локальные публикации. Большинство модифицированных версий Mastodon это поддерживают, но сам Mastodon нет.</string> <string name="sk_settings_local_only_explanation">Для работы этой функции ваш инстанс должен поддерживать локальные публикации. Большинство модифицированных версий Mastodon это поддерживают, но сам Mastodon нет.</string>
<string name="sk_settings_prefix_reply_cw_with_re">Префикс ответа CW с re:</string> <string name="sk_settings_prefix_reply_cw_with_re">Префикс CW с \"re:\" при ответе</string>
<string name="sk_filtered">Отфильтровано: %s</string> <string name="sk_filtered">Отфильтровано: %s</string>
<string name="sk_expand">Развернуть</string> <string name="sk_expand">Развернуть</string>
<string name="sk_collapse">Свернуть</string> <string name="sk_collapse">Свернуть</string>
@@ -331,4 +331,84 @@
<string name="sk_settings_prefix_replies_to_others">Только в ответ другим</string> <string name="sk_settings_prefix_replies_to_others">Только в ответ другим</string>
<string name="sk_settings_unifiedpush_no_distributor">Распределители не найдены</string> <string name="sk_settings_unifiedpush_no_distributor">Распределители не найдены</string>
<string name="sk_settings_content_types_explanation">Позволяет устанавливать тип содержимого вроде Markdown при создании поста. Имейте в виду, что это поддерживается не на всех серверах.</string> <string name="sk_settings_content_types_explanation">Позволяет устанавливать тип содержимого вроде Markdown при создании поста. Имейте в виду, что это поддерживается не на всех серверах.</string>
<string name="sk_settings_allow_remote_loading_explanation">Пробовать получить более точные данные о подписчиках, избранных и продвижениях, загрузив информацию из экземпляра происхождения.</string>
<string name="sk_settings_default_content_type_explanation">Это позволяет предварительно выбирать тип содержимого при создании новых публикаций, переопределяя значение, установленное в “Параметры публикации”.</string>
<string name="sk_trending_posts_info_banner">Эти посты набирают обороты на вашем сервере.</string>
<string name="sk_settings_continues_playback_summary">Позволять продолжить воспроизведение уже проигрываемого медиа, накладывая его на новое воспроизведение</string>
<string name="sk_settings_continues_playback">Наложение аудио</string>
<string name="sk_trending_links_info_banner">Это новости, которые обсуждаются на вашем сервере.</string>
<string name="sk_disable_pill_shaped_active_indicator">Отключить индикатор активной вкладки в виде таблетки</string>
<string name="sk_tab_profile">Профиль</string>
<plurals name="sk_time_seconds">
<item quantity="one">%d секунда</item>
<item quantity="few">%d секунды</item>
<item quantity="many">%d секунд</item>
<item quantity="other">%d секунд</item>
</plurals>
<string name="sk_mute_label">Длительность</string>
<string name="sk_settings_show_emoji_reactions_only_opened">Только когда пост открыт</string>
<plurals name="sk_time_hours">
<item quantity="one">%d час</item>
<item quantity="few">%d часа</item>
<item quantity="many">%d часов</item>
<item quantity="other">%d часов</item>
</plurals>
<string name="sk_tab_home">Главная</string>
<string name="sk_settings_show_emoji_reactions_hide_empty">Скрывать пустые реакции эмодзи</string>
<string name="sk_settings_show_emoji_reactions">Отображать реакции эмодзи в лентах</string>
<plurals name="sk_posts_count_label">
<item quantity="one">пост</item>
<item quantity="few">поста</item>
<item quantity="many">постов</item>
<item quantity="other">постов</item>
</plurals>
<string name="sk_notification_mention">Вы были упомянуты %s</string>
<string name="sk_settings_emoji_reactions">Включить реакции эмодзи</string>
<string name="sk_suicide_search_terms">Суицид, Самоубийство</string>
<string name="sk_duration_minutes_5">5 минут</string>
<string name="sk_load_missing_posts_above">Загрузить более новые посты</string>
<string name="sk_settings_display_pronouns_in_timelines">Отображать местоимения в лентах</string>
<plurals name="sk_time_days">
<item quantity="one">%d день</item>
<item quantity="few">%d дня</item>
<item quantity="many">%d дней</item>
<item quantity="other">%d дней</item>
</plurals>
<string name="sk_settings_show_labels_in_navigation_bar">Отображать ярлыки вкладок на панели навигации</string>
<string name="sk_tab_search">Поиск</string>
<string name="sk_settings_show_emoji_reactions_always">Всегда показывать кнопку добавить</string>
<string name="sk_duration_indefinite">Бессрочно</string>
<string name="sk_search_suicide_hotlines">Найти службу помощи</string>
<string name="sk_duration_hours_1">1 час</string>
<string name="sk_duration_hours_6">6 часов</string>
<string name="sk_enter_emoji_hint">Введите эмодзи или найдете</string>
<string name="sk_duration_days_7">7 дней</string>
<string name="sk_settings_true_black">Абсолютно черный режим</string>
<string name="sk_do_not_show_again">Не показывать снова</string>
<string name="sk_settings_display_pronouns_in_threads">Отображать местоимения в ответах</string>
<string name="sk_enter_emoji_toast">Пожалуйста введите эмодзи</string>
<string name="sk_duration_minutes_30">30 минут</string>
<string name="sk_settings_display_pronouns_in_user_listings">Отображать местоимения в списках пользователей</string>
<string name="sk_button_react">Отреагировать с эмодзи</string>
<string name="sk_duration_days_1">1 день</string>
<string name="sk_load_missing_posts_below">Загрузить более старые посты</string>
<string name="sk_settings_emoji_reactions_explanation">Отображает реакции эмодзи на посты и позволяет добавлять свои. Различные серверы Fediverse поддерживают эту функцию, но Mastodon нет.</string>
<string name="sk_duration_days_3">3 дня</string>
<string name="sk_search_suicide_title">В случае, если вы попали в беду…</string>
<plurals name="sk_time_minutes">
<item quantity="one">%d минута</item>
<item quantity="few">%d минуты</item>
<item quantity="many">%d минут</item>
<item quantity="other">%d минут</item>
</plurals>
<plurals name="sk_users_reacted_with">
<item quantity="one">Один пользователь отреагировал с %2$s</item>
<item quantity="few">%1$,d пользователей отреагировали с %2$s</item>
<item quantity="many">%1$,d пользователей отреагировали с %2$s</item>
<item quantity="other">%1$,d пользователей отреагировали с %2$s</item>
</plurals>
<string name="sk_search_suicide_message">Если вы ищете знак, чтобы не совершить самоубийство, то это он. Если вы попали в беду, обратитесь в местную службу помощи самоубийцам.</string>
<string name="sk_post_contains_media">Пост содержит медиа</string>
<string name="sk_tab_notifications">Уведомления</string>
<string name="sk_list_exclusive_switch_explanation">Участники эксклюзивного списка не будут отображаться в вашей домашней ленте - если ваш экземпляр поддерживает такую возможность.</string>
</resources> </resources>

View File

@@ -11,7 +11,7 @@
<string name="discard">ඉවතලන්න</string> <string name="discard">ඉවතලන්න</string>
<string name="cancel">අවලංගු</string> <string name="cancel">අවලංගු</string>
<string name="media">මාධ්‍ය</string> <string name="media">මාධ්‍ය</string>
<string name="profile_about">පිිබඳව</string> <string name="profile_about">පිිබඳව</string>
<string name="edit_profile">පැතිකඩ සංස්කරණය</string> <string name="edit_profile">පැතිකඩ සංස්කරණය</string>
<string name="mute_user">%s නිහඬ</string> <string name="mute_user">%s නිහඬ</string>
<string name="unmute_user">%s නොනිහඬ</string> <string name="unmute_user">%s නොනිහඬ</string>

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