Merge branch 'main' into feat/hide-non-boostable-boosts

This commit is contained in:
FineFindus
2023-06-08 10:35:12 +02:00
committed by GitHub
431 changed files with 17825 additions and 4185 deletions

View File

@@ -1,7 +1,10 @@
package org.joinmastodon.android.model;
import android.net.Uri;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;
@@ -14,7 +17,7 @@ import java.util.List;
* Represents a user of Mastodon and their associated profile.
*/
@Parcel
public class Account extends BaseModel{
public class Account extends BaseModel implements Searchable{
// Base attributes
/**
@@ -43,7 +46,7 @@ public class Account extends BaseModel{
/**
* The profile's display name.
*/
@RequiredField
// @RequiredField
public String displayName;
/**
* The profile's bio / description.
@@ -62,7 +65,6 @@ public class Account extends BaseModel{
/**
* An image banner that is shown above the profile and in profile cards.
*/
@RequiredField
public String header;
/**
* A static version of the header. Equal to header if its value is a static image; different if header is an animated GIF.
@@ -86,7 +88,7 @@ public class Account extends BaseModel{
/**
* When the account was created.
*/
@RequiredField
// @RequiredField
public Instant createdAt;
/**
* When the most recent status was posted.
@@ -133,6 +135,21 @@ public class Account extends BaseModel{
*/
public Instant muteExpiresAt;
public List<Role> roles;
public @Nullable String fqn; // akkoma has this, mastodon't
@Override
public String getQuery() {
return url;
}
@Parcel
public static class Role {
public String name;
/** #rrggbb */
public String color;
}
@Override
public void postprocess() throws ObjectValidationException{
@@ -149,6 +166,7 @@ public class Account extends BaseModel{
moved.postprocess();
if(TextUtils.isEmpty(displayName))
displayName=username;
if(fqn == null) fqn = getFullyQualifiedName();
}
public boolean isLocal(){
@@ -160,6 +178,10 @@ public class Account extends BaseModel{
return parts.length==1 ? null : parts[1];
}
public String getDomainFromURL() {
return Uri.parse(url).getHost();
}
public String getDisplayUsername(){
return '@'+acct;
}
@@ -168,6 +190,10 @@ public class Account extends BaseModel{
return '@'+acct.split("@")[0];
}
public String getFullyQualifiedName() {
return fqn != null ? fqn : acct.split("@")[0] + "@" + getDomainFromURL();
}
@Override
public String toString(){
return "Account{"+

View File

@@ -8,8 +8,17 @@ import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
public abstract class BaseModel implements Cloneable{
/**
* indicates the profile has been fetched from a foreign instance.
*
* @see MastodonAPIRequest#execRemote
*/
public transient boolean isRemote;
public abstract class BaseModel{
@CallSuper
public void postprocess() throws ObjectValidationException{
try{
@@ -23,4 +32,14 @@ public abstract class BaseModel{
}
}catch(IllegalAccessException ignore){}
}
@NonNull
@Override
public Object clone(){
try{
return super.clone();
}catch(CloneNotSupportedException x){
throw new RuntimeException(x);
}
}
}

View File

@@ -0,0 +1,40 @@
package org.joinmastodon.android.model;
import android.view.Menu;
import androidx.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
import org.joinmastodon.android.R;
public enum ContentType {
@SerializedName("text/plain")
PLAIN,
@SerializedName("text/html")
HTML,
@SerializedName("text/markdown")
MARKDOWN,
@SerializedName("text/bbcode")
BBCODE, // akkoma
@SerializedName("text/x.misskeymarkdown")
MISSKEY_MARKDOWN; // akkoma/*key
public static int getContentTypeRes(@Nullable ContentType contentType) {
return contentType == null ? R.id.content_type_null : switch(contentType) {
case PLAIN -> R.id.content_type_plain;
case HTML -> R.id.content_type_html;
case MARKDOWN -> R.id.content_type_markdown;
case BBCODE -> R.id.content_type_bbcode;
case MISSKEY_MARKDOWN -> R.id.content_type_misskey_markdown;
};
}
public static void adaptMenuToInstance(Menu m, Instance i) {
if (i.pleroma == null) {
// memo: change this if glitch or another mastodon fork supports bbcode or mfm
m.findItem(R.id.content_type_bbcode).setVisible(false);
m.findItem(R.id.content_type_misskey_markdown).setVisible(false);
}
}
}

View File

@@ -2,23 +2,24 @@ package org.joinmastodon.android.model;
import android.text.TextUtils;
import androidx.annotation.Nullable;
import com.google.gson.annotations.SerializedName;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.parceler.Parcel;
import java.time.Instant;
import java.util.EnumSet;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Stream;
@Parcel
public class Filter extends BaseModel{
@RequiredField
public String id;
@RequiredField
public String phrase;
public String title;
public transient EnumSet<FilterContext> context=EnumSet.noneOf(FilterContext.class);
public Instant expiresAt;
public boolean irreversible;
@@ -50,6 +51,7 @@ public class Filter extends BaseModel{
else
pattern=Pattern.compile(Pattern.quote(phrase), Pattern.CASE_INSENSITIVE);
}
if (title == null) title = phrase;
return pattern.matcher(text).find();
}
@@ -61,6 +63,7 @@ public class Filter extends BaseModel{
public String toString(){
return "Filter{"+
"id='"+id+'\''+
", title='"+title+'\''+
", phrase='"+phrase+'\''+
", context="+context+
", expiresAt="+expiresAt+
@@ -77,7 +80,9 @@ public class Filter extends BaseModel{
@SerializedName("public")
PUBLIC,
@SerializedName("thread")
THREAD
THREAD,
@SerializedName("account")
ACCOUNT
}
public enum FilterAction{

View File

@@ -1,8 +1,15 @@
package org.joinmastodon.android.model;
import org.joinmastodon.android.api.ObjectValidationException;
import org.parceler.Parcel;
@Parcel
public class FilterResult extends BaseModel {
public Filter filter;
@Override
public void postprocess() throws ObjectValidationException {
super.postprocess();
if (filter != null) filter.postprocess();
}
}

View File

@@ -11,6 +11,7 @@ import java.net.IDN;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Parcel
public class Instance extends BaseModel{
@@ -45,7 +46,7 @@ public class Instance extends BaseModel{
@RequiredField
public String version;
/**
* Primary langauges of the website and its staff.
* Primary languages of the website and its staff.
*/
// @RequiredField
public List<String> languages;
@@ -86,6 +87,11 @@ public class Instance extends BaseModel{
public Pleroma pleroma;
public PleromaPollLimits pollLimits;
/** like uri, but always without scheme and trailing slash */
public transient String normalizedUri;
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();
@@ -95,6 +101,10 @@ public class Instance extends BaseModel{
rules=Collections.emptyList();
if(shortDescription==null)
shortDescription="";
// akkoma says uri is "https://example.social" while just "example.social" on mastodon
normalizedUri = uri
.replaceFirst("^https://", "")
.replaceFirst("/$", "");
}
@Override
@@ -121,7 +131,7 @@ public class Instance extends BaseModel{
ci.domain=uri;
ci.normalizedDomain=IDN.toUnicode(uri);
ci.description=Html.fromHtml(shortDescription).toString().trim();
if(languages!=null){
if(languages!=null && languages.size() > 0){
ci.language=languages.get(0);
ci.languages=languages;
}else{
@@ -134,6 +144,30 @@ public class Instance extends BaseModel{
return ci;
}
public boolean isAkkoma() {
return pleroma != null;
}
public boolean isPixelfed() {
return version.contains("compatible; Pixelfed");
}
public boolean hasFeature(Feature feature) {
Optional<List<String>> pleromaFeatures = Optional.ofNullable(pleroma)
.map(p -> p.metadata)
.map(m -> m.features);
return switch (feature) {
case BUBBLE_TIMELINE -> pleromaFeatures
.map(f -> f.contains("bubble_timeline"))
.orElse(false);
};
}
public enum Feature {
BUBBLE_TIMELINE
}
@Parcel
public static class Rule{
public String id;
@@ -198,6 +232,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<String> 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;
}
}

View File

@@ -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
}
}

View File

@@ -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 +
'}';
}
}

View File

@@ -20,6 +20,8 @@ public class Notification extends BaseModel implements DisplayItemsParent{
public Account account;
public Status status;
public Report report;
public String emoji;
public String emojiUrl;
@Override
public void postprocess() throws ObjectValidationException{
@@ -51,6 +53,10 @@ public class Notification extends BaseModel implements DisplayItemsParent{
STATUS,
@SerializedName("update")
UPDATE,
@SerializedName("reaction")
REACTION,
@SerializedName("pleroma:emoji_reaction")
PLEROMA_EMOJI_REACTION,
@SerializedName("admin.sign_up")
SIGN_UP,
@SerializedName("admin.report")

View File

@@ -0,0 +1,9 @@
package org.joinmastodon.android.model;
public enum NotificationAction {
FAVORITE,
REBLOG,
UNDO_REBLOG,
BOOKMARK,
REPLY,
}

View File

@@ -0,0 +1,33 @@
package org.joinmastodon.android.model;
import android.text.SpannableStringBuilder;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.joinmastodon.android.ui.utils.CustomEmojiHelper;
import java.util.Collections;
import me.grishka.appkit.imageloader.requests.ImageLoaderRequest;
import me.grishka.appkit.imageloader.requests.UrlImageLoaderRequest;
import me.grishka.appkit.utils.V;
public class ParsedAccount{
public Account account;
public CharSequence parsedName, parsedBio;
public CustomEmojiHelper emojiHelper;
public ImageLoaderRequest avatarRequest;
public ParsedAccount(Account account, String accountID){
this.account=account;
parsedName=HtmlParser.parseCustomEmoji(account.displayName, account.emojis);
parsedBio=HtmlParser.parse(account.note, account.emojis, Collections.emptyList(), Collections.emptyList(), accountID);
emojiHelper=new CustomEmojiHelper();
SpannableStringBuilder ssb=new SpannableStringBuilder(parsedName);
ssb.append(parsedBio);
emojiHelper.setText(ssb);
avatarRequest=new UrlImageLoaderRequest(GlobalUserPreferences.playGifs ? account.avatar : account.avatarStatic, V.dp(40), V.dp(40));
}
}

View File

@@ -16,12 +16,13 @@ public class Poll extends BaseModel{
private boolean expired;
public boolean multiple;
public int votersCount;
public int votesCount;
public boolean voted;
@RequiredField
// @RequiredField
public List<Integer> ownVotes;
@RequiredField
public List<Option> options;
@RequiredField
// @RequiredField
public List<Emoji> emojis;
public transient ArrayList<Option> selectedOptions;
@@ -29,6 +30,8 @@ public class Poll extends BaseModel{
@Override
public void postprocess() throws ObjectValidationException{
super.postprocess();
if (emojis == null) emojis = List.of();
if (ownVotes == null) ownVotes = List.of();
for(Emoji e:emojis)
e.postprocess();
}
@@ -41,10 +44,12 @@ public class Poll extends BaseModel{
", expired="+expired+
", multiple="+multiple+
", votersCount="+votersCount+
", votesCount="+votesCount+
", voted="+voted+
", ownVotes="+ownVotes+
", options="+options+
", emojis="+emojis+
", selectedOptions="+selectedOptions+
'}';
}

View File

@@ -30,10 +30,7 @@ public class PushSubscription extends BaseModel implements Cloneable{
@NonNull
@Override
public PushSubscription clone(){
PushSubscription copy=null;
try{
copy=(PushSubscription) super.clone();
}catch(CloneNotSupportedException ignore){}
PushSubscription copy=(PushSubscription) super.clone();
copy.alerts=alerts.clone();
return copy;
}

View File

@@ -18,6 +18,10 @@ public class Relationship extends BaseModel{
public boolean blockedBy;
public String note;
public boolean canFollow(){
return !(following || blocking || blockedBy || domainBlocking);
}
@Override
public String toString(){
return "Relationship{"+

View File

@@ -1,5 +1,6 @@
package org.joinmastodon.android.model;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
import org.joinmastodon.android.model.Poll.Option;
import org.parceler.Parcel;
@@ -16,7 +17,6 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
public Instant scheduledAt;
@RequiredField
public Params params;
@RequiredField
public List<Attachment> mediaAttachments;
@Override
@@ -24,8 +24,17 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
return id;
}
@Override
public void postprocess() throws ObjectValidationException {
super.postprocess();
if (mediaAttachments == null) mediaAttachments = List.of();
for(Attachment a:mediaAttachments)
a.postprocess();
if (params != null) params.postprocess();
}
@Parcel
public static class Params {
public static class Params extends BaseModel {
@RequiredField
public String text;
public String spoilerText;
@@ -39,10 +48,17 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
public String idempotency;
public String applicationId;
public List<String> mediaIds;
public ContentType contentType;
@Override
public void postprocess() throws ObjectValidationException {
super.postprocess();
if (poll != null) poll.postprocess();
}
}
@Parcel
public static class ScheduledPoll {
public static class ScheduledPoll extends BaseModel {
@RequiredField
public String expiresIn;
@RequiredField
@@ -62,19 +78,13 @@ public class ScheduledStatus extends BaseModel implements DisplayItemsParent{
}
public Status toStatus() {
Status s = new Status();
s.id = id;
Status s = Status.ofFake(id, params.text, scheduledAt);
s.mediaAttachments = mediaAttachments;
s.createdAt = scheduledAt;
s.inReplyToId = params.inReplyToId > 0 ? "" + params.inReplyToId : null;
s.content = s.text = params.text;
s.spoilerText = params.spoilerText;
s.visibility = params.visibility;
s.language = params.language;
s.sensitive = params.sensitive;
s.mentions = List.of();
s.tags = List.of();
s.emojis = List.of();
if (params.poll != null) s.poll = params.poll.toPoll();
return s;
}

View File

@@ -0,0 +1,5 @@
package org.joinmastodon.android.model;
public interface Searchable {
String getQuery();
}

View File

@@ -1,5 +1,14 @@
package org.joinmastodon.android.model;
import static org.joinmastodon.android.api.MastodonAPIController.gson;
import static org.joinmastodon.android.api.MastodonAPIController.gsonWithoutDeserializer;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import org.joinmastodon.android.GlobalUserPreferences;
import org.joinmastodon.android.api.ObjectValidationException;
import org.joinmastodon.android.api.RequiredField;
@@ -8,16 +17,19 @@ import org.joinmastodon.android.events.StatusCountersUpdatedEvent;
import org.joinmastodon.android.ui.text.HtmlParser;
import org.parceler.Parcel;
import java.lang.reflect.Type;
import java.time.Instant;
import java.util.List;
import androidx.annotation.NonNull;
@Parcel
public class Status extends BaseModel implements DisplayItemsParent{
public class Status extends BaseModel implements DisplayItemsParent, Searchable{
@RequiredField
public String id;
@RequiredField
public String uri;
@RequiredField
// @RequiredField // sometimes null on calckey
public Instant createdAt;
@RequiredField
public Account account;
@@ -28,7 +40,6 @@ public class Status extends BaseModel implements DisplayItemsParent{
public boolean sensitive;
@RequiredField
public String spoilerText;
@RequiredField
public List<Attachment> mediaAttachments;
public Application application;
@RequiredField
@@ -41,6 +52,8 @@ public class Status extends BaseModel implements DisplayItemsParent{
public long favouritesCount;
public long repliesCount;
public Instant editedAt;
// might not be provided (by older mastodon servers),
// so megalodon will use the locally cached filters if filtered == null
public List<FilterResult> filtered;
public String url;
@@ -59,12 +72,21 @@ public class Status extends BaseModel implements DisplayItemsParent{
public boolean bookmarked;
public boolean pinned;
public Status quote; // can be boolean in calckey
public transient boolean filterRevealed;
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
public void postprocess() throws ObjectValidationException{
if(spoilerText!=null && !spoilerText.isEmpty() && !sensitive)
sensitive=true;
super.postprocess();
if(application!=null)
application.postprocess();
@@ -74,6 +96,7 @@ public class Status extends BaseModel implements DisplayItemsParent{
t.postprocess();
for(Emoji e:emojis)
e.postprocess();
if (mediaAttachments == null) mediaAttachments = List.of();
for(Attachment a:mediaAttachments)
a.postprocess();
account.postprocess();
@@ -83,6 +106,9 @@ public class Status extends BaseModel implements DisplayItemsParent{
card.postprocess();
if(reblog!=null)
reblog.postprocess();
if(filtered!=null)
for(FilterResult fr : filtered)
fr.postprocess();
spoilerRevealed=GlobalUserPreferences.alwaysExpandContentWarnings || !sensitive;
if (visibility.equals(StatusPrivacy.LOCAL)) localOnly = true;
@@ -166,4 +192,32 @@ public class Status extends BaseModel implements DisplayItemsParent{
s.emojis = List.of();
return s;
}
@Override
public String getQuery() {
return url;
}
public static class StatusDeserializer implements JsonDeserializer<Status> {
@Override
public Status deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject obj = json.getAsJsonObject();
Status quote = null;
if (obj.has("quote") && obj.get("quote").isJsonObject())
quote = gson.fromJson(obj.get("quote"), Status.class);
obj.remove("quote");
Status reblog = null;
if (obj.has("reblog"))
reblog = gson.fromJson(obj.get("reblog"), Status.class);
obj.remove("reblog");
Status status = gsonWithoutDeserializer.fromJson(json, Status.class);
status.quote = quote;
status.reblog = reblog;
return status;
}
}
}

View File

@@ -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,50 @@ 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().map(Instance::isAkkoma).orElse(false);
}
public static final List<TimelineDefinition> 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<TimelineDefinition> ALL_TIMELINES = List.of(
HOME_TIMELINE.copy(),
LOCAL_TIMELINE.copy(),
FEDERATED_TIMELINE.copy(),
POSTS_TIMELINE.copy()
@Override
public boolean wantsDefault(AccountSession session) {
return session.getInstance()
.map(i -> i.hasFeature(Instance.Feature.BUBBLE_TIMELINE))
.orElse(false);
}
};
public static List<TimelineDefinition> 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<TimelineDefinition> 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<TimelineDefinition> DEFAULT_TIMELINES = List.of(
HOME_TIMELINE,
LOCAL_TIMELINE,
BUBBLE_TIMELINE,
FEDERATED_TIMELINE
);
private static final List<TimelineDefinition> ALL_TIMELINES = List.of(
HOME_TIMELINE,
LOCAL_TIMELINE,
FEDERATED_TIMELINE,
POSTS_TIMELINE,
BUBBLE_TIMELINE
);
}