Filter issues by milestone (#980)

Closes #693

Right now I like how the API(filters) is for issues, for PRs it is only accepting Ids. It should be more like issues which has optional titles and more forgiving.

Maybe in the future will implement for PRs when the API become updated.

Issues:
https://codeberg.org/api/swagger#/issue/issueListIssues

PR:
https://codeberg.org/api/swagger#/repository/repoListPullRequests

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/980
Reviewed-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Co-committed-by: M M Arif <mmarif@noreply.codeberg.org>
This commit is contained in:
M M Arif 2021-09-28 11:10:27 +02:00
parent 95aea16a07
commit b493dfc567
9 changed files with 197 additions and 62 deletions

View File

@ -109,7 +109,7 @@ dependencies {
implementation "androidx.work:work-runtime:$work_version" implementation "androidx.work:work-runtime:$work_version"
implementation "io.mikael:urlbuilder:2.0.9" implementation "io.mikael:urlbuilder:2.0.9"
implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2" implementation "org.codeberg.gitnex-garage:emoji-java:v5.1.2"
implementation "org.codeberg.gitnex:tea4j:1.0.20" implementation "org.codeberg.gitnex:tea4j:1.0.24"
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
implementation 'androidx.biometric:biometric:1.1.0' implementation 'androidx.biometric:biometric:1.1.0'
implementation 'com.github.chrisvest:stormpot:2.4.2' implementation 'com.github.chrisvest:stormpot:2.4.2'

View File

@ -81,7 +81,7 @@ public class AddCollaboratorToRepositoryActivity extends BaseActivity {
Call<UserSearch> call = RetrofitClient Call<UserSearch> call = RetrofitClient
.getApiInterface(appCtx) .getApiInterface(appCtx)
.getUserBySearch(Authorization.get(ctx), searchKeyword, 10); .getUserBySearch(Authorization.get(ctx), searchKeyword, 10, 1);
call.enqueue(new Callback<UserSearch>() { call.enqueue(new Callback<UserSearch>() {

View File

@ -110,7 +110,7 @@ public class AddNewTeamMemberActivity extends BaseActivity {
public void loadUserSearchList(String searchKeyword, String teamId) { public void loadUserSearchList(String searchKeyword, String teamId) {
Call<UserSearch> call = RetrofitClient.getApiInterface(ctx).getUserBySearch(Authorization.get(ctx), searchKeyword, 10); Call<UserSearch> call = RetrofitClient.getApiInterface(ctx).getUserBySearch(Authorization.get(ctx), searchKeyword, 10, 1);
mProgressBar.setVisibility(View.VISIBLE); mProgressBar.setVisibility(View.VISIBLE);

View File

@ -1,10 +1,10 @@
package org.mian.gitnex.activities; package org.mian.gitnex.activities;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.ClipData; import android.content.ClipData;
import android.content.ClipboardManager; import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
import android.content.res.ColorStateList; import android.content.res.ColorStateList;
import android.graphics.Typeface; import android.graphics.Typeface;
@ -29,6 +29,7 @@ import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout; import com.google.android.material.tabs.TabLayout;
import com.google.gson.JsonElement; import com.google.gson.JsonElement;
import org.gitnex.tea4j.models.Branches; import org.gitnex.tea4j.models.Branches;
import org.gitnex.tea4j.models.Milestones;
import org.gitnex.tea4j.models.UserRepositories; import org.gitnex.tea4j.models.UserRepositories;
import org.gitnex.tea4j.models.WatchInfo; import org.gitnex.tea4j.models.WatchInfo;
import org.mian.gitnex.R; import org.mian.gitnex.R;
@ -70,6 +71,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF
private FragmentRefreshListenerPr fragmentRefreshListenerPr; private FragmentRefreshListenerPr fragmentRefreshListenerPr;
private FragmentRefreshListenerMilestone fragmentRefreshListenerMilestone; private FragmentRefreshListenerMilestone fragmentRefreshListenerMilestone;
private FragmentRefreshListenerFiles fragmentRefreshListenerFiles; private FragmentRefreshListenerFiles fragmentRefreshListenerFiles;
private FragmentRefreshListenerFilterIssuesByMilestone fragmentRefreshListenerFilterIssuesByMilestone;
private String repositoryOwner; private String repositoryOwner;
private String repositoryName; private String repositoryName;
@ -441,6 +443,9 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF
startActivity(new Intent(RepoDetailActivity.this, CreateFileActivity.class)); startActivity(new Intent(RepoDetailActivity.this, CreateFileActivity.class));
break; break;
case "filterByMilestone":
filterIssuesByMilestone();
break;
case "openIssues": case "openIssues":
if(getFragmentRefreshListener() != null) { if(getFragmentRefreshListener() != null) {
@ -494,8 +499,79 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF
} }
} }
private void filterIssuesByMilestone() {
Dialog progressDialog = new Dialog(this);
progressDialog.setContentView(R.layout.custom_progress_loader);
progressDialog.show();
Call<List<Milestones>> call = RetrofitClient
.getApiInterface(ctx)
.getMilestones(Authorization.get(ctx), repositoryOwner, repositoryName, 1, 50, "open");
call.enqueue(new Callback<List<Milestones>>() {
@Override
public void onResponse(@NonNull Call<List<Milestones>> call, @NonNull Response<List<Milestones>> response) {
progressDialog.hide();
if(response.code() == 200) {
Milestones milestones;
List<String> milestonesList = new ArrayList<>();
int selectedMilestone = 0;
assert response.body() != null;
milestonesList.add("All");
for(int i = 0; i < response.body().size(); i++) {
milestones = response.body().get(i);
milestonesList.add(milestones.getTitle());
}
for(int j = 0; j < milestonesList.size(); j++) {
if(tinyDB.getString("issueMilestoneFilterId").equals(milestonesList.get(j))) {
selectedMilestone = j;
}
}
AlertDialog.Builder pBuilder = new AlertDialog.Builder(ctx);
pBuilder.setTitle(R.string.selectMilestone);
pBuilder.setSingleChoiceItems(milestonesList.toArray(new String[0]), selectedMilestone, (dialogInterface, i) -> {
tinyDB.putString("issueMilestoneFilterId", milestonesList.get(i));
if(getFragmentRefreshListenerFilterIssuesByMilestone() != null) {
getFragmentRefreshListenerFilterIssuesByMilestone().onRefresh(milestonesList.get(i));
}
dialogInterface.dismiss();
});
pBuilder.setNeutralButton(R.string.cancelButton, null);
pBuilder.create().show();
}
}
@Override
public void onFailure(@NonNull Call<List<Milestones>> call, @NonNull Throwable t) {
progressDialog.hide();
Log.e("onFailure", t.toString());
}
});
}
private void chooseBranch() { private void chooseBranch() {
Dialog progressDialog = new Dialog(this);
progressDialog.setContentView(R.layout.custom_progress_loader);
progressDialog.show();
Call<List<Branches>> call = RetrofitClient Call<List<Branches>> call = RetrofitClient
.getApiInterface(ctx) .getApiInterface(ctx)
.getBranches(Authorization.get(ctx), repositoryOwner, repositoryName); .getBranches(Authorization.get(ctx), repositoryOwner, repositoryName);
@ -505,6 +581,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF
@Override @Override
public void onResponse(@NonNull Call<List<Branches>> call, @NonNull Response<List<Branches>> response) { public void onResponse(@NonNull Call<List<Branches>> call, @NonNull Response<List<Branches>> response) {
progressDialog.hide();
if(response.code() == 200) { if(response.code() == 200) {
List<String> branchesList = new ArrayList<>(); List<String> branchesList = new ArrayList<>();
@ -525,19 +602,15 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF
AlertDialog.Builder pBuilder = new AlertDialog.Builder(ctx); AlertDialog.Builder pBuilder = new AlertDialog.Builder(ctx);
pBuilder.setTitle(R.string.pageTitleChooseBranch); pBuilder.setTitle(R.string.pageTitleChooseBranch);
pBuilder.setSingleChoiceItems(branchesList.toArray(new String[0]), selectedBranch, new DialogInterface.OnClickListener() { pBuilder.setSingleChoiceItems(branchesList.toArray(new String[0]), selectedBranch, (dialogInterface, i) -> {
@Override tinyDB.putString("repoBranch", branchesList.get(i));
public void onClick(DialogInterface dialogInterface, int i) {
tinyDB.putString("repoBranch", branchesList.get(i)); if(getFragmentRefreshListenerFiles() != null) {
if(getFragmentRefreshListenerFiles() != null) { getFragmentRefreshListenerFiles().onRefresh(branchesList.get(i));
getFragmentRefreshListenerFiles().onRefresh(branchesList.get(i));
}
dialogInterface.dismiss();
} }
dialogInterface.dismiss();
}); });
pBuilder.setNeutralButton(R.string.cancelButton, null); pBuilder.setNeutralButton(R.string.cancelButton, null);
@ -548,6 +621,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF
@Override @Override
public void onFailure(@NonNull Call<List<Branches>> call, @NonNull Throwable t) { public void onFailure(@NonNull Call<List<Branches>> call, @NonNull Throwable t) {
progressDialog.hide();
Log.e("onFailure", t.toString()); Log.e("onFailure", t.toString());
} }
}); });
@ -715,6 +789,13 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF
} }
// Issues milestone filter interface
public FragmentRefreshListenerFilterIssuesByMilestone getFragmentRefreshListenerFilterIssuesByMilestone() { return fragmentRefreshListenerFilterIssuesByMilestone; }
public void setFragmentRefreshListenerFilterIssuesByMilestone(FragmentRefreshListenerFilterIssuesByMilestone fragmentRefreshListener) { this.fragmentRefreshListenerFilterIssuesByMilestone = fragmentRefreshListener; }
public interface FragmentRefreshListenerFilterIssuesByMilestone { void onRefresh(String text); }
// Issues interface // Issues interface
public FragmentRefreshListener getFragmentRefreshListener() { return fragmentRefreshListener; } public FragmentRefreshListener getFragmentRefreshListener() { return fragmentRefreshListener; }

View File

@ -9,6 +9,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.databinding.BottomSheetIssuesFilterBinding; import org.mian.gitnex.databinding.BottomSheetIssuesFilterBinding;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Version;
/** /**
* Author M M Arif * Author M M Arif
@ -23,6 +25,15 @@ public class BottomSheetIssuesFilterFragment extends BottomSheetDialogFragment {
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
BottomSheetIssuesFilterBinding bottomSheetIssuesFilterBinding = BottomSheetIssuesFilterBinding.inflate(inflater, container, false); BottomSheetIssuesFilterBinding bottomSheetIssuesFilterBinding = BottomSheetIssuesFilterBinding.inflate(inflater, container, false);
TinyDB tinyDb = TinyDB.getInstance(getContext());
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.14.0")) {
bottomSheetIssuesFilterBinding.filterByMilestone.setVisibility(View.VISIBLE);
bottomSheetIssuesFilterBinding.filterByMilestone.setOnClickListener(v1 -> {
bmListener.onButtonClicked("filterByMilestone");
dismiss();
});
}
bottomSheetIssuesFilterBinding.openIssues.setOnClickListener(v1 -> { bottomSheetIssuesFilterBinding.openIssues.setOnClickListener(v1 -> {
bmListener.onButtonClicked("openIssues"); bmListener.onButtonClicked("openIssues");

View File

@ -12,15 +12,11 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.gitnex.tea4j.models.Issues; import org.gitnex.tea4j.models.Issues;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.activities.RepoDetailActivity;
@ -45,18 +41,16 @@ import retrofit2.Response;
public class IssuesFragment extends Fragment { public class IssuesFragment extends Fragment {
private FragmentIssuesBinding fragmentIssuesBinding; private FragmentIssuesBinding fragmentIssuesBinding;
private Context context;
private Menu menu; private Menu menu;
private RecyclerView recyclerView;
private List<Issues> issuesList; private List<Issues> issuesList;
private IssuesAdapter adapter; private IssuesAdapter adapter;
private Context context;
private int pageSize = Constants.issuesPageInit; private int pageSize = Constants.issuesPageInit;
private ProgressBar mProgressBar;
private final String TAG = Constants.tagIssuesList; private final String TAG = Constants.tagIssuesList;
private TextView noDataIssues;
private int resultLimit = Constants.resultLimitOldGiteaInstances; private int resultLimit = Constants.resultLimitOldGiteaInstances;
private final String requestType = Constants.issuesRequestType; private final String requestType = Constants.issuesRequestType;
private ProgressBar progressLoadMore;
@Nullable @Nullable
@Override @Override
@ -66,7 +60,7 @@ public class IssuesFragment extends Fragment {
setHasOptionsMenu(true); setHasOptionsMenu(true);
context = getContext(); context = getContext();
TinyDB tinyDb = TinyDB.getInstance(getContext()); TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName"); String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/"); String[] parts = repoFullName.split("/");
final String repoOwner = parts[0]; final String repoOwner = parts[0];
@ -74,39 +68,32 @@ public class IssuesFragment extends Fragment {
final String loginUid = tinyDb.getString("loginUid"); final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token"); final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
final SwipeRefreshLayout swipeRefresh = fragmentIssuesBinding.pullToRefresh;
// if gitea is 1.12 or higher use the new limit // if gitea is 1.12 or higher use the new limit
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
resultLimit = Constants.resultLimitNewGiteaInstances; resultLimit = Constants.resultLimitNewGiteaInstances;
} }
recyclerView = fragmentIssuesBinding.recyclerView;
issuesList = new ArrayList<>(); issuesList = new ArrayList<>();
progressLoadMore = fragmentIssuesBinding.progressLoadMore; fragmentIssuesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
mProgressBar = fragmentIssuesBinding.progressBar; fragmentIssuesBinding.pullToRefresh.setRefreshing(false);
noDataIssues = fragmentIssuesBinding.noDataIssues; loadInitial(instanceToken, repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"), "");
swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
swipeRefresh.setRefreshing(false);
loadInitial(instanceToken, repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"));
adapter.notifyDataChanged(); adapter.notifyDataChanged();
}, 200)); }, 200));
adapter = new IssuesAdapter(getContext(), issuesList); adapter = new IssuesAdapter(context, issuesList);
adapter.setLoadMoreListener(() -> recyclerView.post(() -> { adapter.setLoadMoreListener(() -> fragmentIssuesBinding.recyclerView.post(() -> {
if(issuesList.size() == resultLimit || pageSize == resultLimit) { if(issuesList.size() == resultLimit || pageSize == resultLimit) {
int page = (issuesList.size() + resultLimit) / resultLimit; int page = (issuesList.size() + resultLimit) / resultLimit;
loadMore(Authorization.get(getContext()), repoOwner, repoName, page, resultLimit, requestType, tinyDb.getString("repoIssuesState")); loadMore(Authorization.get(context), repoOwner, repoName, page, resultLimit, requestType, tinyDb.getString("repoIssuesState"), "");
} }
})); }));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(recyclerView.getContext(), DividerItemDecoration.VERTICAL); DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(fragmentIssuesBinding.recyclerView.getContext(), DividerItemDecoration.VERTICAL);
recyclerView.setHasFixedSize(true); fragmentIssuesBinding.recyclerView.setHasFixedSize(true);
recyclerView.addItemDecoration(dividerItemDecoration); fragmentIssuesBinding.recyclerView.addItemDecoration(dividerItemDecoration);
recyclerView.setLayoutManager(new LinearLayoutManager(context)); fragmentIssuesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context));
recyclerView.setAdapter(adapter); fragmentIssuesBinding.recyclerView.setAdapter(adapter);
((RepoDetailActivity) requireActivity()).setFragmentRefreshListener(issueState -> { ((RepoDetailActivity) requireActivity()).setFragmentRefreshListener(issueState -> {
@ -119,25 +106,47 @@ public class IssuesFragment extends Fragment {
issuesList.clear(); issuesList.clear();
adapter = new IssuesAdapter(getContext(), issuesList); adapter = new IssuesAdapter(context, issuesList);
adapter.setLoadMoreListener(() -> recyclerView.post(() -> { adapter.setLoadMoreListener(() -> fragmentIssuesBinding.recyclerView.post(() -> {
if(issuesList.size() == resultLimit || pageSize == resultLimit) { if(issuesList.size() == resultLimit || pageSize == resultLimit) {
int page = (issuesList.size() + resultLimit) / resultLimit; int page = (issuesList.size() + resultLimit) / resultLimit;
loadMore(Authorization.get(getContext()), repoOwner, repoName, page, resultLimit, requestType, tinyDb.getString("repoIssuesState")); loadMore(Authorization.get(context), repoOwner, repoName, page, resultLimit, requestType, tinyDb.getString("repoIssuesState"), "");
} }
})); }));
tinyDb.putString("repoIssuesState", issueState); tinyDb.putString("repoIssuesState", issueState);
mProgressBar.setVisibility(View.VISIBLE); fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
noDataIssues.setVisibility(View.GONE); fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE);
loadInitial(Authorization.get(getContext()), repoOwner, repoName, resultLimit, requestType, issueState); loadInitial(Authorization.get(context), repoOwner, repoName, resultLimit, requestType, issueState, "");
recyclerView.setAdapter(adapter); fragmentIssuesBinding.recyclerView.setAdapter(adapter);
}); });
loadInitial(Authorization.get(getContext()), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState")); ((RepoDetailActivity) requireActivity()).setFragmentRefreshListenerFilterIssuesByMilestone(filterIssueByMilestone -> {
issuesList.clear();
adapter = new IssuesAdapter(context, issuesList);
adapter.setLoadMoreListener(() -> fragmentIssuesBinding.recyclerView.post(() -> {
if(issuesList.size() == resultLimit || pageSize == resultLimit) {
int page = (issuesList.size() + resultLimit) / resultLimit;
loadMore(Authorization.get(context), repoOwner, repoName, page, resultLimit, requestType, tinyDb.getString("repoIssuesState"), tinyDb.getString("issueMilestoneFilterId"));
}
}));
tinyDb.putString("issueMilestoneFilterId", filterIssueByMilestone);
fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE);
loadInitial(Authorization.get(context), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"), tinyDb.getString("issueMilestoneFilterId"));
fragmentIssuesBinding.recyclerView.setAdapter(adapter);
});
loadInitial(Authorization.get(context), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"), tinyDb.getString("issueMilestoneFilterId"));
return fragmentIssuesBinding.getRoot(); return fragmentIssuesBinding.getRoot();
} }
@ -146,7 +155,7 @@ public class IssuesFragment extends Fragment {
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
TinyDB tinyDb = TinyDB.getInstance(getContext()); TinyDB tinyDb = TinyDB.getInstance(context);
String repoFullName = tinyDb.getString("repoFullName"); String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/"); String[] parts = repoFullName.split("/");
@ -154,14 +163,14 @@ public class IssuesFragment extends Fragment {
final String repoName = parts[1]; final String repoName = parts[1];
if(tinyDb.getBoolean("resumeIssues")) { if(tinyDb.getBoolean("resumeIssues")) {
loadInitial(Authorization.get(getContext()), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState")); loadInitial(Authorization.get(context), repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"), tinyDb.getString("issueMilestoneFilterId"));
tinyDb.putBoolean("resumeIssues", false); tinyDb.putBoolean("resumeIssues", false);
} }
} }
private void loadInitial(String token, String repoOwner, String repoName, int resultLimit, String requestType, String issueState) { private void loadInitial(String token, String repoOwner, String repoName, int resultLimit, String requestType, String issueState, String filterByMilestone) {
Call<List<Issues>> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, 1, resultLimit, requestType, issueState); Call<List<Issues>> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, 1, resultLimit, requestType, issueState, filterByMilestone);
call.enqueue(new Callback<List<Issues>>() { call.enqueue(new Callback<List<Issues>>() {
@Override @Override
@ -173,18 +182,18 @@ public class IssuesFragment extends Fragment {
issuesList.clear(); issuesList.clear();
issuesList.addAll(response.body()); issuesList.addAll(response.body());
adapter.notifyDataChanged(); adapter.notifyDataChanged();
noDataIssues.setVisibility(View.GONE); fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE);
} }
else { else {
issuesList.clear(); issuesList.clear();
adapter.notifyDataChanged(); adapter.notifyDataChanged();
noDataIssues.setVisibility(View.VISIBLE); fragmentIssuesBinding.noDataIssues.setVisibility(View.VISIBLE);
} }
mProgressBar.setVisibility(View.GONE); fragmentIssuesBinding.progressBar.setVisibility(View.GONE);
} }
else if(response.code() == 404) { else if(response.code() == 404) {
noDataIssues.setVisibility(View.VISIBLE); fragmentIssuesBinding.noDataIssues.setVisibility(View.VISIBLE);
mProgressBar.setVisibility(View.GONE); fragmentIssuesBinding.progressBar.setVisibility(View.GONE);
} }
else { else {
Log.e(TAG, String.valueOf(response.code())); Log.e(TAG, String.valueOf(response.code()));
@ -198,11 +207,11 @@ public class IssuesFragment extends Fragment {
}); });
} }
private void loadMore(String token, String repoOwner, String repoName, int page, int resultLimit, String requestType, String issueState) { private void loadMore(String token, String repoOwner, String repoName, int page, int resultLimit, String requestType, String issueState, String filterByMilestone) {
progressLoadMore.setVisibility(View.VISIBLE); fragmentIssuesBinding.progressLoadMore.setVisibility(View.VISIBLE);
Call<List<Issues>> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, page, resultLimit, requestType, issueState); Call<List<Issues>> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, page, resultLimit, requestType, issueState, filterByMilestone);
call.enqueue(new Callback<List<Issues>>() { call.enqueue(new Callback<List<Issues>>() {
@ -220,7 +229,7 @@ public class IssuesFragment extends Fragment {
adapter.setMoreDataAvailable(false); adapter.setMoreDataAvailable(false);
} }
adapter.notifyDataChanged(); adapter.notifyDataChanged();
progressLoadMore.setVisibility(View.GONE); fragmentIssuesBinding.progressLoadMore.setVisibility(View.GONE);
} }
else { else {
Log.e(TAG, String.valueOf(response.code())); Log.e(TAG, String.valueOf(response.code()));

View File

@ -18,6 +18,22 @@
android:orientation="vertical" android:orientation="vertical"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<TextView
android:id="@+id/filterByMilestone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true"
android:drawablePadding="24dp"
android:padding="12dp"
android:text="@string/newIssueMilestoneTitle"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_milestone" />
<TextView <TextView
android:id="@+id/openIssues" android:id="@+id/openIssues"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical">
<com.google.android.material.progressindicator.LinearProgressIndicator
android:id="@+id/progressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:indeterminate="true"
android:minWidth="360dp"
style="@style/Widget.MaterialComponents.LinearProgressIndicator"
app:indicatorColor="?attr/progressIndicatorColor" />
</LinearLayout>

View File

@ -203,6 +203,7 @@
<string name="milestoneNoDescription">No description</string> <string name="milestoneNoDescription">No description</string>
<string name="milestoneIssueStatusOpen">%1$d Open</string> <string name="milestoneIssueStatusOpen">%1$d Open</string>
<string name="milestoneIssueStatusClosed">%1$d Closed</string> <string name="milestoneIssueStatusClosed">%1$d Closed</string>
<string name="selectMilestone">Select Milestone</string>
<string name="newIssueSelectAssigneesListTitle">Select Assignees</string> <string name="newIssueSelectAssigneesListTitle">Select Assignees</string>
<string name="newIssueSelectLabelsListTitle">Select Labels</string> <string name="newIssueSelectLabelsListTitle">Select Labels</string>