refactor milestone pagination and fix closing/opening ms

This commit is contained in:
M M Arif
2022-04-04 18:05:39 +05:00
parent 5d9575d799
commit f5172338ce
4 changed files with 169 additions and 189 deletions

View File

@@ -26,7 +26,7 @@ public class MilestoneActions {
call = RetrofitClient
.getApiInterface(ctx)
.closeReopenMilestone(((BaseActivity) ctx).getAccount().getAuthorization(), repository.getOwner(), repository.getOwner(), milestoneId_, milestoneStateJson);
.closeReopenMilestone(((BaseActivity) ctx).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), milestoneId_, milestoneStateJson);
call.enqueue(new Callback<>() {
@@ -36,7 +36,6 @@ public class MilestoneActions {
if(response.isSuccessful()) {
Toasty.success(ctx, ctx.getString(R.string.milestoneStatusUpdate));
}
else if(response.code() == 401) {
@@ -65,7 +64,7 @@ public class MilestoneActions {
call = RetrofitClient
.getApiInterface(ctx)
.closeReopenMilestone(((BaseActivity) ctx).getAccount().getAuthorization(), repository.getOwner(), repository.getOwner(), milestoneId_, milestoneStateJson);
.closeReopenMilestone(((BaseActivity) ctx).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), milestoneId_, milestoneStateJson);
call.enqueue(new Callback<>() {

View File

@@ -39,9 +39,8 @@ public class MilestonesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
private final Context context;
private List<Milestones> dataList;
private Runnable loadMoreListener;
private boolean isLoading = false;
private boolean isMoreDataAvailable = true;
private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true;
private final RepositoryContext repository;
public MilestonesAdapter(Context ctx, List<Milestones> dataListMain, RepositoryContext repository) {
@@ -63,7 +62,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) {
isLoading = true;
loadMoreListener.run();
loadMoreListener.onLoadMore();
}
((MilestonesAdapter.DataHolder) holder).bindData(dataList.get(position));
}
@@ -123,14 +122,14 @@ public class MilestonesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
MilestoneActions.closeMilestone(ctx, milestoneId_, repository);
dialog.dismiss();
updateAdapter(getAdapterPosition());
updateAdapter(getBindingAdapterPosition());
});
openMilestone.setOnClickListener(v12 -> {
MilestoneActions.openMilestone(ctx, milestoneId_, repository);
dialog.dismiss();
updateAdapter(getAdapterPosition());
updateAdapter(getBindingAdapterPosition());
});
});
@@ -231,12 +230,6 @@ public class MilestonesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
}
}
private void updateAdapter(int position) {
dataList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, dataList.size());
}
@Override
public int getItemViewType(int position) {
return position;
@@ -247,18 +240,32 @@ public class MilestonesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
return dataList.size();
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
private void updateAdapter(int position) {
dataList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, dataList.size());
}
public void setMoreDataAvailable(boolean moreDataAvailable) {
isMoreDataAvailable = moreDataAvailable;
if(!isMoreDataAvailable) {
loadMoreListener.onLoadFinished();
}
}
@SuppressLint("NotifyDataSetChanged")
public void notifyDataChanged() {
notifyDataSetChanged();
isLoading = false;
loadMoreListener.onLoadFinished();
}
public void setLoadMoreListener(Runnable loadMoreListener) {
public interface OnLoadMoreListener {
void onLoadMore();
void onLoadFinished();
}
public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) {
this.loadMoreListener = loadMoreListener;
}

View File

