diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/CacheController.java b/mastodon/src/main/java/org/joinmastodon/android/api/CacheController.java
index e4e54b451..f2ad32cab 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/api/CacheController.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/api/CacheController.java
@@ -19,7 +19,6 @@ import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.Filter;
import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Notification;
-import org.joinmastodon.android.model.PaginatedResponse;
import org.joinmastodon.android.model.SearchResult;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.utils.StatusFilterPredicate;
@@ -160,7 +159,7 @@ public class CacheController{
}
}
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(accountSession.domain);
- new GetNotifications(maxID, count, onlyPosts ? EnumSet.of(Notification.Type.STATUS) : onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class), instance.pleroma != null)
+ new GetNotifications(maxID, count, onlyPosts ? EnumSet.of(Notification.Type.STATUS) : onlyMentions ? EnumSet.of(Notification.Type.MENTION): EnumSet.allOf(Notification.Type.class), instance.isPleroma())
.setCallback(new Callback<>(){
@Override
public void onSuccess(List result){
diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/PleromaMarkNotificationsRead.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/PleromaMarkNotificationsRead.java
new file mode 100644
index 000000000..6e9fe23e7
--- /dev/null
+++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/notifications/PleromaMarkNotificationsRead.java
@@ -0,0 +1,30 @@
+package org.joinmastodon.android.api.requests.notifications;
+
+import android.text.TextUtils;
+
+import com.google.gson.reflect.TypeToken;
+
+import org.joinmastodon.android.api.MastodonAPIRequest;
+import org.joinmastodon.android.model.Notification;
+
+import java.util.List;
+
+import okhttp3.MultipartBody;
+import okhttp3.RequestBody;
+
+public class PleromaMarkNotificationsRead extends MastodonAPIRequest> {
+ private String maxID;
+ public PleromaMarkNotificationsRead(String maxID) {
+ super(HttpMethod.POST, "/pleroma/notifications/read", new TypeToken<>(){});
+ this.maxID = maxID;
+ }
+
+ @Override
+ public RequestBody getRequestBody() {
+ MultipartBody.Builder builder=new MultipartBody.Builder()
+ .setType(MultipartBody.FORM);
+ if(!TextUtils.isEmpty(maxID))
+ builder.addFormDataPart("max_id", maxID);
+ return builder.build();
+ }
+}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetBubbleTimeline.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetBubbleTimeline.java
new file mode 100644
index 000000000..9b54d1895
--- /dev/null
+++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetBubbleTimeline.java
@@ -0,0 +1,23 @@
+package org.joinmastodon.android.api.requests.timelines;
+
+import android.text.TextUtils;
+
+import com.google.gson.reflect.TypeToken;
+
+import org.joinmastodon.android.GlobalUserPreferences;
+import org.joinmastodon.android.api.MastodonAPIRequest;
+import org.joinmastodon.android.model.Status;
+
+import java.util.List;
+
+public class GetBubbleTimeline extends MastodonAPIRequest> {
+ public GetBubbleTimeline(String maxID, int limit) {
+ super(HttpMethod.GET, "/timelines/bubble", new TypeToken<>(){});
+ if(!TextUtils.isEmpty(maxID))
+ addQueryParameter("max_id", maxID);
+ if(limit>0)
+ addQueryParameter("limit", limit+"");
+ if(GlobalUserPreferences.replyVisibility != null)
+ addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
+ }
+}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetHashtagTimeline.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetHashtagTimeline.java
index 4a3c831df..1670c38c2 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetHashtagTimeline.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetHashtagTimeline.java
@@ -2,6 +2,7 @@ package org.joinmastodon.android.api.requests.timelines;
import com.google.gson.reflect.TypeToken;
+import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
@@ -16,5 +17,7 @@ public class GetHashtagTimeline extends MastodonAPIRequest>{
addQueryParameter("min_id", minID);
if(limit>0)
addQueryParameter("limit", ""+limit);
+ if(GlobalUserPreferences.replyVisibility != null)
+ addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
}
}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetListTimeline.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetListTimeline.java
index 145a740bc..82d537971 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetListTimeline.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetListTimeline.java
@@ -2,6 +2,7 @@ package org.joinmastodon.android.api.requests.timelines;
import com.google.gson.reflect.TypeToken;
+import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
@@ -18,5 +19,7 @@ public class GetListTimeline extends MastodonAPIRequest> {
addQueryParameter("limit", ""+limit);
if(sinceID!=null)
addQueryParameter("since_id", sinceID);
+ if(GlobalUserPreferences.replyVisibility != null)
+ addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
}
}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetPublicTimeline.java b/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetPublicTimeline.java
index 6723c18b9..7ec562704 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetPublicTimeline.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/api/requests/timelines/GetPublicTimeline.java
@@ -4,6 +4,7 @@ import android.text.TextUtils;
import com.google.gson.reflect.TypeToken;
+import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.MastodonAPIRequest;
import org.joinmastodon.android.model.Status;
@@ -20,5 +21,7 @@ public class GetPublicTimeline extends MastodonAPIRequest>{
addQueryParameter("max_id", maxID);
if(limit>0)
addQueryParameter("limit", limit+"");
+ if(GlobalUserPreferences.replyVisibility != null)
+ addQueryParameter("reply_visibility", GlobalUserPreferences.replyVisibility);
}
}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java
index da32d9d1a..d94e11d41 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/api/session/AccountSession.java
@@ -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.Instance;
import org.joinmastodon.android.model.Markers;
import org.joinmastodon.android.model.Preferences;
import org.joinmastodon.android.model.PushSubscription;
@@ -87,4 +88,8 @@ public class AccountSession{
pushSubscriptionManager=new PushSubscriptionManager(getID());
return pushSubscriptionManager;
}
+
+ public Instance getInstance() {
+ return AccountSessionManager.getInstance().getInstanceInfo(domain);
+ }
}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
index 445e573c6..1a174099a 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ComposeFragment.java
@@ -1087,7 +1087,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
}
req.status=text;
req.localOnly=localOnly;
- req.visibility=localOnly && instance.pleroma != null ? StatusPrivacy.LOCAL : statusVisibility;
+ req.visibility=localOnly && instance.isPleroma() ? StatusPrivacy.LOCAL : statusVisibility;
req.sensitive=sensitive;
req.language=language;
req.contentType=contentType;
@@ -1743,11 +1743,24 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
pollChanged=true;
updatePublishButtonState();
}));
- option.edit.setFilters(new InputFilter[]{new InputFilter.LengthFilter(instance.configuration!=null && instance.configuration.polls!=null && instance.configuration.polls.maxCharactersPerOption>0 ? instance.configuration.polls.maxCharactersPerOption : 50)});
+
+ int maxCharactersPerOption = 50;
+ if(instance.configuration!=null && instance.configuration.polls!=null && instance.configuration.polls.maxCharactersPerOption>0)
+ maxCharactersPerOption = instance.configuration.polls.maxCharactersPerOption;
+ else if(instance.pollLimits!=null && instance.pollLimits.maxOptionChars>0)
+ maxCharactersPerOption = instance.pollLimits.maxOptionChars;
+ option.edit.setFilters(new InputFilter[]{new InputFilter.LengthFilter(maxCharactersPerOption)});
pollOptionsView.addView(option.view);
pollOptions.add(option);
- if(pollOptions.size()==(instance.configuration!=null && instance.configuration.polls!=null && instance.configuration.polls.maxOptions>0 ? instance.configuration.polls.maxOptions : 4))
+
+ int maxPollOptions = 4;
+ if(instance.configuration!=null && instance.configuration.polls!=null && instance.configuration.polls.maxOptions>0)
+ maxPollOptions = instance.configuration.polls.maxOptions;
+ else if (instance.pollLimits!=null && instance.pollLimits.maxOptions>0)
+ maxPollOptions = instance.pollLimits.maxOptions;
+
+ if(pollOptions.size()==maxPollOptions)
addPollOptionBtn.setVisibility(View.GONE);
return option;
}
@@ -1889,7 +1902,7 @@ public class ComposeFragment extends MastodonToolbarFragment implements OnBackPr
Menu m=visibilityPopup.getMenu();
MenuItem localOnlyItem = visibilityPopup.getMenu().findItem(R.id.local_only);
boolean prefsSaysSupported = GlobalUserPreferences.accountsWithLocalOnlySupport.contains(accountID);
- if (instance.pleroma != null) {
+ if (instance.isPleroma()) {
m.findItem(R.id.vis_local).setVisible(true);
} else if (localOnly || prefsSaysSupported) {
localOnlyItem.setVisible(true);
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/EditTimelinesFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/EditTimelinesFragment.java
index 3dbf2f2c9..784d7920a 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/EditTimelinesFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/EditTimelinesFragment.java
@@ -30,8 +30,11 @@ import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
import org.joinmastodon.android.api.requests.lists.GetLists;
import org.joinmastodon.android.api.requests.tags.GetFollowedHashtags;
+import org.joinmastodon.android.api.session.AccountSession;
+import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.model.Hashtag;
import org.joinmastodon.android.model.HeaderPaginationList;
+import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.ListTimeline;
import org.joinmastodon.android.model.TimelineDefinition;
import org.joinmastodon.android.ui.DividerItemDecoration;
@@ -164,7 +167,7 @@ public class EditTimelinesFragment extends RecyclerFragment
makeBackItem(listsMenu);
makeBackItem(hashtagsMenu);
- TimelineDefinition.ALL_TIMELINES.forEach(tl -> addTimelineToOptions(tl, timelinesMenu));
+ TimelineDefinition.getAllTimelines(accountID).forEach(tl -> addTimelineToOptions(tl, timelinesMenu));
listTimelines.stream().map(TimelineDefinition::ofList).forEach(tl -> addTimelineToOptions(tl, listsMenu));
hashtags.stream().map(TimelineDefinition::ofHashtag).forEach(tl -> addTimelineToOptions(tl, hashtagsMenu));
@@ -190,7 +193,7 @@ public class EditTimelinesFragment extends RecyclerFragment
@Override
protected void doLoadData(int offset, int count){
- onDataLoaded(GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.DEFAULT_TIMELINES), false);
+ onDataLoaded(GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.getDefaultTimelines(accountID)), false);
updateOptionsMenu();
}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java
index 6fa71d645..272692e95 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeFragment.java
@@ -83,6 +83,8 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
homeTabFragment=new HomeTabFragment();
homeTabFragment.setArguments(args);
args=new Bundle(args);
+ Instance instance = AccountSessionManager.getInstance().getAccount(accountID).getInstance();
+ args.putBoolean("isPleroma", instance.isPleroma());
args.putBoolean("noAutoLoad", true);
searchFragment=new DiscoverFragment();
searchFragment.setArguments(args);
@@ -231,6 +233,8 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
if (newFragment instanceof HasFab fabulous) fabulous.showFab();
currentTab=tab;
((FragmentStackActivity)getActivity()).invalidateSystemBarColors(this);
+ if (tab == R.id.tab_search)
+ searchFragment.selectSearch();
}
private void maybeTriggerLoading(Fragment newFragment){
@@ -290,10 +294,10 @@ public class HomeFragment extends AppKitFragment implements OnBackPressedListene
public void updateNotificationBadge() {
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
- Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
+ Instance instance = session.getInstance();
if (instance == null) return;
- new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance != null && instance.pleroma != null)
+ new GetNotifications(null, 1, EnumSet.allOf(Notification.Type.class), instance != null && instance.isPleroma())
.setCallback(new Callback<>() {
@Override
public void onSuccess(List notifications) {
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java
index 0fba783f5..3616eb5e4 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/HomeTabFragment.java
@@ -106,7 +106,7 @@ public class HomeTabFragment extends MastodonToolbarFragment implements Scrollab
super.onCreate(savedInstanceState);
E.register(this);
accountID = getArguments().getString("account");
- timelineDefinitions = GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.DEFAULT_TIMELINES);
+ timelineDefinitions = GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.getDefaultTimelines(accountID));
assert timelineDefinitions != null;
if (timelineDefinitions.size() == 0) timelineDefinitions = List.of(TimelineDefinition.HOME_TIMELINE);
count = timelineDefinitions.size();
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsListFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsListFragment.java
index 18915c7e1..ba30cf5a6 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsListFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/NotificationsListFragment.java
@@ -9,7 +9,10 @@ import com.squareup.otto.Subscribe;
import org.joinmastodon.android.E;
import org.joinmastodon.android.R;
+import org.joinmastodon.android.api.MastodonErrorResponse;
import org.joinmastodon.android.api.requests.markers.SaveMarkers;
+import org.joinmastodon.android.api.requests.notifications.PleromaMarkNotificationsRead;
+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.PollUpdatedEvent;
@@ -18,6 +21,7 @@ import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.CacheablePaginatedResponse;
import org.joinmastodon.android.model.Emoji;
import org.joinmastodon.android.model.Filter;
+import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Notification;
import org.joinmastodon.android.model.Status;
import org.joinmastodon.android.ui.displayitems.AccountCardStatusDisplayItem;
@@ -40,6 +44,7 @@ import java.util.stream.Stream;
import androidx.recyclerview.widget.RecyclerView;
import me.grishka.appkit.Nav;
+import me.grishka.appkit.api.ErrorResponse;
import me.grishka.appkit.api.SimpleCallback;
public class NotificationsListFragment extends BaseStatusListFragment{
@@ -158,6 +163,9 @@ public class NotificationsListFragment extends BaseStatusListFragment(GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.DEFAULT_TIMELINES));
+ pinnedTimelines = new ArrayList<>(GlobalUserPreferences.pinnedTimelines.getOrDefault(accountID, TimelineDefinition.getDefaultTimelines(accountID)));
}
@Override
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java
index a6fe0b022..174d3d19b 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ProfileFragment.java
@@ -31,7 +31,6 @@ import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver;
import android.view.WindowInsets;
import android.view.inputmethod.InputMethodManager;
-import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
@@ -51,6 +50,7 @@ import org.joinmastodon.android.api.requests.accounts.GetAccountStatuses;
import org.joinmastodon.android.api.requests.accounts.GetOwnAccount;
import org.joinmastodon.android.api.requests.accounts.SetAccountFollowed;
import org.joinmastodon.android.api.requests.accounts.UpdateAccountCredentials;
+import org.joinmastodon.android.api.session.AccountSession;
import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.account_list.FollowerListFragment;
import org.joinmastodon.android.fragments.account_list.FollowingListFragment;
@@ -58,6 +58,7 @@ import org.joinmastodon.android.fragments.report.ReportReasonChoiceFragment;
import org.joinmastodon.android.model.Account;
import org.joinmastodon.android.model.AccountField;
import org.joinmastodon.android.model.Attachment;
+import org.joinmastodon.android.model.Instance;
import org.joinmastodon.android.model.Relationship;
import org.joinmastodon.android.ui.BetterItemAnimator;
import org.joinmastodon.android.ui.SimpleViewHolder;
@@ -137,6 +138,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private Account account;
private String accountID;
+ private String domain;
private Relationship relationship;
private int statusBarHeight;
private boolean isOwnProfile;
@@ -151,7 +153,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
private PhotoViewer currentPhotoViewer;
private boolean editModeLoading;
- private static final int MAX_FIELDS=4;
+ private int maxFields = 4;
// from ProfileAboutFragment
public UsableRecyclerView list;
@@ -172,6 +174,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
setRetainInstance(true);
accountID=getArguments().getString("account");
+ domain=AccountSessionManager.getInstance().getAccount(accountID).domain;
if(getArguments().containsKey("profileAccount")){
account=Parcels.unwrap(getArguments().getParcelable("profileAccount"));
profileAccountID=account.id;
@@ -179,6 +182,12 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
loaded=true;
if(!isOwnProfile)
loadRelationship();
+ else {
+ Instance instance = AccountSessionManager.getInstance().getInstanceInfo(domain);
+ if (instance.isPleroma()) {
+ maxFields = instance.pleroma.metadata.fieldsLimits.maxFields;
+ }
+ }
}else{
profileAccountID=getArguments().getString("profileAccountID");
if(!getArguments().getBoolean("noAutoLoad", false))
@@ -324,7 +333,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
username.setOnLongClickListener(v->{
String usernameString=account.acct;
if(!usernameString.contains("@")){
- usernameString+="@"+AccountSessionManager.getInstance().getAccount(accountID).domain;
+ usernameString+="@"+domain;
}
UiUtils.copyText(username, '@'+usernameString);
return true;
@@ -510,7 +519,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
ssb.append(account.acct);
if(isSelf){
ssb.append('@');
- ssb.append(AccountSessionManager.getInstance().getAccount(accountID).domain);
+ ssb.append(domain);
}
ssb.append(" ");
Drawable lock=username.getResources().getDrawable(R.drawable.ic_lock, getActivity().getTheme()).mutate();
@@ -520,7 +529,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
username.setText(ssb);
}else{
// noinspection SetTextI18n
- username.setText('@'+account.acct+(isSelf ? ('@'+AccountSessionManager.getInstance().getAccount(accountID).domain) : ""));
+ username.setText('@'+account.acct+(isSelf ? ('@'+domain) : ""));
}
CharSequence parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
if(TextUtils.isEmpty(parsedBio)){
@@ -1189,7 +1198,7 @@ public class ProfileFragment extends LoaderFragment implements OnBackPressedList
public int getItemCount(){
if(isInEditMode){
int size=metadataListData.size();
- if(size{
PopupMenu popupMenu=new PopupMenu(getActivity(), b, Gravity.CENTER_HORIZONTAL);
popupMenu.inflate(R.menu.reply_visibility);
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java
index 627e7a0ad..9a4ded773 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/ThreadFragment.java
@@ -74,7 +74,7 @@ public class ThreadFragment extends StatusListFragment{
}
AccountSession account=AccountSessionManager.getInstance().getAccount(accountID);
Instance instance=AccountSessionManager.getInstance().getInstanceInfo(account.domain);
- if(instance.pleroma != null){
+ if(instance.isPleroma()){
List threadIds=new ArrayList<>();
threadIds.add(mainStatus.id);
for(Status s:result.descendants){
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/BubbleTimelineFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/BubbleTimelineFragment.java
new file mode 100644
index 000000000..22b746bbc
--- /dev/null
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/BubbleTimelineFragment.java
@@ -0,0 +1,55 @@
+package org.joinmastodon.android.fragments.discover;
+
+import android.os.Bundle;
+import android.view.View;
+
+import org.joinmastodon.android.api.requests.timelines.GetBubbleTimeline;
+import org.joinmastodon.android.api.requests.timelines.GetPublicTimeline;
+import org.joinmastodon.android.fragments.StatusListFragment;
+import org.joinmastodon.android.model.Filter;
+import org.joinmastodon.android.model.Status;
+import org.joinmastodon.android.ui.utils.DiscoverInfoBannerHelper;
+import org.joinmastodon.android.utils.StatusFilterPredicate;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import me.grishka.appkit.api.SimpleCallback;
+
+public class BubbleTimelineFragment extends StatusListFragment {
+ private DiscoverInfoBannerHelper bannerHelper=new DiscoverInfoBannerHelper(DiscoverInfoBannerHelper.BannerType.BUBBLE_TIMELINE);
+ private String maxID;
+
+ @Override
+ protected boolean wantsComposeButton() {
+ return true;
+ }
+
+
+ @Override
+ protected void doLoadData(int offset, int count){
+ currentRequest=new GetBubbleTimeline(refreshing ? null : maxID, count)
+ .setCallback(new SimpleCallback<>(this){
+ @Override
+ public void onSuccess(List result){
+ if(!result.isEmpty())
+ maxID=result.get(result.size()-1).id;
+ if (getActivity() == null) return;
+ result=result.stream().filter(new StatusFilterPredicate(accountID, getFilterContext())).collect(Collectors.toList());
+ onDataLoaded(result, !result.isEmpty());
+ }
+ })
+ .exec(accountID);
+ }
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState){
+ super.onViewCreated(view, savedInstanceState);
+ bannerHelper.maybeAddBanner(contentWrap);
+ }
+
+ @Override
+ protected Filter.FilterContext getFilterContext() {
+ return Filter.FilterContext.PUBLIC;
+ }
+}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java
index 67f7b7a69..0fb383eca 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/DiscoverFragment.java
@@ -19,6 +19,7 @@ import android.widget.TextView;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.R;
+import org.joinmastodon.android.fragments.HomeFragment;
import org.joinmastodon.android.fragments.IsOnTop;
import org.joinmastodon.android.fragments.ScrollableToTop;
import org.joinmastodon.android.ui.SimpleViewHolder;
@@ -238,7 +239,7 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
else scrollToTop();
}
- private void selectSearch() {
+ public void selectSearch() {
searchEdit.requestFocus();
onSearchEditFocusChanged(searchEdit, true);
getActivity().getSystemService(InputMethodManager.class).showSoftInput(searchEdit, 0);
@@ -272,6 +273,8 @@ public class DiscoverFragment extends AppKitFragment implements ScrollableToTop,
searchBack.setEnabled(false);
searchBack.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
getActivity().getSystemService(InputMethodManager.class).hideSoftInputFromWindow(searchEdit.getWindowToken(), 0);
+ if (getArguments().getBoolean("isPleroma"))
+ ((HomeFragment) getParentFragment()).onBackPressed();
}
@Override
diff --git a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java
index bf0b9e4c8..f5063456b 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/fragments/discover/TrendingHashtagsFragment.java
@@ -1,5 +1,8 @@
package org.joinmastodon.android.fragments.discover;
+import static org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem.Holder.withHistoryParams;
+import static org.joinmastodon.android.ui.displayitems.HashtagStatusDisplayItem.Holder.withoutHistoryParams;
+
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
@@ -108,9 +111,11 @@ public class TrendingHashtagsFragment extends RecyclerFragment implemen
if (item.history == null || item.history.isEmpty()) {
subtitle.setText(null);
chart.setVisibility(View.GONE);
+ title.setLayoutParams(withoutHistoryParams);
return;
}
chart.setVisibility(View.VISIBLE);
+ title.setLayoutParams(withHistoryParams);
int numPeople=item.history.get(0).accounts;
if(item.history.size()>1)
numPeople+=item.history.get(1).accounts;
diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/Instance.java b/mastodon/src/main/java/org/joinmastodon/android/model/Instance.java
index 09aae3adc..cd8e94d99 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/model/Instance.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/model/Instance.java
@@ -86,6 +86,8 @@ public class Instance extends BaseModel{
public Pleroma pleroma;
+ public PleromaPollLimits pollLimits;
+
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();
@@ -134,6 +136,10 @@ public class Instance extends BaseModel{
return ci;
}
+ public boolean isPleroma() {
+ return pleroma != null;
+ }
+
@Parcel
public static class Rule{
public String id;
@@ -198,6 +204,28 @@ public class Instance extends BaseModel{
@Parcel
public static class Pleroma extends BaseModel {
- // metadata etc
+ public Pleroma.Metadata metadata;
+
+ @Parcel
+ public static class Metadata {
+ public List features;
+ public Pleroma.Metadata.FieldsLimits fieldsLimits;
+
+ @Parcel
+ public static class FieldsLimits {
+ public int maxFields;
+ public int maxRemoteFields;
+ public int nameLength;
+ public int valueLength;
+ }
+ }
+ }
+
+ @Parcel
+ public static class PleromaPollLimits {
+ public int maxExpiration;
+ public int maxOptionChars;
+ public int maxOptions;
+ public int minExpiration;
}
}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/model/TimelineDefinition.java b/mastodon/src/main/java/org/joinmastodon/android/model/TimelineDefinition.java
index fd7c3346a..bff0046b3 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/model/TimelineDefinition.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/model/TimelineDefinition.java
@@ -8,17 +8,20 @@ import androidx.annotation.DrawableRes;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
-import org.joinmastodon.android.BuildConfig;
import org.joinmastodon.android.R;
+import org.joinmastodon.android.api.session.AccountSession;
+import org.joinmastodon.android.api.session.AccountSessionManager;
import org.joinmastodon.android.fragments.HashtagTimelineFragment;
import org.joinmastodon.android.fragments.HomeTimelineFragment;
import org.joinmastodon.android.fragments.ListTimelineFragment;
import org.joinmastodon.android.fragments.NotificationsListFragment;
+import org.joinmastodon.android.fragments.discover.BubbleTimelineFragment;
import org.joinmastodon.android.fragments.discover.FederatedTimelineFragment;
import org.joinmastodon.android.fragments.discover.LocalTimelineFragment;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
public class TimelineDefinition {
private TimelineType type;
@@ -58,6 +61,14 @@ public class TimelineDefinition {
this.type = type;
}
+ public boolean isCompatible(AccountSession session) {
+ return true;
+ }
+
+ public boolean wantsDefault(AccountSession session) {
+ return true;
+ }
+
public String getTitle(Context ctx) {
return title != null ? title : getDefaultTitle(ctx);
}
@@ -78,6 +89,7 @@ public class TimelineDefinition {
case POST_NOTIFICATIONS -> ctx.getString(R.string.sk_timeline_posts);
case LIST -> listTitle;
case HASHTAG -> hashtagName;
+ case BUBBLE -> ctx.getString(R.string.sk_timeline_bubble);
};
}
@@ -89,6 +101,7 @@ public class TimelineDefinition {
case POST_NOTIFICATIONS -> Icon.POST_NOTIFICATIONS;
case LIST -> Icon.LIST;
case HASHTAG -> Icon.HASHTAG;
+ case BUBBLE -> Icon.BUBBLE;
};
}
@@ -100,6 +113,7 @@ public class TimelineDefinition {
case LIST -> new ListTimelineFragment();
case HASHTAG -> new HashtagTimelineFragment();
case POST_NOTIFICATIONS -> new NotificationsListFragment();
+ case BUBBLE -> new BubbleTimelineFragment();
};
}
@@ -156,7 +170,7 @@ public class TimelineDefinition {
return args;
}
- public enum TimelineType { HOME, LOCAL, FEDERATED, POST_NOTIFICATIONS, LIST, HASHTAG }
+ public enum TimelineType { HOME, LOCAL, FEDERATED, POST_NOTIFICATIONS, LIST, HASHTAG, BUBBLE }
public enum Icon {
HEART(R.drawable.ic_fluent_heart_24_regular, R.string.sk_icon_heart),
@@ -219,7 +233,8 @@ public class TimelineDefinition {
FEDERATED(R.drawable.ic_fluent_earth_24_regular, R.string.sk_timeline_federated, true),
POST_NOTIFICATIONS(R.drawable.ic_fluent_chat_24_regular, R.string.sk_timeline_posts, true),
LIST(R.drawable.ic_fluent_people_24_regular, R.string.sk_list, true),
- HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true);
+ HASHTAG(R.drawable.ic_fluent_number_symbol_24_regular, R.string.sk_hashtag, true),
+ BUBBLE(R.drawable.ic_fluent_circle_24_regular, R.string.sk_timeline_bubble, true);
public final int iconRes, nameRes;
public final boolean hidden;
@@ -239,14 +254,49 @@ public class TimelineDefinition {
public static final TimelineDefinition LOCAL_TIMELINE = new TimelineDefinition(TimelineType.LOCAL);
public static final TimelineDefinition FEDERATED_TIMELINE = new TimelineDefinition(TimelineType.FEDERATED);
public static final TimelineDefinition POSTS_TIMELINE = new TimelineDefinition(TimelineType.POST_NOTIFICATIONS);
+ public static final TimelineDefinition BUBBLE_TIMELINE = new TimelineDefinition(TimelineType.BUBBLE) {
+ @Override
+ public boolean isCompatible(AccountSession session) {
+ // still enabling the bubble timeline for all pleroma/akkoma instances since i know of
+ // at least one instance that supports it, but doesn't list "bubble_timeline"
+ return session.getInstance().isPleroma();
+ }
- public static final List DEFAULT_TIMELINES = BuildConfig.BUILD_TYPE.equals("playRelease")
- ? List.of(HOME_TIMELINE.copy(), LOCAL_TIMELINE.copy())
- : List.of(HOME_TIMELINE.copy(), LOCAL_TIMELINE.copy(), FEDERATED_TIMELINE.copy());
- public static final List ALL_TIMELINES = List.of(
- HOME_TIMELINE.copy(),
- LOCAL_TIMELINE.copy(),
- FEDERATED_TIMELINE.copy(),
- POSTS_TIMELINE.copy()
+ @Override
+ public boolean wantsDefault(AccountSession session) {
+ Instance instance = session.getInstance();
+ return instance.isPleroma() && instance.pleroma.metadata.features.contains("bubble_timeline");
+ }
+ };
+
+ public static List getDefaultTimelines(String accountId) {
+ AccountSession session = AccountSessionManager.getInstance().getAccount(accountId);
+ return DEFAULT_TIMELINES.stream()
+ .filter(tl -> tl.isCompatible(session) && tl.wantsDefault(session))
+ .map(TimelineDefinition::copy)
+ .collect(Collectors.toList());
+ }
+
+ public static List getAllTimelines(String accountId) {
+ AccountSession session = AccountSessionManager.getInstance().getAccount(accountId);
+ return ALL_TIMELINES.stream()
+ .filter(tl -> tl.isCompatible(session))
+ .map(TimelineDefinition::copy)
+ .collect(Collectors.toList());
+ }
+
+ private static final List DEFAULT_TIMELINES = List.of(
+ HOME_TIMELINE,
+ LOCAL_TIMELINE,
+ BUBBLE_TIMELINE,
+ FEDERATED_TIMELINE
+ );
+
+ private static final List ALL_TIMELINES = List.of(
+ HOME_TIMELINE,
+ LOCAL_TIMELINE,
+ FEDERATED_TIMELINE,
+ POSTS_TIMELINE,
+ BUBBLE_TIMELINE
);
}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HashtagStatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HashtagStatusDisplayItem.java
index 586fb45a9..e337083b0 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HashtagStatusDisplayItem.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/HashtagStatusDisplayItem.java
@@ -3,6 +3,7 @@ package org.joinmastodon.android.ui.displayitems;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.RelativeLayout;
import android.widget.TextView;
import org.joinmastodon.android.R;
@@ -26,6 +27,13 @@ public class HashtagStatusDisplayItem extends StatusDisplayItem{
public static class Holder extends StatusDisplayItem.Holder{
private final TextView title, subtitle;
private final HashtagChartView chart;
+ public static final RelativeLayout.LayoutParams
+ withHistoryParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT),
+ withoutHistoryParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
+
+ static {
+ withoutHistoryParams.addRule(RelativeLayout.CENTER_VERTICAL, RelativeLayout.TRUE);
+ }
public Holder(Context context, ViewGroup parent){
super(context, R.layout.item_trending_hashtag, parent);
@@ -41,9 +49,11 @@ public class HashtagStatusDisplayItem extends StatusDisplayItem{
if (item.history == null || item.history.isEmpty()) {
subtitle.setText(null);
chart.setVisibility(View.GONE);
+ title.setLayoutParams(withoutHistoryParams);
return;
}
chart.setVisibility(View.VISIBLE);
+ title.setLayoutParams(withHistoryParams);
int numPeople=item.history.get(0).accounts;
if(item.history.size()>1)
numPeople+=item.history.get(1).accounts;
diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java
index 99de1e3b7..be3b0a779 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/ui/displayitems/StatusDisplayItem.java
@@ -166,6 +166,15 @@ public abstract class StatusDisplayItem{
items.add(replyLine);
}
+ if (statusForContent.quote != null) {
+ boolean hasQuoteInlineTag = statusForContent.content.contains("");
+ if (!hasQuoteInlineTag) {
+ String quoteUrl = statusForContent.quote.url;
+ String quoteInline = String.format("%sRE: %s",
+ statusForContent.content.endsWith("
") ? "" : "
", quoteUrl, quoteUrl);
+ statusForContent.content += quoteInline;
+ }
+ }
if(!TextUtils.isEmpty(statusForContent.content))
items.add(new TextStatusDisplayItem(parentID, HtmlParser.parse(statusForContent.content, statusForContent.emojis, statusForContent.mentions, statusForContent.tags, accountID), fragment, statusForContent, disableTranslate));
else if (!GlobalUserPreferences.replyLineAboveHeader && replyLine != null)
diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/DiscoverInfoBannerHelper.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/DiscoverInfoBannerHelper.java
index edc114101..6c2d01d56 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/DiscoverInfoBannerHelper.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/DiscoverInfoBannerHelper.java
@@ -38,6 +38,7 @@ public class DiscoverInfoBannerHelper{
case LOCAL_TIMELINE -> R.string.local_timeline_info_banner;
case FEDERATED_TIMELINE -> R.string.sk_federated_timeline_info_banner;
case POST_NOTIFICATIONS -> R.string.sk_notify_posts_info_banner;
+ case BUBBLE_TIMELINE -> R.string.sk_bubble_timeline_info_banner;
});
}
}
@@ -63,6 +64,7 @@ public class DiscoverInfoBannerHelper{
LOCAL_TIMELINE,
FEDERATED_TIMELINE,
POST_NOTIFICATIONS,
-// ACCOUNTS
+// ACCOUNTS,
+ BUBBLE_TIMELINE
}
}
diff --git a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java
index 090e0b06b..0d39c0ad9 100644
--- a/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java
+++ b/mastodon/src/main/java/org/joinmastodon/android/ui/utils/UiUtils.java
@@ -99,6 +99,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
import java.net.URISyntaxException;
+import java.net.URL;
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZonedDateTime;
@@ -946,7 +947,7 @@ public class UiUtils {
public static String getInstanceName(String accountID) {
AccountSession session = AccountSessionManager.getInstance().getAccount(accountID);
- Instance instance = AccountSessionManager.getInstance().getInstanceInfo(session.domain);
+ Instance instance = session.getInstance();
return instance != null && !instance.title.isBlank() ? instance.title : session.domain;
}
@@ -1112,14 +1113,20 @@ public class UiUtils {
if (!results.statuses.isEmpty()) {
args.putParcelable("status", Parcels.wrap(results.statuses.get(0)));
Nav.go((Activity) context, ThreadFragment.class, args);
- } else if (!results.accounts.isEmpty()) {
- args.putParcelable("profileAccount", Parcels.wrap(results.accounts.get(0)));
- Nav.go((Activity) context, ProfileFragment.class, args);
- } else {
- if (launchBrowser) launchWebBrowser(context, url);
- else
- Toast.makeText(context, R.string.sk_resource_not_found, Toast.LENGTH_SHORT).show();
+ return;
}
+ Optional account = results.accounts.stream()
+ .filter(a -> uri.equals(Uri.parse(a.url))).findAny();
+ if (account.isPresent()) {
+ args.putParcelable("profileAccount", Parcels.wrap(account.get()));
+ Nav.go((Activity) context, ProfileFragment.class, args);
+ return;
+ }
+ if (launchBrowser) {
+ launchWebBrowser(context, url);
+ return;
+ }
+ Toast.makeText(context, R.string.sk_resource_not_found, Toast.LENGTH_SHORT).show();
}
@Override
diff --git a/mastodon/src/main/res/values/strings_sk.xml b/mastodon/src/main/res/values/strings_sk.xml
index 6eae86635..06cf3eeb4 100644
--- a/mastodon/src/main/res/values/strings_sk.xml
+++ b/mastodon/src/main/res/values/strings_sk.xml
@@ -30,6 +30,7 @@
Turned off post notifications for %s
Federation
These are the most recent posts by the people in your federation.
+ These are the most recent posts by the people in your Akkoma server\'s bubble.
Megalodon %s is ready to download.
Megalodon %s is downloaded and ready to install.
Check for update
@@ -148,6 +149,7 @@
Home
Local
Federation
+ Bubble
Type to start searching
Remove as follower
Remove %s as a follower by blocking and immediately unblocking them?