diff --git a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java index 33025b40..7fdf0744 100644 --- a/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java +++ b/app/src/main/java/app/fedilab/android/client/endpoints/MastodonTimelinesService.java @@ -55,7 +55,10 @@ public interface MastodonTimelinesService { @GET("trends/statuses") - Call> getStatusTrends(@Header("Authorization") String token); + Call> getStatusTrends( + @Header("Authorization") String token, + @Query("offset") String offset, + @Query("limit") Integer limit); @GET("trends/tags") diff --git a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java index dc0aad32..d5d8ebf1 100644 --- a/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java +++ b/app/src/main/java/app/fedilab/android/client/entities/app/Timeline.java @@ -379,7 +379,7 @@ public class Timeline { @SerializedName("TREND_MESSAGE") TREND_MESSAGE("TREND_MESSAGE"), @SerializedName("PUBLIC_TREND_MESSAGE") - PUBLIC_TREND_MESSAGE("PUBLIC_TREND_MESSAGE"), + TREND_MESSAGE_PUBLIC("TREND_MESSAGE_PUBLIC"), @SerializedName("STATUS_HISTORY") STATUS_HISTORY("STATUS_HISTORY"), @SerializedName("ACCOUNT_TIMELINE") @@ -394,6 +394,8 @@ public class Timeline { FAVOURITE_TIMELINE("FAVOURITE_TIMELINE"), @SerializedName("REBLOG_TIMELINE") REBLOG_TIMELINE("REBLOG_TIMELINE"), + @SerializedName("STATUS_REPORT") + STATUS_REPORT("STATUS_REPORT"), @SerializedName("SCHEDULED_TOOT_SERVER") SCHEDULED_TOOT_SERVER("SCHEDULED_TOOT_SERVER"), @SerializedName("SCHEDULED_TOOT_CLIENT") diff --git a/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java b/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java index bc413bc5..a769e91f 100644 --- a/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java +++ b/app/src/main/java/app/fedilab/android/helper/MastodonHelper.java @@ -147,6 +147,26 @@ public class MastodonHelper { return pagination; } + + /** + * Retrieve pagination from header + * + * @param headers Headers + * @return Pagination + */ + public static Pagination getOffSetPagination(Headers headers) { + String link = headers.get("Link"); + Pagination pagination = new Pagination(); + if (link != null) { + Pattern patternMaxId = Pattern.compile("offset=([0-9a-zA-Z]+)\\s?>\\s?;\\s?rel=\"next\""); + Matcher matcherMaxId = patternMaxId.matcher(link); + if (matcherMaxId.find()) { + pagination.max_id = matcherMaxId.group(1); + } + } + return pagination; + } + /*public static Pagination getPaginationNotification(List notificationList) { Pagination pagination = new Pagination(); if (notificationList == null || notificationList.size() == 0) { diff --git a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java index 993656eb..fdb2a6d4 100644 --- a/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java +++ b/app/src/main/java/app/fedilab/android/ui/drawer/StatusAdapter.java @@ -641,7 +641,7 @@ public class StatusAdapter extends RecyclerView.Adapter } else { holder.binding.card.setVisibility(View.GONE); } - if (!canBeFederated) { + if (!canBeFederated && timelineType != Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC) { holder.binding.actionShareContainer.setVisibility(View.VISIBLE); holder.binding.actionShare.setOnClickListener(v -> { Intent sendIntent = new Intent(Intent.ACTION_SEND); diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginPickInstanceMastodon.java b/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginPickInstanceMastodon.java index 8a4c7441..d756ce24 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginPickInstanceMastodon.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/login/FragmentLoginPickInstanceMastodon.java @@ -140,9 +140,8 @@ public class FragmentLoginPickInstanceMastodon extends Fragment implements Insta if (joinMastodonInstanceList != null) { JoinMastodonInstance clickedInstance = joinMastodonInstanceList.get(position); Bundle args = new Bundle(); - args.putBoolean(Helper.ARG_MINIFIED, true); args.putSerializable(Helper.ARG_REMOTE_INSTANCE_STRING, clickedInstance.domain); - args.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TREND_MESSAGE); + args.putSerializable(Helper.ARG_TIMELINE_TYPE, Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC); Helper.addFragment( getParentFragmentManager(), android.R.id.content, new FragmentMastodonTimeline(), diff --git a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java index 9fe8c6e2..8d3eebcb 100644 --- a/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java +++ b/app/src/main/java/app/fedilab/android/ui/fragment/timeline/FragmentMastodonTimeline.java @@ -299,6 +299,9 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. canBeFederated = false; } } + if (timelineType == Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC) { + canBeFederated = false; + } publicTrendsDomain = getArguments().getString(Helper.ARG_REMOTE_INSTANCE_STRING, null); isViewInitialized = getArguments().getBoolean(Helper.ARG_INITIALIZE_VIEW, true); tagTimeline = (TagTimeline) getArguments().getSerializable(Helper.ARG_TAG_TIMELINE); @@ -360,7 +363,6 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. binding.loadingNextElements.setVisibility(View.GONE); flagLoading = false; - if (timelineStatuses != null && fetched_statuses != null && fetched_statuses.statuses != null && fetched_statuses.statuses.size() > 0) { try { if (statusToUpdate != null) { @@ -407,7 +409,15 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } } //Update the timeline with new statuses - int insertedStatus = updateStatusListWith(fetched_statuses.statuses); + int insertedStatus; + if (timelineType != Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC && timelineType != Timeline.TimeLineEnum.TREND_MESSAGE) { + insertedStatus = updateStatusListWith(fetched_statuses.statuses); + } else { //Trends cannot be ordered by id + insertedStatus = fetched_statuses.statuses.size(); + int fromPosition = timelineStatuses.size(); + timelineStatuses.addAll(fetched_statuses.statuses); + statusAdapter.notifyItemRangeInserted(fromPosition, insertedStatus); + } //For these directions, the app will display counters for new messages if (insertedStatus >= 0 && update != null && direction != DIRECTION.FETCH_NEW && !fetchingMissing) { update.onUpdate(insertedStatus, timelineType, slug); @@ -420,7 +430,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. if (!fetchingMissing) { if (fetched_statuses.pagination.max_id == null) { flagLoading = true; - } else if (max_id == null || Helper.compareTo(fetched_statuses.pagination.max_id, max_id) < 0) { + } else if (max_id == null || Helper.compareTo(fetched_statuses.pagination.max_id, max_id) < 0 || timelineType.getValue().startsWith("TREND_")) { max_id = fetched_statuses.pagination.max_id; } if (min_id == null || (fetched_statuses.pagination.min_id != null && Helper.compareTo(fetched_statuses.pagination.min_id, min_id) > 0)) { @@ -501,7 +511,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. timelineStatuses.add(statusReport); } timelineStatuses.addAll(statuses.statuses); - if (max_id == null || (statuses.pagination.max_id != null && Helper.compareTo(statuses.pagination.max_id, max_id) < 0)) { + if (max_id == null || (statuses.pagination.max_id != null && Helper.compareTo(statuses.pagination.max_id, max_id) < 0) || timelineType.getValue().startsWith("TREND_")) { max_id = statuses.pagination.max_id; } if (min_id == null || (statuses.pagination.min_id != null && Helper.compareTo(statuses.pagination.min_id, min_id) > 0)) { @@ -977,29 +987,23 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter. } } else if (timelineType == Timeline.TimeLineEnum.TREND_MESSAGE) { if (direction == null) { - timelinesVM.getStatusTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance) - .observe(getViewLifecycleOwner(), statusesTrends -> { - Statuses statuses = new Statuses(); - statuses.statuses = new ArrayList<>(); - if (statusesTrends != null) { - statuses.statuses.addAll(statusesTrends); - } - statuses.pagination = new Pagination(); - initializeStatusesCommonView(statuses); - }); + timelinesVM.getStatusTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, null, MastodonHelper.statusesPerCall(requireActivity())) + .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView); + } else if (direction == DIRECTION.BOTTOM) { + timelinesVM.getStatusTrends(BaseMainActivity.currentToken, BaseMainActivity.currentInstance, max_id, MastodonHelper.statusesPerCall(requireActivity())) + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); + } else { + flagLoading = false; } - } else if (timelineType == Timeline.TimeLineEnum.PUBLIC_TREND_MESSAGE) { + } else if (timelineType == Timeline.TimeLineEnum.TREND_MESSAGE_PUBLIC) { if (direction == null) { - timelinesVM.getStatusTrends(null, publicTrendsDomain) - .observe(getViewLifecycleOwner(), statusesTrends -> { - Statuses statuses = new Statuses(); - statuses.statuses = new ArrayList<>(); - if (statusesTrends != null) { - statuses.statuses.addAll(statusesTrends); - } - statuses.pagination = new Pagination(); - initializeStatusesCommonView(statuses); - }); + timelinesVM.getStatusTrends(null, publicTrendsDomain, null, MastodonHelper.statusesPerCall(requireActivity())) + .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView); + } else if (direction == DIRECTION.BOTTOM) { + timelinesVM.getStatusTrends(null, publicTrendsDomain, max_id, MastodonHelper.statusesPerCall(requireActivity())) + .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false)); + } else { + flagLoading = false; } } diff --git a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java index 01a2fcab..124bb8ec 100644 --- a/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java +++ b/app/src/main/java/app/fedilab/android/viewmodel/mastodon/TimelinesVM.java @@ -160,28 +160,29 @@ public class TimelinesVM extends AndroidViewModel { return retrofit.create(MastodonTimelinesService.class); } - public LiveData> getStatusTrends(String token, @NonNull String instance) { + public LiveData getStatusTrends(String token, @NonNull String instance, String max_id, Integer limit) { MastodonTimelinesService mastodonTimelinesService = init(instance); - statusListMutableLiveData = new MutableLiveData<>(); + statusesMutableLiveData = new MutableLiveData<>(); new Thread(() -> { - Call> publicTlCall = mastodonTimelinesService.getStatusTrends(token); - List statusList = null; + Call> publicTlCall = mastodonTimelinesService.getStatusTrends(token, max_id, limit); + Statuses statuses = new Statuses(); if (publicTlCall != null) { try { Response> publicTlResponse = publicTlCall.execute(); if (publicTlResponse.isSuccessful()) { - statusList = publicTlResponse.body(); + List statusList = publicTlResponse.body(); + statuses.statuses = TimelineHelper.filterStatus(getApplication().getApplicationContext(), statusList, Timeline.TimeLineEnum.TREND_MESSAGE); + statuses.pagination = MastodonHelper.getOffSetPagination(publicTlResponse.headers()); } } catch (Exception e) { e.printStackTrace(); } } Handler mainHandler = new Handler(Looper.getMainLooper()); - List finalStatusList = statusList; - Runnable myRunnable = () -> statusListMutableLiveData.setValue(finalStatusList); + Runnable myRunnable = () -> statusesMutableLiveData.setValue(statuses); mainHandler.post(myRunnable); }).start(); - return statusListMutableLiveData; + return statusesMutableLiveData; } public LiveData> getTagsTrends(String token, @NonNull String instance) { diff --git a/app/src/main/res/layout/drawer_instance_reg.xml b/app/src/main/res/layout/drawer_instance_reg.xml index 2d508e28..44e53624 100644 --- a/app/src/main/res/layout/drawer_instance_reg.xml +++ b/app/src/main/res/layout/drawer_instance_reg.xml @@ -91,6 +91,7 @@ android:text="@string/watch_trends_for_instance" android:textColor="@color/cyanea_accent_dark_reference" app:icon="@drawable/ic_baseline_remove_red_eye_24" + app:iconTint="@color/cyanea_accent_dark_reference" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="@+id/instance_description" app:strokeColor="@color/cyanea_accent_dark_reference" />