forked from mirrors/Fedilab
Add Bubble timeline support
This commit is contained in:
parent
818f32ffb5
commit
f976b6dd72
8 changed files with 84 additions and 60 deletions
|
@ -53,6 +53,19 @@ public interface MastodonTimelinesService {
|
||||||
@Query("limit") Integer limit
|
@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")
|
@GET("trends/statuses")
|
||||||
Call<List<Status>> getStatusTrends(
|
Call<List<Status>> getStatusTrends(
|
||||||
|
|
|
@ -364,6 +364,8 @@ public class Timeline {
|
||||||
LOCAL("LOCAL"),
|
LOCAL("LOCAL"),
|
||||||
@SerializedName("PUBLIC")
|
@SerializedName("PUBLIC")
|
||||||
PUBLIC("PUBLIC"),
|
PUBLIC("PUBLIC"),
|
||||||
|
@SerializedName("BUBBLE")
|
||||||
|
BUBBLE("BUBBLE"),
|
||||||
@SerializedName("CONTEXT")
|
@SerializedName("CONTEXT")
|
||||||
CONTEXT("CONTEXT"),
|
CONTEXT("CONTEXT"),
|
||||||
@SerializedName("TAG")
|
@SerializedName("TAG")
|
||||||
|
|
|
@ -22,7 +22,6 @@ import static app.fedilab.android.BaseMainActivity.show_replies;
|
||||||
import static app.fedilab.android.ui.pageadapter.FedilabPageAdapter.BOTTOM_TIMELINE_COUNT;
|
import static app.fedilab.android.ui.pageadapter.FedilabPageAdapter.BOTTOM_TIMELINE_COUNT;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
|
@ -57,6 +56,7 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
import app.fedilab.android.BaseMainActivity;
|
import app.fedilab.android.BaseMainActivity;
|
||||||
import app.fedilab.android.R;
|
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.api.MastodonList;
|
||||||
import app.fedilab.android.client.entities.app.BottomMenu;
|
import app.fedilab.android.client.entities.app.BottomMenu;
|
||||||
import app.fedilab.android.client.entities.app.Pinned;
|
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) {
|
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
|
//Values must be initialized if there is no records in db
|
||||||
|
@ -159,8 +106,8 @@ public class PinnedTimelineHelper {
|
||||||
pinned.pinnedTimelines = new ArrayList<>();
|
pinned.pinnedTimelines = new ArrayList<>();
|
||||||
}
|
}
|
||||||
//Set the slug of first visible fragment
|
//Set the slug of first visible fragment
|
||||||
String slugOfFirstFragment = PinnedTimelineHelper.firstTimelineSlug(activity, pinned, bottomMenu);
|
/*String slugOfFirstFragment = PinnedTimelineHelper.firstTimelineSlug(activity, pinned, bottomMenu);
|
||||||
Helper.setSlugOfFirstFragment(activity, slugOfFirstFragment, currentUserID, currentInstance);
|
Helper.setSlugOfFirstFragment(activity, slugOfFirstFragment, currentUserID, currentInstance);*/
|
||||||
|
|
||||||
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
SharedPreferences sharedpreferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
boolean singleBar = sharedpreferences.getBoolean(activity.getString(R.string.SET_USE_SINGLE_TOPBAR), false);
|
boolean singleBar = sharedpreferences.getBoolean(activity.getString(R.string.SET_USE_SINGLE_TOPBAR), false);
|
||||||
|
@ -187,6 +134,7 @@ public class PinnedTimelineHelper {
|
||||||
|
|
||||||
activityMainBinding.viewPager.setLayoutParams(params);
|
activityMainBinding.viewPager.setLayoutParams(params);
|
||||||
List<PinnedTimeline> pinnedTimelines = pinned.pinnedTimelines;
|
List<PinnedTimeline> pinnedTimelines = pinned.pinnedTimelines;
|
||||||
|
boolean extraFeatures = sharedpreferences.getBoolean(activity.getString(R.string.SET_EXTAND_EXTRA_FEATURES) + MainActivity.currentUserID + MainActivity.currentInstance, false);
|
||||||
|
|
||||||
if (singleBar) {
|
if (singleBar) {
|
||||||
boolean createDefaultAtTop = true;
|
boolean createDefaultAtTop = true;
|
||||||
|
@ -222,15 +170,40 @@ public class PinnedTimelineHelper {
|
||||||
pinnedTimelineConversations.type = Timeline.TimeLineEnum.DIRECT;
|
pinnedTimelineConversations.type = Timeline.TimeLineEnum.DIRECT;
|
||||||
pinnedTimelineConversations.position = 4;
|
pinnedTimelineConversations.position = 4;
|
||||||
pinned.pinnedTimelines.add(pinnedTimelineConversations);
|
pinned.pinnedTimelines.add(pinnedTimelineConversations);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
new Pinned(activity).updatePinned(pinned);
|
new Pinned(activity).updatePinned(pinned);
|
||||||
} catch (DBException e) {
|
} catch (DBException e) {
|
||||||
e.printStackTrace();
|
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);
|
sortPositionAsc(pinnedTimelines);
|
||||||
//Check if changes occurred, if mastodonLists is null it does need, because it is the first call to draw pinned
|
//Check if changes occurred, if mastodonLists is null it does need, because it is the first call to draw pinned
|
||||||
boolean needRedraw = mastodonLists == null;
|
boolean needRedraw = mastodonLists == null;
|
||||||
|
@ -421,6 +394,9 @@ public class PinnedTimelineHelper {
|
||||||
case DIRECT:
|
case DIRECT:
|
||||||
tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.ic_baseline_mail_24);
|
tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.ic_baseline_mail_24);
|
||||||
break;
|
break;
|
||||||
|
case BUBBLE:
|
||||||
|
tabCustomDefaultViewBinding.icon.setImageResource(R.drawable.ic_baseline_bubble_chart_24);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
tab.setCustomView(tabCustomDefaultViewBinding.getRoot());
|
tab.setCustomView(tabCustomDefaultViewBinding.getRoot());
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,6 +141,10 @@ public class ReorderTabAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
|
||||||
holder.binding.icon.setImageResource(R.drawable.ic_baseline_mail_24);
|
holder.binding.icon.setImageResource(R.drawable.ic_baseline_mail_24);
|
||||||
holder.binding.text.setText(R.string.v_direct);
|
holder.binding.text.setText(R.string.v_direct);
|
||||||
break;
|
break;
|
||||||
|
case BUBBLE:
|
||||||
|
holder.binding.icon.setImageResource(R.drawable.ic_baseline_bubble_chart_24);
|
||||||
|
holder.binding.text.setText(R.string.bubble);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ package app.fedilab.android.ui.fragment.timeline;
|
||||||
|
|
||||||
|
|
||||||
import static app.fedilab.android.BaseMainActivity.currentInstance;
|
import static app.fedilab.android.BaseMainActivity.currentInstance;
|
||||||
import static app.fedilab.android.BaseMainActivity.currentUserID;
|
|
||||||
import static app.fedilab.android.BaseMainActivity.networkAvailable;
|
import static app.fedilab.android.BaseMainActivity.networkAvailable;
|
||||||
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
|
@ -342,6 +341,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
||||||
minified = getArguments().getBoolean(Helper.ARG_MINIFIED, false);
|
minified = getArguments().getBoolean(Helper.ARG_MINIFIED, false);
|
||||||
statusReport = (Status) getArguments().getSerializable(Helper.ARG_STATUS_REPORT);
|
statusReport = (Status) getArguments().getSerializable(Helper.ARG_STATUS_REPORT);
|
||||||
}
|
}
|
||||||
|
|
||||||
//When visiting a profile without being authenticated
|
//When visiting a profile without being authenticated
|
||||||
if (checkRemotely) {
|
if (checkRemotely) {
|
||||||
String[] acctArray = accountTimeline.acct.split("@");
|
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
|
//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);
|
route(DIRECTION.FETCH_NEW, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -712,6 +712,10 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
||||||
timelineParams.local = false;
|
timelineParams.local = false;
|
||||||
timelineParams.remote = true;
|
timelineParams.remote = true;
|
||||||
break;
|
break;
|
||||||
|
case BUBBLE:
|
||||||
|
timelineParams.onlyMedia = false;
|
||||||
|
timelineParams.remote = false;
|
||||||
|
break;
|
||||||
case LIST:
|
case LIST:
|
||||||
timelineParams.listId = list_id;
|
timelineParams.listId = list_id;
|
||||||
break;
|
break;
|
||||||
|
@ -898,6 +902,8 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
|
||||||
routeCommon(direction, fetchingMissing, statusToUpdate);
|
routeCommon(direction, fetchingMissing, statusToUpdate);
|
||||||
} else if (timelineType == Timeline.TimeLineEnum.PUBLIC) { //PUBLIC TIMELINE
|
} else if (timelineType == Timeline.TimeLineEnum.PUBLIC) { //PUBLIC TIMELINE
|
||||||
routeCommon(direction, fetchingMissing, statusToUpdate);
|
routeCommon(direction, fetchingMissing, statusToUpdate);
|
||||||
|
} else if (timelineType == Timeline.TimeLineEnum.BUBBLE) { //BUBBLE TIMELINE
|
||||||
|
routeCommon(direction, fetchingMissing, statusToUpdate);
|
||||||
} else if (timelineType == Timeline.TimeLineEnum.REMOTE) { //REMOTE TIMELINE
|
} else if (timelineType == Timeline.TimeLineEnum.REMOTE) { //REMOTE TIMELINE
|
||||||
//NITTER TIMELINES
|
//NITTER TIMELINES
|
||||||
if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) {
|
if (pinnedTimeline != null && pinnedTimeline.remoteInstance.type == RemoteInstance.InstanceType.NITTER) {
|
||||||
|
|
|
@ -417,6 +417,9 @@ public class TimelinesVM extends AndroidViewModel {
|
||||||
case PUBLIC:
|
case PUBLIC:
|
||||||
timelineCall = mastodonTimelinesService.getPublic(timelineParams.token, false, true, timelineParams.onlyMedia, timelineParams.maxId, timelineParams.sinceId, timelineParams.minId, timelineParams.limit);
|
timelineCall = mastodonTimelinesService.getPublic(timelineParams.token, false, true, timelineParams.onlyMedia, timelineParams.maxId, timelineParams.sinceId, timelineParams.minId, timelineParams.limit);
|
||||||
break;
|
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 ART:
|
||||||
case TAG:
|
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);
|
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 String userId;
|
||||||
public Boolean remote;
|
public Boolean remote;
|
||||||
public Boolean onlyMedia;
|
public Boolean onlyMedia;
|
||||||
|
public Boolean withMuted;
|
||||||
public String hashtagTrim;
|
public String hashtagTrim;
|
||||||
public List<String> all;
|
public List<String> all;
|
||||||
public List<String> any;
|
public List<String> any;
|
||||||
|
@ -961,6 +965,8 @@ public class TimelinesVM extends AndroidViewModel {
|
||||||
public int limit = 40;
|
public int limit = 40;
|
||||||
public Boolean local;
|
public Boolean local;
|
||||||
public List<String> excludeType;
|
public List<String> excludeType;
|
||||||
|
public List<String> excludeVisibilities;
|
||||||
|
public String replyVisibility;
|
||||||
|
|
||||||
public TimelineParams(@NonNull Timeline.TimeLineEnum timeLineEnum, @Nullable FragmentMastodonTimeline.DIRECTION timelineDirection, @Nullable String ident) {
|
public TimelineParams(@NonNull Timeline.TimeLineEnum timeLineEnum, @Nullable FragmentMastodonTimeline.DIRECTION timelineDirection, @Nullable String ident) {
|
||||||
if (type != Timeline.TimeLineEnum.REMOTE) {
|
if (type != Timeline.TimeLineEnum.REMOTE) {
|
||||||
|
|
16
app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml
Normal file
16
app/src/main/res/drawable/ic_baseline_bubble_chart_24.xml
Normal 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>
|
|
@ -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="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_quote_indication">Display the \"Quote\" button</string>
|
||||||
<string name="set_display_reaction_indication">Display \"Reactions\" buttons</string>
|
<string name="set_display_reaction_indication">Display \"Reactions\" buttons</string>
|
||||||
|
<string name="bubble">Bubble</string>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue