Loading app/src/main/java/app/fedilab/android/mastodon/client/entities/api/Status.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java +54 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 -> { Loading Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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) { Loading @@ -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); Loading Loading @@ -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; Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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 { Loading Loading @@ -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); } Loading app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java +43 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } /** Loading Loading @@ -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; } Loading @@ -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); } Loading @@ -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); } Loading @@ -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); } Loading Loading @@ -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; } Loading @@ -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 { Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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); } } Loading app/src/main/res/layouts/mastodon/layout/drawer_message_fetching.xml 0 → 100644 +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 app/src/main/res/values/strings.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
app/src/main/java/app/fedilab/android/mastodon/client/entities/api/Status.java +2 −0 Original line number Diff line number Diff line Loading @@ -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; Loading
app/src/main/java/app/fedilab/android/mastodon/ui/drawer/StatusAdapter.java +54 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 -> { Loading Loading @@ -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); Loading Loading @@ -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) { Loading @@ -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) { Loading @@ -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); Loading Loading @@ -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; Loading @@ -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) { Loading @@ -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) { Loading Loading @@ -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; Loading @@ -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 { Loading Loading @@ -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); } Loading
app/src/main/java/app/fedilab/android/mastodon/ui/fragment/timeline/FragmentMastodonTimeline.java +43 −20 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } /** Loading Loading @@ -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; } Loading @@ -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); } Loading @@ -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); } Loading @@ -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); } Loading Loading @@ -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; } Loading @@ -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 { Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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; } Loading @@ -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); } } Loading
app/src/main/res/layouts/mastodon/layout/drawer_message_fetching.xml 0 → 100644 +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
app/src/main/res/values/strings.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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