Compare commits
53 Commits
v1.2.0+for
...
v1.2.0+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebdd1a0b03 | ||
|
|
6c44575f7a | ||
|
|
8be832239a | ||
|
|
c7be202430 | ||
|
|
244c5dc6b4 | ||
|
|
6bbb9a638e | ||
|
|
44041b136a | ||
|
|
7e17c30ce2 | ||
|
|
c4d3d1b409 | ||
|
|
03de63754b | ||
|
|
0e506f0b1a | ||
|
|
a2ab752870 | ||
|
|
eaa032828a | ||
|
|
cceb0b4c6c | ||
|
|
a58640a718 | ||
|
|
920384b26c | ||
|
|
193a2c4f70 | ||
|
|
793dec98b2 | ||
|
|
11ddf8015d | ||
|
|
1753bdbd8b | ||
|
|
d6e563486b | ||
|
|
0112bfa9c4 | ||
|
|
5951611fb0 | ||
|
|
2d31b726ac | ||
|
|
d2f295ef88 | ||
|
|
d1b53554ce | ||
|
|
ec5db122d0 | ||
|
|
0216e22fcc | ||
|
|
5734b19d8c | ||
|
|
cc8c818e13 | ||
|
|
e58aeec097 | ||
|
|
58b000927a | ||
|
|
797642b972 | ||
|
|
2e1f273d78 | ||
|
|
35d6800877 | ||
|
|
781856b822 | ||
|
|
ff272179e7 | ||
|
|
bec47f40f7 | ||
|
|
f9607a434a | ||
|
|
b650ca85bc | ||
|
|
91e154bbee | ||
|
|
f4365ed163 | ||
|
|
0c02b0cb68 | ||
|
|
b0aaa58fa7 | ||
|
|
054ab774d5 | ||
|
|
8ca33b552d | ||
|
|
6734c2b9f7 | ||
|
|
c484477d6a | ||
|
|
d9b5223749 | ||
|
|
55856450b3 | ||
|
|
bb28a3bf83 | ||
|
|
5e4e56bd2c | ||
|
|
82fac1d4e7 |
@@ -55,7 +55,7 @@ On the Fediverse, it’s quite common for people to pin posts they want others t
|
||||
|
||||
[apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk](https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk)
|
||||
|
||||
<a href="#installation"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
|
||||
<a href="https://apt.izzysoft.de/fdroid/index/apk/org.joinmastodon.android.sk"><img height="50" alt="Get it on IzzyOnDroid" src="img/izzy-badge.png"></a>
|
||||
|
||||
Note that you'll need to add Izzy's F-Droid repository to your F-Droid app first:
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@ android {
|
||||
applicationId "org.joinmastodon.android.sk"
|
||||
minSdk 23
|
||||
targetSdk 33
|
||||
versionCode 79
|
||||
versionName "1.2.0+fork.79"
|
||||
versionCode 83
|
||||
versionName "1.2.0+fork.83"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
resConfigs "ar-rSA", "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", "vi-rVN", "zh-rCN", "zh-rTW"
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
<action android:name="android.intent.action.PROCESS_TEXT" />
|
||||
<data android:mimeType="text/plain" />
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="android.intent.action.TRANSLATE" />
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.joinmastodon.android.api.requests.statuses.SetStatusFavorited;
|
||||
import org.joinmastodon.android.api.requests.statuses.SetStatusReblogged;
|
||||
import org.joinmastodon.android.api.session.AccountSession;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.NotificationReceivedEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.NotificationAction;
|
||||
import org.joinmastodon.android.model.Preferences;
|
||||
@@ -55,6 +56,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent){
|
||||
UiUtils.setUserPreferredTheme(context);
|
||||
if(BuildConfig.DEBUG){
|
||||
Log.e(TAG, "received: "+intent);
|
||||
Bundle extras=intent.getExtras();
|
||||
@@ -84,6 +86,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
||||
}
|
||||
String accountID=account.getID();
|
||||
PushNotification pn=AccountSessionManager.getInstance().getAccount(accountID).getPushSubscriptionManager().decryptNotification(k, p, s);
|
||||
E.post(new NotificationReceivedEvent(accountID, pn.notificationId+""));
|
||||
new GetNotificationByID(pn.notificationId+"")
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
@@ -185,7 +188,7 @@ public class PushNotificationReceiver extends BroadcastReceiver{
|
||||
.setShowWhen(true)
|
||||
.setCategory(Notification.CATEGORY_SOCIAL)
|
||||
.setAutoCancel(true)
|
||||
.setColor(context.getColor(R.color.shortcut_icon_background));
|
||||
.setColor(UiUtils.getThemeColor(context, android.R.attr.colorAccent));
|
||||
|
||||
if (!GlobalUserPreferences.uniformNotificationIcon) {
|
||||
builder.setSmallIcon(switch (pn.notificationType) {
|
||||
|
||||
@@ -11,7 +11,7 @@ public class ApiUtils{
|
||||
//no instance
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>> List<String> enumSetToStrings(EnumSet<E> e, Class<E> cls){
|
||||
public static <E extends Enum<E>> List<String> enumSetToStrings(EnumSet<E> e, Class<E> cls){
|
||||
return e.stream().map(ev->{
|
||||
try{
|
||||
SerializedName annotation=cls.getField(ev.name()).getAnnotation(SerializedName.class);
|
||||
|
||||
@@ -128,7 +128,7 @@ public class CacheController{
|
||||
});
|
||||
}
|
||||
|
||||
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean onlyPosts, boolean forceReload, Callback<PaginatedResponse<List<Notification>>> callback){
|
||||
public void getNotifications(String maxID, int count, boolean onlyMentions, boolean onlyPosts, boolean forceReload, Callback<CacheablePaginatedResponse<List<Notification>>> callback){
|
||||
cancelDelayedClose();
|
||||
databaseThread.postRunnable(()->{
|
||||
try{
|
||||
@@ -156,7 +156,7 @@ public class CacheController{
|
||||
result.add(ntf);
|
||||
}while(cursor.moveToNext());
|
||||
String _newMaxID=newMaxID;
|
||||
uiHandler.post(()->callback.onSuccess(new PaginatedResponse<>(result, _newMaxID)));
|
||||
uiHandler.post(()->callback.onSuccess(new CacheablePaginatedResponse<>(result, _newMaxID, true)));
|
||||
return;
|
||||
}
|
||||
}catch(IOException x){
|
||||
@@ -168,7 +168,7 @@ public class CacheController{
|
||||
.setCallback(new Callback<>(){
|
||||
@Override
|
||||
public void onSuccess(List<Notification> result){
|
||||
callback.onSuccess(new PaginatedResponse<>(result.stream().filter(ntf->{
|
||||
callback.onSuccess(new CacheablePaginatedResponse<>(result.stream().filter(ntf->{
|
||||
if(ntf.status!=null){
|
||||
for(Filter filter:filters){
|
||||
if(filter.matches(ntf.status)){
|
||||
@@ -177,7 +177,7 @@ public class CacheController{
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id));
|
||||
}).collect(Collectors.toList()), result.isEmpty() ? null : result.get(result.size()-1).id, false));
|
||||
putNotifications(result, onlyMentions, onlyPosts, maxID==null);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package org.joinmastodon.android.api.requests.markers;
|
||||
|
||||
import org.joinmastodon.android.api.ApiUtils;
|
||||
import org.joinmastodon.android.api.MastodonAPIRequest;
|
||||
import org.joinmastodon.android.model.Marker;
|
||||
import org.joinmastodon.android.model.Markers;
|
||||
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class GetMarkers extends MastodonAPIRequest<Markers> {
|
||||
public GetMarkers(EnumSet<Marker.Type> timelines) {
|
||||
super(HttpMethod.GET, "/markers", Markers.class);
|
||||
for (String type : ApiUtils.enumSetToStrings(timelines, Marker.Type.class)){
|
||||
addQueryParameter("timeline[]", type);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import org.joinmastodon.android.api.StatusInteractionController;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Application;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Markers;
|
||||
import org.joinmastodon.android.model.Preferences;
|
||||
import org.joinmastodon.android.model.PushSubscription;
|
||||
import org.joinmastodon.android.model.Token;
|
||||
@@ -31,6 +32,7 @@ public class AccountSession{
|
||||
public String pushAccountID;
|
||||
public Preferences preferences;
|
||||
public AccountActivationInfo activationInfo;
|
||||
public Markers markers;
|
||||
private transient MastodonAPIController apiController;
|
||||
private transient StatusInteractionController statusInteractionController, remoteStatusInteractionController;
|
||||
private transient CacheController cacheController;
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.joinmastodon.android.api.requests.accounts.GetWordFilters;
|
||||
import org.joinmastodon.android.api.requests.instance.GetCustomEmojis;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
|
||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
||||
import org.joinmastodon.android.api.requests.markers.GetMarkers;
|
||||
import org.joinmastodon.android.api.requests.oauth.CreateOAuthApp;
|
||||
import org.joinmastodon.android.events.EmojiUpdatedEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
@@ -33,6 +34,8 @@ import org.joinmastodon.android.model.Emoji;
|
||||
import org.joinmastodon.android.model.EmojiCategory;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.model.Marker;
|
||||
import org.joinmastodon.android.model.Markers;
|
||||
import org.joinmastodon.android.model.Preferences;
|
||||
import org.joinmastodon.android.model.Token;
|
||||
|
||||
@@ -46,6 +49,7 @@ import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -255,6 +259,7 @@ public class AccountSessionManager{
|
||||
// if(now-session.filtersLastUpdated>3600_000L){
|
||||
updateSessionWordFilters(session);
|
||||
// }
|
||||
updateSessionMarkers(session);
|
||||
}
|
||||
if(loadedInstances){
|
||||
maybeUpdateCustomEmojis(domains);
|
||||
@@ -271,6 +276,15 @@ public class AccountSessionManager{
|
||||
}
|
||||
}
|
||||
|
||||
private void preferencesFromSource(AccountSession session, Account account) {
|
||||
if (account != null && account.source != null && session.preferences != null) {
|
||||
if (account.source.privacy != null)
|
||||
session.preferences.postingDefaultVisibility = account.source.privacy;
|
||||
if (account.source.language != null)
|
||||
session.preferences.postingDefaultLanguage = account.source.language;
|
||||
}
|
||||
}
|
||||
|
||||
private void updateSessionLocalInfo(AccountSession session){
|
||||
new GetOwnAccount()
|
||||
.setCallback(new Callback<>(){
|
||||
@@ -278,19 +292,12 @@ public class AccountSessionManager{
|
||||
public void onSuccess(Account result){
|
||||
session.self=result;
|
||||
session.infoLastUpdated=System.currentTimeMillis();
|
||||
if(session.preferences != null && session.preferences.postingDefaultVisibility != null){
|
||||
session.preferences.postingDefaultVisibility = result.source.privacy;
|
||||
}
|
||||
if(session.preferences != null && session.preferences.postingDefaultLanguage != null){
|
||||
session.preferences.postingDefaultLanguage = result.source.language;
|
||||
}
|
||||
preferencesFromSource(session, result);
|
||||
writeAccountsFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error){
|
||||
|
||||
}
|
||||
public void onError(ErrorResponse error){}
|
||||
})
|
||||
.exec(session.getID());
|
||||
}
|
||||
@@ -300,16 +307,13 @@ public class AccountSessionManager{
|
||||
@Override
|
||||
public void onSuccess(Preferences preferences) {
|
||||
session.preferences=preferences;
|
||||
preferencesFromSource(session, session.self);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error) {
|
||||
Preferences preferences = new Preferences();
|
||||
if(session.self != null){
|
||||
preferences.postingDefaultVisibility = session.self.source.privacy;
|
||||
preferences.postingDefaultLanguage = session.self.source.language;
|
||||
}
|
||||
session.preferences = preferences;
|
||||
session.preferences = new Preferences();
|
||||
preferencesFromSource(session, session.self);
|
||||
}
|
||||
}).exec(session.getID());
|
||||
}
|
||||
@@ -332,6 +336,21 @@ public class AccountSessionManager{
|
||||
.exec(session.getID());
|
||||
}
|
||||
|
||||
private void updateSessionMarkers(AccountSession session) {
|
||||
new GetMarkers(EnumSet.allOf(Marker.Type.class)).setCallback(new Callback<>() {
|
||||
@Override
|
||||
public void onSuccess(Markers markers) {
|
||||
session.markers = markers;
|
||||
writeAccountsFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error) {
|
||||
|
||||
}
|
||||
}).exec(session.getID());
|
||||
}
|
||||
|
||||
public void updateInstanceInfo(String domain){
|
||||
new GetInstance()
|
||||
.setCallback(new Callback<>(){
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
package org.joinmastodon.android.events;
|
||||
|
||||
public class AllNotificationsSeenEvent {
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package org.joinmastodon.android.events;
|
||||
|
||||
public class NotificationReceivedEvent {
|
||||
public String account, id;
|
||||
public NotificationReceivedEvent(String account, String id) {
|
||||
this.account = account;
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
@@ -62,7 +62,6 @@ import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
@@ -70,7 +69,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends BaseRecyclerFragment<T> implements PhotoViewerHost, ScrollableToTop{
|
||||
public abstract class BaseStatusListFragment<T extends DisplayItemsParent> extends RecyclerFragment<T> implements PhotoViewerHost, ScrollableToTop{
|
||||
protected ArrayList<StatusDisplayItem> displayItems=new ArrayList<>();
|
||||
protected DisplayItemsAdapter adapter;
|
||||
protected String accountID;
|
||||
|
||||
@@ -47,11 +47,10 @@ import java.util.Map;
|
||||
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class EditTimelinesFragment extends BaseRecyclerFragment<TimelineDefinition> implements ScrollableToTop {
|
||||
public class EditTimelinesFragment extends RecyclerFragment<TimelineDefinition> implements ScrollableToTop {
|
||||
private String accountID;
|
||||
private TimelinesAdapter adapter;
|
||||
private final ItemTouchHelper itemTouchHelper;
|
||||
|
||||
@@ -38,7 +38,6 @@ import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
@@ -47,7 +46,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class FollowRequestsListFragment extends BaseRecyclerFragment<FollowRequestsListFragment.AccountWrapper> implements ScrollableToTop{
|
||||
public class FollowRequestsListFragment extends RecyclerFragment<FollowRequestsListFragment.AccountWrapper> implements ScrollableToTop{
|
||||
private String accountID;
|
||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||
private GetAccountRelationships relationshipsRequest;
|
||||
|
||||
@@ -16,11 +16,10 @@ import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class FollowedHashtagsFragment extends BaseRecyclerFragment<Hashtag> implements ScrollableToTop {
|
||||
public class FollowedHashtagsFragment extends RecyclerFragment<Hashtag> implements ScrollableToTop {
|
||||
private String nextMaxID;
|
||||
private String accountId;
|
||||
|
||||
|
||||
@@ -16,21 +16,34 @@ import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.notifications.GetNotifications;
|
||||
import org.joinmastodon.android.api.session.AccountSession;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.AllNotificationsSeenEvent;
|
||||
import org.joinmastodon.android.events.NotificationReceivedEvent;
|
||||
import org.joinmastodon.android.fragments.discover.DiscoverFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.model.Notification;
|
||||
import org.joinmastodon.android.ui.AccountSwitcherSheet;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
import org.joinmastodon.android.ui.views.TabBar;
|
||||
import org.parceler.Parcels;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.squareup.otto.Subscribe;
|
||||
|
||||
import me.grishka.appkit.FragmentStackActivity;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.AppKitFragment;
|
||||
import me.grishka.appkit.fragments.LoaderFragment;
|
||||
import me.grishka.appkit.fragments.OnBackPressedListener;
|
||||
@@ -48,6 +61,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
||||
private TabBar tabBar;
|
||||
private View tabBarWrap;
|
||||
private ImageView tabBarAvatar;
|
||||
private ImageView notificationTabIcon;
|
||||
@IdRes
|
||||
private int currentTab=R.id.tab_home;
|
||||
|
||||
@@ -56,6 +70,7 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState){
|
||||
super.onCreate(savedInstanceState);
|
||||
E.register(this);
|
||||
accountID=getArguments().getString("account");
|
||||
setTitle(R.string.sk_app_name);
|
||||
|
||||
@@ -108,6 +123,9 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
||||
Account self=AccountSessionManager.getInstance().getAccount(accountID).self;
|
||||
ViewImageLoader.load(tabBarAvatar, null, new UrlImageLoaderRequest(self.avatar, V.dp(28), V.dp(28)));
|
||||
|
||||
notificationTabIcon=content.findViewById(R.id.tab_notifications);
|
||||
updateNotificationBadge();
|
||||
|
||||
if(savedInstanceState==null){
|
||||
getChildFragmentManager().beginTransaction()
|
||||
.add(R.id.fragment_wrap, homeTabFragment)
|
||||
@@ -267,4 +285,47 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
|
||||
if (notificationsFragment.isAdded()) getChildFragmentManager().putFragment(outState, "notificationsFragment", notificationsFragment);
|
||||
if (profileFragment.isAdded()) getChildFragmentManager().putFragment(outState, "profileFragment", profileFragment);
|
||||
}
|
||||
|
||||
public void updateNotificationBadge() {
|
||||
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
|
||||
Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
|
||||
if (instance == null) return;
|
||||
|
||||
new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance.pleroma != null)
|
||||
.setCallback(new Callback<>() {
|
||||
@Override
|
||||
public void onSuccess(List<Notification> notifications) {
|
||||
if (notifications.size() > 0) {
|
||||
try {
|
||||
long newestId = Long.parseLong(notifications.get(0).id);
|
||||
long lastSeenId = Long.parseLong(session.markers.notifications.lastReadId);
|
||||
setNotificationBadge(newestId > lastSeenId);
|
||||
} catch (Exception ignored) {
|
||||
setNotificationBadge(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorResponse error) {
|
||||
setNotificationBadge(false);
|
||||
}
|
||||
}).exec(accountID);
|
||||
}
|
||||
|
||||
public void setNotificationBadge(boolean badge) {
|
||||
notificationTabIcon.setImageResource(badge
|
||||
? R.drawable.ic_fluent_alert_28_selector_badged
|
||||
: R.drawable.ic_fluent_alert_28_selector);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onNotificationReceived(NotificationReceivedEvent notificationReceivedEvent) {
|
||||
if (notificationReceivedEvent.account.equals(accountID)) setNotificationBadge(true);
|
||||
}
|
||||
|
||||
@Subscribe
|
||||
public void onAllNotificationsSeen(AllNotificationsSeenEvent allNotificationsSeenEvent) {
|
||||
setNotificationBadge(false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +166,10 @@ public class HomeTimelineFragment extends StatusListFragment {
|
||||
}
|
||||
})
|
||||
.exec(accountID);
|
||||
|
||||
if (parent.getParentFragment() instanceof HomeFragment homeFragment) {
|
||||
homeFragment.updateNotificationBadge();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -37,11 +37,10 @@ import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class ListTimelinesFragment extends BaseRecyclerFragment<ListTimeline> implements ScrollableToTop {
|
||||
public class ListTimelinesFragment extends RecyclerFragment<ListTimeline> implements ScrollableToTop {
|
||||
private String accountId;
|
||||
private String profileAccountId;
|
||||
private final HashMap<String, Boolean> userInListBefore = new HashMap<>();
|
||||
|
||||
@@ -11,9 +11,11 @@ import org.joinmastodon.android.E;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.events.AllNotificationsSeenEvent;
|
||||
import org.joinmastodon.android.events.PollUpdatedEvent;
|
||||
import org.joinmastodon.android.events.RemoveAccountPostsEvent;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.CacheablePaginatedResponse;
|
||||
import org.joinmastodon.android.model.Filter;
|
||||
import org.joinmastodon.android.model.Notification;
|
||||
import org.joinmastodon.android.model.PaginatedResponse;
|
||||
@@ -127,7 +129,7 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
||||
.getAccount(accountID).getCacheController()
|
||||
.getNotifications(offset>0 ? maxID : null, count, onlyMentions, onlyPosts, refreshing, new SimpleCallback<>(this){
|
||||
@Override
|
||||
public void onSuccess(PaginatedResponse<List<Notification>> result){
|
||||
public void onSuccess(CacheablePaginatedResponse<List<Notification>> result){
|
||||
if (getActivity() == null) return;
|
||||
if(refreshing)
|
||||
relationships.clear();
|
||||
@@ -139,8 +141,12 @@ public class NotificationsListFragment extends BaseStatusListFragment<Notificati
|
||||
loadRelationships(needRelationships);
|
||||
maxID=result.maxID;
|
||||
|
||||
if(offset==0 && !result.items.isEmpty()){
|
||||
if(offset==0 && !result.items.isEmpty() && !result.isFromCache()){
|
||||
E.post(new AllNotificationsSeenEvent());
|
||||
new SaveMarkers(null, result.items.get(0).id).exec(accountID);
|
||||
AccountSessionManager.getInstance().getAccount(accountID).markers
|
||||
.notifications.lastReadId = result.items.get(0).id;
|
||||
AccountSessionManager.getInstance().writeAccountsFile();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -439,6 +439,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
|
||||
toolbarTitleView.setTranslationY(titleTransY);
|
||||
toolbarSubtitleView.setTranslationY(titleTransY);
|
||||
}
|
||||
RecyclerFragment.setRefreshLayoutColors(refreshLayout);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.joinmastodon.android.fragments;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
|
||||
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.ui.utils.UiUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
|
||||
|
||||
public abstract class RecyclerFragment<T> extends BaseRecyclerFragment<T> {
|
||||
public RecyclerFragment(int perPage) {
|
||||
super(perPage);
|
||||
}
|
||||
|
||||
public RecyclerFragment(int layout, int perPage) {
|
||||
super(layout, perPage);
|
||||
}
|
||||
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
if (refreshLayout != null) setRefreshLayoutColors(refreshLayout);
|
||||
}
|
||||
|
||||
public static void setRefreshLayoutColors(SwipeRefreshLayout l) {
|
||||
List<Integer> colors = new ArrayList<>(Arrays.asList(
|
||||
R.color.primary_600,
|
||||
R.color.red_primary_600,
|
||||
R.color.green_primary_600,
|
||||
R.color.blue_primary_600,
|
||||
R.color.purple_600
|
||||
));
|
||||
int primary = UiUtils.getThemeColorRes(l.getContext(), R.attr.colorPrimary600);
|
||||
if (!colors.contains(primary)) colors.add(0, primary);
|
||||
int offset = colors.indexOf(primary);
|
||||
int[] sorted = new int[colors.size()];
|
||||
for (int i = 0; i < colors.size(); i++) {
|
||||
sorted[i] = colors.get((i + offset) % colors.size());
|
||||
}
|
||||
l.setColorSchemeResources(sorted);
|
||||
}
|
||||
}
|
||||
@@ -151,7 +151,7 @@ public abstract class StatusListFragment extends BaseStatusListFragment<Status>{
|
||||
|
||||
protected void onRemoveAccountPostsEvent(RemoveAccountPostsEvent ev){
|
||||
List<Status> toRemove=Stream.concat(data.stream(), preloadedData.stream())
|
||||
.filter(s->s.account.id.equals(ev.postsByAccountID) || (s.reblog!=null && s.reblog.account.id.equals(ev.postsByAccountID)))
|
||||
.filter(s->s.account.id.equals(ev.postsByAccountID) || (!ev.isUnfollow && s.reblog!=null && s.reblog.account.id.equals(ev.postsByAccountID)))
|
||||
.collect(Collectors.toList());
|
||||
for(Status s:toRemove){
|
||||
removeStatus(s);
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||
import org.joinmastodon.android.api.session.AccountSessionManager;
|
||||
import org.joinmastodon.android.fragments.ListTimelinesFragment;
|
||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||
import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.Relationship;
|
||||
@@ -48,7 +49,6 @@ import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.APIRequest;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
@@ -57,7 +57,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseAccountListFragment.AccountItem>{
|
||||
public abstract class BaseAccountListFragment extends RecyclerFragment<BaseAccountListFragment.AccountItem> {
|
||||
protected HashMap<String, Relationship> relationships=new HashMap<>();
|
||||
protected String accountID;
|
||||
protected ArrayList<APIRequest<?>> relationshipsRequests=new ArrayList<>();
|
||||
@@ -295,7 +295,6 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
|
||||
|
||||
menu.findItem(R.id.block).setTitle(getString(relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getShortUsername()));
|
||||
menu.findItem(R.id.report).setTitle(getString(R.string.report_user, account.getShortUsername()));
|
||||
menu.findItem(R.id.manage_user_lists).setTitle(getString(R.string.sk_lists_with_user, account.getShortUsername())).setVisible(relationship.following);
|
||||
menu.findItem(R.id.soft_block).setVisible(relationship.followedBy && !relationship.following);
|
||||
MenuItem hideBoosts=menu.findItem(R.id.hide_boosts);
|
||||
MenuItem manageUserLists=menu.findItem(R.id.manage_user_lists);
|
||||
@@ -309,7 +308,7 @@ public abstract class BaseAccountListFragment extends BaseRecyclerFragment<BaseA
|
||||
manageUserLists.setVisible(true);
|
||||
}else{
|
||||
hideBoosts.setVisible(false);
|
||||
manageUserLists.setVisible(true);
|
||||
manageUserLists.setVisible(false);
|
||||
}
|
||||
menu.findItem(R.id.block_domain).setVisible(false);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountRelationships;
|
||||
import org.joinmastodon.android.api.requests.accounts.GetFollowSuggestions;
|
||||
import org.joinmastodon.android.fragments.IsOnTop;
|
||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||
import org.joinmastodon.android.model.Account;
|
||||
import org.joinmastodon.android.model.FollowSuggestion;
|
||||
@@ -40,7 +41,6 @@ import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
@@ -49,7 +49,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class DiscoverAccountsFragment extends BaseRecyclerFragment<DiscoverAccountsFragment.AccountWrapper> implements ScrollableToTop, IsOnTop {
|
||||
public class DiscoverAccountsFragment extends RecyclerFragment<DiscoverAccountsFragment.AccountWrapper> implements ScrollableToTop, IsOnTop {
|
||||
private String accountID;
|
||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||
private GetAccountRelationships relationshipsRequest;
|
||||
|
||||
@@ -11,6 +11,7 @@ import android.widget.TextView;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.trends.GetTrendingLinks;
|
||||
import org.joinmastodon.android.fragments.IsOnTop;
|
||||
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||
import org.joinmastodon.android.model.Card;
|
||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||
@@ -26,7 +27,6 @@ import java.util.stream.Collectors;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
@@ -35,7 +35,7 @@ import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class DiscoverNewsFragment extends BaseRecyclerFragment<Card> implements ScrollableToTop, IsOnTop {
|
||||
public class DiscoverNewsFragment extends RecyclerFragment<Card> implements ScrollableToTop, IsOnTop {
|
||||
private String accountID;
|
||||
private List<ImageLoaderRequest> imageRequests=Collections.emptyList();
|
||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_LINKS);
|
||||
|
||||
@@ -247,7 +247,7 @@ public class SearchFragment extends BaseStatusListFragment<SearchResult> impleme
|
||||
}
|
||||
|
||||
public void setQuery(String q){
|
||||
if(Objects.equals(q, currentQuery))
|
||||
if(Objects.equals(q, currentQuery) || q.isBlank())
|
||||
return;
|
||||
if(currentRequest!=null){
|
||||
currentRequest.cancel();
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.widget.TextView;
|
||||
import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.requests.trends.GetTrendingHashtags;
|
||||
import org.joinmastodon.android.fragments.IsOnTop;
|
||||
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||
import org.joinmastodon.android.fragments.ScrollableToTop;
|
||||
import org.joinmastodon.android.model.Hashtag;
|
||||
import org.joinmastodon.android.ui.DividerItemDecoration;
|
||||
@@ -20,11 +21,10 @@ import java.util.List;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class TrendingHashtagsFragment extends BaseRecyclerFragment<Hashtag> implements ScrollableToTop, IsOnTop {
|
||||
public class TrendingHashtagsFragment extends RecyclerFragment<Hashtag> implements ScrollableToTop, IsOnTop {
|
||||
private String accountID;
|
||||
private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.TRENDING_HASHTAGS);
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.joinmastodon.android.R;
|
||||
import org.joinmastodon.android.api.MastodonAPIController;
|
||||
import org.joinmastodon.android.api.MastodonErrorResponse;
|
||||
import org.joinmastodon.android.api.requests.instance.GetInstance;
|
||||
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||
import org.joinmastodon.android.model.Instance;
|
||||
import org.joinmastodon.android.model.catalog.CatalogInstance;
|
||||
import org.joinmastodon.android.ui.M3AlertDialogBuilder;
|
||||
@@ -44,7 +45,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.utils.BindableViewHolder;
|
||||
import me.grishka.appkit.utils.MergeRecyclerAdapter;
|
||||
import me.grishka.appkit.utils.V;
|
||||
@@ -52,7 +52,7 @@ import okhttp3.Call;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.Response;
|
||||
|
||||
abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInstance>{
|
||||
abstract class InstanceCatalogFragment extends RecyclerFragment<CatalogInstance> {
|
||||
protected RecyclerView.Adapter adapter;
|
||||
protected MergeRecyclerAdapter mergeAdapter;
|
||||
protected CatalogInstance chosenInstance;
|
||||
@@ -75,7 +75,7 @@ abstract class InstanceCatalogFragment extends BaseRecyclerFragment<CatalogInsta
|
||||
private static final double DUNBAR=Math.log(800);
|
||||
|
||||
public InstanceCatalogFragment(int layout, int perPage){
|
||||
super(layout, perPage);
|
||||
super(layout, perPage);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.joinmastodon.android.api.requests.accounts.GetFollowSuggestions;
|
||||
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
|
||||
import org.joinmastodon.android.fragments.HomeFragment;
|
||||
import org.joinmastodon.android.fragments.ProfileFragment;
|
||||
import org.joinmastodon.android.fragments.RecyclerFragment;
|
||||
import org.joinmastodon.android.model.FollowSuggestion;
|
||||
import org.joinmastodon.android.model.ParsedAccount;
|
||||
import org.joinmastodon.android.model.Relationship;
|
||||
@@ -43,7 +44,6 @@ import me.grishka.appkit.Nav;
|
||||
import me.grishka.appkit.api.Callback;
|
||||
import me.grishka.appkit.api.ErrorResponse;
|
||||
import me.grishka.appkit.api.SimpleCallback;
|
||||
import me.grishka.appkit.fragments.BaseRecyclerFragment;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderRecyclerAdapter;
|
||||
import me.grishka.appkit.imageloader.ImageLoaderViewHolder;
|
||||
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
@@ -52,7 +52,7 @@ import me.grishka.appkit.utils.V;
|
||||
import me.grishka.appkit.views.FragmentRootLinearLayout;
|
||||
import me.grishka.appkit.views.UsableRecyclerView;
|
||||
|
||||
public class OnboardingFollowSuggestionsFragment extends BaseRecyclerFragment<ParsedAccount>{
|
||||
public class OnboardingFollowSuggestionsFragment extends RecyclerFragment<ParsedAccount> {
|
||||
private String accountID;
|
||||
private Map<String, Relationship> relationships=Collections.emptyMap();
|
||||
private GetAccountRelationships relationshipsRequest;
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package org.joinmastodon.android.model;
|
||||
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
|
||||
import org.joinmastodon.android.api.AllFieldsAreRequired;
|
||||
|
||||
import java.time.Instant;
|
||||
@@ -18,4 +20,11 @@ public class Marker extends BaseModel{
|
||||
", updatedAt="+updatedAt+
|
||||
'}';
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
@SerializedName("home")
|
||||
HOME,
|
||||
@SerializedName("notifications")
|
||||
NOTIFICATIONS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
package org.joinmastodon.android.model;
|
||||
|
||||
public class Markers {
|
||||
public Marker notifications;
|
||||
public Marker home;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Markers{" +
|
||||
"notifications=" + notifications +
|
||||
", home=" + home +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,8 @@ public class Status extends BaseModel implements DisplayItemsParent, Searchable{
|
||||
public transient boolean spoilerRevealed;
|
||||
public transient boolean textExpanded, textExpandable;
|
||||
public transient boolean hasGapAfter;
|
||||
public transient TranslatedStatus translation;
|
||||
public transient boolean translationShown;
|
||||
private transient String strippedText;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package org.joinmastodon.android.ui.displayitems;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.graphics.Outline;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Typeface;
|
||||
import android.graphics.drawable.Animatable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
@@ -264,7 +268,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
progress.dismiss();
|
||||
}, rel->{
|
||||
relationship=rel;
|
||||
Toast.makeText(activity, activity.getString(rel.following ? R.string.followed_user : R.string.unfollowed_user, account.getShortUsername()), Toast.LENGTH_SHORT).show();
|
||||
Toast.makeText(activity, activity.getString(rel.following ? R.string.followed_user : rel.requested ? R.string.following_user_requested : R.string.unfollowed_user, account.getDisplayUsername()), Toast.LENGTH_SHORT).show();
|
||||
});
|
||||
}else if(id==R.id.block_domain){
|
||||
UiUtils.confirmToggleBlockDomain(activity, item.parentFragment.getAccountID(), account.getDomain(), relationship!=null && relationship.domainBlocking, ()->{});
|
||||
@@ -463,6 +467,7 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
}
|
||||
|
||||
Account account=item.user;
|
||||
String username = account.getShortUsername();
|
||||
boolean isOwnPost=AccountSessionManager.getInstance().isSelf(item.parentFragment.getAccountID(), account);
|
||||
boolean isPostScheduled=item.scheduledStatus!=null;
|
||||
menu.findItem(R.id.open_with_account).setVisible(!isPostScheduled && hasMultipleAccounts);
|
||||
@@ -498,14 +503,15 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
manageUserLists.setVisible(false);
|
||||
}else{
|
||||
mute.setVisible(true);
|
||||
block.setVisible(true);
|
||||
// hiding when following to keep menu item count equal (trading it for user lists)
|
||||
block.setVisible(relationship == null || !relationship.following);
|
||||
report.setVisible(true);
|
||||
follow.setVisible(relationship==null || relationship.following || (!relationship.blocking && !relationship.blockedBy && !relationship.domainBlocking && !relationship.muting));
|
||||
mute.setTitle(item.parentFragment.getString(relationship!=null && relationship.muting ? R.string.unmute_user : R.string.mute_user, account.getShortUsername()));
|
||||
mute.setTitle(item.parentFragment.getString(relationship!=null && relationship.muting ? R.string.unmute_user : R.string.mute_user, username));
|
||||
mute.setIcon(relationship!=null && relationship.muting ? R.drawable.ic_fluent_speaker_0_24_regular : R.drawable.ic_fluent_speaker_off_24_regular);
|
||||
UiUtils.insetPopupMenuIcon(item.parentFragment.getContext(), mute);
|
||||
block.setTitle(item.parentFragment.getString(relationship!=null && relationship.blocking ? R.string.unblock_user : R.string.block_user, account.getShortUsername()));
|
||||
report.setTitle(item.parentFragment.getString(R.string.report_user, account.getShortUsername()));
|
||||
block.setTitle(item.parentFragment.getString(relationship!=null && relationship.blocking ? R.string.unblock_user : R.string.block_user, username));
|
||||
report.setTitle(item.parentFragment.getString(R.string.report_user, username));
|
||||
// disabled in megalodon. domain blocks from a post clutters the context menu and looks out of place
|
||||
// if(!account.isLocal()){
|
||||
// blockDomain.setVisible(true);
|
||||
@@ -514,12 +520,53 @@ public class HeaderStatusDisplayItem extends StatusDisplayItem{
|
||||
blockDomain.setVisible(false);
|
||||
// }
|
||||
boolean following = relationship!=null && relationship.following;
|
||||
follow.setTitle(item.parentFragment.getString(following ? R.string.unfollow_user : R.string.follow_user, account.getShortUsername()));
|
||||
follow.setTitle(item.parentFragment.getString(following ? R.string.unfollow_user : R.string.follow_user, username));
|
||||
follow.setIcon(following ? R.drawable.ic_fluent_person_delete_24_regular : R.drawable.ic_fluent_person_add_24_regular);
|
||||
manageUserLists.setVisible(relationship != null && relationship.following);
|
||||
manageUserLists.setTitle(item.parentFragment.getString(R.string.sk_lists_with_user, account.getShortUsername()));
|
||||
manageUserLists.setTitle(item.parentFragment.getString(R.string.sk_lists_with_user, username));
|
||||
UiUtils.insetPopupMenuIcon(item.parentFragment.getContext(), follow);
|
||||
}
|
||||
|
||||
workaroundChangingMenuItemWidths(menu, username);
|
||||
}
|
||||
|
||||
// ugliest piece of code you'll see in a while: i measure the menu items' text widths to
|
||||
// determine the biggest one, because it's probably not being displayed at first
|
||||
// (before the relationship loaded). i take the largest one's size and add a space to the
|
||||
// last item ("open in browser") until it takes up as much space as the largest item.
|
||||
// goal: no more ugly ellipsis after the relationship loads in when opening the context menu
|
||||
// of a post
|
||||
private void workaroundChangingMenuItemWidths(Menu menu, String username) {
|
||||
String openInBrowserText = item.parentFragment.getString(R.string.open_in_browser);
|
||||
if (relationship == null) {
|
||||
float largestWidth = 0;
|
||||
Paint paint = new Paint();
|
||||
paint.setTypeface(Typeface.create("sans-serif", Typeface.NORMAL));
|
||||
String[] otherStrings = new String[] {
|
||||
item.parentFragment.getString(R.string.unfollow_user, username),
|
||||
item.parentFragment.getString(R.string.unblock_user, username),
|
||||
item.parentFragment.getString(R.string.unmute_user, username),
|
||||
item.parentFragment.getString(R.string.sk_lists_with_user, username),
|
||||
};
|
||||
for (int i = 0; i < menu.size(); i++) {
|
||||
MenuItem item = menu.getItem(i);
|
||||
if (item.getItemId() == R.id.open_in_browser || !item.isVisible()) continue;
|
||||
float width = paint.measureText(menu.getItem(i).getTitle().toString());
|
||||
if (width > largestWidth) largestWidth = width;
|
||||
}
|
||||
for (String str : otherStrings) {
|
||||
float width = paint.measureText(str);
|
||||
if (width > largestWidth) largestWidth = width;
|
||||
}
|
||||
float textWidth = paint.measureText(openInBrowserText);
|
||||
float missingWidth = Math.max(0, largestWidth - textWidth);
|
||||
float singleSpaceWidth = paint.measureText(" ");
|
||||
int howManySpaces = (int) Math.ceil(missingWidth / singleSpaceWidth);
|
||||
String enlargedText = openInBrowserText + " ".repeat(howManySpaces);
|
||||
menu.findItem(R.id.open_in_browser).setTitle(enlargedText);
|
||||
} else {
|
||||
menu.findItem(R.id.open_in_browser).setTitle(openInBrowserText);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -247,10 +247,11 @@ public class MediaGridStatusDisplayItem extends StatusDisplayItem{
|
||||
altTextAnimator.cancel();
|
||||
|
||||
View btn=controllers.get(altTextIndex).btnsWrap;
|
||||
int i=0;
|
||||
for(MediaAttachmentViewController c:controllers){
|
||||
if(c.btnsWrap!=null && c.btnsWrap!=btn) {
|
||||
if(c.btnsWrap!=null && c.btnsWrap!=btn && !TextUtils.isEmpty(item.attachments.get(i).description))
|
||||
c.btnsWrap.setVisibility(View.VISIBLE);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
int[] loc={0, 0};
|
||||
|
||||
@@ -32,23 +32,23 @@ import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
|
||||
import me.grishka.appkit.utils.V;
|
||||
|
||||
public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
||||
private CharSequence text, compactText;
|
||||
private CharSequence text;
|
||||
@DrawableRes
|
||||
private int icon;
|
||||
private StatusPrivacy visibility;
|
||||
@DrawableRes
|
||||
private int iconEnd;
|
||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper();
|
||||
private CustomEmojiHelper emojiHelper=new CustomEmojiHelper(), fullTextEmojiHelper;
|
||||
private View.OnClickListener handleClick;
|
||||
boolean belowHeader, needBottomPadding;
|
||||
ReblogOrReplyLineStatusDisplayItem extra;
|
||||
String contentDescription;
|
||||
CharSequence fullText;
|
||||
|
||||
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick) {
|
||||
this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, null);
|
||||
this(parentID, parentFragment, text, emojis, icon, visibility, handleClick, text);
|
||||
}
|
||||
|
||||
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, String contentDescription) {
|
||||
public ReblogOrReplyLineStatusDisplayItem(String parentID, BaseStatusListFragment parentFragment, CharSequence text, List<Emoji> emojis, @DrawableRes int icon, StatusPrivacy visibility, @Nullable View.OnClickListener handleClick, CharSequence fullText) {
|
||||
super(parentID, parentFragment);
|
||||
SpannableStringBuilder ssb=new SpannableStringBuilder(text);
|
||||
HtmlParser.parseCustomEmoji(ssb, emojis);
|
||||
@@ -59,7 +59,15 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
||||
TypedValue outValue = new TypedValue();
|
||||
context.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
|
||||
updateVisibility(visibility);
|
||||
this.contentDescription = contentDescription;
|
||||
|
||||
if (fullText != null) {
|
||||
fullTextEmojiHelper = new CustomEmojiHelper();
|
||||
SpannableStringBuilder fullTextSsb = new SpannableStringBuilder(fullText);
|
||||
HtmlParser.parseCustomEmoji(fullTextSsb, emojis);
|
||||
this.fullText=fullTextSsb;
|
||||
fullTextEmojiHelper.setText(fullTextSsb);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void updateVisibility(StatusPrivacy visibility) {
|
||||
@@ -90,31 +98,23 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
||||
public static class Holder extends StatusDisplayItem.Holder<ReblogOrReplyLineStatusDisplayItem> implements ImageLoaderViewHolder{
|
||||
private final TextView text, extraText;
|
||||
private final View separator;
|
||||
private int currentOrientation = -1;
|
||||
private final ViewGroup parent;
|
||||
|
||||
public Holder(Activity activity, ViewGroup parent){
|
||||
super(activity, R.layout.display_item_reblog_or_reply_line, parent);
|
||||
this.parent = parent;
|
||||
text=findViewById(R.id.text);
|
||||
extraText=findViewById(R.id.extra_text);
|
||||
separator=findViewById(R.id.separator);
|
||||
if (GlobalUserPreferences.replyLineAboveHeader && GlobalUserPreferences.compactReblogReplyLine) {
|
||||
itemView.getViewTreeObserver().addOnPreDrawListener(() -> {
|
||||
if (item == null) return true;
|
||||
int orientation = ((LinearLayout) itemView).getOrientation();
|
||||
if (orientation == currentOrientation) return true; // only run once
|
||||
currentOrientation = orientation;
|
||||
extraText.setPaddingRelative(extraText.getPaddingStart(), item.extra != null && orientation == LinearLayout.VERTICAL ? 0 : V.dp(16), extraText.getPaddingEnd(), extraText.getPaddingBottom());
|
||||
separator.setVisibility(item.extra != null && orientation == LinearLayout.HORIZONTAL ? View.VISIBLE : View.GONE);
|
||||
((LinearLayout) itemView).removeView(extraText);
|
||||
if (orientation == LinearLayout.VERTICAL) ((LinearLayout) itemView).addView(extraText);
|
||||
else ((LinearLayout) itemView).addView(extraText, 0);
|
||||
return true;
|
||||
parent.addOnLayoutChangeListener((v, l, t, right, b, ol, ot, oldRight, ob) -> {
|
||||
if (right != oldRight) layoutLine();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void bindLine(ReblogOrReplyLineStatusDisplayItem item, TextView text) {
|
||||
if (item.contentDescription != null) text.setContentDescription(item.contentDescription);
|
||||
if (item.fullText != null) text.setContentDescription(item.fullText);
|
||||
text.setText(item.text);
|
||||
text.setCompoundDrawablesRelativeWithIntrinsicBounds(item.icon, 0, item.iconEnd, 0);
|
||||
text.setOnClickListener(item.handleClick);
|
||||
@@ -146,6 +146,27 @@ public class ReblogOrReplyLineStatusDisplayItem extends StatusDisplayItem{
|
||||
params.topMargin = item.belowHeader ? V.dp(-6) : 0;
|
||||
itemView.setLayoutParams(params);
|
||||
itemView.setPadding(itemView.getPaddingLeft(), itemView.getPaddingTop(), itemView.getPaddingRight(), item.needBottomPadding ? V.dp(16) : 0);
|
||||
layoutLine();
|
||||
}
|
||||
|
||||
private void layoutLine() {
|
||||
// layout line only if above header, compact and has extra
|
||||
if (!GlobalUserPreferences.replyLineAboveHeader
|
||||
|| !GlobalUserPreferences.compactReblogReplyLine
|
||||
|| item.extra == null) return;
|
||||
itemView.measure(
|
||||
View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY),
|
||||
View.MeasureSpec.UNSPECIFIED);
|
||||
boolean isVertical = ((LinearLayout) itemView).getOrientation() == LinearLayout.VERTICAL;
|
||||
extraText.setPaddingRelative(extraText.getPaddingStart(), item.extra != null && isVertical ? 0 : V.dp(16), extraText.getPaddingEnd(), extraText.getPaddingBottom());
|
||||
separator.setVisibility(item.extra != null && !isVertical ? View.VISIBLE : View.GONE);
|
||||
((LinearLayout) itemView).removeView(extraText);
|
||||
if (isVertical) ((LinearLayout) itemView).addView(extraText);
|
||||
else ((LinearLayout) itemView).addView(extraText, 0);
|
||||
text.setText(isVertical ? item.fullText : item.text);
|
||||
if (item.extra != null) {
|
||||
extraText.setText(isVertical ? item.extra.fullText : item.extra.text);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -6,7 +6,6 @@ import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Button;
|
||||
import android.widget.ScrollView;
|
||||
@@ -49,9 +48,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
private CharSequence parsedSpoilerText;
|
||||
public boolean textSelectable;
|
||||
public final Status status;
|
||||
public boolean disableTranslate;
|
||||
public boolean translated = false;
|
||||
public TranslatedStatus translation = null;
|
||||
public boolean disableTranslate, translationShown;
|
||||
private AccountSession session;
|
||||
public static final Pattern BOTTOM_TEXT_PATTERN = Pattern.compile("(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️)(?:\uD83D\uDC49\uD83D\uDC48(?:[\uD83E\uDEC2\uD83D\uDC96✨\uD83E\uDD7A,]+|❤️))*\uD83D\uDC49\uD83D\uDC48");
|
||||
|
||||
@@ -60,6 +57,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
this.text=text;
|
||||
this.status=status;
|
||||
this.disableTranslate=disableTranslate;
|
||||
this.translationShown=status.translationShown;
|
||||
emojiHelper.setText(text);
|
||||
if(!TextUtils.isEmpty(status.spoilerText)){
|
||||
parsedSpoilerText=HtmlParser.parseCustomEmoji(status.spoilerText, status.emojis);
|
||||
@@ -69,6 +67,11 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
session = AccountSessionManager.getInstance().getAccount(parentFragment.getAccountID());
|
||||
}
|
||||
|
||||
public void setTranslationShown(boolean translationShown) {
|
||||
this.translationShown = translationShown;
|
||||
status.translationShown = translationShown;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType(){
|
||||
return Type.TEXT;
|
||||
@@ -131,8 +134,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
|
||||
@Override
|
||||
public void onBind(TextStatusDisplayItem item){
|
||||
text.setText(item.translated
|
||||
? HtmlParser.parse(item.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID())
|
||||
text.setText(item.translationShown
|
||||
? HtmlParser.parse(item.status.translation.content, item.status.emojis, item.status.mentions, item.status.tags, item.parentFragment.getAccountID())
|
||||
: item.text);
|
||||
text.setTextIsSelectable(item.textSelectable);
|
||||
if (item.textSelectable) {
|
||||
@@ -169,8 +172,14 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
boolean translateEnabled = !item.disableTranslate && instanceInfo != null &&
|
||||
instanceInfo.v2 != null && instanceInfo.v2.configuration.translation != null &&
|
||||
instanceInfo.v2.configuration.translation.enabled;
|
||||
boolean isBottomText = BOTTOM_TEXT_PATTERN.matcher(item.status.getStrippedText()).find();
|
||||
boolean translateVisible = (isBottomText || (
|
||||
String bottomText = null;
|
||||
try {
|
||||
bottomText = BOTTOM_TEXT_PATTERN.matcher(item.status.getStrippedText()).find()
|
||||
? new StatusTextEncoder(Bottom::decode).decode(item.status.getStrippedText(), BOTTOM_TEXT_PATTERN)
|
||||
: null;
|
||||
} catch (TranslationError ignored) {}
|
||||
|
||||
boolean translateVisible = (bottomText != null || (
|
||||
translateEnabled &&
|
||||
!item.status.visibility.isLessVisibleThan(StatusPrivacy.UNLISTED) &&
|
||||
item.status.language != null &&
|
||||
@@ -178,17 +187,18 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
!item.status.language.equalsIgnoreCase(Locale.getDefault().getLanguage())))
|
||||
&& (!GlobalUserPreferences.translateButtonOpenedOnly || item.textSelectable);
|
||||
translateWrap.setVisibility(translateVisible ? View.VISIBLE : View.GONE);
|
||||
translateButton.setText(item.translated ? R.string.sk_translate_show_original : R.string.sk_translate_post);
|
||||
translateInfo.setText(item.translated ? itemView.getResources().getString(R.string.sk_translated_using, isBottomText ? "bottom-java" : item.translation.provider) : "");
|
||||
translateButton.setText(item.translationShown ? R.string.sk_translate_show_original : R.string.sk_translate_post);
|
||||
translateInfo.setText(item.translationShown ? itemView.getResources().getString(R.string.sk_translated_using, bottomText != null ? "bottom-java" : item.status.translation.provider) : "");
|
||||
String finalBottomText = bottomText;
|
||||
translateButton.setOnClickListener(v->{
|
||||
if (item.translation == null) {
|
||||
if (isBottomText) {
|
||||
if (item.status.translation == null) {
|
||||
if (finalBottomText != null) {
|
||||
try {
|
||||
item.translation = new TranslatedStatus();
|
||||
item.translation.content = new StatusTextEncoder(Bottom::decode).decode(item.status.getStrippedText(), BOTTOM_TEXT_PATTERN);
|
||||
item.translated = true;
|
||||
item.status.translation = new TranslatedStatus();
|
||||
item.status.translation.content = finalBottomText;
|
||||
item.setTranslationShown(true);
|
||||
} catch (TranslationError err) {
|
||||
item.translation = null;
|
||||
item.status.translation = null;
|
||||
Toast.makeText(itemView.getContext(), err.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
rebind();
|
||||
@@ -200,8 +210,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
new TranslateStatus(item.status.id).setCallback(new Callback<>() {
|
||||
@Override
|
||||
public void onSuccess(TranslatedStatus translatedStatus) {
|
||||
item.translation = translatedStatus;
|
||||
item.translated = true;
|
||||
item.status.translation = translatedStatus;
|
||||
item.setTranslationShown(true);
|
||||
if (item.parentFragment.getActivity() == null) return;
|
||||
translateProgress.setVisibility(View.GONE);
|
||||
translateButton.setClickable(true);
|
||||
@@ -218,7 +228,7 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
}
|
||||
}).exec(item.parentFragment.getAccountID());
|
||||
} else {
|
||||
item.translated = !item.translated;
|
||||
item.setTranslationShown(!item.translationShown);
|
||||
rebind();
|
||||
}
|
||||
});
|
||||
@@ -237,9 +247,8 @@ public class TextStatusDisplayItem extends StatusDisplayItem{
|
||||
|
||||
if (GlobalUserPreferences.collapseLongPosts && !item.status.textExpandable) {
|
||||
boolean tooBig = text.getMeasuredHeight() > textMaxHeight;
|
||||
boolean inTimeline = !item.textSelectable;
|
||||
boolean hasSpoiler = !TextUtils.isEmpty(item.status.spoilerText);
|
||||
boolean expandable = inTimeline && tooBig && !hasSpoiler;
|
||||
boolean expandable = tooBig && !hasSpoiler;
|
||||
item.parentFragment.onEnableExpandable(Holder.this, expandable);
|
||||
}
|
||||
|
||||
|
||||
@@ -338,12 +338,21 @@ public class UiUtils {
|
||||
}
|
||||
|
||||
public static int getThemeColor(Context context, @AttrRes int attr) {
|
||||
if (context == null) return 0xff00ff00;
|
||||
TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
|
||||
int color = ta.getColor(0, 0xff00ff00);
|
||||
ta.recycle();
|
||||
return color;
|
||||
}
|
||||
|
||||
public static int getThemeColorRes(Context context, @AttrRes int attr) {
|
||||
if (context == null) return 0xff00ff00;
|
||||
TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
|
||||
int color = ta.getResourceId(0, R.color.black);
|
||||
ta.recycle();
|
||||
return color;
|
||||
}
|
||||
|
||||
public static void openProfileByID(Context context, String selfID, String id) {
|
||||
Bundle args = new Bundle();
|
||||
args.putString("account", selfID);
|
||||
@@ -712,7 +721,7 @@ public class UiUtils {
|
||||
public void onSuccess(Relationship result) {
|
||||
resultCallback.accept(result);
|
||||
progressCallback.accept(false);
|
||||
if (!result.following) {
|
||||
if(!result.following && !result.requested){
|
||||
E.post(new RemoveAccountPostsEvent(accountID, account.id, true));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_fluent_alert_28_filled" android:left="2dp" android:right="2dp" android:top="2dp" android:bottom="2dp"/>
|
||||
<item android:width="14dp" android:height="14dp" android:gravity="top|right">
|
||||
<shape android:shape="oval">
|
||||
<stroke android:color="?toolbarBackground" android:width="2dp"/>
|
||||
<solid android:color="?android:colorAccent"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:drawable="@drawable/ic_fluent_alert_28_regular" android:left="2dp" android:right="2dp" android:top="2dp" android:bottom="2dp"/>
|
||||
<item android:width="14dp" android:height="14dp" android:gravity="top|right">
|
||||
<shape android:shape="oval">
|
||||
<stroke android:color="?toolbarBackground" android:width="2dp"/>
|
||||
<solid android:color="?android:colorAccent"/>
|
||||
</shape>
|
||||
</item>
|
||||
</layer-list>
|
||||
@@ -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_alert_28_filled_badged" android:state_activated="true"/>
|
||||
<item android:drawable="@drawable/ic_fluent_alert_28_filled_badged" android:state_checked="true"/>
|
||||
<item android:drawable="@drawable/ic_fluent_alert_28_filled_badged" android:state_selected="true"/>
|
||||
<item android:drawable="@drawable/ic_fluent_alert_28_regular_badged"/>
|
||||
</selector>
|
||||
@@ -51,7 +51,6 @@
|
||||
android:scaleType="center"
|
||||
android:contentDescription="@string/notifications"
|
||||
android:background="?android:selectableItemBackgroundBorderless"
|
||||
android:tint="?android:colorPrimary"
|
||||
android:src="@drawable/ic_fluent_alert_28_selector"/>
|
||||
|
||||
<Space
|
||||
|
||||
@@ -8,11 +8,11 @@
|
||||
<item android:id="@+id/delete_and_redraft" android:title="@string/sk_delete_and_redraft" android:icon="@drawable/ic_fluent_arrow_clockwise_24_regular" />
|
||||
<item android:id="@+id/pin" android:title="@string/sk_pin_post" android:icon="@drawable/ic_fluent_pin_24_regular"/>
|
||||
<item android:id="@+id/unpin" android:title="@string/sk_unpin_post" android:icon="@drawable/ic_fluent_pin_off_24_regular"/>
|
||||
<item android:id="@+id/manage_user_lists" android:title="@string/sk_lists_with_user" android:icon="@drawable/ic_fluent_people_24_regular"/>
|
||||
<item android:id="@+id/mute" android:title="@string/mute_user" android:icon="@drawable/ic_fluent_speaker_off_24_regular"/>
|
||||
<item android:id="@+id/follow" android:title="@string/follow_user" android:icon="@drawable/ic_fluent_person_add_24_regular"/>
|
||||
<item android:id="@+id/block" android:title="@string/block_user" android:icon="@drawable/ic_fluent_person_prohibited_24_regular"/>
|
||||
<item android:id="@+id/block_domain" android:title="@string/block_domain" android:icon="@drawable/ic_fluent_shield_prohibited_24_regular"/>
|
||||
<item android:id="@+id/follow" android:title="@string/follow_user" android:icon="@drawable/ic_fluent_person_add_24_regular"/>
|
||||
<item android:id="@+id/manage_user_lists" android:title="@string/sk_lists_with_user" android:icon="@drawable/ic_fluent_people_24_regular"/>
|
||||
<item android:id="@+id/report" android:title="@string/report_user" android:icon="@drawable/ic_fluent_warning_24_regular"/>
|
||||
<item android:id="@+id/bookmark" android:title="@string/add_bookmark" android:icon="@drawable/ic_fluent_bookmark_24_regular"/>
|
||||
<item android:id="@+id/copy_link" android:title="@string/sk_copy_link_to_post" android:icon="@drawable/ic_fluent_link_24_regular"/>
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:id="@+id/open_with_account" android:title="@string/sk_open_with_account" android:icon="@drawable/ic_fluent_person_swap_24_regular">
|
||||
<item android:id="@+id/open_with_account" android:title="@string/sk_open_with_account" android:visible="false" android:icon="@drawable/ic_fluent_person_swap_24_regular">
|
||||
<menu android:id="@+id/accounts" />
|
||||
</item>
|
||||
<item android:id="@+id/share" android:title="@string/share_user" android:icon="@drawable/ic_fluent_share_24_regular"/>
|
||||
<item android:id="@+id/manage_user_lists" android:title="@string/sk_lists_with_user" android:icon="@drawable/ic_fluent_people_24_regular"/>
|
||||
<item android:id="@+id/mute" android:title="@string/mute_user" android:icon="@drawable/ic_fluent_speaker_off_24_regular"/>
|
||||
<item android:id="@+id/block" android:title="@string/block_user" android:icon="@drawable/ic_fluent_person_prohibited_24_regular"/>
|
||||
<item android:id="@+id/report" android:title="@string/report_user" android:icon="@drawable/ic_fluent_warning_24_regular"/>
|
||||
<item android:id="@+id/soft_block" android:title="@string/sk_remove_follower" android:icon="@drawable/ic_fluent_person_delete_24_regular"/>
|
||||
<item android:id="@+id/report" android:title="@string/report_user" android:icon="@drawable/ic_fluent_warning_24_regular"/>
|
||||
<item android:id="@+id/block_domain" android:title="@string/block_domain" android:icon="@drawable/ic_fluent_shield_prohibited_24_regular"/>
|
||||
<item android:id="@+id/hide_boosts" android:title="@string/hide_boosts_from_user" android:icon="@drawable/ic_fluent_arrow_repeat_all_off_24_regular"/>
|
||||
<item android:id="@+id/manage_user_lists" android:title="@string/sk_lists_with_user" android:icon="@drawable/ic_fluent_people_24_regular"/>
|
||||
<item android:id="@+id/open_in_browser" android:title="@string/open_in_browser" android:icon="@drawable/ic_fluent_globe_24_regular"/>
|
||||
</menu>
|
||||
@@ -285,6 +285,7 @@
|
||||
<string name="follow_user">%s folgen</string>
|
||||
<string name="unfollowed_user">%s entfolgt</string>
|
||||
<string name="followed_user">Du folgst nun %s</string>
|
||||
<string name="following_user_requested">Deine Follower-Anfrage an %s wurde gesendet</string>
|
||||
<string name="open_in_browser">Im Browser öffnen</string>
|
||||
<string name="hide_boosts_from_user">geteilte Beiträge von %s ausblenden</string>
|
||||
<string name="show_boosts_from_user">geteilte Beiträge von %s anzeigen</string>
|
||||
|
||||
@@ -267,4 +267,8 @@
|
||||
<string name="sk_settings_reply_visibility_following">Antworten auf Follows</string>
|
||||
<string name="sk_settings_reply_visibility_self">Antworten an mich</string>
|
||||
<string name="sk_quoting_user">Zitiere %s</string>
|
||||
<string name="sk_notification_action_replied">Antwort an %s gesendet</string>
|
||||
<string name="sk_show_thread">Thread öffnen</string>
|
||||
<string name="sk_compact_reblog_reply_line">Kompakte Geteilt/Geantwortet-Zeile</string>
|
||||
<string name="sk_reply_line_above_avatar">“Als Antwort auf”-Zeile über Profilbild</string>
|
||||
</resources>
|
||||
@@ -263,4 +263,13 @@
|
||||
<string name="sk_followed_as">Seguido desde %s</string>
|
||||
<string name="sk_settings_hide_fab">Ocultar automáticamente el botón Redactar</string>
|
||||
<string name="sk_in_reply">Respondiendo a</string>
|
||||
<string name="sk_quoting_user">Citando %s</string>
|
||||
<string name="sk_settings_reply_visibility">Visibilidad de la respuesta</string>
|
||||
<string name="sk_settings_reply_visibility_all">Todas las respuestas</string>
|
||||
<string name="sk_settings_reply_visibility_following">Responde a mis seguidores</string>
|
||||
<string name="sk_settings_reply_visibility_self">Respondeme</string>
|
||||
<string name="sk_notification_action_replied">Respuesta enviada a %s</string>
|
||||
<string name="sk_reply_line_above_avatar">\"En respuesta a\" línea sobre el avatar</string>
|
||||
<string name="sk_show_thread">Mostrar hilo</string>
|
||||
<string name="sk_compact_reblog_reply_line">Línea compacta de reblog/respuesta</string>
|
||||
</resources>
|
||||
@@ -264,4 +264,13 @@
|
||||
<string name="sk_followed_as">Suivi depuis %s</string>
|
||||
<string name="sk_settings_hide_fab">Masquer automatiquement le bouton Composer</string>
|
||||
<string name="sk_in_reply">En réponse</string>
|
||||
<string name="sk_quoting_user">Citation %s</string>
|
||||
<string name="sk_settings_reply_visibility">Visibilité des réponses</string>
|
||||
<string name="sk_settings_reply_visibility_all">Toutes les réponses</string>
|
||||
<string name="sk_settings_reply_visibility_following">Réponses à mes suivis</string>
|
||||
<string name="sk_settings_reply_visibility_self">Me répond</string>
|
||||
<string name="sk_notification_action_replied">Réponse envoyée à %s</string>
|
||||
<string name="sk_show_thread">Afficher le fil</string>
|
||||
<string name="sk_compact_reblog_reply_line">Ligne de repost/réponse compacte</string>
|
||||
<string name="sk_reply_line_above_avatar">Ligne \"En réponse à\" au-dessus de l\'avatar</string>
|
||||
</resources>
|
||||
@@ -285,6 +285,7 @@
|
||||
<string name="follow_user">Segue a %s</string>
|
||||
<string name="unfollowed_user">Deixaches de seguir a %s</string>
|
||||
<string name="followed_user">Estás a seguir a %s</string>
|
||||
<string name="following_user_requested">Solicitaches seguir a %s</string>
|
||||
<string name="open_in_browser">Abrir nun navegador</string>
|
||||
<string name="hide_boosts_from_user">Agochar promocións de @%s</string>
|
||||
<string name="show_boosts_from_user">Mostrar promocións de %s</string>
|
||||
|
||||
@@ -263,4 +263,13 @@
|
||||
<string name="sk_followed_as">Seguida dende %s</string>
|
||||
<string name="sk_settings_hide_fab">Auto-ocultar botón de redacción</string>
|
||||
<string name="sk_in_reply">Respondendo</string>
|
||||
<string name="sk_quoting_user">Citando a %s</string>
|
||||
<string name="sk_settings_reply_visibility">Visibilidade da resposta</string>
|
||||
<string name="sk_settings_reply_visibility_all">Todas as respostas</string>
|
||||
<string name="sk_settings_reply_visibility_following">Respostas aos meus seguidos</string>
|
||||
<string name="sk_settings_reply_visibility_self">Respostas a min</string>
|
||||
<string name="sk_notification_action_replied">Resposta enviada a %s</string>
|
||||
<string name="sk_reply_line_above_avatar">Liña \"en resposta a\" sobre o avatar</string>
|
||||
<string name="sk_show_thread">Mostrar chío</string>
|
||||
<string name="sk_compact_reblog_reply_line">Compactar liña de promoción/resposta</string>
|
||||
</resources>
|
||||
@@ -264,4 +264,13 @@
|
||||
<string name="sk_unfinished_attachments_message">Beberapa lampiran belum selesai diunggah.</string>
|
||||
<string name="sk_settings_hide_fab">Sembunyikan tombol Komposer</string>
|
||||
<string name="sk_in_reply">Dalam balasan</string>
|
||||
<string name="sk_settings_reply_visibility_following">Balasan ke yang saya ikuti</string>
|
||||
<string name="sk_quoting_user">Mengutip %s</string>
|
||||
<string name="sk_settings_reply_visibility">Keterlihatan balasan</string>
|
||||
<string name="sk_settings_reply_visibility_all">Semua balasan</string>
|
||||
<string name="sk_settings_reply_visibility_self">Balasan kepada saya</string>
|
||||
<string name="sk_notification_action_replied">Mengirim balasan ke %s</string>
|
||||
<string name="sk_reply_line_above_avatar">Baris “Membalas ke” di atas avatar</string>
|
||||
<string name="sk_show_thread">Tampilkan utasan</string>
|
||||
<string name="sk_compact_reblog_reply_line">Baris berbagi/balasan</string>
|
||||
</resources>
|
||||
@@ -285,6 +285,7 @@
|
||||
<string name="follow_user">Segui %s</string>
|
||||
<string name="unfollowed_user">Smetti di seguire %s</string>
|
||||
<string name="followed_user">Hai cominciato a seguire %s</string>
|
||||
<string name="following_user_requested">Richiesto di seguire %s</string>
|
||||
<string name="open_in_browser">Apri nel browser</string>
|
||||
<string name="hide_boosts_from_user">Nascondi le condivisioni di %s</string>
|
||||
<string name="show_boosts_from_user">Mostra le condivisioni di %s</string>
|
||||
|
||||
@@ -251,7 +251,7 @@
|
||||
<string name="notify_favorites">Mijn bericht als favoriet markeert</string>
|
||||
<string name="notify_follow">Mij volgt</string>
|
||||
<string name="notify_reblog">boost mijn bericht</string>
|
||||
<string name="notify_mention">vermeldt mij</string>
|
||||
<string name="notify_mention">Mij vermeldt</string>
|
||||
<string name="settings_boring">De saaie zone</string>
|
||||
<string name="settings_account">Accountinstellingen</string>
|
||||
<string name="settings_contribute">Bijdragen aan Mastodon</string>
|
||||
@@ -285,6 +285,7 @@
|
||||
<string name="follow_user">%s volgen</string>
|
||||
<string name="unfollowed_user">%s ontvolgd</string>
|
||||
<string name="followed_user">Je volgt %s nu</string>
|
||||
<string name="following_user_requested">Je volgverzoek is aan %s verstuurd</string>
|
||||
<string name="open_in_browser">Openen in browser</string>
|
||||
<string name="hide_boosts_from_user">Boosts van %s verbergen</string>
|
||||
<string name="show_boosts_from_user">Boosts van %s tonen</string>
|
||||
|
||||
@@ -262,4 +262,13 @@
|
||||
<string name="sk_follow_as">Obserwuj z innego konta</string>
|
||||
<string name="sk_settings_hide_fab">Automatycznie ukrywaj przycisk tworzenia nowego wpisu</string>
|
||||
<string name="sk_in_reply">W odpowiedzi</string>
|
||||
<string name="sk_settings_reply_visibility_following">Odpowiedzi do moich obserwacji</string>
|
||||
<string name="sk_quoting_user">Cytowanie %s</string>
|
||||
<string name="sk_settings_reply_visibility">Widoczność odpowiedzi</string>
|
||||
<string name="sk_settings_reply_visibility_all">Wszystkie odpowiedzi</string>
|
||||
<string name="sk_settings_reply_visibility_self">Odpowiedzi do mnie</string>
|
||||
<string name="sk_notification_action_replied">Wysłano odpowiedź do %s</string>
|
||||
<string name="sk_reply_line_above_avatar">Tekst \"W odpowiedzi na\" nad avatarem</string>
|
||||
<string name="sk_show_thread">Pokaż wątek</string>
|
||||
<string name="sk_compact_reblog_reply_line">Zmniejsz linię reblogu/odpowiedzi</string>
|
||||
</resources>
|
||||
@@ -315,6 +315,7 @@
|
||||
<string name="follow_user">Sledi %s</string>
|
||||
<string name="unfollowed_user">Konec sledenja %s</string>
|
||||
<string name="followed_user">Zdaj sledite %s</string>
|
||||
<string name="following_user_requested">Zaprošeni ste, da sledite %s</string>
|
||||
<string name="open_in_browser">Odpri v brskalniku</string>
|
||||
<string name="hide_boosts_from_user">Skrij poobjave %s</string>
|
||||
<string name="show_boosts_from_user">Pokaži poobjave %s</string>
|
||||
|
||||
@@ -270,6 +270,7 @@
|
||||
<string name="follow_user">ติดตาม %s</string>
|
||||
<string name="unfollowed_user">เลิกติดตาม %s แล้ว</string>
|
||||
<string name="followed_user">ตอนนี้คุณกำลังติดตาม %s</string>
|
||||
<string name="following_user_requested">ขอติดตาม %s แล้ว</string>
|
||||
<string name="open_in_browser">เปิดในเบราว์เซอร์</string>
|
||||
<string name="hide_boosts_from_user">ซ่อนการดันจาก %s</string>
|
||||
<string name="show_boosts_from_user">แสดงการดันจาก %s</string>
|
||||
|
||||
@@ -263,4 +263,13 @@
|
||||
<string name="sk_followed_as">Відстежується з %s</string>
|
||||
<string name="sk_settings_hide_fab">Автоматично ховати кнопку компонування</string>
|
||||
<string name="sk_in_reply">У відповідь</string>
|
||||
<string name="sk_quoting_user">Цитування %s</string>
|
||||
<string name="sk_settings_reply_visibility">Видимість відповіді</string>
|
||||
<string name="sk_settings_reply_visibility_all">Усі відповіді</string>
|
||||
<string name="sk_settings_reply_visibility_following">Відповіді моїм підписникам</string>
|
||||
<string name="sk_settings_reply_visibility_self">Відповіді мені</string>
|
||||
<string name="sk_notification_action_replied">Надіслано відповідь на %s</string>
|
||||
<string name="sk_reply_line_above_avatar">Рядок «У відповідь» над аватаром</string>
|
||||
<string name="sk_show_thread">Показати потік</string>
|
||||
<string name="sk_compact_reblog_reply_line">Компактний рядок для поширеного допису/відповіді</string>
|
||||
</resources>
|
||||
@@ -270,6 +270,7 @@
|
||||
<string name="follow_user">Theo dõi %s</string>
|
||||
<string name="unfollowed_user">Ngưng theo dõi %s</string>
|
||||
<string name="followed_user">Bạn đã theo dõi %s</string>
|
||||
<string name="following_user_requested">Yêu cầu theo dõi %s</string>
|
||||
<string name="open_in_browser">Mở trong trình duyệt</string>
|
||||
<string name="hide_boosts_from_user">Ẩn đăng lại từ %s</string>
|
||||
<string name="show_boosts_from_user">Hiện đăng lại từ %s</string>
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="sk_pinned_posts">置顶</string>
|
||||
<string name="sk_delete_and_redraft">删除以重新编辑</string>
|
||||
<string name="sk_confirm_delete_and_redraft_title">删除嘟文并重新编辑</string>
|
||||
<string name="sk_confirm_delete_and_redraft">确定要删除这条嘟文并重新编辑吗?</string>
|
||||
<string name="sk_delete_and_redraft">删除并重新编辑</string>
|
||||
<string name="sk_confirm_delete_and_redraft_title">删除并重新编辑帖文</string>
|
||||
<string name="sk_confirm_delete_and_redraft">确定要删除并重新编辑此帖文吗?</string>
|
||||
<string name="sk_pin_post">置顶</string>
|
||||
<string name="sk_confirm_pin_post_title">置顶嘟文</string>
|
||||
<string name="sk_confirm_pin_post">确定要在你的资料页置顶这条嘟文吗?</string>
|
||||
<string name="sk_pinning">正在置顶嘟文…</string>
|
||||
<string name="sk_confirm_pin_post_title">置顶帖文</string>
|
||||
<string name="sk_confirm_pin_post">你确定要在资料页置顶此帖文吗?</string>
|
||||
<string name="sk_pinning">正在置顶帖文…</string>
|
||||
<string name="sk_unpin_post">取消置顶</string>
|
||||
<string name="sk_confirm_unpin_post_title">取消嘟文置顶</string>
|
||||
<string name="sk_confirm_unpin_post">确定不再置顶这条嘟文吗?</string>
|
||||
<string name="sk_confirm_unpin_post_title">取消帖文置顶</string>
|
||||
<string name="sk_confirm_unpin_post">你确定不再置顶此帖文吗?</string>
|
||||
<string name="sk_unpinning">正在取消置顶…</string>
|
||||
<string name="sk_image_description">图片描述</string>
|
||||
<string name="sk_visibility_unlisted">不公开</string>
|
||||
<string name="sk_federated_timeline">联邦时间轴</string>
|
||||
<string name="sk_federated_timeline_info_banner">这是在你的联邦宇宙中最新发布的嘟文。</string>
|
||||
<string name="sk_federated_timeline_info_banner">这些是互联实例中最新发布的帖文。</string>
|
||||
<string name="sk_app_name">Megalodon</string>
|
||||
<string name="sk_settings_show_replies">显示回复</string>
|
||||
<string name="sk_settings_show_boosts">显示转嘟</string>
|
||||
<string name="sk_settings_load_new_posts">自动加载新嘟文</string>
|
||||
<string name="sk_settings_show_boosts">显示转发</string>
|
||||
<string name="sk_settings_load_new_posts">自动加载新帖文</string>
|
||||
<string name="sk_settings_show_interaction_counts">显示互动次数</string>
|
||||
<string name="sk_settings_app_version">Megalodon v%1$s (%2$d)</string>
|
||||
<string name="sk_mark_media_as_sensitive">标记为敏感媒体</string>
|
||||
<string name="sk_user_post_notifications_on">为 %s启用嘟文通知</string>
|
||||
<string name="sk_user_post_notifications_off">关闭%s的嘟文通知</string>
|
||||
<string name="sk_user_post_notifications_on">启用 %s 的帖文通知</string>
|
||||
<string name="sk_user_post_notifications_off">关闭 %s 的帖文通知</string>
|
||||
<string name="sk_update_available">Megalodon %s 已经可以下载了。</string>
|
||||
<string name="sk_update_ready">Megalodon %s 已下载,准备安装。</string>
|
||||
<string name="sk_check_for_update">检查更新</string>
|
||||
<string name="sk_no_update_available">已经是最新版本</string>
|
||||
<string name="sk_no_update_available">无可用更新</string>
|
||||
<string name="sk_list_timelines">列表</string>
|
||||
<string name="sk_accept_follow_request">接受关注请求</string>
|
||||
<string name="sk_reject_follow_request">拒绝关注请求</string>
|
||||
@@ -45,31 +45,31 @@
|
||||
<string name="sk_color_palette_blue">蓝</string>
|
||||
<string name="sk_color_palette_brown">棕</string>
|
||||
<string name="sk_color_palette_yellow">黄</string>
|
||||
<string name="sk_notification_type_status">嘟文</string>
|
||||
<string name="sk_notify_posts">嘟文通知</string>
|
||||
<string name="sk_notification_type_status">帖文</string>
|
||||
<string name="sk_notify_posts">帖文通知</string>
|
||||
<string name="sk_translate_post">翻译</string>
|
||||
<string name="sk_translate_show_original">显示原文</string>
|
||||
<string name="sk_poll_allow_multiple">允许多选</string>
|
||||
<string name="sk_welcome_text">鲨鱼向你致敬!要想开始,请在下面输入你的账户所在实例的域名。</string>
|
||||
<string name="sk_welcome_text">鲨鱼向你致敬!首先,请在下方输入你所在主实例的域名。</string>
|
||||
<string name="sk_welcome_title">欢迎!</string>
|
||||
<string name="sk_clear_recent_languages">清除最近使用的语言</string>
|
||||
<string name="sk_confirm_clear_recent_languages">您确定要清除最近使用的语言吗?</string>
|
||||
<string name="sk_confirm_clear_recent_languages">你确定要清除最近使用的语言吗?</string>
|
||||
<string name="sk_translated_using">使用 %s 翻译</string>
|
||||
<string name="sk_post_language">语言: %s</string>
|
||||
<string name="sk_post_language">语言:%s</string>
|
||||
<string name="sk_available_languages">可用语言</string>
|
||||
<string name="sk_language_name">%s (%s)</string>
|
||||
<string name="sk_example_domain">example.social</string>
|
||||
<string name="sk_tabs_disable_swipe">禁用选项卡之间的滑动</string>
|
||||
<string name="sk_settings_profile">设置个人资料</string>
|
||||
<string name="sk_settings_posting">发布偏好</string>
|
||||
<string name="sk_settings_posting">发帖偏好</string>
|
||||
<string name="sk_settings_filters">配置过滤器</string>
|
||||
<string name="sk_settings_auth">安全设置</string>
|
||||
<string name="sk_settings_rules">规则</string>
|
||||
<string name="sk_settings_about">关于应用程序</string>
|
||||
<string name="sk_settings_about">关于此应用</string>
|
||||
<string name="sk_settings_donate">捐赠</string>
|
||||
<string name="sk_color_palette_material3">系统</string>
|
||||
<string name="sk_color_palette_red">红</string>
|
||||
<string name="sk_delete_notification_confirm">您确定要删除此通知吗?</string>
|
||||
<string name="sk_delete_notification_confirm">你确定要删除此通知吗?</string>
|
||||
<string name="sk_enable_delete_notifications">启用删除通知</string>
|
||||
<string name="sk_delete_notification">删除通知</string>
|
||||
<string name="sk_delete_notification_confirm_action">删除通知</string>
|
||||
@@ -80,85 +80,85 @@
|
||||
<string name="sk_settings_translation_availability_note_unavailable">%s 似乎不支持翻译。</string>
|
||||
<string name="sk_clear_all_notifications">清除所有通知</string>
|
||||
<string name="sk_clear_all_notifications_confirm_action">删除所有</string>
|
||||
<string name="sk_clear_all_notifications_confirm">您确定要清除所有通知吗?</string>
|
||||
<string name="sk_loading_fediverse_resource_title">在联邦宇宙上查找它</string>
|
||||
<string name="sk_undo_reblog">撤销转嘟</string>
|
||||
<string name="sk_reblog_with_visibility">转嘟可见性</string>
|
||||
<string name="sk_quote_post">关于这个嘟文</string>
|
||||
<string name="sk_copy_link_to_post">复制链接到嘟文</string>
|
||||
<string name="sk_hashtags_you_follow">您关注的标签</string>
|
||||
<string name="sk_clear_all_notifications_confirm">你确定要清除所有通知吗?</string>
|
||||
<string name="sk_loading_fediverse_resource_title">在联邦宇宙上查找</string>
|
||||
<string name="sk_undo_reblog">撤销转发</string>
|
||||
<string name="sk_reblog_with_visibility">转发可见性</string>
|
||||
<string name="sk_quote_post">引用此帖文</string>
|
||||
<string name="sk_copy_link_to_post">复制帖文链接</string>
|
||||
<string name="sk_hashtags_you_follow">你关注的标签</string>
|
||||
<string name="sk_loading_resource_on_instance_title">在 %s 上查找</string>
|
||||
<string name="sk_resource_not_found">找不到资源</string>
|
||||
<string name="sk_open_with_account">用另一个帐户打开</string>
|
||||
<string name="sk_bookmark_as">与其他帐户的书签</string>
|
||||
<string name="sk_bookmarked_as">已标记为 %s</string>
|
||||
<string name="sk_already_bookmarked">已加入书签</string>
|
||||
<string name="sk_open_with_account">用其它帐户打开</string>
|
||||
<string name="sk_bookmark_as">用其它帐户加入书签</string>
|
||||
<string name="sk_bookmarked_as">已加入书签为 %s</string>
|
||||
<string name="sk_already_bookmarked">已加入书签过</string>
|
||||
<string name="sk_favorite_as">用其他账号收藏</string>
|
||||
<string name="sk_favorited_as">收藏为 %s</string>
|
||||
<string name="sk_already_favorited">已收藏</string>
|
||||
<string name="sk_reblog_as">用其他账号转嘟</string>
|
||||
<string name="sk_reblogged_as">重新登录为 %s</string>
|
||||
<string name="sk_already_reblogged">已重新登录</string>
|
||||
<string name="sk_favorited_as">已收藏为 %s</string>
|
||||
<string name="sk_already_favorited">已收藏过</string>
|
||||
<string name="sk_reblog_as">用其他账号转发</string>
|
||||
<string name="sk_reblogged_as">已转发为 %s</string>
|
||||
<string name="sk_already_reblogged">已转发过</string>
|
||||
<string name="sk_reply_as">用其他帐号回复</string>
|
||||
<string name="sk_settings_uniform_icon_for_notifications">所有通知的统一图标</string>
|
||||
<string name="sk_unsent_posts">未发送的嘟文</string>
|
||||
<string name="sk_unsent_posts">未发送的帖文</string>
|
||||
<string name="sk_confirm_delete_draft_title">删除草稿</string>
|
||||
<string name="sk_draft">草稿</string>
|
||||
<string name="sk_schedule">预订</string>
|
||||
<string name="sk_confirm_delete_scheduled_post_title">删除预订嘟文</string>
|
||||
<string name="sk_confirm_delete_scheduled_post">您确定要删除此预定嘟文吗?</string>
|
||||
<string name="sk_draft_or_schedule">草稿或预订</string>
|
||||
<string name="sk_compose_draft">嘟文将保存为草稿。</string>
|
||||
<string name="sk_compose_scheduled">预定于</string>
|
||||
<string name="sk_schedule">定时</string>
|
||||
<string name="sk_confirm_delete_scheduled_post_title">删除定时帖文</string>
|
||||
<string name="sk_confirm_delete_scheduled_post">你确定要删除此定时帖文吗?</string>
|
||||
<string name="sk_draft_or_schedule">草稿或定时</string>
|
||||
<string name="sk_compose_draft">帖文将保存为草稿。</string>
|
||||
<string name="sk_compose_scheduled">定时于</string>
|
||||
<string name="sk_draft_saved">草稿已保存</string>
|
||||
<string name="sk_post_scheduled">预订嘟文</string>
|
||||
<string name="sk_post_scheduled">帖文已定时</string>
|
||||
<string name="sk_forward_report_to">转发给 %s</string>
|
||||
<string name="sk_confirm_delete_draft">您确定要删除此嘟文草稿吗?</string>
|
||||
<string name="sk_scheduled_too_soon_title">预定的时间过早</string>
|
||||
<string name="sk_scheduled_too_soon">嘟文必须预订在未来至少 10 分钟后。</string>
|
||||
<string name="sk_save_draft">保存草稿?</string>
|
||||
<string name="sk_confirm_delete_draft">你确定要删除此帖文草稿吗?</string>
|
||||
<string name="sk_scheduled_too_soon_title">定时时间过早</string>
|
||||
<string name="sk_scheduled_too_soon">帖文只能设置为 10 分钟或更晚发送。</string>
|
||||
<string name="sk_save_draft">保存为草稿?</string>
|
||||
<string name="sk_save_changes">保存更改?</string>
|
||||
<string name="sk_confirm_save_draft">保存草稿?</string>
|
||||
<string name="sk_confirm_save_changes">保存更改?</string>
|
||||
<string name="sk_mark_as_draft">标记为草稿</string>
|
||||
<string name="sk_schedule_post">预订嘟文</string>
|
||||
<string name="sk_compose_no_schedule">不预订</string>
|
||||
<string name="sk_schedule_post">定时帖文</string>
|
||||
<string name="sk_compose_no_schedule">不要定时</string>
|
||||
<string name="sk_compose_no_draft">不要标记为草稿</string>
|
||||
<string name="sk_settings_reduce_motion">减少动画中的效果</string>
|
||||
<string name="sk_schedule_or_draft">预订或草稿</string>
|
||||
<string name="sk_settings_reduce_motion">减少动画效果</string>
|
||||
<string name="sk_schedule_or_draft">定时或草稿</string>
|
||||
<string name="sk_announcements">公告</string>
|
||||
<string name="sk_mark_as_read">标记为已读</string>
|
||||
<string name="sk_settings_about_instance">关于实例</string>
|
||||
<string name="sk_settings_single_notification">只显示一个通知</string>
|
||||
<string name="sk_settings_single_notification">仅显示单条通知</string>
|
||||
<string name="sk_create">创建</string>
|
||||
<string name="sk_create_list_title">创建列表</string>
|
||||
<string name="sk_list_name_hint">列表名</string>
|
||||
<string name="sk_list_name_hint">列表名称</string>
|
||||
<string name="sk_list_replies_policy">显示回复</string>
|
||||
<string name="sk_list_replies_policy_list">列出成员</string>
|
||||
<string name="sk_list_replies_policy_followed">关注的用户</string>
|
||||
<string name="sk_list_replies_policy_none">没有人</string>
|
||||
<string name="sk_list_replies_policy_list">列表成员</string>
|
||||
<string name="sk_list_replies_policy_followed">已关注用户</string>
|
||||
<string name="sk_list_replies_policy_none">无人</string>
|
||||
<string name="sk_delete_list">删除列表</string>
|
||||
<string name="sk_delete_list_confirm">您确定要删除列表“%s”吗?</string>
|
||||
<string name="sk_delete_list_confirm">你确定要删除列表 “%s” 吗?</string>
|
||||
<string name="sk_edit_list_title">编辑列表</string>
|
||||
<string name="sk_your_lists">你的列表</string>
|
||||
<string name="sk_timeline_federated">联邦</string>
|
||||
<string name="sk_recent_searches_placeholder">输入开始搜索</string>
|
||||
<string name="sk_recent_searches_placeholder">输入以开始搜索</string>
|
||||
<string name="sk_remove_follower">删除关注者</string>
|
||||
<string name="sk_do_remove_follower">删除</string>
|
||||
<string name="sk_remove_follower_success">成功删除关注者</string>
|
||||
<string name="sk_remove_follower_success">已成功删除关注者</string>
|
||||
<string name="sk_changelog">变更日志</string>
|
||||
<string name="sk_timeline_home">主页</string>
|
||||
<string name="sk_timeline_local">本站</string>
|
||||
<string name="sk_alt_text_missing">至少一个附件不包含描述。</string>
|
||||
<string name="sk_alt_text_missing">至少有一个附件不包含描述。</string>
|
||||
<string name="sk_publish_anyway">仍然发布</string>
|
||||
<string name="sk_notify_posts_info_banner">如果您为某些人启用嘟文通知,他们的新帖子将显示在这里。</string>
|
||||
<string name="sk_notify_posts_info_banner">如果你为某些人启用了帖文通知,其新帖文将显示在此处。</string>
|
||||
<string name="sk_timelines">时间线</string>
|
||||
<string name="sk_edit_timelines">编辑时间线</string>
|
||||
<string name="sk_alt_button">ALT</string>
|
||||
<string name="sk_post_edited">编辑</string>
|
||||
<string name="sk_notification_type_update">编辑嘟文</string>
|
||||
<string name="sk_alt_text_missing_title">缺少ALT文字</string>
|
||||
<string name="sk_timeline_posts">嘟文</string>
|
||||
<string name="sk_notification_type_update">编辑帖文</string>
|
||||
<string name="sk_alt_text_missing_title">缺少 ALT 文本</string>
|
||||
<string name="sk_timeline_posts">帖文</string>
|
||||
<string name="sk_timelines_add">添加</string>
|
||||
<string name="sk_timeline">时间线</string>
|
||||
<string name="sk_list">列表</string>
|
||||
@@ -172,7 +172,7 @@
|
||||
<string name="sk_icon_heart">心</string>
|
||||
<string name="sk_icon_star">星</string>
|
||||
<string name="sk_edit_timeline">编辑时间线</string>
|
||||
<string name="sk_settings_disable_alt_text_reminder">禁用添加ALT文本的提醒</string>
|
||||
<string name="sk_settings_disable_alt_text_reminder">禁用添加 ALT 文本的提醒</string>
|
||||
<string name="sk_icon_city">城市</string>
|
||||
<string name="sk_icon_cat">猫</string>
|
||||
<string name="sk_icon_dog">狗</string>
|
||||
@@ -223,41 +223,54 @@
|
||||
<string name="sk_icon_headphones">耳机</string>
|
||||
<string name="sk_icon_human">人类</string>
|
||||
<string name="sk_icon_globe">地球</string>
|
||||
<string name="sk_notify_update">编辑了你转嘟的嘟文</string>
|
||||
<string name="sk_notify_update">编辑已转发帖文</string>
|
||||
<string name="sk_icon_pin">钉子</string>
|
||||
<string name="sk_remove_follower_confirm">通过屏蔽并立即解除屏蔽以移除%s的关注者身份?</string>
|
||||
<string name="sk_icon_clapper_board">拍板</string>
|
||||
<string name="sk_icon_math_formula">数学公式</string>
|
||||
<string name="sk_searching">搜索中…</string>
|
||||
<string name="sk_no_results">没结果</string>
|
||||
<string name="sk_no_alt_text">没有可用的ALT文字</string>
|
||||
<string name="sk_searching">正在搜索…</string>
|
||||
<string name="sk_no_results">无结果</string>
|
||||
<string name="sk_no_alt_text">无可用的 ALT 文本</string>
|
||||
<string name="sk_updater_enable_pre_releases">启用预发布</string>
|
||||
<string name="sk_save_draft_message">您要保存对此草稿的更改还是立即发布?</string>
|
||||
<string name="sk_settings_show_alt_indicator">ALT文本指示器</string>
|
||||
<string name="sk_settings_show_no_alt_indicator">缺少ALT文本的指示器</string>
|
||||
<string name="sk_signed_up">注册</string>
|
||||
<string name="sk_reported">报告</string>
|
||||
<string name="sk_save_draft_message">你要保存对此草稿的更改还是立即发布?</string>
|
||||
<string name="sk_settings_show_alt_indicator">ALT 文本的指示器</string>
|
||||
<string name="sk_settings_show_no_alt_indicator">缺少 ALT 文本的指示器</string>
|
||||
<string name="sk_signed_up">已注册</string>
|
||||
<string name="sk_reported">已举报</string>
|
||||
<string name="sk_inline_local_only">仅限本站</string>
|
||||
<string name="sk_inline_direct">仅提及</string>
|
||||
<string name="sk_separator">·</string>
|
||||
<string name="sk_local_only">仅本地实例</string>
|
||||
<string name="sk_instance_features">实例特征</string>
|
||||
<string name="sk_instance_features">实例特性</string>
|
||||
<string name="sk_settings_support_local_only">服务器支持仅本地发布</string>
|
||||
<string name="sk_settings_local_only_explanation">您的家庭实例必须支持仅本地发布才能正常工作。大多数 Mastodon 的修改版本都可以,但 Mastodon 没有。</string>
|
||||
<string name="sk_settings_local_only_explanation">你的主实例必须支持仅本地发布才能正常工作。大多数 Mastodon 的修改版本都支持,但 Mastodon 原版不支持。</string>
|
||||
<string name="sk_settings_glitch_instance">Glitch 本地模式</string>
|
||||
<string name="sk_settings_glitch_mode_explanation">如果您的主实例在 Glitch 上运行,请启用此功能。Hometown 或 Akkoma 不需要。</string>
|
||||
<string name="sk_settings_glitch_mode_explanation">如果你的主实例运行 Glitch,请启用此功能。Hometown 或 Akkoma 不需要启用。</string>
|
||||
<string name="sk_sign_ups">用户注册</string>
|
||||
<string name="sk_new_reports">新报告</string>
|
||||
<string name="sk_settings_see_new_posts_button">“查看新嘟文”按钮</string>
|
||||
<string name="sk_new_reports">新举报</string>
|
||||
<string name="sk_settings_see_new_posts_button">“查看新帖文” 按钮</string>
|
||||
<string name="sk_settings_server_version">服务器版本: %s</string>
|
||||
<string name="sk_notify_poll_results">投票结果</string>
|
||||
<string name="sk_expand">扩增</string>
|
||||
<string name="sk_expand">展开</string>
|
||||
<string name="sk_collapse">折叠</string>
|
||||
<string name="sk_unfinished_attachments">修复附件?</string>
|
||||
<string name="sk_unfinished_attachments_message">部分附件尚未上传完毕。</string>
|
||||
<string name="sk_filtered">已过滤: %s</string>
|
||||
<string name="sk_settings_collapse_long_posts">折叠很长的嘟文</string>
|
||||
<string name="sk_settings_prefix_reply_cw_with_re">在回复带有内容警告的嘟文前加上 \"re:\"</string>
|
||||
<string name="sk_filtered">已过滤:%s</string>
|
||||
<string name="sk_settings_collapse_long_posts">折叠很长的帖文</string>
|
||||
<string name="sk_settings_prefix_reply_cw_with_re">在回复带有内容警告的帖文前加上 \"re:\"</string>
|
||||
<string name="sk_spectator_mode">旁观模式</string>
|
||||
<string name="sk_settings_hide_interaction">隐藏互动按钮</string>
|
||||
<string name="sk_settings_reply_visibility_self">对我的回复</string>
|
||||
<string name="sk_in_reply">回复</string>
|
||||
<string name="sk_follow_as">用其它账号关注</string>
|
||||
<string name="sk_followed_as">已被 %s 关注</string>
|
||||
<string name="sk_settings_hide_fab">自动隐藏撰写按钮</string>
|
||||
<string name="sk_quoting_user">引用了 %s</string>
|
||||
<string name="sk_settings_reply_visibility">回复可见范围</string>
|
||||
<string name="sk_settings_reply_visibility_all">所有回复</string>
|
||||
<string name="sk_settings_reply_visibility_following">对正在关注的回复</string>
|
||||
<string name="sk_notification_action_replied">已向 %s 发送回复</string>
|
||||
<string name="sk_reply_line_above_avatar">头像上方的 “回复” 一行</string>
|
||||
<string name="sk_compact_reblog_reply_line">紧凑转发/回复行</string>
|
||||
<string name="sk_show_thread">显示同主题帖文</string>
|
||||
</resources>
|
||||
@@ -185,7 +185,7 @@
|
||||
<string name="category_tech">科技</string>
|
||||
<string name="confirm_email_title">請檢查您的收件夾</string>
|
||||
<!-- %s is the email address -->
|
||||
<string name="confirm_email_subtitle">請點擊我們寄給您連結以驗證 %s。我們將在此稍候。</string>
|
||||
<string name="confirm_email_subtitle">請點擊我們寄給您連結以驗證 %s。我們將於此稍候。</string>
|
||||
<string name="confirm_email_didnt_get">無法取得連結嗎?</string>
|
||||
<string name="resend">重新發送</string>
|
||||
<string name="open_email_app">開啟電子郵件 App</string>
|
||||
@@ -270,6 +270,7 @@
|
||||
<string name="follow_user">跟隨 %s</string>
|
||||
<string name="unfollowed_user">取消跟隨 %s</string>
|
||||
<string name="followed_user">您現在開始跟隨 %s</string>
|
||||
<string name="following_user_requested">要求跟隨 %s</string>
|
||||
<string name="open_in_browser">在瀏覽器中開啟</string>
|
||||
<string name="hide_boosts_from_user">隱藏來自 %s 的轉嘟</string>
|
||||
<string name="show_boosts_from_user">顯示來自 %s 的轉嘟</string>
|
||||
@@ -381,7 +382,7 @@
|
||||
<string name="welcome_page3_text">不同人基於各式各樣的原因挑選不同的伺服器。art.example 也許對藝術家來說是個好地方,glasgow.example 也許對於蘇格蘭人來說是個好選擇。\n\n任何我們推薦的伺服器都是不錯的選擇(或著您也能從搜尋欄中輸入您自己的伺服器),您不會錯過任何來自聯邦宇宙角落的嘟嘟聲。</string>
|
||||
<string name="signup_random_server_explain">如果您不選擇而繼續的話,我們將透過您的語言設定替您選擇一台伺服器。</string>
|
||||
<string name="server_filter_any_language">任何語言</string>
|
||||
<string name="server_filter_instant_signup">馬上註冊</string>
|
||||
<string name="server_filter_instant_signup">立即註冊</string>
|
||||
<string name="server_filter_manual_review">手動審核</string>
|
||||
<string name="server_filter_any_signup_speed">任何註冊速度</string>
|
||||
<string name="server_filter_region_europe">歐洲</string>
|
||||
|
||||
@@ -291,6 +291,7 @@
|
||||
<string name="follow_user">Follow %s</string>
|
||||
<string name="unfollowed_user">Unfollowed %s</string>
|
||||
<string name="followed_user">You\'re now following %s</string>
|
||||
<string name="following_user_requested">Requested to follow %s</string>
|
||||
<string name="open_in_browser">Open in browser</string>
|
||||
<string name="hide_boosts_from_user">Hide reblogs from %s</string>
|
||||
<string name="show_boosts_from_user">Show reblogs from %s</string>
|
||||
|
||||
5
metadata/de-DE/changelogs/83.txt
Normal file
5
metadata/de-DE/changelogs/83.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
- Favorisieren/Lesezeichen/Antworten direkt über Android-Benachrichtigungen
|
||||
- Verbesserte Kopfzeilen für Reblogs und Antworten in der Timeline
|
||||
- Benachrichtigungs-Punkt (Benachrichtigungen werden aktuell noch nicht automatisch nachgeladen)
|
||||
- Für Akkoma-Benutzer_innen: Antwort-Sichtbarkeit, sortierte Thread-Antworten, Zitate, …
|
||||
- Crashes behoben und kleinere Verbesserungen
|
||||
5
metadata/en-US/changelogs/83.txt
Normal file
5
metadata/en-US/changelogs/83.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
- Like/bookmark/reply directly from notification shade
|
||||
- Prettier and more consistent headers for reblogs and replies in timeline
|
||||
- Notification dot (which doesn't actually load the notifications just yet)
|
||||
- For Akkoma users: Reply visibility, sorted thread replies, quoting, …
|
||||
- Crash fixes and minor tweaks
|
||||
Reference in New Issue
Block a user