Compare commits
31 Commits
v1.2.0+for
...
v1.2.0+for
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
244c5dc6b4 | ||
|
|
cceb0b4c6c | ||
|
|
a58640a718 | ||
|
|
d6e563486b | ||
|
|
0112bfa9c4 | ||
|
|
5951611fb0 | ||
|
|
2d31b726ac | ||
|
|
d2f295ef88 | ||
|
|
d1b53554ce | ||
|
|
ec5db122d0 | ||
|
|
0216e22fcc | ||
|
|
5734b19d8c | ||
|
|
e58aeec097 | ||
|
|
58b000927a | ||
|
|
797642b972 | ||
|
|
781856b822 | ||
|
|
ff272179e7 | ||
|
|
bec47f40f7 | ||
|
|
f9607a434a | ||
|
|
b650ca85bc | ||
|
|
f4365ed163 | ||
|
|
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 82
|
||||
versionName "1.2.0+fork.82"
|
||||
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>
|
||||
@@ -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/82.txt
Normal file
5
metadata/de-DE/changelogs/82.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/82.txt
Normal file
5
metadata/en-US/changelogs/82.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