diff --git a/app/build.gradle b/app/build.gradle index 6e4210e2..ce12f266 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -109,7 +109,7 @@ dependencies { implementation "androidx.work:work-runtime:$work_version" implementation "io.mikael:urlbuilder:2.0.9" 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" implementation 'androidx.biometric:biometric:1.1.0' implementation 'com.github.chrisvest:stormpot:2.4.2' diff --git a/app/src/main/java/org/mian/gitnex/activities/AddCollaboratorToRepositoryActivity.java b/app/src/main/java/org/mian/gitnex/activities/AddCollaboratorToRepositoryActivity.java index 546ae5bf..1769f6a8 100644 --- a/app/src/main/java/org/mian/gitnex/activities/AddCollaboratorToRepositoryActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/AddCollaboratorToRepositoryActivity.java @@ -81,7 +81,7 @@ public class AddCollaboratorToRepositoryActivity extends BaseActivity { Call call = RetrofitClient .getApiInterface(appCtx) - .getUserBySearch(Authorization.get(ctx), searchKeyword, 10); + .getUserBySearch(Authorization.get(ctx), searchKeyword, 10, 1); call.enqueue(new Callback() { diff --git a/app/src/main/java/org/mian/gitnex/activities/AddNewTeamMemberActivity.java b/app/src/main/java/org/mian/gitnex/activities/AddNewTeamMemberActivity.java index c34bde9f..43905572 100644 --- a/app/src/main/java/org/mian/gitnex/activities/AddNewTeamMemberActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/AddNewTeamMemberActivity.java @@ -110,7 +110,7 @@ public class AddNewTeamMemberActivity extends BaseActivity { public void loadUserSearchList(String searchKeyword, String teamId) { - Call call = RetrofitClient.getApiInterface(ctx).getUserBySearch(Authorization.get(ctx), searchKeyword, 10); + Call call = RetrofitClient.getApiInterface(ctx).getUserBySearch(Authorization.get(ctx), searchKeyword, 10, 1); mProgressBar.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java b/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java index 6e611788..bd70e623 100644 --- a/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java @@ -1,10 +1,10 @@ package org.mian.gitnex.activities; import android.annotation.SuppressLint; +import android.app.Dialog; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; -import android.content.DialogInterface; import android.content.Intent; import android.content.res.ColorStateList; import android.graphics.Typeface; @@ -29,6 +29,7 @@ import androidx.viewpager.widget.ViewPager; import com.google.android.material.tabs.TabLayout; import com.google.gson.JsonElement; import org.gitnex.tea4j.models.Branches; +import org.gitnex.tea4j.models.Milestones; import org.gitnex.tea4j.models.UserRepositories; import org.gitnex.tea4j.models.WatchInfo; import org.mian.gitnex.R; @@ -70,6 +71,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF private FragmentRefreshListenerPr fragmentRefreshListenerPr; private FragmentRefreshListenerMilestone fragmentRefreshListenerMilestone; private FragmentRefreshListenerFiles fragmentRefreshListenerFiles; + private FragmentRefreshListenerFilterIssuesByMilestone fragmentRefreshListenerFilterIssuesByMilestone; private String repositoryOwner; private String repositoryName; @@ -441,6 +443,9 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF startActivity(new Intent(RepoDetailActivity.this, CreateFileActivity.class)); break; + case "filterByMilestone": + filterIssuesByMilestone(); + break; case "openIssues": 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> call = RetrofitClient + .getApiInterface(ctx) + .getMilestones(Authorization.get(ctx), repositoryOwner, repositoryName, 1, 50, "open"); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + progressDialog.hide(); + if(response.code() == 200) { + + Milestones milestones; + List 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> call, @NonNull Throwable t) { + + progressDialog.hide(); + Log.e("onFailure", t.toString()); + } + + }); + + } + private void chooseBranch() { + Dialog progressDialog = new Dialog(this); + progressDialog.setContentView(R.layout.custom_progress_loader); + progressDialog.show(); + Call> call = RetrofitClient .getApiInterface(ctx) .getBranches(Authorization.get(ctx), repositoryOwner, repositoryName); @@ -505,6 +581,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF @Override public void onResponse(@NonNull Call> call, @NonNull Response> response) { + progressDialog.hide(); if(response.code() == 200) { List branchesList = new ArrayList<>(); @@ -525,19 +602,15 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF AlertDialog.Builder pBuilder = new AlertDialog.Builder(ctx); 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 - public void onClick(DialogInterface dialogInterface, int i) { + tinyDB.putString("repoBranch", branchesList.get(i)); - tinyDB.putString("repoBranch", branchesList.get(i)); + if(getFragmentRefreshListenerFiles() != null) { - if(getFragmentRefreshListenerFiles() != null) { - - getFragmentRefreshListenerFiles().onRefresh(branchesList.get(i)); - } - dialogInterface.dismiss(); + getFragmentRefreshListenerFiles().onRefresh(branchesList.get(i)); } + dialogInterface.dismiss(); }); pBuilder.setNeutralButton(R.string.cancelButton, null); @@ -548,6 +621,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetRepoF @Override public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + progressDialog.hide(); 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 public FragmentRefreshListener getFragmentRefreshListener() { return fragmentRefreshListener; } diff --git a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetIssuesFilterFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetIssuesFilterFragment.java index af941435..ccb8bbd0 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetIssuesFilterFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetIssuesFilterFragment.java @@ -9,6 +9,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import org.mian.gitnex.databinding.BottomSheetIssuesFilterBinding; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Version; /** * 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) { 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 -> { bmListener.onButtonClicked("openIssues"); diff --git a/app/src/main/java/org/mian/gitnex/fragments/IssuesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/IssuesFragment.java index eda404ac..2808760a 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/IssuesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/IssuesFragment.java @@ -12,15 +12,11 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.EditorInfo; -import android.widget.ProgressBar; -import android.widget.TextView; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import androidx.recyclerview.widget.DividerItemDecoration; import androidx.recyclerview.widget.LinearLayoutManager; -import androidx.recyclerview.widget.RecyclerView; -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.gitnex.tea4j.models.Issues; import org.mian.gitnex.R; import org.mian.gitnex.activities.RepoDetailActivity; @@ -45,18 +41,16 @@ import retrofit2.Response; public class IssuesFragment extends Fragment { private FragmentIssuesBinding fragmentIssuesBinding; + private Context context; + private Menu menu; - private RecyclerView recyclerView; private List issuesList; private IssuesAdapter adapter; - private Context context; + private int pageSize = Constants.issuesPageInit; - private ProgressBar mProgressBar; private final String TAG = Constants.tagIssuesList; - private TextView noDataIssues; private int resultLimit = Constants.resultLimitOldGiteaInstances; private final String requestType = Constants.issuesRequestType; - private ProgressBar progressLoadMore; @Nullable @Override @@ -66,7 +60,7 @@ public class IssuesFragment extends Fragment { setHasOptionsMenu(true); context = getContext(); - TinyDB tinyDb = TinyDB.getInstance(getContext()); + TinyDB tinyDb = TinyDB.getInstance(context); String repoFullName = tinyDb.getString("repoFullName"); String[] parts = repoFullName.split("/"); final String repoOwner = parts[0]; @@ -74,39 +68,32 @@ public class IssuesFragment extends Fragment { final String loginUid = tinyDb.getString("loginUid"); 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(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) { resultLimit = Constants.resultLimitNewGiteaInstances; } - recyclerView = fragmentIssuesBinding.recyclerView; issuesList = new ArrayList<>(); - progressLoadMore = fragmentIssuesBinding.progressLoadMore; - mProgressBar = fragmentIssuesBinding.progressBar; - noDataIssues = fragmentIssuesBinding.noDataIssues; - - swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { - swipeRefresh.setRefreshing(false); - loadInitial(instanceToken, repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState")); + fragmentIssuesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { + fragmentIssuesBinding.pullToRefresh.setRefreshing(false); + loadInitial(instanceToken, repoOwner, repoName, resultLimit, requestType, tinyDb.getString("repoIssuesState"), ""); adapter.notifyDataChanged(); }, 200)); - adapter = new IssuesAdapter(getContext(), issuesList); - adapter.setLoadMoreListener(() -> recyclerView.post(() -> { + 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(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); - recyclerView.setHasFixedSize(true); - recyclerView.addItemDecoration(dividerItemDecoration); - recyclerView.setLayoutManager(new LinearLayoutManager(context)); - recyclerView.setAdapter(adapter); + DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(fragmentIssuesBinding.recyclerView.getContext(), DividerItemDecoration.VERTICAL); + fragmentIssuesBinding.recyclerView.setHasFixedSize(true); + fragmentIssuesBinding.recyclerView.addItemDecoration(dividerItemDecoration); + fragmentIssuesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(context)); + fragmentIssuesBinding.recyclerView.setAdapter(adapter); ((RepoDetailActivity) requireActivity()).setFragmentRefreshListener(issueState -> { @@ -119,25 +106,47 @@ public class IssuesFragment extends Fragment { issuesList.clear(); - adapter = new IssuesAdapter(getContext(), issuesList); - adapter.setLoadMoreListener(() -> recyclerView.post(() -> { + 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(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); - mProgressBar.setVisibility(View.VISIBLE); - noDataIssues.setVisibility(View.GONE); + fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE); + fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE); - loadInitial(Authorization.get(getContext()), repoOwner, repoName, resultLimit, requestType, issueState); - recyclerView.setAdapter(adapter); + loadInitial(Authorization.get(context), repoOwner, repoName, resultLimit, requestType, issueState, ""); + 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(); } @@ -146,7 +155,7 @@ public class IssuesFragment extends Fragment { public void onResume() { super.onResume(); - TinyDB tinyDb = TinyDB.getInstance(getContext()); + TinyDB tinyDb = TinyDB.getInstance(context); String repoFullName = tinyDb.getString("repoFullName"); String[] parts = repoFullName.split("/"); @@ -154,14 +163,14 @@ public class IssuesFragment extends Fragment { final String repoName = parts[1]; 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); } } - 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> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, 1, resultLimit, requestType, issueState); + Call> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, 1, resultLimit, requestType, issueState, filterByMilestone); call.enqueue(new Callback>() { @Override @@ -173,18 +182,18 @@ public class IssuesFragment extends Fragment { issuesList.clear(); issuesList.addAll(response.body()); adapter.notifyDataChanged(); - noDataIssues.setVisibility(View.GONE); + fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE); } else { issuesList.clear(); 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) { - noDataIssues.setVisibility(View.VISIBLE); - mProgressBar.setVisibility(View.GONE); + fragmentIssuesBinding.noDataIssues.setVisibility(View.VISIBLE); + fragmentIssuesBinding.progressBar.setVisibility(View.GONE); } else { 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> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, page, resultLimit, requestType, issueState); + Call> call = RetrofitClient.getApiInterface(context).getIssues(token, repoOwner, repoName, page, resultLimit, requestType, issueState, filterByMilestone); call.enqueue(new Callback>() { @@ -220,7 +229,7 @@ public class IssuesFragment extends Fragment { adapter.setMoreDataAvailable(false); } adapter.notifyDataChanged(); - progressLoadMore.setVisibility(View.GONE); + fragmentIssuesBinding.progressLoadMore.setVisibility(View.GONE); } else { Log.e(TAG, String.valueOf(response.code())); diff --git a/app/src/main/res/layout/bottom_sheet_issues_filter.xml b/app/src/main/res/layout/bottom_sheet_issues_filter.xml index 81f9b081..b0704f49 100644 --- a/app/src/main/res/layout/bottom_sheet_issues_filter.xml +++ b/app/src/main/res/layout/bottom_sheet_issues_filter.xml @@ -18,6 +18,22 @@ android:orientation="vertical" android:layout_height="wrap_content"> + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 52bf35d1..a73f9a13 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -203,6 +203,7 @@ No description %1$d Open %1$d Closed + Select Milestone Select Assignees Select Labels