Add Bubble timeline support

This commit is contained in:
Thomas 2022-12-31 18:12:31 +01:00
parent 818f32ffb5
commit f976b6dd72
8 changed files with 84 additions and 60 deletions

View file

@ -53,6 +53,19 @@ public interface MastodonTimelinesService {
@Query("limit") Integer limit
);
@GET("timelines/bubble")
Call<List<Status>> getBubble(
@Header("Authorization") String token,
@Query("only_media") Boolean only_media,
@Query("remote") Boolean remote,
@Query("with_muted") Boolean with_muted,
@Query("exclude_visibilities") List<String> exclude_visibilities,
@Query("reply_visibility") String reply_visibility,
@Query("max_id") String max_id,
@Query("since_id") String since_id,
@Query("min_id") String min_id,
@Query("limit") Integer limit
);
@GET("trends/statuses")
Call<List<Status>> getStatusTrends(

View file

@ -364,6 +364,8 @@ public class Timeline {
LOCAL("LOCAL"),
@SerializedName("PUBLIC")
PUBLIC("PUBLIC"),
@SerializedName("BUBBLE")
BUBBLE("BUBBLE"),
@SerializedName("CONTEXT")
CONTEXT("CONTEXT"),
@SerializedName("TAG")

View file

@ -22,7 +22,6 @@ import static app.fedilab.android.BaseMainActivity.show_replies;
import static app.fedilab.android.ui.pageadapter.FedilabPageAdapter.BOTTOM_TIMELINE_COUNT;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.text.Editable;
@ -57,6 +56,7 @@ import java.util.regex.Pattern;
import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.client.entities.api.MastodonList;
import app.fedilab.android.client.entities.app.BottomMenu;
import app.fedilab.android.client.entities.app.Pinned;
@ -94,59 +94,6 @@ public class PinnedTimelineHelper {
}
/**
* Returns the slug of the first loaded fragment
*
* @param context - Context
* @param pinned - {@link Pinned}
* @param bottomMenu - {@link BottomMenu}
* @return String - slug
*/
public static String firstTimelineSlug(Context context, Pinned pinned, BottomMenu bottomMenu) {
String slug = Timeline.TimeLineEnum.HOME.getValue();
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(context);
boolean singleBar = sharedpreferences.getBoolean(context.getString(R.string.SET_USE_SINGLE_TOPBAR), false);
PinnedTimeline pinnedTimelineMin = null;
if (singleBar) {
if (pinned != null && pinned.pinnedTimelines != null) {
for (PinnedTimeline pinnedTimeline : pinned.pinnedTimelines) {
if (pinnedTimeline.displayed) {
if (pinnedTimelineMin == null) {
pinnedTimelineMin = pinnedTimeline;
} else if (pinnedTimelineMin.position > pinnedTimeline.position) {
pinnedTimelineMin = pinnedTimeline;
}
}
}
}
} else {
if (bottomMenu != null && bottomMenu.bottom_menu != null && bottomMenu.bottom_menu.size() > 0) {
BottomMenu.MenuItem menuItem = bottomMenu.bottom_menu.get(0);
return menuItem.item_menu_type.getValue();
}
}
String ident = null;
if (pinnedTimelineMin != null) {
if (pinnedTimelineMin.tagTimeline != null) {
ident = "@T@" + pinnedTimelineMin.tagTimeline.name;
if (pinnedTimelineMin.tagTimeline.isART) {
pinnedTimelineMin.type = Timeline.TimeLineEnum.ART;
}
} else if (pinnedTimelineMin.mastodonList != null) {
ident = "@l@" + pinnedTimelineMin.mastodonList.id;
} else if (pinnedTimelineMin.remoteInstance != null) {
if (pinnedTimelineMin.remoteInstance.type == RemoteInstance.InstanceType.NITTER) {
String remoteInstance = sharedpreferences.getString(context.getString(R.string.SET_NITTER_HOST), context.getString(R.string.DEFAULT_NITTER_HOST)).toLowerCase();
ident = "@R@" + remoteInstance;
} else {
ident = "@R@" + pinnedTimelineMin.remoteInstance.host;
}
}
slug = pinnedTimelineMin.type.getValue() + (ident != null ? "|" + ident : "");
}
return slug;
}
public synchronized static void redrawTopBarPinned(BaseMainActivity activity, ActivityMainBinding activityMainBinding, Pinned pinned, BottomMenu bottomMenu, List<MastodonList> mastodonLists) {
//Values must be initialized if there is no records in db
@ -159,8 +106,8 @@ public class PinnedTimelineHelper {
pinned.pinnedTimelines = new ArrayList<>();
}
//Set the slug of first visible fragment
String slugOfFirstFragment = PinnedTimelineHelper.firstTimelineSlug(activity, pinned, bottomMenu);
Helper.setSlugOfFirstFragment(activity, slugOfFirstFragment, currentUserID, currentInstance);
/*String slugOfFirstFragment = PinnedTimelineHelper.firstTimelineSlug(activity, pinned, bottomMenu);
Helper.setSlugOfFirstFragment(activity, slugOfFirstFragment, currentUserID, currentInstance);*/
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity);
boolean singleBar = sharedpreferences.getBoolean(activity.getString(R.string.SET_USE_SINGLE_TOPBAR), false);
@ -187,6 +134,7 @@ public class PinnedTimelineHelper {
activityMainBinding.viewPager.setLayoutParams(params);
List<PinnedTimeline> pinnedTimelines = pinned.pinnedTimelines;
boolean extraFeatures = sharedpreferences.getBoolean(activity.getString(R.string.SET_EXTAND_EXTRA_FEATURES) + MainActivity.currentUserID + MainActivity.currentInstance, false);
if (singleBar) {
boolean createDefaultAtTop = true;
@ -222,15 +170,40 @@ public class PinnedTimelineHelper {
pinnedTimelineConversations.type = Timeline.TimeLineEnum.DIRECT;
pinnedTimelineConversations.position = 4;
pinned.pinnedTimelines.add(pinnedTimelineConversations);
try {
new Pinned(activity).updatePinned(pinned);
} catch (DBException e) {
e.printStackTrace();
}
}
}
if (extraFeatures) {
try {
Pinned pinnedAll = new Pinned(activity).getAllPinned(currentAccount);
boolean createDefaultBubbleAtTop = true;
for (PinnedTimeline pinnedTimeline : pinnedAll.pinnedTimelines) {
if (pinnedTimeline.type == Timeline.TimeLineEnum.BUBBLE) {
createDefaultBubbleAtTop = false;
break;
}
}
if (createDefaultBubbleAtTop) {
PinnedTimeline pinnedTimelineBubble = new PinnedTimeline();
pinnedTimelineBubble.type = Timeline.TimeLineEnum.BUBBLE;
pinnedTimelineBubble.position = pinnedAll.pinnedTimelines != null ? pinnedAll.pinnedTimelines.size() : 0;
pinned.pinnedTimelines.add(pinnedTimelineBubble);
boolean exist = new Pinned(activity).pinnedExist(pinned);
if (exist) {
new Pinned(activity).updatePinned(pinned);
} else {
new Pinned(activity).insertPinned(pinned);
}
}
} catch (DBException e) {
e.printStackTrace();
}
}
sortPositionAsc(pinnedTimelines);
//Check if changes occurred, if mastodonLists is null it does need, because it is the first call to draw pinned
boolean needRedraw = mastodonLists == null;
@ -421,6 +394,9 @@ public class PinnedTimelineHelper {
case DIRECT:
tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.ic_baseline_mail_24);
break;
case BUBBLE:
tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.ic_baseline_bubble_chart_24);
break;
}
tab.setCustomView(tabCustomDefaultViewBinding.getRoot());
}

