Compare commits
88 Commits
upstream/f
...
v2.1.6+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd3de97d55 | ||
|
|
4853a25710 | ||
|
|
eba9a1da7b | ||
|
|
068c62b060 | ||
|
|
5d7f06eba0 | ||
|
|
fed9dec33a | ||
|
|
7973914a5f | ||
|
|
35efb3f047 | ||
|
|
0a4ed50904 | ||
|
|
002c66174a | ||
|
|
22aac3d943 | ||
|
|
872f47305a | ||
|
|
75d5332411 | ||
|
|
035da8a517 | ||
|
|
4c2c877d41 | ||
|
|
0cc8cddfc3 | ||
|
|
4428ef7ac2 | ||
|
|
44912b7982 | ||
|
|
c930db6068 | ||
|
|
d96d4dd581 | ||
|
|
67e3a5bb47 | ||
|
|
b0a5aa93e1 | ||
|
|
0bc1459898 | ||
|
|
fae25e93a5 | ||
|
|
c0c121050c | ||
|
|
afe572ca7f | ||
|
|
8cb4db5fcf | ||
|
|
de235ec7cc | ||
|
|
140c2a7b9d | ||
|
|
c833513344 | ||
|
|
1e95536208 | ||
|
|
b58fda9795 | ||
|
|
3135aef398 | ||
|
|
c83dc51322 | ||
|
|
9cfaed89e6 | ||
|
|
5374ac766c | ||
|
|
98596e77f2 | ||
|
|
54aa89c7f8 | ||
|
|
f59157b160 | ||
|
|
6b38db9607 | ||
|
|
53afc120f3 | ||
|
|
c10cdfd795 | ||
|
|
c2184e7bd8 | ||
|
|
baf756e163 | ||
|
|
efc67fd7e8 | ||
|
|
43e737425a | ||
|
|
b5b3cb42a1 | ||
|
|
f72f7cb831 | ||
|
|
f86d60be23 | ||
|
|
7c8624bd53 | ||
|
|
a75ce70615 | ||
|
|
331548b38d | ||
|
|
8b8f192dfa | ||
|
|
061b2ee3de | ||
|
|
5ea2864bd5 | ||
|
|
ee2b4b6a1f | ||
|
|
697f801c1a | ||
|
|
ebb49c44fe | ||
|
|
bc4619e6b1 | ||
|
|
4a3b948760 | ||
|
|
f81283c892 | ||
|
|
7eae879037 | ||
|
|
1b0ce5d893 | ||
|
|
5d26ea85e9 | ||
|
|
6efe263dd8 | ||
|
|
0379347f2d | ||
|
|
1299b2ad42 | ||
|
|
f3b3bcaa0a | ||
|
|
b1bec870c5 | ||
|
|
36e05a6d14 | ||
|
|
2e11f78e9d | ||
|
|
9fcfbe5593 | ||
|
|
c17745368d | ||
|
|
e78b518654 | ||
|
|
55a8634be2 | ||
|
|
ac891eea53 | ||
|
|
74fa2a3081 | ||
|
|
6c1c5b7759 | ||
|
|
1f4152b588 | ||
|
|
70386ea1b2 | ||
|
|
cbce90c461 | ||
|
|
74ae3bf706 | ||
|
|
1feccdc26d | ||
|
|
c38c2a425b | ||
|
|
f43352b790 | ||
|
|
c5b52b2781 | ||
|
|
b91840fb95 | ||
|
|
e40841c128 |
@@ -15,8 +15,8 @@ android {
|
||||
applicationId "org.joinmastodon.android.sk"
|
||||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 100
|
||||
versionName "2.1.4+fork.100"
|
||||
versionCode 102
|
||||
versionName "2.1.6+fork.102"
|
||||
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']
|
||||
}
|
||||
@@ -70,7 +70,7 @@ dependencies {
|
||||
implementation 'me.grishka.litex:viewpager:1.0.0'
|
||||
implementation 'me.grishka.litex:viewpager2: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 'org.jsoup:jsoup:1.14.3'
|
||||
implementation 'com.squareup:otto:1.3.8'
|
||||
|
||||
@@ -1,56 +1,43 @@
|
||||
13bells.com
|
||||
1611.social
|
||||
4aem.com
|
||||
5dollah.click
|
||||
adachi.party
|
||||
anime.website
|
||||
adtension.com
|
||||
annihilation.social
|
||||
anon-kenkai.com
|
||||
asbestos.cafe
|
||||
bae.st
|
||||
bajax.us
|
||||
banepo.st
|
||||
baraag.net
|
||||
bassam.social
|
||||
battlepenguin.video
|
||||
beefyboys.win
|
||||
beepboop.ga
|
||||
berserker.town
|
||||
bikeshed.party
|
||||
boks.moe
|
||||
boymoder.biz
|
||||
brainsoap.net
|
||||
breastmilk.club
|
||||
brighteon.social
|
||||
bungle.online
|
||||
cachapa.xyz
|
||||
canary.fedinuke.example.com
|
||||
catgirl.life
|
||||
cawfee.club
|
||||
childlove.space
|
||||
clew.lol
|
||||
clubcyberia.co
|
||||
collapsitarian.io
|
||||
comfyboy.club
|
||||
contrapointsfan.club
|
||||
crucible.world
|
||||
cum.camp
|
||||
cum.salon
|
||||
darknight-coffee.org
|
||||
decayable.ink
|
||||
dembased.xyz
|
||||
desupost.soy
|
||||
detroitriotcity.com
|
||||
eatthebugs.social
|
||||
djsumdog.com
|
||||
eientei.org
|
||||
elementality.org
|
||||
eveningzoo.club
|
||||
firedragonstudios.com
|
||||
firefaithfellowship.com
|
||||
fluf.club
|
||||
foxfam.club
|
||||
freak.university
|
||||
freeatlantis.com
|
||||
freedomstrike.org
|
||||
freesoftwareextremist.com
|
||||
freespeech.group
|
||||
freespeechextremist.com
|
||||
freetalklive.com
|
||||
froth.zone
|
||||
fulltermprivacy.com
|
||||
gameliberty.club
|
||||
gearlandia.haus
|
||||
genderheretics.xyz
|
||||
@@ -59,42 +46,34 @@ gleasonator.com
|
||||
glee.li
|
||||
glindr.org
|
||||
goyim.app
|
||||
goyslop.cafe
|
||||
h5q.net
|
||||
haeder.net
|
||||
handholding.io
|
||||
hitchhiker.social
|
||||
hunk.city
|
||||
iddqd.social
|
||||
intkos.link
|
||||
justicewarrior.social
|
||||
kawa-kun.com
|
||||
kitsunemimi.club
|
||||
kiwifarms.cc
|
||||
kompost.cz
|
||||
kurosawa.moe
|
||||
kyaruc.moe
|
||||
leafposter.club
|
||||
leftychan.net
|
||||
lewdieheaven.com
|
||||
liberdon.com
|
||||
ligma.pro
|
||||
lolicon.rocks
|
||||
lolison.network
|
||||
lolison.top
|
||||
lovingexpressions.net
|
||||
mahodou.moe
|
||||
makemysarcophagus.com
|
||||
maladaptive.art
|
||||
marsey.moe
|
||||
masochi.st
|
||||
mastinator.com
|
||||
merovingian.club
|
||||
midwaytrades.com
|
||||
mirr0r.city
|
||||
moa.st
|
||||
morale.ch
|
||||
mouse.services
|
||||
mugicha.club
|
||||
narrativerry.xyz
|
||||
natehiggers.online
|
||||
neckbeard.xyz
|
||||
needs.vodka
|
||||
neenster.org
|
||||
nicecrew.digital
|
||||
@@ -103,18 +82,18 @@ noagendasocial.com
|
||||
noagendasocial.nl
|
||||
noagendatube.com
|
||||
nobodyhasthe.biz
|
||||
nukem.biz
|
||||
obo.sh
|
||||
norwoodzero.net
|
||||
nyanide.com
|
||||
onionfarms.org
|
||||
pawlicker.com
|
||||
pawoo.net
|
||||
pedo.school
|
||||
peervideo.club
|
||||
piazza.today
|
||||
pibvt.net
|
||||
pieville.net
|
||||
pisskey.io
|
||||
plagu.ee
|
||||
pmth.us
|
||||
poa.st
|
||||
poast.org
|
||||
poast.tv
|
||||
@@ -123,17 +102,18 @@ prospeech.space
|
||||
quodverum.com
|
||||
r18.social
|
||||
rakket.app
|
||||
rapemeat.express
|
||||
rapemeat.solutions
|
||||
rdrama.cc
|
||||
rayci.st
|
||||
rebelbase.site
|
||||
retardedniggers.forsale
|
||||
rojogato.com
|
||||
ryona.agency
|
||||
sad.cab
|
||||
schwartzwelt.xyz
|
||||
seal.cafe
|
||||
shaw.app
|
||||
shigusegubu.club
|
||||
shitpost.cloud
|
||||
shota.house
|
||||
shortstacksran.ch
|
||||
silliness.observer
|
||||
skinheads.eu
|
||||
skinheads.io
|
||||
@@ -148,23 +128,20 @@ sneed.social
|
||||
sonichu.com
|
||||
spinster.xyz
|
||||
springbo.cc
|
||||
starnix.network
|
||||
strelizia.net
|
||||
syspxl.xyz
|
||||
tastingtraffic.net
|
||||
teci.world
|
||||
theapex.social
|
||||
thechimp.zone
|
||||
thenobody.club
|
||||
thepostearthdestination.com
|
||||
tkammer.de
|
||||
trumpislovetrumpis.life
|
||||
truthsocial.co.in
|
||||
urchan.org
|
||||
usualsuspects.lol
|
||||
varishangout.net
|
||||
whinge.house
|
||||
whinge.town
|
||||
wideboys.org
|
||||
vtuberfan.social
|
||||
wolfgirl.bar
|
||||
xn--p1abe3d.xn--80asehdb
|
||||
yggdrasil.social
|
||||
youjo.love
|
||||
zztails.gay
|
||||
|
||||
@@ -32,7 +32,6 @@ public class ExternalShareActivity extends FragmentStackActivity{
|
||||
UiUtils.setUserPreferredTheme(this);
|
||||
super.onCreate(savedInstanceState);
|
||||
if(savedInstanceState==null){
|
||||
|
||||
Optional<String> text = Optional.ofNullable(getIntent().getStringExtra(Intent.EXTRA_TEXT));
|
||||
Optional<Pair<String, Optional<String>>> fediHandle = text.flatMap(UiUtils::parseFediverseHandle);
|
||||
boolean isFediUrl = text.map(UiUtils::looksLikeFediverseUrl).orElse(false);
|
||||
|
||||
@@ -57,7 +57,6 @@ public class GlobalUserPreferences{
|
||||
public static boolean allowRemoteLoading;
|
||||
public static boolean forwardReportDefault;
|
||||
public static AutoRevealMode autoRevealEqualSpoilers;
|
||||
public static ColorPreference color;
|
||||
public static boolean disableM3PillActiveIndicator;
|
||||
public static boolean showNavigationLabels;
|
||||
public static boolean displayPronounsInTimelines, displayPronounsInThreads, displayPronounsInUserListings;
|
||||
@@ -133,14 +132,8 @@ public class GlobalUserPreferences{
|
||||
.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) < 101) migrateToVersion101();
|
||||
}
|
||||
|
||||
public static void save(){
|
||||
@@ -171,7 +164,6 @@ public class GlobalUserPreferences{
|
||||
.putBoolean("spectatorMode", spectatorMode)
|
||||
.putBoolean("autoHideFab", autoHideFab)
|
||||
.putBoolean("compactReblogReplyLine", compactReblogReplyLine)
|
||||
.putString("color", color.name())
|
||||
.putBoolean("allowRemoteLoading", allowRemoteLoading)
|
||||
.putString("autoRevealEqualSpoilers", autoRevealEqualSpoilers.name())
|
||||
.putBoolean("forwardReportDefault", forwardReportDefault)
|
||||
@@ -185,6 +177,16 @@ public class GlobalUserPreferences{
|
||||
.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(){
|
||||
Log.d(TAG, "Migrating preferences to upstream version 61!!");
|
||||
|
||||
@@ -235,30 +237,6 @@ public class GlobalUserPreferences{
|
||||
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{
|
||||
AUTO,
|
||||
LIGHT,
|
||||
|
||||
@@ -39,7 +39,8 @@ import me.grishka.appkit.api.ErrorResponse;
|
||||
public class MainActivity extends FragmentStackActivity implements ProvidesAssistContent {
|
||||
@Override
|
||||
protected void onCreate(@Nullable Bundle savedInstanceState){
|
||||
UiUtils.setUserPreferredTheme(this);
|
||||
AccountSession session=getCurrentSession();
|
||||
UiUtils.setUserPreferredTheme(this, session);
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if(savedInstanceState==null){
|
||||
@@ -217,6 +218,36 @@ public class MainActivity extends FragmentStackActivity implements ProvidesAssis
|
||||
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(){
|
||||
if(AccountSessionManager.getInstance().getLoggedInAccounts().isEmpty()){
|
||||
showFragmentClearingBackStack(new CustomWelcomeFragment());
|
||||
|
||||
@@ -74,7 +74,6 @@ public class CacheController{
|
||||
result.add(status);
|
||||
}while(cursor.moveToNext());
|
||||
String _newMaxID=newMaxID;
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.HOME);
|
||||
uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
|
||||
return;
|
||||
}
|
||||
@@ -86,9 +85,7 @@ public class CacheController{
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
ArrayList<Status> filtered=new ArrayList<>(result);
|
||||
AccountSessionManager.get(accountID).filterStatuses(filtered, FilterContext.HOME);
|
||||
callback.onSuccess(new CacheablePaginatedResponse<>(filtered, result.isEmpty() ? null : result.get(result.size()-1).id, false));
|
||||
callback.onSuccess(new CacheablePaginatedResponse<>(result, result.isEmpty() ? null : result.get(result.size()-1).id, false));
|
||||
putHomeTimeline(result, maxID==null);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ public class PushSubscriptionManager{
|
||||
deviceToken=getPrefs().getString("deviceToken", null);
|
||||
int tokenVersion=getPrefs().getInt("version", 0);
|
||||
if(!TextUtils.isEmpty(deviceToken) && tokenVersion==BuildConfig.VERSION_CODE){
|
||||
registerAllAccountsForPush(true); // TODO: revert this before release
|
||||
registerAllAccountsForPush(false);
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "tryRegisterFCM: no token found or app was updated. Trying to get push token...");
|
||||
|
||||
@@ -13,7 +13,7 @@ import okhttp3.MultipartBody;
|
||||
import okhttp3.RequestBody;
|
||||
|
||||
public class PleromaMarkNotificationsRead extends MastodonAPIRequest<List<Notification>> {
|
||||
private String maxID;
|
||||
private final String maxID;
|
||||
public PleromaMarkNotificationsRead(String maxID) {
|
||||
super(HttpMethod.POST, "/pleroma/notifications/read", new TypeToken<>(){});
|
||||
this.maxID = maxID;
|
||||
|
||||
@@ -6,9 +6,13 @@ import static org.joinmastodon.android.api.MastodonAPIController.gson;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.annotation.StringRes;
|
||||
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.model.ContentType;
|
||||
import org.joinmastodon.android.model.Emoji;
|
||||
import org.joinmastodon.android.model.TimelineDefinition;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
@@ -36,12 +40,15 @@ public class AccountLocalPreferences{
|
||||
public String publishButtonText;
|
||||
public String timelineReplyVisibility; // akkoma-only
|
||||
public boolean keepOnlyLatestNotification;
|
||||
|
||||
public boolean emojiReactionsEnabled;
|
||||
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 timelinesType = new TypeToken<ArrayList<TimelineDefinition>>() {}.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 recentCustomEmojiType=new TypeToken<ArrayList<Emoji>>() {}.getType();
|
||||
|
||||
public AccountLocalPreferences(SharedPreferences prefs, AccountSession session){
|
||||
this.prefs=prefs;
|
||||
@@ -66,6 +73,9 @@ public class AccountLocalPreferences{
|
||||
keepOnlyLatestNotification=prefs.getBoolean("keepOnlyLatestNotification", false);
|
||||
emojiReactionsEnabled=prefs.getBoolean("emojiReactionsEnabled", session.getInstance().isPresent() && session.getInstance().get().isAkkoma());
|
||||
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(){
|
||||
@@ -99,9 +109,36 @@ public class AccountLocalPreferences{
|
||||
.putBoolean("keepOnlyLatestNotification", keepOnlyLatestNotification)
|
||||
.putBoolean("emojiReactionsEnabled", emojiReactionsEnabled)
|
||||
.putString("showEmojiReactions", showEmojiReactions.name())
|
||||
.putString("color", color.name())
|
||||
.putBoolean("likeIcon", likeIcon)
|
||||
.putString("recentCustomEmoji", gson.toJson(recentCustomEmoji))
|
||||
.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{
|
||||
HIDE_EMPTY,
|
||||
ONLY_OPENED,
|
||||
|
||||
@@ -40,7 +40,6 @@ import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
@@ -255,52 +254,62 @@ public class AccountSession{
|
||||
filterStatusContainingObjects(objects, extractor, context, null);
|
||||
}
|
||||
|
||||
public <T> void filterStatusContainingObjects(List<T> objects, Function<T, Status> extractor, FilterContext context, Account profile){
|
||||
Predicate<Status> statusIsOnOwnProfile = (s) -> self != null && profile != null && s.account != null
|
||||
private boolean statusIsOnOwnProfile(Status s, Account profile){
|
||||
return self != null && profile != null && s.account != null
|
||||
&& Objects.equals(self.id, profile.id) && Objects.equals(self.id, s.account.id);
|
||||
}
|
||||
|
||||
if(getLocalPreferences().serverSideFiltersSupported){
|
||||
// Even with server-side filters, clients are expected to remove statuses that match a filter that hides them
|
||||
objects.removeIf(o->{
|
||||
Status s=extractor.apply(o);
|
||||
if(s==null)
|
||||
return false;
|
||||
if(s.filtered==null)
|
||||
return false;
|
||||
// don't hide own posts in own profile
|
||||
if (statusIsOnOwnProfile.test(s))
|
||||
return false;
|
||||
for(FilterResult filter:s.filtered){
|
||||
if(filter.filter.isActive() && filter.filter.filterAction==FilterAction.HIDE)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
if(wordFilters==null)
|
||||
return;
|
||||
for(T obj:objects){
|
||||
private boolean isFilteredType(Status s){
|
||||
return (!localPreferences.showReplies && s.inReplyToId != null)
|
||||
|| (!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){
|
||||
getLocalPreferences().serverSideFiltersSupported=true;
|
||||
getLocalPreferences().save();
|
||||
return;
|
||||
localPreferences.serverSideFiltersSupported=true;
|
||||
localPreferences.save();
|
||||
}
|
||||
}
|
||||
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){
|
||||
|
||||
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);
|
||||
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)
|
||||
return false;
|
||||
// don't hide own posts in own profile
|
||||
if(statusIsOnOwnProfile(s, profile))
|
||||
return false;
|
||||
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)
|
||||
return true;
|
||||
}
|
||||
}else if(wordFilters!=null){
|
||||
for(LegacyFilter filter : wordFilters){
|
||||
if(filter.context.contains(context) && filter.matches(s) && filter.isActive())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void updateAccountInfo(){
|
||||
|
||||
@@ -9,19 +9,16 @@ import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||
import org.joinmastodon.android.events.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.events.StatusUnpinnedEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.FilterContext;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.displayitems.HeaderStatusDisplayItem;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
|
||||
@@ -55,15 +52,14 @@ public class AccountTimelineFragment extends StatusListFragment{
|
||||
|
||||
@Override
|
||||
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){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if(getActivity()==null) return;
|
||||
AccountSessionManager asm = AccountSessionManager.getInstance();
|
||||
boolean empty=result.isEmpty();
|
||||
boolean more=applyMaxID(result);
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext(), user);
|
||||
onDataLoaded(result, !empty);
|
||||
onDataLoaded(result, more);
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
|
||||
@@ -97,7 +97,7 @@ public class AnnouncementsFragment extends BaseStatusListFragment<Announcement>
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<Announcement> result){
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
|
||||
// get unread items first
|
||||
List<Announcement> data = result.stream().filter(a -> !a.read).collect(toList());
|
||||
|
||||
@@ -9,7 +9,6 @@ import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowInsets;
|
||||
@@ -90,6 +89,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
protected Rect tmpRect=new Rect();
|
||||
protected TypedObjectPool<MediaGridStatusDisplayItem.GridItemType, MediaAttachmentViewController> attachmentViewsPool=new TypedObjectPool<>(this::makeNewMediaAttachmentView);
|
||||
protected boolean currentlyScrolling;
|
||||
protected String maxID;
|
||||
|
||||
public BaseStatusListFragment(){
|
||||
super(20);
|
||||
@@ -156,6 +156,8 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
}
|
||||
|
||||
protected String getMaxID(){
|
||||
if(refreshing) return null;
|
||||
if(maxID!=null) return maxID;
|
||||
if(!preloadedData.isEmpty())
|
||||
return preloadedData.get(preloadedData.size()-1).getID();
|
||||
else if(!data.isEmpty())
|
||||
@@ -164,6 +166,12 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
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 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
|
||||
status.sensitiveRevealed = !status.sensitiveRevealed;
|
||||
}
|
||||
holder.rebind();
|
||||
if(holder.getItem().hasVisibilityToggle) holder.animateVisibilityToggle(false);
|
||||
}
|
||||
|
||||
public void onSensitiveRevealed(MediaGridStatusDisplayItem.Holder holder) {
|
||||
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){
|
||||
@@ -846,7 +854,7 @@ public abstract class BaseStatusListFragment<T extends DisplayItemsParent> exten
|
||||
if(getContext()==null) return;
|
||||
super.onDataLoaded(d, 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class BookmarkedStatusListFragment extends StatusListFragment{
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(HeaderPaginationList<Status> result){
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
if(result.nextPageUri!=null)
|
||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||
else
|
||||
|
||||
@@ -162,7 +162,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
private int charCount, charLimit, trimmedCharCount;
|
||||
|
||||
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 View sensitiveBtn;
|
||||
private TextView replyText;
|
||||
@@ -294,7 +294,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
|
||||
@Override
|
||||
public View onCreateContentView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
|
||||
creatingView=true;
|
||||
emojiKeyboard=new CustomEmojiPopupKeyboard(getActivity(), customEmojis, instanceDomain);
|
||||
emojiKeyboard=new CustomEmojiPopupKeyboard(getActivity(), accountID, customEmojis, instanceDomain);
|
||||
emojiKeyboard.setListener(new CustomEmojiPopupKeyboard.Listener(){
|
||||
@Override
|
||||
public void onEmojiSelected(Emoji emoji){
|
||||
|
||||
@@ -26,12 +26,12 @@ import android.widget.ImageView;
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.model.Attachment;
|
||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||
import org.joinmastodon.android.ui.photoviewer.PhotoViewer;
|
||||
import org.joinmastodon.android.ui.utils.ColorPalette;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.FixedAspectRatioImageView;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -54,16 +54,16 @@ public class ComposeImageDescriptionFragment extends MastodonToolbarFragment imp
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
accountID=getArguments().getString("account");
|
||||
attachmentID=getArguments().getString("attachment");
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity){
|
||||
super.onAttach(activity);
|
||||
accountID=getArguments().getString("account");
|
||||
attachmentID=getArguments().getString("attachment");
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -169,7 +169,7 @@ public class EditTimelinesFragment extends MastodonRecyclerFragment<TimelineDefi
|
||||
}
|
||||
|
||||
private void updateOptionsMenu() {
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
optionsMenu.clear();
|
||||
timelineByMenuItem.clear();
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ public class FavoritedStatusListFragment extends StatusListFragment{
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(HeaderPaginationList<Status> result){
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
if(result.nextPageUri!=null)
|
||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||
else
|
||||
|
||||
@@ -83,7 +83,7 @@ public class FollowRequestsListFragment extends MastodonRecyclerFragment<FollowR
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(HeaderPaginationList<Account> result){
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
if(result.nextPageUri!=null)
|
||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||
else
|
||||
|
||||
@@ -56,7 +56,7 @@ public class FollowedHashtagsFragment extends MastodonRecyclerFragment<Hashtag>
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(HeaderPaginationList<Hashtag> result){
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
if(result.nextPageUri!=null)
|
||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||
else
|
||||
|
||||
@@ -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.SetTagFollowed;
|
||||
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.Hashtag;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
@@ -85,16 +86,19 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
||||
|
||||
@Override
|
||||
protected TimelineDefinition makeTimelineDefinition() {
|
||||
return TimelineDefinition.ofHashtag(hashtag);
|
||||
return TimelineDefinition.ofHashtag(hashtagName);
|
||||
}
|
||||
|
||||
@Override
|
||||
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){
|
||||
@Override
|
||||
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);
|
||||
@@ -217,8 +221,6 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
||||
followMenuItem=optionsMenu.findItem(R.id.follow_hashtag);
|
||||
pinMenuItem=optionsMenu.findItem(R.id.pin);
|
||||
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);
|
||||
super.updatePinButton(pinMenuItem);
|
||||
if(toolbarContentVisible){
|
||||
@@ -260,7 +262,7 @@ public class HashtagTimelineFragment extends PinnableStatusListFragment{
|
||||
}
|
||||
|
||||
private void updateHeader(){
|
||||
if(hashtag==null)
|
||||
if(hashtag==null || getActivity()==null)
|
||||
return;
|
||||
|
||||
if(hashtag.history!=null && !hashtag.history.isEmpty()){
|
||||
|
||||
@@ -287,7 +287,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
||||
new GetAnnouncements(false).setCallback(new Callback<>() {
|
||||
@Override
|
||||
public void onSuccess(List<Announcement> result) {
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
if (result.stream().anyMatch(a -> !a.read)) {
|
||||
announcementsBadged = true;
|
||||
announcements.setVisible(false);
|
||||
@@ -381,7 +381,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
|
||||
}
|
||||
|
||||
private void updateOverflowMenu() {
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
Menu m = overflowPopup.getMenu();
|
||||
m.clear();
|
||||
overflowPopup.inflate(R.menu.home_overflow);
|
||||
|
||||
@@ -11,7 +11,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
||||
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.model.CacheablePaginatedResponse;
|
||||
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.StatusDisplayItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -49,16 +49,6 @@ public class HomeTimelineFragment extends StatusListFragment {
|
||||
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
|
||||
protected void doLoadData(int offset, int count){
|
||||
AccountSessionManager.getInstance()
|
||||
@@ -66,10 +56,11 @@ public class HomeTimelineFragment extends StatusListFragment {
|
||||
.getHomeTimeline(offset>0 ? maxID : null, count, refreshing, new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(CacheablePaginatedResponse<List<Status>> result){
|
||||
if (getActivity() == null) return;
|
||||
List<Status> filteredItems = filterPosts(result.items);
|
||||
if(getActivity()==null) return;
|
||||
boolean empty=result.items.isEmpty();
|
||||
maxID=result.maxID;
|
||||
onDataLoaded(filteredItems, !result.items.isEmpty());
|
||||
AccountSessionManager.get(accountID).filterStatuses(result.items, getFilterContext());
|
||||
onDataLoaded(result.items, !empty);
|
||||
if(result.isFromCache())
|
||||
loadNewPosts();
|
||||
}
|
||||
@@ -142,23 +133,26 @@ public class HomeTimelineFragment extends StatusListFragment {
|
||||
public void onSuccess(List<Status> result){
|
||||
currentRequest=null;
|
||||
dataLoading=false;
|
||||
result = filterPosts(result);
|
||||
if(result.isEmpty() || getActivity()==null)
|
||||
return;
|
||||
Status last=result.get(result.size()-1);
|
||||
List<Status> toAdd;
|
||||
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{
|
||||
result.get(result.size()-1).hasGapAfter=true;
|
||||
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());
|
||||
if(!toAdd.isEmpty()){
|
||||
prependItems(toAdd, true);
|
||||
if (parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton();
|
||||
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAdd, false);
|
||||
if(parent != null && GlobalUserPreferences.showNewPostsButton) parent.showNewPostsButton();
|
||||
}
|
||||
if(toAddUnfiltered.isEmpty())
|
||||
AccountSessionManager.getInstance().getAccount(accountID).getCacheController().putHomeTimeline(toAddUnfiltered, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,6 +16,7 @@ import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.lists.GetList;
|
||||
import org.joinmastodon.android.api.requests.lists.UpdateList;
|
||||
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.ListUpdatedCreatedEvent;
|
||||
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.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.ListEditor;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
@@ -63,7 +62,7 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
||||
new GetList(listID).setCallback(new Callback<>() {
|
||||
@Override
|
||||
public void onSuccess(ListTimeline listTimeline) {
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
// TODO: save updated info
|
||||
if (!listTimeline.title.equals(listTitle)) setTitle(listTimeline.title);
|
||||
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<>() {
|
||||
@Override
|
||||
public void onSuccess(ListTimeline list) {
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
setTitle(list.title);
|
||||
listTitle = list.title;
|
||||
repliesPolicy = list.repliesPolicy;
|
||||
@@ -134,13 +133,14 @@ public class ListTimelineFragment extends PinnableStatusListFragment {
|
||||
|
||||
@Override
|
||||
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) {
|
||||
@Override
|
||||
public void onSuccess(List<Status> result) {
|
||||
if (getActivity() == null) return;
|
||||
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
if(getActivity()==null) return;
|
||||
boolean more=applyMaxID(result);
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||
onDataLoaded(result, more);
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
|
||||
@@ -140,7 +140,7 @@ public class ListsFragment extends MastodonRecyclerFragment<ListTimeline> implem
|
||||
.setCallback(new SimpleCallback<>(this) {
|
||||
@Override
|
||||
public void onSuccess(List<ListTimeline> lists) {
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
for (ListTimeline l : lists) userInListBefore.put(l.id, true);
|
||||
userInList.putAll(userInListBefore);
|
||||
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) {
|
||||
@Override
|
||||
public void onSuccess(List<ListTimeline> allLists) {
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
List<ListTimeline> newLists = new ArrayList<>();
|
||||
for (ListTimeline l : allLists) {
|
||||
if (lists.stream().noneMatch(e -> e.id.equals(l.id))) newLists.add(l);
|
||||
|
||||
@@ -254,7 +254,7 @@ public class NotificationsFragment extends MastodonToolbarFragment implements Sc
|
||||
new GetFollowRequests(null, 1).setCallback(new Callback<>() {
|
||||
@Override
|
||||
public void onSuccess(HeaderPaginationList<Account> accounts) {
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
getToolbar().getMenu().findItem(R.id.follow_requests).setVisible(!accounts.isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@@ -134,6 +134,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
||||
return;
|
||||
maxID=result.maxID;
|
||||
onDataLoaded(result.items.stream().filter(n->n.type!=null).collect(Collectors.toList()), !result.items.isEmpty());
|
||||
if(bannerHelper!=null) bannerHelper.onBannerBecameVisible();
|
||||
reloadingFromCache=false;
|
||||
if (getParentFragment() instanceof NotificationsFragment nf) {
|
||||
nf.updateMarkAllReadButton();
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.os.Bundle;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
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.FilterContext;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
@@ -35,6 +36,8 @@ public class PinnedPostsListFragment extends StatusListFragment{
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if(getActivity()==null) return;
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||
onDataLoaded(result, false);
|
||||
}
|
||||
}).exec(accountID);
|
||||
|
||||
@@ -133,6 +133,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
private ImageView avatar;
|
||||
private CoverImageView cover;
|
||||
private View avatarBorder;
|
||||
private View usernameWrap;
|
||||
private TextView name, username, bio, followersCount, followersLabel, followingCount, followingLabel;
|
||||
private ImageView lockIcon, botIcon;
|
||||
private ProgressBarButton actionButton, notifyButton;
|
||||
@@ -233,6 +234,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
cover=content.findViewById(R.id.cover);
|
||||
avatarBorder=content.findViewById(R.id.avatar_border);
|
||||
name=content.findViewById(R.id.name);
|
||||
usernameWrap=content.findViewById(R.id.username_wrap);
|
||||
username=content.findViewById(R.id.username);
|
||||
lockIcon=content.findViewById(R.id.lock_icon);
|
||||
botIcon=content.findViewById(R.id.bot_icon);
|
||||
@@ -480,7 +482,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(Account result){
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
onAccountLoaded(result);
|
||||
}
|
||||
})
|
||||
@@ -892,7 +894,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
}
|
||||
|
||||
private void updateRelationship(){
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
invalidateOptionsMenu();
|
||||
actionButton.setVisibility(View.VISIBLE);
|
||||
notifyButton.setVisibility(relationship.following ? View.VISIBLE : View.GONE);
|
||||
@@ -1114,7 +1116,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
|
||||
name.setVisibility(View.GONE);
|
||||
rolesView.setVisibility(View.GONE);
|
||||
username.setVisibility(View.GONE);
|
||||
usernameWrap.setVisibility(View.GONE);
|
||||
bio.setVisibility(View.GONE);
|
||||
countersLayout.setVisibility(View.GONE);
|
||||
|
||||
@@ -1163,7 +1165,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
bioEditWrap.setVisibility(View.GONE);
|
||||
name.setVisibility(View.VISIBLE);
|
||||
rolesView.setVisibility(View.VISIBLE);
|
||||
username.setVisibility(View.VISIBLE);
|
||||
usernameWrap.setVisibility(View.VISIBLE);
|
||||
bio.setVisibility(View.VISIBLE);
|
||||
countersLayout.setVisibility(View.VISIBLE);
|
||||
refreshLayout.setEnabled(true);
|
||||
@@ -1189,7 +1191,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
savingEdits=false;
|
||||
account=result;
|
||||
AccountSessionManager.getInstance().updateAccountInfo(accountID, account);
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
exitEditMode();
|
||||
setActionProgressVisible(false);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,7 @@ public class ScheduledStatusListFragment extends BaseStatusListFragment<Schedule
|
||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||
else
|
||||
nextMaxID=null;
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
onDataLoaded(result, nextMaxID!=null);
|
||||
}
|
||||
})
|
||||
|
||||
@@ -47,13 +47,12 @@ public class SplashFragment extends AppKitFragment{
|
||||
private ProgressBarButton defaultServerButton;
|
||||
private ProgressBar defaultServerProgress;
|
||||
private String chosenDefaultServer=DEFAULT_SERVER;
|
||||
private boolean loadingDefaultServer;
|
||||
private boolean loadingDefaultServer, loadedDefaultServer;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
motionEffect=new InterpolatingMotionEffect(MastodonApp.context);
|
||||
loadAndChooseDefaultServer();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -101,6 +100,8 @@ public class SplashFragment extends AppKitFragment{
|
||||
});
|
||||
}
|
||||
});
|
||||
if(!loadedDefaultServer && !loadingDefaultServer)
|
||||
loadAndChooseDefaultServer();
|
||||
|
||||
return contentView;
|
||||
}
|
||||
@@ -239,6 +240,7 @@ public class SplashFragment extends AppKitFragment{
|
||||
private void setChosenDefaultServer(String domain){
|
||||
chosenDefaultServer=domain;
|
||||
loadingDefaultServer=false;
|
||||
loadedDefaultServer=true;
|
||||
if(defaultServerButton!=null && getActivity()!=null){
|
||||
defaultServerButton.setTextVisible(true);
|
||||
defaultServerProgress.setVisibility(View.GONE);
|
||||
|
||||
@@ -48,8 +48,8 @@ public class StatusEditHistoryFragment extends StatusListFragment{
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if(getActivity()==null) return;
|
||||
Collections.sort(result, Comparator.comparing((Status s)->s.createdAt).reversed());
|
||||
if (getActivity() == null) return;
|
||||
onDataLoaded(result, false);
|
||||
}
|
||||
})
|
||||
|
||||
@@ -42,10 +42,12 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>
|
||||
boolean isMainThreadStatus = this instanceof ThreadFragment t && s.id.equals(t.mainStatus.id);
|
||||
int flags = 0;
|
||||
AccountLocalPreferences lp=getLocalPrefs();
|
||||
if (GlobalUserPreferences.spectatorMode)
|
||||
if(GlobalUserPreferences.spectatorMode)
|
||||
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;
|
||||
if(GlobalUserPreferences.translateButtonOpenedOnly)
|
||||
flags |= StatusDisplayItem.FLAG_NO_TRANSLATE;
|
||||
return StatusDisplayItem.buildItems(this, s, accountID, s, knownAccounts, getFilterContext(), isMainThreadStatus ? 0 : flags);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ import org.joinmastodon.android.GlobalUserPreferences.AutoRevealMode;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.statuses.GetStatusByID;
|
||||
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.StatusCreatedEvent;
|
||||
import org.joinmastodon.android.events.StatusUpdatedEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
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.utils.UiUtils;
|
||||
import org.joinmastodon.android.utils.ProvidesAssistContent;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
@@ -195,8 +194,8 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
|
||||
// TODO: figure out how this code works
|
||||
if (isInstanceAkkoma()) sortStatusContext(mainStatus, result);
|
||||
|
||||
result.descendants=filterStatuses(result.descendants);
|
||||
result.ancestors=filterStatuses(result.ancestors);
|
||||
filterStatuses(result.descendants);
|
||||
filterStatuses(result.ancestors);
|
||||
restoreStatusStates(result.descendants, oldData);
|
||||
restoreStatusStates(result.ancestors, oldData);
|
||||
|
||||
@@ -332,11 +331,8 @@ public class ThreadFragment extends StatusListFragment implements ProvidesAssist
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Status> filterStatuses(List<Status> statuses){
|
||||
StatusFilterPredicate statusFilterPredicate=new StatusFilterPredicate(accountID,getFilterContext());
|
||||
return statuses.stream()
|
||||
.filter(statusFilterPredicate)
|
||||
.collect(Collectors.toList());
|
||||
private void filterStatuses(List<Status> statuses){
|
||||
AccountSessionManager.get(accountID).filterStatuses(statuses, getFilterContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -83,7 +83,7 @@ public abstract class BaseAccountListFragment extends MastodonRecyclerFragment<A
|
||||
for(Relationship rel:result){
|
||||
relationships.put(rel.id, rel);
|
||||
}
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
if(list==null)
|
||||
return;
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
|
||||
@@ -133,7 +133,7 @@ public abstract class PaginatedAccountListFragment<T> extends BaseAccountListFra
|
||||
nextMaxID=result.nextPageUri.getQueryParameter("max_id");
|
||||
else
|
||||
nextMaxID=null;
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
List<AccountViewModel> items = result.stream()
|
||||
.filter(a -> d.size() > 1000 || d.stream()
|
||||
.noneMatch(i -> i.account.url.equals(a.url)))
|
||||
|
||||
@@ -6,21 +6,19 @@ import android.os.Bundle;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
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.model.FilterContext;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
|
||||
import org.joinmastodon.android.utils.StatusFilterPredicate;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||
|
||||
public class BubbleTimelineFragment extends StatusListFragment {
|
||||
private DiscoverInfoBannerHelper bannerHelper;
|
||||
private String maxID;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
@@ -36,15 +34,15 @@ public class BubbleTimelineFragment extends StatusListFragment {
|
||||
|
||||
@Override
|
||||
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){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if(!result.isEmpty())
|
||||
maxID=result.get(result.size()-1).id;
|
||||
if (getActivity() == null) return;
|
||||
result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
|
||||
onDataLoaded(result, !result.isEmpty());
|
||||
if(getActivity()==null) return;
|
||||
boolean more=applyMaxID(result);
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||
onDataLoaded(result, more);
|
||||
bannerHelper.onBannerBecameVisible();
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
|
||||
@@ -77,7 +77,7 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
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);
|
||||
loadRelationships();
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public class DiscoverAccountsFragment extends MastodonRecyclerFragment<DiscoverA
|
||||
public void onSuccess(List<Relationship> result){
|
||||
relationshipsRequest=null;
|
||||
relationships=result.stream().collect(Collectors.toMap(rel->rel.id, Function.identity()));
|
||||
if (getActivity() == null) return;
|
||||
if(getActivity()==null) return;
|
||||
if(list==null)
|
||||
return;
|
||||
for(int i=0;i<list.getChildCount();i++){
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
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.model.FilterContext;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
@@ -17,6 +18,7 @@ import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||
|
||||
public class DiscoverPostsFragment extends StatusListFragment{
|
||||
private DiscoverInfoBannerHelper bannerHelper;
|
||||
private int offset;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
@@ -25,12 +27,17 @@ public class DiscoverPostsFragment extends StatusListFragment{
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doLoadData(int offset, int count){
|
||||
protected void doLoadData(int o, int count){
|
||||
if(refreshing) offset=0;
|
||||
currentRequest=new GetTrendingStatuses(offset, count)
|
||||
.setCallback(new SimpleCallback<>(this){
|
||||
@Override
|
||||
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();
|
||||
}
|
||||
}).exec(accountID);
|
||||
|
||||
@@ -29,15 +29,14 @@ public class FederatedTimelineFragment extends StatusListFragment{
|
||||
|
||||
@Override
|
||||
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){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if(!result.isEmpty())
|
||||
maxID=result.get(result.size()-1).id;
|
||||
boolean empty=result.isEmpty();
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.PUBLIC);
|
||||
onDataLoaded(result, !empty);
|
||||
if(getActivity()==null) return;
|
||||
boolean more=applyMaxID(result);
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||
onDataLoaded(result, more);
|
||||
bannerHelper.onBannerBecameVisible();
|
||||
}
|
||||
})
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.joinmastodon.android.fragments.discover;
|
||||
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
@@ -30,15 +29,14 @@ public class LocalTimelineFragment extends StatusListFragment{
|
||||
|
||||
@Override
|
||||
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){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if(!result.isEmpty())
|
||||
maxID=result.get(result.size()-1).id;
|
||||
boolean empty=result.isEmpty();
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, FilterContext.PUBLIC);
|
||||
onDataLoaded(result, !empty);
|
||||
if(getActivity()==null) return;
|
||||
boolean more=applyMaxID(result);
|
||||
AccountSessionManager.get(accountID).filterStatuses(result, getFilterContext());
|
||||
onDataLoaded(result, more);
|
||||
bannerHelper.onBannerBecameVisible();
|
||||
}
|
||||
})
|
||||
|
||||
@@ -83,10 +83,11 @@ public class ReportAddPostsChoiceFragment extends StatusListFragment{
|
||||
|
||||
@Override
|
||||
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){
|
||||
@Override
|
||||
public void onSuccess(List<Status> result){
|
||||
if(getActivity()==null) return;
|
||||
for(Status s:result){
|
||||
s.sensitive=true;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.MastodonApp;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||
import org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference;
|
||||
import org.joinmastodon.android.api.session.AccountSession;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.StatusDisplaySettingsChangedEvent;
|
||||
@@ -37,7 +38,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
||||
private CheckableListItem<Void> revealCWsItem, hideSensitiveMediaItem, interactionCountsItem, emojiInNamesItem;
|
||||
|
||||
// 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 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)),
|
||||
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)),
|
||||
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),
|
||||
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)),
|
||||
@@ -96,12 +98,14 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
||||
|
||||
boolean restartPlease=
|
||||
GlobalUserPreferences.disableM3PillActiveIndicator!=disablePillItem.checked ||
|
||||
GlobalUserPreferences.showNavigationLabels!=showNavigationLabelsItem.checked;
|
||||
GlobalUserPreferences.showNavigationLabels!=showNavigationLabelsItem.checked ||
|
||||
lp.likeIcon!=likeIconItem.checked;
|
||||
|
||||
lp.revealCWs=revealCWsItem.checked;
|
||||
lp.hideSensitiveMedia=hideSensitiveMediaItem.checked;
|
||||
lp.showInteractionCounts=interactionCountsItem.checked;
|
||||
lp.customEmojiInNames=emojiInNamesItem.checked;
|
||||
lp.likeIcon=likeIconItem.checked;
|
||||
lp.save();
|
||||
GlobalUserPreferences.toolbarMarquee=marqueeItem.checked;
|
||||
GlobalUserPreferences.reduceMotion=reduceMotionItem.checked;
|
||||
@@ -131,7 +135,7 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
||||
}
|
||||
|
||||
private @StringRes int getColorPaletteValue(){
|
||||
return switch(GlobalUserPreferences.color){
|
||||
return switch(AccountSessionManager.get(accountID).getLocalPreferences().color){
|
||||
case MATERIAL3 -> R.string.sk_color_palette_material3;
|
||||
case PINK -> R.string.sk_color_palette_pink;
|
||||
case PURPLE -> R.string.sk_color_palette_purple;
|
||||
@@ -196,18 +200,18 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
||||
}
|
||||
|
||||
private void onColorClick(){
|
||||
int selected=GlobalUserPreferences.color.ordinal();
|
||||
int selected=lp.color.ordinal();
|
||||
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())
|
||||
.setTitle(R.string.settings_theme)
|
||||
.setTitle(R.string.sk_settings_color_palette)
|
||||
.setSingleChoiceItems(names,
|
||||
selected, (dlg, item)->newSelected[0]=item)
|
||||
.setPositiveButton(R.string.ok, (dlg, item)->{
|
||||
GlobalUserPreferences.ColorPreference pref=GlobalUserPreferences.ColorPreference.values()[newSelected[0]];
|
||||
if(pref!=GlobalUserPreferences.color){
|
||||
GlobalUserPreferences.ColorPreference prev=GlobalUserPreferences.color;
|
||||
GlobalUserPreferences.color=pref;
|
||||
ColorPreference pref=ColorPreference.values()[newSelected[0]];
|
||||
if(pref!=lp.color){
|
||||
ColorPreference prev=lp.color;
|
||||
lp.color=pref;
|
||||
GlobalUserPreferences.save();
|
||||
colorItem.subtitleRes=getColorPaletteValue();
|
||||
rebindItem(colorItem);
|
||||
@@ -257,17 +261,17 @@ public class SettingsDisplayFragment extends BaseSettingsFragment<Void>{
|
||||
.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(prevTrueBlack==null) prevTrueBlack=GlobalUserPreferences.trueBlackTheme;
|
||||
if(prevColor==null) prevColor=GlobalUserPreferences.color;
|
||||
if(prevColor==null) prevColor=lp.color;
|
||||
|
||||
boolean isCurrentDark=prevTheme==GlobalUserPreferences.ThemePreference.DARK ||
|
||||
(prevTheme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive());
|
||||
boolean isNewDark=GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.DARK ||
|
||||
(GlobalUserPreferences.theme==GlobalUserPreferences.ThemePreference.AUTO && Build.VERSION.SDK_INT>=30 && getResources().getConfiguration().isNightModeActive());
|
||||
boolean isNewBlack=GlobalUserPreferences.trueBlackTheme;
|
||||
if(isCurrentDark!=isNewDark || prevColor!=GlobalUserPreferences.color || (isNewDark && prevTrueBlack!=isNewBlack)){
|
||||
if(isCurrentDark!=isNewDark || prevColor!=lp.color || (isNewDark && prevTrueBlack!=isNewBlack)){
|
||||
restartActivityToApplyNewTheme();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,7 +163,7 @@ public class SettingsMainFragment extends BaseSettingsFragment<Void>{
|
||||
.setMessage(getString(R.string.confirm_log_out, session.getFullUsername()))
|
||||
.setPositiveButton(R.string.log_out, (dialog, which)->account.logOut(getActivity(), ()->{
|
||||
loggedOut=true;
|
||||
((MainActivity)getActivity()).restartHomeFragment();
|
||||
((MainActivity)getActivity()).restartActivity();
|
||||
}))
|
||||
.setNegativeButton(R.string.cancel, null)
|
||||
.show();
|
||||
|
||||
@@ -68,6 +68,14 @@ public class Attachment extends BaseModel{
|
||||
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(){
|
||||
if(meta==null)
|
||||
return 0;
|
||||
|
||||
@@ -14,7 +14,7 @@ public class FilterResult extends BaseModel {
|
||||
@Override
|
||||
public void postprocess() throws ObjectValidationException {
|
||||
super.postprocess();
|
||||
if(filter!=null) filter.postprocess();
|
||||
if(filter!=null) filter.postprocess();
|
||||
if(keywordMatches==null) keywordMatches=List.of();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +147,7 @@ public class AccountSwitcherSheet extends BottomSheet{
|
||||
|
||||
private void logOut(String accountID){
|
||||
AccountSessionManager.get(accountID).logOut(activity, ()->{
|
||||
dismiss();
|
||||
((MainActivity)activity).restartHomeFragment();
|
||||
((MainActivity)activity).restartActivity();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -317,14 +316,14 @@ public class AccountSwitcherSheet extends BottomSheet{
|
||||
@Override
|
||||
public void onClick(){
|
||||
setOnDismissListener(null);
|
||||
dismiss();
|
||||
if (onClick != null) {
|
||||
dismiss();
|
||||
onClick.accept(item.getID(), false);
|
||||
return;
|
||||
}
|
||||
if(AccountSessionManager.getInstance().tryGetAccount(item.getID())!=null){
|
||||
AccountSessionManager.getInstance().setLastActiveAccountID(item.getID());
|
||||
((MainActivity)activity).restartHomeFragment();
|
||||
((MainActivity)activity).restartActivity();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -170,12 +170,14 @@ public class EmojiReactionsStatusDisplayItem extends StatusDisplayItem {
|
||||
@Override
|
||||
public void onBind(EmojiReactionsStatusDisplayItem item) {
|
||||
if(emojiKeyboard != null) root.removeView(emojiKeyboard.getView());
|
||||
addButton.setSelected(false);
|
||||
AccountSession session=item.parentFragment.getSession();
|
||||
item.status.reactions.forEach(r->r.request=r.getUrl(item.playGifs)!=null
|
||||
? new UrlImageLoaderRequest(r.getUrl(item.playGifs), V.sp(24), V.sp(24))
|
||||
: null);
|
||||
emojiKeyboard=new CustomEmojiPopupKeyboard(
|
||||
(Activity) item.parentFragment.getContext(),
|
||||
item.accountID,
|
||||
AccountSessionManager.getInstance().getCustomEmojis(session.domain),
|
||||
session.domain, true);
|
||||
emojiKeyboard.setListener(this);
|
||||
|
||||
@@ -14,6 +14,8 @@ import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
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.StatusEditHistoryFragment;
|
||||
import org.joinmastodon.android.fragments.account_list.StatusFavoritesListFragment;
|
||||
@@ -74,6 +76,9 @@ public class ExtendedFooterStatusDisplayItem extends StatusDisplayItem{
|
||||
@Override
|
||||
public void onBind(ExtendedFooterStatusDisplayItem item){
|
||||
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));
|
||||
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);
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
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.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -17,6 +15,7 @@ import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.Button;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
@@ -57,13 +56,14 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
public static class Holder extends StatusDisplayItem.Holder<FooterStatusDisplayItem>{
|
||||
private final TextView replies, boosts, favorites;
|
||||
private final View reply, boost, favorite, share, bookmark;
|
||||
private final ImageView favIcon;
|
||||
|
||||
private View touchingView = null;
|
||||
private boolean longClickPerformed = false;
|
||||
private final Runnable longClickRunnable = () -> {
|
||||
longClickPerformed = touchingView != null && touchingView.performLongClick();
|
||||
if (longClickPerformed && touchingView != null) {
|
||||
touchingView.startAnimation(opacityIn);
|
||||
UiUtils.opacityIn(touchingView);
|
||||
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);
|
||||
share=findViewById(R.id.share_btn);
|
||||
bookmark=findViewById(R.id.bookmark_btn);
|
||||
favIcon=findViewById(R.id.favorite_icon);
|
||||
|
||||
reply.setOnTouchListener(this::onButtonTouch);
|
||||
reply.setOnClickListener(this::onReplyClick);
|
||||
@@ -132,6 +133,16 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
boolean condenseBottom = !item.isMainStatus && item.hasDescendantNeighbor &&
|
||||
!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();
|
||||
params.setMargins(params.leftMargin, params.topMargin, params.rightMargin,
|
||||
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 (disabled) return true;
|
||||
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) {
|
||||
longClickPerformed = false;
|
||||
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();
|
||||
if (disabled) return true;
|
||||
v.postDelayed(longClickRunnable, ViewConfiguration.getLongPressTimeout());
|
||||
v.startAnimation(opacityOut);
|
||||
UiUtils.opacityOut(v);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void onReplyClick(View v){
|
||||
v.startAnimation(opacityIn);
|
||||
UiUtils.opacityIn(v);
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", item.accountID);
|
||||
args.putParcelable("replyTo", Parcels.wrap(item.status));
|
||||
@@ -198,7 +209,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
|
||||
private void onBoostClick(View v){
|
||||
if (GlobalUserPreferences.confirmBoost) {
|
||||
v.startAnimation(opacityIn);
|
||||
UiUtils.opacityIn(v);
|
||||
onBoostLongClick(v);
|
||||
return;
|
||||
}
|
||||
@@ -207,7 +218,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
}
|
||||
|
||||
private void boostConsumer(View v, Status r) {
|
||||
v.startAnimation(opacityIn);
|
||||
UiUtils.opacityIn(v);
|
||||
bindText(boosts, r.reblogsCount);
|
||||
}
|
||||
|
||||
@@ -218,7 +229,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
AccountSession session = AccountSessionManager.getInstance().getAccount(item.accountID);
|
||||
|
||||
Consumer<StatusPrivacy> doReblog = (visibility) -> {
|
||||
v.startAnimation(opacityOut);
|
||||
UiUtils.opacityOut(v);
|
||||
session.getStatusInteractionController()
|
||||
.setReblogged(item.status, !item.status.reblogged, visibility, r->boostConsumer(v, r));
|
||||
dialog.dismiss();
|
||||
@@ -271,7 +282,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
|
||||
menu.findViewById(R.id.quote).setOnClickListener(c->{
|
||||
dialog.dismiss();
|
||||
v.startAnimation(opacityIn);
|
||||
UiUtils.opacityIn(v);
|
||||
Bundle args=new Bundle();
|
||||
args.putString("account", item.accountID);
|
||||
AccountSession accountSession=AccountSessionManager.getInstance().getAccount(item.accountID);
|
||||
@@ -296,7 +307,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
private void onFavoriteClick(View v){
|
||||
favorite.setSelected(!item.status.favourited);
|
||||
AccountSessionManager.getInstance().getAccount(item.accountID).getStatusInteractionController().setFavorited(item.status, !item.status.favourited, r->{
|
||||
v.startAnimation(opacityIn);
|
||||
UiUtils.opacityIn(v);
|
||||
bindText(favorites, r.favouritesCount);
|
||||
});
|
||||
}
|
||||
@@ -318,7 +329,7 @@ public class FooterStatusDisplayItem extends StatusDisplayItem{
|
||||
private void onBookmarkClick(View v){
|
||||
bookmark.setSelected(!item.status.bookmarked);
|
||||
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){
|
||||
v.startAnimation(opacityIn);
|
||||
UiUtils.opacityIn(v);
|
||||
Intent intent=new Intent(Intent.ACTION_SEND);
|
||||
intent.setType("text/plain");
|
||||
intent.putExtra(Intent.EXTRA_TEXT, item.status.url);
|
||||
|
||||
@@ -72,7 +72,7 @@ public class GapStatusDisplayItem extends StatusDisplayItem{
|
||||
private void onViewClick(View v){
|
||||
if(item.loading) return;
|
||||
boolean isTop=v==top;
|
||||
(isTop ? textTop : textBottom).startAnimation(UiUtils.opacityOut);
|
||||
UiUtils.opacityOut(isTop ? textTop : textBottom);
|
||||
V.setVisibilityAnimated((isTop ? progressTop : progressBottom), View.VISIBLE);
|
||||
item.parentFragment.onGapClick(this, isTop);
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
@@ -76,7 +77,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||
private SpannableStringBuilder parsedName;
|
||||
public final Status status;
|
||||
private boolean hasVisibilityToggle;
|
||||
public boolean hasVisibilityToggle;
|
||||
boolean needBottomPadding;
|
||||
private CharSequence extraText;
|
||||
private Notification notification;
|
||||
@@ -294,17 +295,6 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
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")
|
||||
@Override
|
||||
public void onBind(HeaderStatusDisplayItem item){
|
||||
@@ -331,23 +321,13 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
botIcon.setColorFilter(username.getCurrentTextColor());
|
||||
|
||||
deleteNotification.setVisibility(GlobalUserPreferences.enableDeleteNotifications && item.notification!=null && !item.inset ? View.VISIBLE : View.GONE);
|
||||
visibility.setVisibility(item.hasVisibilityToggle ? View.VISIBLE : View.GONE);
|
||||
if (item.hasVisibilityToggle){
|
||||
boolean hidden = !item.status.sensitiveRevealed || (item.status.hasSpoiler() && !item.status.spoilerRevealed);
|
||||
|
||||
// doing this because V.setVisibilityAnimated ignores changes between INVISIBLE and GONE
|
||||
int newVis=hidden ? View.INVISIBLE : View.VISIBLE;
|
||||
if(newVis==View.INVISIBLE && visibility.getVisibility()==View.GONE)
|
||||
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);
|
||||
boolean visible = item.status.sensitiveRevealed && (!item.status.hasSpoiler() || item.status.spoilerRevealed);
|
||||
visibility.setAlpha(visible ? 1 : 0f);
|
||||
visibility.setScaleY(visible ? 1 : 0.8f);
|
||||
visibility.setScaleX(visible ? 1 : 0.8f);
|
||||
visibility.setEnabled(visible);
|
||||
}
|
||||
itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), item.needBottomPadding ? V.dp(16) : 0);
|
||||
if(TextUtils.isEmpty(item.extraText)){
|
||||
@@ -412,6 +392,16 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
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
|
||||
public void setImage(int index, Drawable drawable){
|
||||
if(index>0){
|
||||
|
||||
@@ -46,11 +46,13 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
private final String accountID;
|
||||
private final CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||
private final CharSequence text;
|
||||
private final CharSequence timestamp;
|
||||
|
||||
public NotificationHeaderStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, Notification notification, String accountID){
|
||||
super(parentID, parentFragment);
|
||||
this.notification=notification;
|
||||
this.accountID=accountID;
|
||||
this.timestamp=notification.createdAt==null ? null : UiUtils.formatRelativeTimestamp(context, notification.createdAt);
|
||||
|
||||
if(notification.type==Notification.Type.POLL){
|
||||
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{
|
||||
private final ImageView icon, avatar;
|
||||
private final TextView text;
|
||||
private final TextView text, timestamp;
|
||||
private final int selectableItemBackground;
|
||||
|
||||
public Holder(Activity activity, ViewGroup parent){
|
||||
@@ -120,6 +122,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
icon=findViewById(R.id.icon);
|
||||
avatar=findViewById(R.id.avatar);
|
||||
text=findViewById(R.id.text);
|
||||
timestamp=findViewById(R.id.timestamp);
|
||||
|
||||
avatar.setOutlineProvider(OutlineProviders.roundedRect(8));
|
||||
avatar.setClipToOutline(true);
|
||||
@@ -152,6 +155,7 @@ public class NotificationHeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
@Override
|
||||
public void onBind(NotificationHeaderStatusDisplayItem item){
|
||||
text.setText(item.text);
|
||||
timestamp.setText(item.timestamp);
|
||||
avatar.setVisibility(item.notification.type==Notification.Type.POLL ? View.GONE : View.VISIBLE);
|
||||
icon.setImageResource(switch(item.notification.type){
|
||||
case FAVORITE -> R.drawable.ic_fluent_star_24_filled;
|
||||
|
||||
@@ -68,7 +68,7 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
|
||||
private final TextView text, percent;
|
||||
private final View button;
|
||||
private final ImageView icon;
|
||||
private final Drawable progressBg, progressBgInset;
|
||||
private final Drawable progressBg;
|
||||
|
||||
public Holder(Activity activity, ViewGroup parent){
|
||||
super(activity, R.layout.display_item_poll_option, parent);
|
||||
@@ -77,7 +77,6 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
|
||||
icon=findViewById(R.id.icon);
|
||||
button=findViewById(R.id.button);
|
||||
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);
|
||||
button.setOutlineProvider(OutlineProviders.roundedRect(20));
|
||||
button.setClipToOutline(true);
|
||||
@@ -93,22 +92,17 @@ public class PollOptionStatusDisplayItem extends StatusDisplayItem{
|
||||
item.showResults ? R.drawable.ic_poll_option_button : R.drawable.ic_fluent_radio_button_24_selector
|
||||
));
|
||||
if(item.showResults){
|
||||
Drawable bg=item.inset ? progressBgInset : progressBg;
|
||||
Drawable bg=progressBg;
|
||||
bg.setLevel(Math.round(10000f*item.votesFraction));
|
||||
button.setBackground(bg);
|
||||
itemView.setSelected(item.poll.ownVotes!=null && item.poll.ownVotes.contains(item.optionIndex));
|
||||
percent.setText(String.format(Locale.getDefault(), "%d%%", Math.round(item.votesFraction*100f)));
|
||||
}else{
|
||||
itemView.setSelected(item.poll.selectedOptions!=null && item.poll.selectedOptions.contains(item.option));
|
||||
button.setBackgroundResource(item.inset ? R.drawable.bg_poll_option_clickable_inset : 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));
|
||||
percent.setTextColor(UiUtils.getThemeColor(itemView.getContext(), R.attr.colorM3OnSecondaryContainer));
|
||||
button.setBackgroundResource(R.drawable.bg_poll_option_clickable);
|
||||
}
|
||||
text.setTextColor(UiUtils.getThemeColor(itemView.getContext(), android.R.attr.textColorPrimary));
|
||||
percent.setTextColor(UiUtils.getThemeColor(itemView.getContext(), R.attr.colorM3OnSecondaryContainer));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -204,11 +204,12 @@ public abstract class StatusDisplayItem{
|
||||
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){
|
||||
for(FilterResult filter:status.filtered){
|
||||
if(filter.filter.isActive()){
|
||||
filtered=true;
|
||||
LegacyFilter f=filter.filter;
|
||||
if(f.isActive() && filterContext != null && f.context.contains(filterContext)){
|
||||
applyingFilter=f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -315,14 +316,7 @@ public abstract class StatusDisplayItem{
|
||||
}
|
||||
}
|
||||
|
||||
LegacyFilter applyingFilter = null;
|
||||
if (!statusForContent.filterRevealed) {
|
||||
StatusFilterPredicate predicate = new StatusFilterPredicate(accountID, filterContext, FilterAction.WARN);
|
||||
statusForContent.filterRevealed = predicate.test(status);
|
||||
applyingFilter = predicate.getApplyingFilter();
|
||||
}
|
||||
|
||||
return statusForContent.filterRevealed ? items :
|
||||
return applyingFilter==null ? items :
|
||||
new ArrayList<>(List.of(new WarningFilteredStatusDisplayItem(parentID, fragment, statusForContent, items, applyingFilter)));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import static org.joinmastodon.android.ui.utils.UiUtils.opacityIn;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -16,6 +14,7 @@ import android.widget.TextView;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.fragments.BaseStatusListFragment;
|
||||
import org.joinmastodon.android.model.Status;
|
||||
import org.joinmastodon.android.model.Translation;
|
||||
@@ -29,6 +28,7 @@ import java.util.Locale;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.MovieDrawable;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.CubicBezierInterpolator;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
@@ -112,7 +112,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
}else{
|
||||
text.setText(item.text);
|
||||
}
|
||||
text.setTextIsSelectable(item.textSelectable);
|
||||
text.setTextIsSelectable(false);
|
||||
if(item.textSelectable) itemView.post(() -> text.setTextIsSelectable(true));
|
||||
text.setInvalidateOnEveryFrame(false);
|
||||
itemView.setClickable(false);
|
||||
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);
|
||||
translationButton.setOnClickListener(v->item.parentFragment.togglePostTranslation(item.status, item.parentID));
|
||||
}
|
||||
if(translationButton!=null) translationButton.animate().cancel();
|
||||
if(item.status.translationState==Status.TranslationState.HIDDEN){
|
||||
if(updateText) text.setText(item.text);
|
||||
if(translationFooter==null) return;
|
||||
translationFooter.setVisibility(translateEnabled ? View.VISIBLE : View.GONE);
|
||||
translationProgress.setVisibility(View.GONE);
|
||||
Translation existingTrans=item.status.getContentStatus().translation;
|
||||
String lang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null;
|
||||
String displayLang=Locale.forLanguageTag(lang!=null ? lang : item.status.getContentStatus().language).getDisplayLanguage();
|
||||
String existingTransLang=existingTrans!=null ? existingTrans.detectedSourceLanguage : null;
|
||||
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.setEnabled(true);
|
||||
translationButton.setAlpha(1);
|
||||
translationButton.setClickable(true);
|
||||
translationButton.animate().alpha(1).setDuration(100).start();
|
||||
translationInfo.setVisibility(View.GONE);
|
||||
UiUtils.beginLayoutTransition((ViewGroup) translationButtonWrap);
|
||||
}else{
|
||||
@@ -218,8 +222,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
if(item.status.translationState==Status.TranslationState.SHOWN){
|
||||
translationProgress.setVisibility(View.GONE);
|
||||
translationButton.setText(R.string.translation_show_original);
|
||||
translationButton.setEnabled(true);
|
||||
translationButton.setAlpha(1);
|
||||
translationButton.setClickable(true);
|
||||
translationButton.animate().alpha(1).setDuration(200).start();
|
||||
translationInfo.setVisibility(View.VISIBLE);
|
||||
translationButton.setVisibility(View.VISIBLE);
|
||||
String displayLang=Locale.forLanguageTag(item.status.translation.detectedSourceLanguage).getDisplayLanguage();
|
||||
@@ -233,8 +237,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
}
|
||||
}else{ // LOADING
|
||||
translationProgress.setVisibility(View.VISIBLE);
|
||||
translationButton.setEnabled(false);
|
||||
translationButton.startAnimation(opacityIn);
|
||||
translationButton.setClickable(false);
|
||||
translationButton.animate().alpha(UiUtils.ALPHA_PRESSED).setStartDelay(50).setDuration(300).setInterpolator(CubicBezierInterpolator.DEFAULT).start();
|
||||
translationInfo.setVisibility(View.INVISIBLE);
|
||||
UiUtils.beginLayoutTransition((ViewGroup) translationButton.getParent());
|
||||
}
|
||||
|
||||
@@ -31,13 +31,11 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
|
||||
}
|
||||
|
||||
public static class Holder extends StatusDisplayItem.Holder<WarningFilteredStatusDisplayItem>{
|
||||
public final View warningWrap;
|
||||
public final TextView text;
|
||||
public List<StatusDisplayItem> filteredItems;
|
||||
|
||||
public Holder(Context context, ViewGroup parent) {
|
||||
super(context, R.layout.display_item_filter_warning, parent);
|
||||
warningWrap=findViewById(R.id.warning_wrap);
|
||||
text=findViewById(R.id.text);
|
||||
}
|
||||
|
||||
@@ -45,11 +43,7 @@ public class WarningFilteredStatusDisplayItem extends StatusDisplayItem{
|
||||
public void onBind(WarningFilteredStatusDisplayItem item) {
|
||||
filteredItems = item.filteredItems;
|
||||
text.setText(item.parentFragment.getString(R.string.sk_filtered, item.applyingFilter.title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick() {
|
||||
item.parentFragment.onWarningClick(this);
|
||||
itemView.setOnClickListener(v->item.parentFragment.onWarningClick(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,10 @@ public class BlurhashCrossfadeDrawable extends Drawable{
|
||||
|
||||
public void setImageDrawable(Drawable imageDrawable){
|
||||
this.imageDrawable=imageDrawable;
|
||||
if(imageDrawable!=null){
|
||||
width=imageDrawable.getIntrinsicWidth();
|
||||
height=imageDrawable.getIntrinsicHeight();
|
||||
}
|
||||
invalidateSelf();
|
||||
}
|
||||
|
||||
@@ -99,11 +103,15 @@ public class BlurhashCrossfadeDrawable extends Drawable{
|
||||
|
||||
@Override
|
||||
public int getIntrinsicWidth(){
|
||||
if(width==0)
|
||||
return imageDrawable==null ? 1920 : imageDrawable.getIntrinsicWidth();
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntrinsicHeight(){
|
||||
if(height==0)
|
||||
return imageDrawable==null ? 1080 : imageDrawable.getIntrinsicHeight();
|
||||
return height;
|
||||
}
|
||||
|
||||
|
||||
@@ -734,9 +734,18 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
||||
public void onBind(Attachment item){
|
||||
super.onBind(item);
|
||||
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) imageView.getLayoutParams();
|
||||
params.width=item.getWidth();
|
||||
params.height=item.getHeight();
|
||||
ViewImageLoader.load(this, listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition()), new UrlImageLoaderRequest(item.url), false);
|
||||
Drawable currentDrawable=listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition());
|
||||
if(item.hasKnownDimensions()){
|
||||
params.width=item.getWidth();
|
||||
params.height=item.getHeight();
|
||||
}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
|
||||
@@ -778,9 +787,18 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
||||
super.onBind(item);
|
||||
playerReady=false;
|
||||
FrameLayout.LayoutParams params=(FrameLayout.LayoutParams) wrap.getLayoutParams();
|
||||
params.width=item.getWidth();
|
||||
params.height=item.getHeight();
|
||||
wrap.setBackground(listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition()));
|
||||
Drawable currentDrawable=listener.getPhotoViewCurrentDrawable(getAbsoluteAdapterPosition());
|
||||
if(item.hasKnownDimensions()){
|
||||
params.width=item.getWidth();
|
||||
params.height=item.getHeight();
|
||||
}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);
|
||||
if(itemView.isAttachedToWindow()){
|
||||
reset();
|
||||
@@ -841,7 +859,9 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
||||
@Override
|
||||
public boolean onError(MediaPlayer mp, int what, int 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(){
|
||||
@@ -862,6 +882,8 @@ public class PhotoViewer implements ZoomPanView.Listener{
|
||||
player.prepareAsync();
|
||||
}catch(IOException x){
|
||||
Log.w(TAG, "Error initializing gif player", x);
|
||||
Toast.makeText(activity, R.string.error_playing_video, Toast.LENGTH_SHORT).show();
|
||||
onStartSwipeToDismissTransition(0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -119,8 +119,10 @@ public class ZoomPanView extends FrameLayout implements ScaleGestureDetector.OnS
|
||||
|
||||
int width=right-left;
|
||||
int height=bottom-top;
|
||||
if(width==0 || height==0)
|
||||
if(width==0 || height==0 || child.getWidth()==0 || child.getWidth()==0){
|
||||
matrix.reset();
|
||||
return;
|
||||
}
|
||||
|
||||
float scale=Math.min(width/(float)child.getWidth(), height/(float)child.getHeight());
|
||||
minScale=scale;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
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.trueBlackTheme;
|
||||
import static org.joinmastodon.android.api.session.AccountLocalPreferences.ColorPreference.*;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
@@ -11,20 +11,21 @@ import androidx.annotation.StyleRes;
|
||||
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.session.AccountLocalPreferences;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ColorPalette {
|
||||
public static final Map<GlobalUserPreferences.ColorPreference, ColorPalette> palettes = Map.of(
|
||||
ColorPreference.MATERIAL3, new ColorPalette(R.style.ColorPalette_Material3)
|
||||
public static final Map<AccountLocalPreferences.ColorPreference, ColorPalette> palettes = Map.of(
|
||||
MATERIAL3, new ColorPalette(R.style.ColorPalette_Material3)
|
||||
.dark(R.style.ColorPalette_Material3_Dark, R.style.ColorPalette_Material3_AutoLightDark),
|
||||
ColorPreference.PINK, new ColorPalette(R.style.ColorPalette_Pink),
|
||||
ColorPreference.PURPLE, new ColorPalette(R.style.ColorPalette_Purple),
|
||||
ColorPreference.GREEN, new ColorPalette(R.style.ColorPalette_Green),
|
||||
ColorPreference.BLUE, new ColorPalette(R.style.ColorPalette_Blue),
|
||||
ColorPreference.BROWN, new ColorPalette(R.style.ColorPalette_Brown),
|
||||
ColorPreference.RED, new ColorPalette(R.style.ColorPalette_Red),
|
||||
ColorPreference.YELLOW, new ColorPalette(R.style.ColorPalette_Yellow)
|
||||
PINK, new ColorPalette(R.style.ColorPalette_Pink),
|
||||
PURPLE, new ColorPalette(R.style.ColorPalette_Purple),
|
||||
GREEN, new ColorPalette(R.style.ColorPalette_Green),
|
||||
BLUE, new ColorPalette(R.style.ColorPalette_Blue),
|
||||
BROWN, new ColorPalette(R.style.ColorPalette_Brown),
|
||||
RED, new ColorPalette(R.style.ColorPalette_Red),
|
||||
YELLOW, new ColorPalette(R.style.ColorPalette_Yellow)
|
||||
);
|
||||
|
||||
private @StyleRes int base;
|
||||
|
||||
@@ -28,6 +28,7 @@ public class MediaAttachmentViewController{
|
||||
private final Context context;
|
||||
private boolean didClear;
|
||||
private Status status;
|
||||
private Attachment attachment;
|
||||
|
||||
public MediaAttachmentViewController(Context context, MediaGridStatusDisplayItem.GridItemType type){
|
||||
view=context.getSystemService(LayoutInflater.class).inflate(switch(type){
|
||||
@@ -54,6 +55,7 @@ public class MediaAttachmentViewController{
|
||||
|
||||
public void bind(Attachment attachment, Status status){
|
||||
this.status=status;
|
||||
this.attachment=attachment;
|
||||
crossfadeDrawable.setSize(attachment.getWidth(), attachment.getHeight());
|
||||
crossfadeDrawable.setBlurhashDrawable(attachment.blurhashPlaceholder);
|
||||
crossfadeDrawable.setCrossfadeAlpha(0f);
|
||||
@@ -76,6 +78,11 @@ public class MediaAttachmentViewController{
|
||||
crossfadeDrawable.setImageDrawable(drawable);
|
||||
if(didClear)
|
||||
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(){
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.joinmastodon.android.ui.utils;
|
||||
|
||||
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.trueBlackTheme;
|
||||
|
||||
@@ -53,9 +54,8 @@ import android.view.MenuItem;
|
||||
import android.view.SubMenu;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewPropertyAnimator;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.animation.AlphaAnimation;
|
||||
import android.view.animation.Animation;
|
||||
import android.webkit.MimeTypeMap;
|
||||
import android.widget.Button;
|
||||
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.GetStatusByID;
|
||||
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.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.ScheduledStatusDeletedEvent;
|
||||
@@ -176,17 +177,6 @@ public class UiUtils {
|
||||
public static int MAX_WIDTH, SCROLL_TO_TOP_DELTA;
|
||||
|
||||
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() {
|
||||
}
|
||||
@@ -973,14 +963,20 @@ public class UiUtils {
|
||||
}
|
||||
|
||||
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 DARK -> R.style.Theme_Mastodon_Dark;
|
||||
default -> R.style.Theme_Mastodon_AutoLightDark;
|
||||
});
|
||||
|
||||
ColorPalette palette = ColorPalette.palettes.get(GlobalUserPreferences.color);
|
||||
if (palette != null) palette.apply(context);
|
||||
AccountLocalPreferences prefs=session != null ? session.getLocalPreferences() : null;
|
||||
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();
|
||||
MAX_WIDTH = (int) res.getDimension(R.dimen.layout_max_width);
|
||||
@@ -997,9 +993,9 @@ public class UiUtils {
|
||||
}
|
||||
|
||||
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 theme == GlobalUserPreferences.ThemePreference.DARK;
|
||||
return theme == DARK;
|
||||
}
|
||||
|
||||
public static Optional<Pair<String, Optional<String>>> parseFediverseHandle(String maybeFediHandle) {
|
||||
@@ -1740,4 +1736,16 @@ public class UiUtils {
|
||||
.filter(Objects::nonNull)
|
||||
.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import android.widget.TextView;
|
||||
import org.joinmastodon.android.GlobalUserPreferences;
|
||||
import org.joinmastodon.android.R;
|
||||
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.AccountSessionManager;
|
||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||
@@ -66,7 +67,7 @@ public class ComposeLanguageAlertViewController{
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if(!TextUtils.isEmpty(preferred)){
|
||||
MastodonLanguage lang = resolver.fromOrFallback(preferred);
|
||||
MastodonLanguage lang=resolver.fromOrFallback(preferred);
|
||||
specialLocales.add(new SpecialLocaleInfo(
|
||||
lang,
|
||||
lang.getDisplayName(context),
|
||||
@@ -75,7 +76,7 @@ public class ComposeLanguageAlertViewController{
|
||||
}
|
||||
|
||||
if(!Locale.getDefault().getLanguage().equals(preferred)){
|
||||
MastodonLanguage lang = resolver.getDefault();
|
||||
MastodonLanguage lang=resolver.getDefault();
|
||||
specialLocales.add(new SpecialLocaleInfo(
|
||||
lang,
|
||||
lang.getDisplayName(context),
|
||||
@@ -91,8 +92,18 @@ public class ComposeLanguageAlertViewController{
|
||||
detectLanguage(detected, postText);
|
||||
}
|
||||
|
||||
if (session!=null && session.getLocalPreferences().bottomEncoding) {
|
||||
specialLocales.add(new SpecialLocaleInfo(null, "\uD83E\uDD7A\uD83D\uDC49\uD83D\uDC48", "bottom"));
|
||||
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"));
|
||||
}
|
||||
}
|
||||
|
||||
if(previouslySelected!=null){
|
||||
@@ -323,7 +334,7 @@ public class ComposeLanguageAlertViewController{
|
||||
public void onClick(){
|
||||
selectItem(getAbsoluteAdapterPosition());
|
||||
selectedLocale=item.language;
|
||||
selectedEncoding = item.title.equals("bottom") ? "bottom" : null;
|
||||
selectedEncoding=item.title != null && item.title.equals("bottom") ? "bottom" : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/bookmark_selected" android:state_selected="true"/>
|
||||
<item android:color="?android:textColorSecondary"/>
|
||||
<item android:color="?colorM3OnSurfaceVariant"/>
|
||||
</selector>
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<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" />
|
||||
</selector>
|
||||
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:color="@color/favorite_selected" android:state_selected="true"/>
|
||||
<item android:color="?android:textColorSecondary"/>
|
||||
<item android:color="?colorM3OnSurfaceVariant"/>
|
||||
</selector>
|
||||
5
mastodon/src/main/res/color/like_icon.xml
Normal file
5
mastodon/src/main/res/color/like_icon.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
7
mastodon/src/main/res/drawable/bg_filter_warning.xml
Normal file
7
mastodon/src/main/res/drawable/bg_filter_warning.xml
Normal 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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -3,8 +3,7 @@
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/warning_wrap"
|
||||
android:background="@drawable/bg_timeline_gap">
|
||||
android:background="@drawable/bg_filter_warning">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
android:layout_marginStart="16dp"
|
||||
android:duplicateParentState="true"
|
||||
android:src="@drawable/ic_fluent_chat_multiple_24_selector_text"
|
||||
android:tint="?android:textColorSecondary"
|
||||
android:tint="?colorM3OnSurfaceVariant"
|
||||
android:gravity="center_vertical" />
|
||||
<TextView
|
||||
android:id="@+id/reply"
|
||||
@@ -47,6 +47,7 @@
|
||||
android:minWidth="16dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textAppearance="@style/m3_label_large"
|
||||
android:textColor="?colorM3OnSurfaceVariant"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
tools:text="123"
|
||||
@@ -62,7 +63,6 @@
|
||||
android:id="@+id/boost_btn"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:foregroundTint="@color/boost_icon"
|
||||
android:paddingVertical="12dp">
|
||||
<ImageView
|
||||
android:layout_width="24sp"
|
||||
@@ -101,6 +101,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:paddingVertical="12dp">
|
||||
<ImageView
|
||||
android:id="@+id/favorite_icon"
|
||||
android:layout_width="24sp"
|
||||
android:layout_height="24sp"
|
||||
android:layout_gravity="center_vertical"
|
||||
@@ -160,7 +161,7 @@
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:src="@drawable/ic_fluent_share_24_regular"
|
||||
android:tint="?android:textColorSecondary"
|
||||
android:tint="?colorM3OnSurfaceVariant"
|
||||
android:gravity="center_vertical"/>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
@@ -43,6 +43,8 @@
|
||||
android:layout_height="48dp"
|
||||
android:background="?android:actionBarItemBackground"
|
||||
android:scaleType="center"
|
||||
android:contentDescription="@string/spoiler_hide"
|
||||
android:tooltipText="@string/spoiler_hide"
|
||||
android:src="@drawable/ic_fluent_eye_24_regular"
|
||||
android:tint="?colorM3OnSurfaceVariant"
|
||||
android:visibility="gone" />
|
||||
|
||||
@@ -22,14 +22,42 @@
|
||||
android:layout_height="32dp"
|
||||
android:layout_marginStart="12dp"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textColor="?colorM3OnSurface"
|
||||
android:singleLine="true"
|
||||
tools:text="Notification text"/>
|
||||
<org.joinmastodon.android.ui.views.HeaderSubtitleLinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:textAppearance="@style/m3_body_large"
|
||||
android:textColor="?colorM3OnSurface"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
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>
|
||||
@@ -132,7 +132,7 @@
|
||||
android:layout_marginTop="-4dp"
|
||||
android:layout_marginStart="-12dp"
|
||||
android:background="@drawable/bg_tabbar_badge"
|
||||
android:textColor="?colorM3OnPrimary"
|
||||
android:textColor="?colorM3OnError"
|
||||
android:gravity="center"
|
||||
android:includeFontPadding="false"
|
||||
android:textAppearance="@style/m3_label_small"
|
||||
|
||||
@@ -316,4 +316,10 @@
|
||||
<string name="sk_federated_timeline_info_banner">هذه هي أحدث المنشورات للأعضاء في فديراليتك.</string>
|
||||
<string name="sk_bubble_timeline_info_banner">هذه هي أحدث المنشورات على الشبكة والتي انتقاها مُدراء خادمكم.</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>
|
||||
@@ -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_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_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_minutes_5">5 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_load_missing_posts_below">Ältere 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>
|
||||
@@ -367,7 +367,7 @@
|
||||
<item quantity="other">%1$,d usuarios reaccionaron con %2$s</item>
|
||||
</plurals>
|
||||
<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_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>
|
||||
@@ -400,4 +400,6 @@
|
||||
<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_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>
|
||||
@@ -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_default_content_type">Eduki-mota lehenetsia</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">erreakzionatuta</string>
|
||||
<string name="sk_reacted_with">%1$s-(e)k honela erreakzionatu du: %2$s</string>
|
||||
<string name="sk_reacted">%s-(e)k erreakzionatu du</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>
|
||||
@@ -9,7 +9,7 @@
|
||||
<string name="preparing_auth">Valmistellaan todennusta…</string>
|
||||
<string name="finishing_auth">Viimeistellään todennusta…</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="user_followed_you">%s seurasi sinua</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_favorite">Suosikki</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_poll">Lisää kysely</string>
|
||||
<string name="emoji">Emoji</string>
|
||||
@@ -240,8 +240,8 @@
|
||||
<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="open_in_browser">Avaa selaimessa</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="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="signup_reason">Miksi haluat liittyä?</string>
|
||||
<string name="signup_reason_note">Tämä auttaa meitä arvioimaan hakemustasi.</string>
|
||||
<string name="clear">Tyhjennä</string>
|
||||
@@ -270,11 +270,11 @@
|
||||
<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 -->
|
||||
<plurals name="x_followers">
|
||||
<item quantity="one">%d seuraaja</item>
|
||||
<item quantity="other">%d seuraajaa</item>
|
||||
<item quantity="one">%,d seuraaja</item>
|
||||
<item quantity="other">%,d seuraajaa</item>
|
||||
</plurals>
|
||||
<plurals name="x_following">
|
||||
<item quantity="one">%d seurattu</item>
|
||||
<item quantity="one">%,d seurattu</item>
|
||||
<item quantity="other">%d seurattua</item>
|
||||
</plurals>
|
||||
<plurals name="x_favorites">
|
||||
@@ -351,7 +351,7 @@
|
||||
<string name="server_filter_region_asia">Aasia</string>
|
||||
<string name="server_filter_region_oceania">Oseania</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="pick_server_for_me">Valitse minulle</string>
|
||||
<string name="profile_add_row">Lisää rivi</string>
|
||||
@@ -385,7 +385,7 @@
|
||||
<string name="signup_or_login">tai</string>
|
||||
<string name="learn_more">Lue lisää</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="welcome_paragraph2">Jokainen Mastodon tili isännöi palvelimella - kullakin on omat arvot, säännöt, & 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>
|
||||
@@ -583,11 +583,14 @@
|
||||
<string name="time_hours_ago_short">%dh sitten</string>
|
||||
<string name="time_days_ago_short">%dd sitten</string>
|
||||
<!-- %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 -->
|
||||
<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_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">
|
||||
<item quantity="one">%d osallistuja</item>
|
||||
<item quantity="other">%d osallistujaa</item>
|
||||
@@ -596,4 +599,5 @@
|
||||
<item quantity="one">%,d viesti tänään</item>
|
||||
<item quantity="other">%,d viestiä tänään</item>
|
||||
</plurals>
|
||||
<string name="error_playing_video">Virhe videon toistossa</string>
|
||||
</resources>
|
||||
|
||||
@@ -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_button_react">Reagoi emojilla</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_hint">Kirjoita vastataksesi emojilla</string>
|
||||
<string name="sk_enter_emoji_toast">Lisää emoji</string>
|
||||
<string name="sk_enter_emoji_hint">Lisää emoji tai etsi</string>
|
||||
<string name="sk_mute_label">Kesto</string>
|
||||
<string name="sk_duration_indefinite">Loputon</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_nobody">Ei koskaan</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_translate_show_original">Näytä alkuperäinen</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_forward_report_to">Lähetä edelleen kohteeseen %s</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_confirm_save_draft">Tallenna luonnos\?</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_single_notification">Näytä vain yksi ilmoitus</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_remove_follower">Poista seuraajista</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_all">Kaikki vastaukset</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>
|
||||
<plurals name="sk_users_reacted_with">
|
||||
<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_content_type_bbcode">BBCode</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_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>
|
||||
@@ -359,7 +359,7 @@
|
||||
<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_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_alt_text_missing">Selitys puuttuu vähintään yhdestä liitteestä.</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_continues_playback_summary">Anna mediatoiston jatkua lisäten uusi raita</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>
|
||||
@@ -372,7 +372,7 @@
|
||||
</plurals>
|
||||
<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_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>
|
||||
<plurals name="sk_posts_count_label">
|
||||
<item quantity="one">message</item>
|
||||
@@ -393,12 +393,15 @@
|
||||
<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_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 d’elles 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_below">Charger les anciens messages</string>
|
||||
<string name="sk_time_seconds">%d secondes</string>
|
||||
<string name="sk_time_minutes">%d minutes</string>
|
||||
<string name="sk_time_hours">%d heures</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>
|
||||
@@ -13,6 +13,7 @@
|
||||
<string name="user_sent_follow_request">%s հետեւելու հարցում է ուղարկել</string>
|
||||
<string name="user_favorited">%s-ը հավանեց ձեր գրառումը</string>
|
||||
<string name="notification_boosted">%s տարածեց ձեր գրառումը</string>
|
||||
<string name="poll_ended">Տեսեք ձեր քվեարկած հարցման արդյունքները</string>
|
||||
<string name="share_toot_title">Տարածել</string>
|
||||
<string name="settings">Կարգավորումներ</string>
|
||||
<string name="publish">Հրապարակել</string>
|
||||
@@ -102,6 +103,7 @@
|
||||
<string name="deleting">Ջնջում…</string>
|
||||
<string name="play">Նվագարկել</string>
|
||||
<string name="pause">Դադար տալ</string>
|
||||
<string name="log_out">Ելք</string>
|
||||
<string name="add_account">Ավելացնել հաշիվ</string>
|
||||
<string name="search_hint">Որոնել</string>
|
||||
<string name="hashtags">Պիտակներ</string>
|
||||
|
||||
@@ -554,5 +554,18 @@
|
||||
<string name="time_hours_ago_short">%dj yang lalu</string>
|
||||
<string name="time_days_ago_short">%dh yang lalu</string>
|
||||
<!-- %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 -->
|
||||
<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>
|
||||
|
||||
@@ -366,7 +366,7 @@
|
||||
<item quantity="other">%1$,d pengguna bereaksi dengan %2$s</item>
|
||||
</plurals>
|
||||
<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_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>
|
||||
@@ -387,11 +387,14 @@
|
||||
<string name="sk_search_suicide_hotlines">Temukan hotline</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_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_search_suicide_title">Jika Anda dalam kesulitan…</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_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_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>
|
||||
@@ -599,4 +599,5 @@
|
||||
<item quantity="one">%,d færsla í dag</item>
|
||||
<item quantity="other">%,d færslur í dag</item>
|
||||
</plurals>
|
||||
<string name="error_playing_video">Villa við að spila myndskeið</string>
|
||||
</resources>
|
||||
|
||||
@@ -588,6 +588,8 @@
|
||||
<string name="post_translated">Tradotto da %1$s utilizzando %2$s</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="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>
|
||||
<plurals name="x_participants">
|
||||
<item quantity="one">%,d participante</item>
|
||||
@@ -597,4 +599,5 @@
|
||||
<item quantity="one">%,d post oggi</item>
|
||||
<item quantity="other">%,d post oggi</item>
|
||||
</plurals>
|
||||
<string name="error_playing_video">Errore nella riproduzione del video</string>
|
||||
</resources>
|
||||
|
||||
@@ -568,4 +568,5 @@
|
||||
<plurals name="x_posts_today">
|
||||
<item quantity="other">今日の投稿 %,d 件</item>
|
||||
</plurals>
|
||||
<string name="error_playing_video">動画再生に失敗しました</string>
|
||||
</resources>
|
||||
|
||||
@@ -572,5 +572,15 @@
|
||||
<string name="time_hours_ago_short">%dh atrás</string>
|
||||
<string name="time_days_ago_short">%dd atrás</string>
|
||||
<!-- %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 -->
|
||||
<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>
|
||||
|
||||
@@ -379,7 +379,7 @@
|
||||
<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_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_suicide_helplines_url">http://www.antisuicid.com/</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_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_blocked_accounts">Conturi blocate</string>
|
||||
<string name="sk_muted_accounts">Conturi amuțite</string>
|
||||
</resources>
|
||||
@@ -661,4 +661,5 @@
|
||||
<item quantity="many">%,d постов сегодня</item>
|
||||
<item quantity="other">%,d постов сегодня</item>
|
||||
</plurals>
|
||||
<string name="error_playing_video">Ошибка воспроизведения видео</string>
|
||||
</resources>
|
||||
|
||||
@@ -250,7 +250,7 @@
|
||||
<string name="sk_settings_server_version">Версия сервера: %s</string>
|
||||
<string name="sk_notify_poll_results">Итоги голосования</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_expand">Развернуть</string>
|
||||
<string name="sk_collapse">Свернуть</string>
|
||||
@@ -331,4 +331,84 @@
|
||||
<string name="sk_settings_prefix_replies_to_others">Только в ответ другим</string>
|
||||
<string name="sk_settings_unifiedpush_no_distributor">Распределители не найдены</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>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user