Commit 1b886338 authored by Thomas's avatar Thomas
Browse files

Add fetching message

parent bc274451
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -114,6 +114,8 @@ public class Status implements Serializable, Cloneable {


    public transient boolean isFetchMore = false;
    public transient boolean isFetching = false;

    public transient PositionFetchMore positionFetchMore = PositionFetchMore.BOTTOM;

    public Attachment art_attachment;
+54 −20
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ import app.fedilab.android.BaseMainActivity;
import app.fedilab.android.R;
import app.fedilab.android.activities.MainActivity;
import app.fedilab.android.databinding.DrawerFetchMoreBinding;
import app.fedilab.android.databinding.DrawerMessageFetchingBinding;
import app.fedilab.android.databinding.DrawerStatusArtBinding;
import app.fedilab.android.databinding.DrawerStatusBinding;
import app.fedilab.android.databinding.DrawerStatusFilteredBinding;
@@ -1621,12 +1622,16 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                                videoSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
                                        .createMediaSource(mediaItem);
                            }
                            try {
                                ExoPlayer player = new ExoPlayer.Builder(context).build();
                                player.setRepeatMode(Player.REPEAT_MODE_ONE);
                                layoutMediaBinding.mediaVideo.setPlayer(player);
                                player.setMediaSource(videoSource);
                                player.prepare();
                                player.setPlayWhenReady(true);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }

                            int finalMediaPosition = mediaPosition;
                            layoutMediaBinding.mediaVideo.setOnClickListener(v -> {
@@ -1686,12 +1691,16 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                                videoSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
                                        .createMediaSource(mediaItem);
                            }
                            try {
                                ExoPlayer player = new ExoPlayer.Builder(context).build();
                                player.setRepeatMode(Player.REPEAT_MODE_ONE);
                                layoutMediaBinding.mediaVideo.setPlayer(player);
                                player.setMediaSource(videoSource);
                                player.prepare();
                                player.setPlayWhenReady(true);
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                            int finalMediaPosition = mediaPosition;
                            layoutMediaBinding.mediaVideo.setOnClickListener(v -> {
                                final int timeout = sharedpreferences.getInt(context.getString(R.string.SET_NSFW_TIMEOUT), 5);
@@ -2447,6 +2456,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                }
                drawerFetchMoreBinding.fetchMoreMin.setOnClickListener(v -> {
                    status.isFetchMore = false;
                    status.isFetching = true;
                    int position = holder.getBindingAdapterPosition();
                    adapter.notifyItemChanged(position);
                    if (position < statusList.size() - 1) {
@@ -2456,25 +2466,27 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                        } else {
                            fromId = status.id;
                        }
                        fetchMoreCallBack.onClickMinId(fromId);
                        fetchMoreCallBack.onClickMinId(fromId, status);
                    }
                });
                drawerFetchMoreBinding.fetchMoreMax.setOnClickListener(v -> {
                    //We hide the button
                    status.isFetchMore = false;
                    status.isFetching = true;
                    String fromId;
                    if (status.positionFetchMore == Status.PositionFetchMore.TOP || holder.getBindingAdapterPosition() == 0) {
                        fromId = statusList.get(holder.getBindingAdapterPosition()).id;
                    } else {
                        fromId = statusList.get(holder.getBindingAdapterPosition() - 1).id;
                    }
                    fetchMoreCallBack.onClickMaxId(fromId);
                    fetchMoreCallBack.onClickMaxId(fromId, status);
                    adapter.notifyItemChanged(holder.getBindingAdapterPosition());
                });
            } else {
                holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
                holder.binding.fetchMoreContainerTop.setVisibility(View.GONE);
                status.isFetchMore = false;
                status.isFetching = true;
                int position = holder.getBindingAdapterPosition();
                String statusIdMin = null, statusIdMax;
                if (position < statusList.size() - 1) {
@@ -2490,6 +2502,23 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                    statusIdMax = statusList.get(holder.getBindingAdapterPosition() - 1).id;
                }
                fetchMoreCallBack.autoFetch(statusIdMin, statusIdMax, status);
                adapter.notifyItemChanged(holder.getBindingAdapterPosition());
            }
        } else if (status.isFetching) {
            DrawerMessageFetchingBinding drawerMessageFetchingBinding = DrawerMessageFetchingBinding.inflate(LayoutInflater.from(context));
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
            drawerMessageFetchingBinding.fetchingContainer.setLayoutParams(lp);
            drawerMessageFetchingBinding.fetchingProgress.getIndeterminateDrawable().setColorFilter(ThemeHelper.getAttColor(context, R.attr.colorPrimary), PorterDuff.Mode.SRC_IN);
            if (status.positionFetchMore == Status.PositionFetchMore.BOTTOM) {
                holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
                holder.binding.fetchMoreContainerTop.setVisibility(View.VISIBLE);
                holder.binding.fetchMoreContainerTop.removeAllViews();
                holder.binding.fetchMoreContainerTop.addView(drawerMessageFetchingBinding.getRoot());
            } else {
                holder.binding.fetchMoreContainerBottom.setVisibility(View.VISIBLE);
                holder.binding.fetchMoreContainerTop.setVisibility(View.GONE);
                holder.binding.fetchMoreContainerBottom.removeAllViews();
                holder.binding.fetchMoreContainerBottom.addView(drawerMessageFetchingBinding.getRoot());
            }
        } else {
            holder.binding.fetchMoreContainerBottom.setVisibility(View.GONE);
@@ -2996,6 +3025,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                    holder.bindingFilteredHide.layoutFetchMore.fetchMoreContainer.setVisibility(View.VISIBLE);
                    holder.bindingFilteredHide.layoutFetchMore.fetchMoreMin.setOnClickListener(v -> {
                        status.isFetchMore = false;
                        status.isFetching = true;
                        notifyItemChanged(holder.getBindingAdapterPosition());
                        if (holder.getBindingAdapterPosition() < statusList.size() - 1) {
                            String fromId;
@@ -3004,12 +3034,13 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                            } else {
                                fromId = status.id;
                            }
                            fetchMoreCallBack.onClickMinId(fromId);
                            fetchMoreCallBack.onClickMinId(fromId, status);
                        }
                    });
                    holder.bindingFilteredHide.layoutFetchMore.fetchMoreMax.setOnClickListener(v -> {
                        //We hide the button
                        status.isFetchMore = false;
                        status.isFetching = true;
                        notifyItemChanged(holder.getBindingAdapterPosition());
                        String fromId;
                        if (status.positionFetchMore == Status.PositionFetchMore.TOP || holder.getBindingAdapterPosition() == 0) {
@@ -3017,11 +3048,12 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                        } else {
                            fromId = statusList.get(holder.getBindingAdapterPosition() - 1).id;
                        }
                        fetchMoreCallBack.onClickMaxId(fromId);
                        fetchMoreCallBack.onClickMaxId(fromId, status);

                    });
                } else {
                    status.isFetchMore = false;
                    status.isFetching = true;
                    String minId = null, maxId;
                    if (holder.getBindingAdapterPosition() < statusList.size() - 1) {
                        if (status.positionFetchMore == Status.PositionFetchMore.TOP) {
@@ -3053,6 +3085,7 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                holder.bindingFiltered.layoutFetchMore.fetchMoreContainer.setVisibility(View.VISIBLE);
                holder.bindingFiltered.layoutFetchMore.fetchMoreMin.setOnClickListener(v -> {
                    status.isFetchMore = false;
                    status.isFetching = true;
                    notifyItemChanged(holder.getBindingAdapterPosition());
                    if (holder.getBindingAdapterPosition() < statusList.size() - 1) {
                        String fromId;
@@ -3061,19 +3094,20 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>
                        } else {
                            fromId = status.id;
                        }
                        fetchMoreCallBack.onClickMinId(fromId);
                        fetchMoreCallBack.onClickMinId(fromId, status);
                    }
                });
                holder.bindingFiltered.layoutFetchMore.fetchMoreMax.setOnClickListener(v -> {
                    //We hide the button
                    status.isFetchMore = false;
                    status.isFetching = true;
                    String fromId;
                    if (status.positionFetchMore == Status.PositionFetchMore.TOP || holder.getBindingAdapterPosition() == 0) {
                        fromId = statusList.get(holder.getBindingAdapterPosition()).id;
                    } else {
                        fromId = statusList.get(holder.getBindingAdapterPosition() - 1).id;
                    }
                    fetchMoreCallBack.onClickMaxId(fromId);
                    fetchMoreCallBack.onClickMaxId(fromId, status);
                    notifyItemChanged(holder.getBindingAdapterPosition());
                });
            } else {
@@ -3194,9 +3228,9 @@ public class StatusAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>


    public interface FetchMoreCallBack {
        void onClickMinId(String min_id);
        void onClickMinId(String min_id, Status fetchStatus);

        void onClickMaxId(String max_id);
        void onClickMaxId(String max_id, Status fetchStatus);

        void autoFetch(String min_id, String max_id, Status status);
    }
+43 −20
Original line number Diff line number Diff line
@@ -434,10 +434,17 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
     *
     * @param fetched_statuses Statuses
     */
    private synchronized void dealWithPagination(Statuses fetched_statuses, DIRECTION direction, boolean fetchingMissing, boolean canScroll) {
    private synchronized void dealWithPagination(Statuses fetched_statuses, DIRECTION direction, boolean fetchingMissing, boolean canScroll, Status fetchStatus) {
        if (binding == null || !isAdded() || getActivity() == null) {
            return;
        }
        if (fetchStatus != null) {
            int position = getPosition(fetchStatus);
            if (position >= 0 && position < timelineStatuses.size()) {
                timelineStatuses.get(position).isFetching = false;
                statusAdapter.notifyItemChanged(position);
            }
        }
        binding.swipeContainer.setRefreshing(false);
        binding.loadingNextElements.setVisibility(View.GONE);
        flagLoading = false;
@@ -509,7 +516,15 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
        if (direction == DIRECTION.SCROLL_TOP) {
            new Handler().postDelayed(() -> binding.recyclerView.scrollToPosition(0), 200);
        }
    }

    /**
     * Update view and pagination when scrolling down
     *
     * @param fetched_statuses Statuses
     */
    private synchronized void dealWithPagination(Statuses fetched_statuses, DIRECTION direction, boolean fetchingMissing, boolean canScroll) {
        dealWithPagination(fetched_statuses, direction, fetchingMissing, canScroll, null);
    }

    /**
@@ -902,13 +917,21 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
        }
    }


    /**
     * Router for timelines
     *
     * @param direction - DIRECTION null if first call, then is set to TOP or BOTTOM depending of scroll
     */
    private void route(DIRECTION direction, boolean fetchingMissing) {
        route(direction, fetchingMissing, null);
    }

    /**
     * Router for timelines
     *
     * @param direction - DIRECTION null if first call, then is set to TOP or BOTTOM depending of scroll
     */
    private void route(DIRECTION direction, boolean fetchingMissing, Status fetchStatus) {
        if (binding == null || !isAdded() || getActivity() == null) {
            return;
        }
@@ -933,14 +956,14 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                            });
                } else if (direction == DIRECTION.BOTTOM) {
                    timelinesVM.getNitter(pinnedTimeline.remoteInstance.host, max_id)
                            .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true));
                            .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
                } else if (direction == DIRECTION.TOP) {
                    flagLoading = false;
                } else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
                    timelinesVM.getNitter(pinnedTimeline.remoteInstance.host, null)
                            .observe(getViewLifecycleOwner(), statusesRefresh -> {
                                if (statusAdapter != null) {
                                    dealWithPagination(statusesRefresh, direction, true, true);
                                    dealWithPagination(statusesRefresh, direction, true, true, fetchStatus);
                                } else {
                                    initializeStatusesCommonView(statusesRefresh);
                                }
@@ -956,14 +979,14 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                            .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
                } else if (direction == DIRECTION.BOTTOM) {
                    timelinesVM.getMisskey(remoteInstance, max_id, MastodonHelper.statusesPerCall(requireActivity()))
                            .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true));
                            .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
                } else if (direction == DIRECTION.TOP) {
                    flagLoading = false;
                } else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
                    timelinesVM.getMisskey(remoteInstance, null, MastodonHelper.statusesPerCall(requireActivity()))
                            .observe(getViewLifecycleOwner(), statusesRefresh -> {
                                if (statusAdapter != null) {
                                    dealWithPagination(statusesRefresh, direction, true, true);
                                    dealWithPagination(statusesRefresh, direction, true, true, fetchStatus);
                                } else {
                                    initializeStatusesCommonView(statusesRefresh);
                                }
@@ -976,14 +999,14 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                            .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
                } else if (direction == DIRECTION.BOTTOM) {
                    timelinesVM.getPeertube(remoteInstance, String.valueOf(timelineStatuses.size()), MastodonHelper.statusesPerCall(requireActivity()))
                            .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true));
                            .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
                } else if (direction == DIRECTION.TOP) {
                    flagLoading = false;
                } else if (direction == DIRECTION.REFRESH || direction == DIRECTION.SCROLL_TOP) {
                    timelinesVM.getPeertube(remoteInstance, null, MastodonHelper.statusesPerCall(requireActivity()))
                            .observe(getViewLifecycleOwner(), statusesRefresh -> {
                                if (statusAdapter != null) {
                                    dealWithPagination(statusesRefresh, direction, true, true);
                                    dealWithPagination(statusesRefresh, direction, true, true, fetchStatus);
                                } else {
                                    initializeStatusesCommonView(statusesRefresh);
                                }
@@ -1065,7 +1088,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                }
            } else if (direction == DIRECTION.BOTTOM) {
                accountsVM.getAccountStatuses(tempInstance, tempToken, accountId, max_id, null, null, exclude_replies, exclude_reblogs, media_only, false, MastodonHelper.statusesPerCall(requireActivity()))
                        .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true));
                        .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
            } else {
                flagLoading = false;
            }