@@ -4,7 +4,6 @@ import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@@ -15,6 +14,7 @@ import android.view.inputmethod.EditorInfo;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import org.gitnex.tea4j.models.Milestones;
@@ -22,34 +22,26 @@ import org.mian.gitnex.R;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.adapters.MilestonesAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentMilestonesBinding;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.contexts.RepositoryContext;
import org.mian.gitnex.viewmodels.MilestonesViewModel;
import java.util.ArrayList;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
* @author M M Arif
*/
public class MilestonesFragment extends Fragment {
private FragmentMilestonesBinding viewBinding;
private Menu menu;
private List<Milestones> dataList;
private MilestonesAdapter adapter;
private Context ctx;
private int pageSize = Constants.milestonesPageInit;
private final String TAG = Constants.tagMilestonesFragment;
private int resultLimit = Constants.resultLimitOldGiteaInstances;
private RepositoryContext repository;
private String milestoneId;
private int page = 1;
public String state = "open";
public static MilestonesFragment newInstance(RepositoryContext repository) {
MilestonesFragment fragment = new MilestonesFragment();
@@ -68,7 +60,7 @@ public class MilestonesFragment extends Fragment {
viewBinding = FragmentMilestonesBinding.inflate(inflater, container, false);
setHasOptionsMenu(true);
ctx = getContext();
Context ctx = getContext();
milestoneId = requireActivity().getIntent().getStringExtra("milestoneId");
requireActivity().getIntent().removeExtra("milestoneId");
@@ -76,135 +68,84 @@ public class MilestonesFragment extends Fragment {
viewBinding.recyclerView.setHasFixedSize(true);
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
// if gitea is 1.12 or higher use the new limit
if(((BaseActivity) requireActivity()).getAccount().requiresVersion("1.12.0")) {
resultLimit = Constants.resultLimitNewGiteaInstances;
}
dataList = new ArrayList<>();
adapter = new MilestonesAdapter(ctx, dataList, repository);
if(((BaseActivity) requireActivity()).getAccount().requiresVersion("1.12.0")) {
adapter.setLoadMoreListener(() -> viewBinding.recyclerView.post(() -> {
if(dataList.size() == resultLimit || pageSize == resultLimit) {
int page = (dataList.size() + resultLimit) / resultLimit;
loadMore(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), page, resultLimit, repository.getMilestoneState().toString());
}
}));
}
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(viewBinding.recyclerView.getContext(), DividerItemDecoration.VERTICAL);
viewBinding.recyclerView.addItemDecoration(dividerItemDecoration);
viewBinding.recyclerView.setHasFixedSize(true);
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
viewBinding.recyclerView.setAdapter(adapter);
viewBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
page = 1;
dataList.clear();
viewBinding.pullToRefresh.setRefreshing(false);
loadInitial(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), resultLimit, repository.getMilestoneState().toString());
adapter.updateList(dataList);
fetchDataAsync(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), state);
}, 50));
((RepoDetailActivity) requireActivity()).setFragmentRefreshListenerMilestone(milestoneState -> {
if(milestoneState.equals("closed")) {
menu.getItem(1).setIcon(R.drawable.ic_filter_closed);
}
else {
menu.getItem(1).setIcon(R.drawable.ic_filter);
}
dataList.clear();
adapter = new MilestonesAdapter(ctx, dataList, repository);
if(((BaseActivity) requireActivity()).getAccount().requiresVersion("1.12.0")) {
adapter.setLoadMoreListener(() -> viewBinding.recyclerView.post(() -> {
if(dataList.size() == resultLimit || pageSize == resultLimit) {
int page = (dataList.size() + resultLimit) / resultLimit;
loadMore(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), page, resultLimit, milestoneState);
}
}));
state = milestoneState;
if(milestoneState.equals("open")) {
menu.getItem(1).setIcon(R.drawable.ic_filter);
}
else {
menu.getItem(1).setIcon(R.drawable.ic_filter_closed);
}
page = 1;
dataList.clear();
viewBinding.progressBar.setVisibility(View.VISIBLE);
viewBinding.noDataMilestone.setVisibility(View.GONE);
loadInitial(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), resultLimit, milestoneState);
viewBinding.recyclerView.setAdapter(adapter);
fetchDataAsync(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), milestoneState);
});
loadInitial(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), resultLimit, repository.getMilestoneState().toString());
fetchDataAsync(((BaseActivity) requireActivity()).getAccount().getAuthorization(), repository.getOwner(), repository.getName(), state);
return viewBinding.getRoot();
}
private void loadInitial(String token, String repoOwner, String repoName, int resultLimit, String milestoneState) {
private void fetchDataAsync(String instanceToken, String repoOwner, String repoName, String state) {
Call<List<Milestones>> call = RetrofitClient.getApiInterface(ctx).getMilestones(token, repoOwner, repoName, 1, resultLimit, milestoneState);
MilestonesViewModel milestonesViewModel = new ViewModelProvider(this).get(MilestonesViewModel.class);
call.enqueue(new Callback<List<Milestones>>() {
milestonesViewModel.getMilestonesList(instanceToken, repoOwner, repoName, state, getContext()).observe(getViewLifecycleOwner(), milestonesListMain -> {
@Override
public void onResponse(@NonNull Call<List<Milestones>> call, @NonNull Response<List<Milestones>> response) {
adapter = new MilestonesAdapter(getContext(), milestonesListMain, repository);
adapter.setLoadMoreListener(new MilestonesAdapter.OnLoadMoreListener() {
if(response.code() == 200) {
@Override
public void onLoadMore() {
assert response.body() != null;
if(response.body().size() > 0) {
page += 1;
MilestonesViewModel.loadMoreMilestones(instanceToken, repoOwner, repoName, page, state, getContext(), adapter);
viewBinding.progressBar.setVisibility(View.VISIBLE);
}
dataList.clear();
dataList.addAll(response.body());
adapter.notifyDataChanged();
viewBinding.noDataMilestone.setVisibility(View.GONE);
@Override
public void onLoadFinished() {
if(milestoneId != null) {
viewBinding.recyclerView.scrollToPosition(getMilestoneIndex(Integer.parseInt(milestoneId), response.body()));
}
viewBinding.progressBar.setVisibility(View.GONE);
}
});
}
else {
if(adapter.getItemCount() > 0) {
viewBinding.recyclerView.setAdapter(adapter);
viewBinding.noDataMilestone.setVisibility(View.GONE);
dataList.addAll(milestonesListMain);
if(milestoneId != null) {
viewBinding.recyclerView.scrollToPosition(getMilestoneIndex(Integer.parseInt(milestoneId), milestonesListMain));
}
}
else {
adapter.notifyDataChanged();
viewBinding.recyclerView.setAdapter(adapter);
viewBinding.noDataMilestone.setVisibility(View.VISIBLE);
}
dataList.clear();
adapter.notifyDataChanged();
viewBinding.noDataMilestone.setVisibility(View.VISIBLE);
}
viewBinding.progressBar.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Milestones>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
viewBinding.progressBar.setVisibility(View.GONE);
});
}
private static int getMilestoneIndex(int milestoneId, List<Milestones> milestones) {
for (Milestones milestone : milestones) {
@@ -215,59 +156,6 @@ public class MilestonesFragment extends Fragment {
return -1;
}
private void loadMore(String token, String repoOwner, String repoName, int page, int resultLimit, String milestoneState) {
viewBinding.progressLoadMore.setVisibility(View.VISIBLE);
Call<List<Milestones>> call = RetrofitClient.getApiInterface(ctx).getMilestones(token, repoOwner, repoName, page, resultLimit, milestoneState);
call.enqueue(new Callback<List<Milestones>>() {
@Override
public void onResponse(@NonNull Call<List<Milestones>> call, @NonNull Response<List<Milestones>> response) {
if(response.code() == 200) {
//remove loading view
dataList.remove(dataList.size() - 1);
List<Milestones> result = response.body();
assert result != null;
if(result.size() > 0) {
pageSize = result.size();
dataList.addAll(result);
}
else {
adapter.setMoreDataAvailable(false);
}
adapter.notifyDataChanged();
viewBinding.progressLoadMore.setVisibility(View.GONE);
}
else {
Log.e(TAG, String.valueOf(response.code()));
}
}
@Override
public void onFailure(@NonNull Call<List<Milestones>> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
@@ -276,12 +164,6 @@ public class MilestonesFragment extends Fragment {
inflater.inflate(R.menu.filter_menu_milestone, menu);
super.onCreateOptionsMenu(menu, inflater);
if(repository.getMilestoneState() == RepositoryContext.State.CLOSED) {
menu.getItem(1).setIcon(R.drawable.ic_filter_closed);
} else {
menu.getItem(1).setIcon(R.drawable.ic_filter);
}
MenuItem searchItem = menu.findItem(R.id.action_search);
androidx.appcompat.widget.SearchView searchView = (androidx.appcompat.widget.SearchView) searchItem.getActionView();
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
@@ -299,11 +181,8 @@ public class MilestonesFragment extends Fragment {
filter(newText);
return false;
}
});
}
private void filter(String text) {
@@ -321,5 +200,4 @@ public class MilestonesFragment extends Fragment {
adapter.updateList(arr);
}
}

View File

@@ -0,0 +1,96 @@
package org.mian.gitnex.viewmodels;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.gitnex.tea4j.models.Milestones;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.MilestonesAdapter;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.Toasty;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* @author M M Arif
*/
public class MilestonesViewModel extends ViewModel {
private static MutableLiveData<List<Milestones>> milestonesList;
private static final int resultLimit = Constants.resultLimitNewGiteaInstances;
public LiveData<List<Milestones>> getMilestonesList(String token, String repoOwner, String repoName, String milestoneState, Context ctx) {
milestonesList = new MutableLiveData<>();
loadMilestonesList(token, repoOwner, repoName, milestoneState, ctx);
return milestonesList;
}
public static void loadMilestonesList(String token, String repoOwner, String repoName, String milestoneState, Context ctx) {
Call<List<Milestones>> call = RetrofitClient.getApiInterface(ctx).getMilestones(token, repoOwner, repoName, 1, resultLimit, milestoneState);
call.enqueue(new Callback<>() {
@Override
public void onResponse(@NonNull Call<List<Milestones>> call, @NonNull Response<List<Milestones>> response) {
if(response.isSuccessful()) {
milestonesList.postValue(response.body());
}
else {
Toasty.error(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<List<Milestones>> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
}
});
}
public static void loadMoreMilestones(String token, String repoOwner, String repoName, int page, String milestoneState, Context ctx, MilestonesAdapter adapter) {
Call<List<Milestones>> call = RetrofitClient.getApiInterface(ctx).getMilestones(token, repoOwner, repoName, page, resultLimit, milestoneState);
call.enqueue(new Callback<>() {
@Override
public void onResponse(@NonNull Call<List<Milestones>> call, @NonNull Response<List<Milestones>> response) {
if(response.isSuccessful()) {
List<Milestones> list = milestonesList.getValue();
assert list != null;
assert response.body() != null;
if(response.body().size() != 0) {
list.addAll(response.body());
adapter.updateList(list);
}
else {
adapter.setMoreDataAvailable(false);
}
}
else {
Toasty.error(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<List<Milestones>> call, @NonNull Throwable t) {
Toasty.error(ctx, ctx.getString(R.string.genericServerResponseError));
}
});
}
}