View file

@ -141,6 +141,10 @@ public class ReorderTabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
holder.binding.icon.setImageResource(R.drawable.ic_baseline_mail_24);
holder.binding.text.setText(R.string.v_direct);
break;
case BUBBLE:
holder.binding.icon.setImageResource(R.drawable.ic_baseline_bubble_chart_24);
holder.binding.text.setText(R.string.bubble);
break;
}

View file

@ -16,7 +16,6 @@ package app.fedilab.android.ui.fragment.timeline;
import static app.fedilab.android.BaseMainActivity.currentInstance;
import static app.fedilab.android.BaseMainActivity.currentUserID;
import static app.fedilab.android.BaseMainActivity.networkAvailable;
import android.content.BroadcastReceiver;
@ -342,6 +341,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
minified = getArguments().getBoolean(Helper.ARG_MINIFIED, false);
statusReport = (Status) getArguments().getSerializable(Helper.ARG_STATUS_REPORT);
}
//When visiting a profile without being authenticated
if (checkRemotely) {
String[] acctArray = accountTimeline.acct.split("@");
@ -619,7 +619,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
}
});
//For first tab we fetch new messages, if we keep position
if (slug != null && slug.compareTo(Helper.getSlugOfFirstFragment(requireActivity(), currentUserID, currentInstance)) == 0 && rememberPosition) {
if (slug != null /*&& slug.compareTo(Helper.getSlugOfFirstFragment(requireActivity(), currentUserID, currentInstance)) == 0*/ && rememberPosition) {
route(DIRECTION.FETCH_NEW, true);
}
}
@ -712,6 +712,10 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
timelineParams.local = false;
timelineParams.remote = true;
break;
case BUBBLE:
timelineParams.onlyMedia = false;
timelineParams.remote = false;
break;
case LIST:
timelineParams.listId = list_id;
break;
@ -898,6 +902,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
routeCommon(direction, fetchingMissing, statusToUpdate);
} else if (timelineType == Timeline.TimeLineEnum.PUBLIC) { //PUBLIC TIMELINE
routeCommon(direction, fetchingMissing, statusToUpdate);
} else if (timelineType == Timeline.TimeLineEnum.BUBBLE) { //BUBBLE TIMELINE
routeCommon(direction, fetchingMissing, statusToUpdate);
} else if (timelineType == Timeline.TimeLineEnum.REMOTE) { //REMOTE TIMELINE
//NITTER TIMELINES
if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) {

View file

@ -417,6 +417,9 @@ public class TimelinesVM extends AndroidViewModel {
case PUBLIC:
timelineCall = mastodonTimelinesService.getPublic(timelineParams.token, false, true, timelineParams.onlyMedia, timelineParams.maxId, timelineParams.sinceId, timelineParams.minId, timelineParams.limit);
break;
case BUBBLE:
timelineCall = mastodonTimelinesService.getBubble(timelineParams.token, timelineParams.onlyMedia, timelineParams.remote, timelineParams.withMuted, timelineParams.excludeVisibilities, timelineParams.replyVisibility, timelineParams.maxId, timelineParams.sinceId, timelineParams.minId, timelineParams.limit);
break;
case ART:
case TAG:
timelineCall = mastodonTimelinesService.getHashTag(timelineParams.token, timelineParams.hashtagTrim, timelineParams.local, timelineParams.onlyMedia, timelineParams.all, timelineParams.any, timelineParams.none, timelineParams.maxId, timelineParams.sinceId, timelineParams.minId, timelineParams.limit);
@ -949,6 +952,7 @@ public class TimelinesVM extends AndroidViewModel {
public String userId;
public Boolean remote;
public Boolean onlyMedia;
public Boolean withMuted;
public String hashtagTrim;
public List<String> all;
public List<String> any;
@ -961,6 +965,8 @@ public class TimelinesVM extends AndroidViewModel {
public int limit = 40;
public Boolean local;
public List<String> excludeType;
public List<String> excludeVisibilities;
public String replyVisibility;
public TimelineParams(@NonNull Timeline.TimeLineEnum timeLineEnum, @Nullable FragmentMastodonTimeline.DIRECTION timelineDirection, @Nullable String ident) {
if (type != Timeline.TimeLineEnum.REMOTE) {

View file

@ -0,0 +1,16 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="#FFFFFF"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M7.2,14.4m-3.2,0a3.2,3.2 0,1 1,6.4 0a3.2,3.2 0,1 1,-6.4 0" />
<path
android:fillColor="@android:color/white"
android:pathData="M14.8,18m-2,0a2,2 0,1 1,4 0a2,2 0,1 1,-4 0" />
<path
android:fillColor="@android:color/white"
android:pathData="M15.2,8.8m-4.8,0a4.8,4.8 0,1 1,9.6 0a4.8,4.8 0,1 1,-9.6 0" />
</vector>

View file

@ -2174,4 +2174,5 @@
<string name="icons_extra_features_visibility_summary">If your instance does not accept some extra features, you can hide these icons</string>
<string name="set_display_quote_indication">Display the \"Quote\" button</string>
<string name="set_display_reaction_indication">Display \"Reactions\" buttons</string>
<string name="bubble">Bubble</string>
</resources>