@@ -1090,7 +1113,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                                Statuses statuses = new Statuses();
                                statuses.statuses = results.statuses;
                                statuses.pagination = new Pagination();
                                dealWithPagination(statuses, direction, false, true);
                                dealWithPagination(statuses, direction, false, true, fetchStatus);
                            }
                        });
            } else {
@@ -1115,7 +1138,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                        .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
            } else if (direction == DIRECTION.BOTTOM) {
                accountsVM.getFavourites(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, String.valueOf(MastodonHelper.statusesPerCall(requireActivity())), null, max_id)
                        .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true));
                        .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
            } else {
                flagLoading = false;
            }
@@ -1125,7 +1148,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                        .observe(getViewLifecycleOwner(), this::initializeStatusesCommonView);
            } else if (direction == DIRECTION.BOTTOM) {
                accountsVM.getBookmarks(BaseMainActivity.currentInstance, BaseMainActivity.currentToken, String.valueOf(MastodonHelper.statusesPerCall(requireActivity())), max_id, null, null)
                        .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true));
                        .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
            } else {
                flagLoading = false;
            }
@@ -1135,7 +1158,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                        .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, true));
                        .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
            } else {
                flagLoading = false;
            }
@@ -1145,7 +1168,7 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
                        .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, true));
                        .observe(getViewLifecycleOwner(), statusesBottom -> dealWithPagination(statusesBottom, DIRECTION.BOTTOM, false, true, fetchStatus));
            } else {
                flagLoading = false;
            }
@@ -1163,26 +1186,26 @@ public class FragmentMastodonTimeline extends Fragment implements StatusAdapter.
    }

    @Override
    public void onClickMinId(String min_id) {
    public void onClickMinId(String min_id, Status fetchStatus) {
        //Fetch more has been pressed
        min_id_fetch_more = min_id;
        route(DIRECTION.TOP, true);
    }

    @Override
    public void onClickMaxId(String max_id) {
    public void onClickMaxId(String max_id, Status fetchStatus) {
        max_id_fetch_more = max_id;
        route(DIRECTION.BOTTOM, true);
        route(DIRECTION.BOTTOM, true, fetchStatus);
    }

    @Override
    public void autoFetch(String min_id, String max_id, Status statusToUpdate) {
    public void autoFetch(String min_id, String max_id, Status fetchStatus) {
        if (scrollingUp) {
            min_id_fetch_more = min_id;
            route(DIRECTION.TOP, true);
            route(DIRECTION.TOP, true, fetchStatus);
        } else {
            max_id_fetch_more = max_id;
            route(DIRECTION.BOTTOM, true);
            route(DIRECTION.BOTTOM, true, fetchStatus);
        }
    }

+24 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<androidx.appcompat.widget.LinearLayoutCompat xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fetching_container"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:orientation="vertical"
    android:paddingHorizontal="6dp">

    <ProgressBar
        android:id="@+id/fetching_progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:indeterminate="true" />

    <androidx.appcompat.widget.AppCompatTextView
        style="@style/TextAppearance.AppCompat.Title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="@string/fetching_messages"
        android:textAlignment="center"
        android:textColor="?colorPrimary" />
</androidx.appcompat.widget.LinearLayoutCompat>
 No newline at end of file
+1 −0
Original line number Diff line number Diff line
@@ -1958,4 +1958,5 @@
    <string name="load_media_remotely">Load media remotely</string>
    <string name="toast_error_media">Media cannot be loaded!</string>
    <string name="fetch_remote_media">Automatically fetch remote media when they are not available</string>
    <string name="fetching_messages">Fetching messages</string>
</resources>
 No newline at end of file