Filter issues by labels and mentioned (me) (#1419)

Closes #933

Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1419
Co-authored-by: M M Arif <mmarif@swatian.com>
Co-committed-by: M M Arif <mmarif@swatian.com>
This commit is contained in:
M M Arif
2025-03-16 19:52:09 +00:00
committed by M M Arif
parent 912922fdc1
commit f6e0278e44
8 changed files with 514 additions and 241 deletions

View File

@@ -4,7 +4,9 @@ import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
@@ -12,23 +14,31 @@ import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import androidx.viewpager2.widget.ViewPager2;
import com.google.android.flexbox.FlexboxLayout;
import com.google.android.material.chip.Chip;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.progressindicator.LinearProgressIndicator;
import com.google.android.material.tabs.TabLayout;
import com.google.android.material.tabs.TabLayoutMediator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.gitnex.tea4j.v2.models.Label;
import org.gitnex.tea4j.v2.models.Milestone;
import org.gitnex.tea4j.v2.models.Organization;
import org.gitnex.tea4j.v2.models.Repository;
@@ -90,6 +100,9 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe
private FragmentRefreshListener fragmentRefreshListenerFiles;
private FragmentRefreshListener fragmentRefreshListenerFilterIssuesByMilestone;
private FragmentRefreshListener fragmentRefreshListenerReleases;
private FragmentRefreshListenerFilterIssuesByLabels fragmentRefreshListenerFilterIssuesByLabels;
private final List<Label> labelsList = new ArrayList<>();
private final Map<String, Boolean> selectedStates = new HashMap<>();
private Dialog progressDialog;
private MaterialAlertDialogBuilder materialAlertDialogBuilder;
private Intent intentWiki;
@@ -121,6 +134,8 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe
TextView toolbarTitle = findViewById(R.id.toolbar_title);
toolbarTitle.setText(repository.getFullName());
fetchLabels();
setSupportActionBar(toolbar);
Objects.requireNonNull(getSupportActionBar()).setTitle(repository.getName());
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
@@ -205,7 +220,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe
} else if (id == R.id.filter) {
BottomSheetIssuesFilterFragment filterBottomSheet =
new BottomSheetIssuesFilterFragment();
BottomSheetIssuesFilterFragment.newInstance(repository);
filterBottomSheet.show(getSupportFragmentManager(), "repoFilterMenuBottomSheet");
return true;
} else if (id == R.id.filterPr) {
@@ -221,11 +236,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe
filterMilestoneBottomSheet.show(
getSupportFragmentManager(), "repoFilterMenuMilestoneBottomSheet");
return true;
} /*else if (id == R.id.switchBranches) {
chooseBranch();
return true;
}*/ else if (id == R.id.branchCommits) {
} else if (id == R.id.branchCommits) {
Intent intent = repository.getIntent(ctx, CommitsActivity.class);
@@ -242,10 +253,49 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe
return super.onOptionsItemSelected(item);
}
private void fetchLabels() {
Call<List<Label>> call =
RetrofitClient.getApiInterface(this)
.issueListLabels(repository.getOwner(), repository.getName(), 1, 50);
call.enqueue(
new Callback<>() {
@Override
public void onResponse(
@NonNull Call<List<Label>> call,
@NonNull Response<List<Label>> response) {
if (response.isSuccessful() && response.body() != null) {
labelsList.clear();
labelsList.addAll(response.body());
for (Label label : labelsList) {
selectedStates.put(label.getName(), false); // Initialize states
}
}
}
@Override
public void onFailure(@NonNull Call<List<Label>> call, @NonNull Throwable t) {
Toasty.error(
RepoDetailActivity.this,
getString(R.string.genericServerResponseError));
}
});
}
@Override
public void onButtonClicked(String text) {
if (text.startsWith("mentionedByMe:")) {
String usernameWithPrefix = text.substring("mentionedByMe:".length());
String username = "null".equals(usernameWithPrefix) ? null : usernameWithPrefix;
if (getFragmentRefreshListenerFilterIssuesByMentions() != null) {
getFragmentRefreshListenerFilterIssuesByMentions().onRefresh(username);
}
}
switch (text) {
case "filterByLabels":
showLabelFilterDialog();
break;
case "openWebRepo":
AppUtil.openUrlInBrowser(this, repository.getRepository().getHtmlUrl());
break;
@@ -334,6 +384,63 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe
}
}
private void showLabelFilterDialog() {
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(this);
View dialogView =
LayoutInflater.from(this).inflate(R.layout.custom_filter_issues_by_labels, null);
FlexboxLayout labelsContainer = dialogView.findViewById(R.id.labelsContainer);
Button filterButton = dialogView.findViewById(R.id.filterButton);
labelsContainer.removeAllViews();
for (Label label : labelsList) {
Chip chip =
(Chip)
LayoutInflater.from(this)
.inflate(
R.layout.list_filter_issues_by_labels,
labelsContainer,
false);
chip.setText(label.getName());
chip.setCheckable(true);
chip.setChecked(
Boolean.TRUE.equals(selectedStates.getOrDefault(label.getName(), false)));
GradientDrawable dot = new GradientDrawable();
dot.setShape(GradientDrawable.OVAL);
dot.setSize(16, 16);
dot.setColor(Color.parseColor("#" + label.getColor()));
chip.setChipIcon(dot);
chip.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
selectedStates.put(label.getName(), isChecked);
});
labelsContainer.addView(chip);
}
AlertDialog dialog = builder.setView(dialogView).create();
filterButton.setOnClickListener(
v -> {
String selectedLabels =
selectedStates.entrySet().stream()
.filter(Map.Entry::getValue)
.map(Map.Entry::getKey)
.collect(Collectors.joining(","));
if (getFragmentRefreshListenerFilterIssuesByLabels() != null) {
getFragmentRefreshListenerFilterIssuesByLabels()
.onRefresh(selectedLabels.isEmpty() ? null : selectedLabels);
}
dialog.dismiss();
});
dialog.show();
}
private void filterIssuesByMilestone() {
progressDialog = new Dialog(this);
@@ -735,6 +842,39 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe
});
}
// filter by mentioned
public interface FragmentRefreshListenerFilterIssuesByMentions {
void onRefresh(String username);
}
private FragmentRefreshListenerFilterIssuesByMentions
fragmentRefreshListenerFilterIssuesByMentions;
public void setFragmentRefreshListenerFilterIssuesByMentions(
FragmentRefreshListenerFilterIssuesByMentions listener) {
this.fragmentRefreshListenerFilterIssuesByMentions = listener;
}
public FragmentRefreshListenerFilterIssuesByMentions
getFragmentRefreshListenerFilterIssuesByMentions() {
return fragmentRefreshListenerFilterIssuesByMentions;
}
// filter issues by labels
public interface FragmentRefreshListenerFilterIssuesByLabels {
void onRefresh(String labels);
}
public void setFragmentRefreshListenerFilterIssuesByLabels(
FragmentRefreshListenerFilterIssuesByLabels listener) {
this.fragmentRefreshListenerFilterIssuesByLabels = listener;
}
public FragmentRefreshListenerFilterIssuesByLabels
getFragmentRefreshListenerFilterIssuesByLabels() {
return fragmentRefreshListenerFilterIssuesByLabels;
}
// Issues milestone filter interface
public FragmentRefreshListener getFragmentRefreshListenerFilterIssuesByMilestone() {
return fragmentRefreshListenerFilterIssuesByMilestone;

View File

@@ -10,6 +10,7 @@ import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.databinding.BottomSheetIssuesFilterBinding;
import org.mian.gitnex.helpers.contexts.RepositoryContext;
import org.mian.gitnex.structs.BottomSheetListener;
/**
@@ -18,6 +19,16 @@ import org.mian.gitnex.structs.BottomSheetListener;
public class BottomSheetIssuesFilterFragment extends BottomSheetDialogFragment {
private BottomSheetListener bmListener;
private BottomSheetIssuesFilterBinding binding;
private RepositoryContext repository;
public static BottomSheetIssuesFilterFragment newInstance(RepositoryContext repository) {
BottomSheetIssuesFilterFragment fragment = new BottomSheetIssuesFilterFragment();
Bundle args = new Bundle();
args.putSerializable(RepositoryContext.INTENT_EXTRA, repository);
fragment.setArguments(args);
return fragment;
}
@Nullable @Override
public View onCreateView(
@@ -25,42 +36,90 @@ public class BottomSheetIssuesFilterFragment extends BottomSheetDialogFragment {
@Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
BottomSheetIssuesFilterBinding bottomSheetIssuesFilterBinding =
BottomSheetIssuesFilterBinding.inflate(inflater, container, false);
binding = BottomSheetIssuesFilterBinding.inflate(inflater, container, false);
if (((BaseActivity) requireActivity()).getAccount().requiresVersion("1.14.0")) {
bottomSheetIssuesFilterBinding.filterByMilestone.setVisibility(View.VISIBLE);
bottomSheetIssuesFilterBinding.filterByMilestone.setOnClickListener(
v1 -> {
bmListener.onButtonClicked("filterByMilestone");
dismiss();
});
if (getArguments() != null) {
repository =
(RepositoryContext)
getArguments().getSerializable(RepositoryContext.INTENT_EXTRA);
}
if (repository == null) {
throw new IllegalStateException("RepositoryContext is required");
}
bottomSheetIssuesFilterBinding.openIssues.setOnClickListener(
v1 -> {
bmListener.onButtonClicked("openIssues");
if (((BaseActivity) requireActivity()).getAccount().requiresVersion("1.14.0")) {
binding.milestoneChip.setVisibility(View.VISIBLE);
}
binding.openChip.setChecked(repository.getIssueState() == RepositoryContext.State.OPEN);
binding.closedChip.setChecked(repository.getIssueState() == RepositoryContext.State.CLOSED);
binding.mentionsChip.setChecked(repository.getMentionedBy() != null);
binding.openChip.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (isChecked && repository.getIssueState() != RepositoryContext.State.OPEN) {
repository.setIssueState(RepositoryContext.State.OPEN);
bmListener.onButtonClicked("openIssues");
dismiss();
} else if (!isChecked) {
buttonView.setChecked(true);
}
});
binding.closedChip.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
if (isChecked && repository.getIssueState() != RepositoryContext.State.CLOSED) {
repository.setIssueState(RepositoryContext.State.CLOSED);
bmListener.onButtonClicked("closedIssues");
dismiss();
} else if (!isChecked) {
buttonView.setChecked(true);
}
});
binding.mentionsChip.setOnCheckedChangeListener(
(buttonView, isChecked) -> {
String username =
isChecked
? ((BaseActivity) requireActivity())
.getAccount()
.getAccount()
.getUserName()
: null;
repository.setMentionedBy(username);
bmListener.onButtonClicked(
"mentionedByMe:" + (username != null ? username : "null"));
dismiss();
});
bottomSheetIssuesFilterBinding.closedIssues.setOnClickListener(
v12 -> {
bmListener.onButtonClicked("closedIssues");
binding.labelsChip.setOnClickListener(
v -> {
bmListener.onButtonClicked("filterByLabels");
dismiss();
});
return bottomSheetIssuesFilterBinding.getRoot();
binding.milestoneChip.setOnClickListener(
v -> {
bmListener.onButtonClicked("filterByMilestone");
dismiss();
});
return binding.getRoot();
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
try {
bmListener = (BottomSheetListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(context + " must implement BottomSheetListener");
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}

View File

@@ -50,6 +50,8 @@ public class IssuesFragment extends Fragment {
private int pageSize = Constants.issuesPageInit;
private int resultLimit;
private RepositoryContext repository;
private String selectedLabels = null;
private String mentionedBy;
public static IssuesFragment newInstance(RepositoryContext repository) {
IssuesFragment f = new IssuesFragment();
@@ -67,6 +69,7 @@ public class IssuesFragment extends Fragment {
context = getContext();
repository = RepositoryContext.fromBundle(requireArguments());
mentionedBy = repository.getMentionedBy();
boolean archived = repository.getRepository().isArchived();
@@ -89,7 +92,9 @@ public class IssuesFragment extends Fragment {
requestType,
repository.getIssueState().toString(),
repository.getIssueMilestoneFilterName(),
null);
null,
selectedLabels,
mentionedBy);
adapter.notifyDataChanged();
},
200));
@@ -109,7 +114,9 @@ public class IssuesFragment extends Fragment {
resultLimit,
requestType,
repository.getIssueState().toString(),
repository.getIssueMilestoneFilterName());
repository.getIssueMilestoneFilterName(),
selectedLabels,
mentionedBy);
}
}));
@@ -125,90 +132,36 @@ public class IssuesFragment extends Fragment {
((RepoDetailActivity) requireActivity())
.setFragmentRefreshListener(
issueState -> {
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(
repository.getOwner(),
repository.getName(),
page,
resultLimit,
requestType,
repository
.getIssueState()
.toString(),
repository
.getIssueMilestoneFilterName());
}
}));
fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE);
loadInitial(
repository.getOwner(),
repository.getName(),
resultLimit,
requestType,
issueState,
repository.getIssueMilestoneFilterName(),
null);
fragmentIssuesBinding.recyclerView.setAdapter(adapter);
});
issueState -> refreshIssues(issueState, selectedLabels, mentionedBy));
((RepoDetailActivity) requireActivity())
.setFragmentRefreshListenerFilterIssuesByMilestone(
filterIssueByMilestone -> {
issuesList.clear();
filterIssueByMilestone ->
refreshIssues(
repository.getIssueState().toString(),
selectedLabels,
mentionedBy,
filterIssueByMilestone));
adapter = new IssuesAdapter(context, issuesList, "");
adapter.setLoadMoreListener(
() ->
fragmentIssuesBinding.recyclerView.post(
() -> {
if (issuesList.size() == resultLimit
|| pageSize == resultLimit) {
int page =
(issuesList.size()
+ resultLimit)
/ resultLimit;
loadMore(
repository.getOwner(),
repository.getName(),
page,
resultLimit,
requestType,
repository
.getIssueState()
.toString(),
repository
.getIssueMilestoneFilterName());
}
}));
fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE);
loadInitial(
repository.getOwner(),
repository.getName(),
resultLimit,
requestType,
((RepoDetailActivity) requireActivity())
.setFragmentRefreshListenerFilterIssuesByLabels(
filterLabels -> {
selectedLabels = filterLabels;
refreshIssues(
repository.getIssueState().toString(),
filterIssueByMilestone,
null);
fragmentIssuesBinding.recyclerView.setAdapter(adapter);
selectedLabels,
mentionedBy);
});
((RepoDetailActivity) requireActivity())
.setFragmentRefreshListenerFilterIssuesByMentions(
username -> {
mentionedBy = username;
repository.setMentionedBy(username);
refreshIssues(
repository.getIssueState().toString(),
selectedLabels,
mentionedBy);
});
loadInitial(
@@ -218,7 +171,9 @@ public class IssuesFragment extends Fragment {
requestType,
repository.getIssueState().toString(),
repository.getIssueMilestoneFilterName(),
null);
null,
selectedLabels,
mentionedBy);
getPinnedIssues(repository.getOwner(), repository.getName());
@@ -227,7 +182,6 @@ public class IssuesFragment extends Fragment {
}
if (repository.getRepository().isHasIssues() && !archived) {
fragmentIssuesBinding.createNewIssue.setVisibility(View.VISIBLE);
fragmentIssuesBinding.createNewIssue.setOnClickListener(
v12 -> {
@@ -237,18 +191,15 @@ public class IssuesFragment extends Fragment {
getContext(), CreateIssueActivity.class));
});
} else {
fragmentIssuesBinding.createNewIssue.setVisibility(View.GONE);
}
requireActivity()
.addMenuProvider(
new MenuProvider() {
@Override
public void onCreateMenu(
@NonNull Menu menu, @NonNull MenuInflater menuInflater) {
menuInflater.inflate(R.menu.search_menu, menu);
menuInflater.inflate(R.menu.filter_menu, menu);
@@ -268,7 +219,6 @@ public class IssuesFragment extends Fragment {
searchView.setOnQueryTextListener(
new androidx.appcompat.widget.SearchView
.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
loadInitial(
@@ -278,7 +228,9 @@ public class IssuesFragment extends Fragment {
requestType,
repository.getIssueState().toString(),
repository.getIssueMilestoneFilterName(),
query);
query,
selectedLabels,
mentionedBy);
searchView.setQuery(null, false);
searchItem.collapseActionView();
return false;
@@ -313,25 +265,98 @@ public class IssuesFragment extends Fragment {
requestType,
repository.getIssueState().toString(),
repository.getIssueMilestoneFilterName(),
null);
"",
selectedLabels,
mentionedBy);
getPinnedIssues(repository.getOwner(), repository.getName());
resumeIssues = false;
}
}
private void getPinnedIssues(String repoOwner, String repoName) {
private void refreshIssues(String issueState, String labels, String mentionedBy) {
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(
repository.getOwner(),
repository.getName(),
page,
resultLimit,
requestType,
issueState,
repository.getIssueMilestoneFilterName(),
labels,
mentionedBy);
}
}));
fragmentIssuesBinding.recyclerView.setAdapter(adapter);
fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE);
loadInitial(
repository.getOwner(),
repository.getName(),
resultLimit,
requestType,
issueState,
repository.getIssueMilestoneFilterName(),
null,
labels,
mentionedBy);
}
private void refreshIssues(
String issueState, String labels, String mentionedBy, String filterByMilestone) {
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(
repository.getOwner(),
repository.getName(),
page,
resultLimit,
requestType,
issueState,
filterByMilestone,
labels,
mentionedBy);
}
}));
fragmentIssuesBinding.recyclerView.setAdapter(adapter);
fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
fragmentIssuesBinding.noDataIssues.setVisibility(View.GONE);
loadInitial(
repository.getOwner(),
repository.getName(),
resultLimit,
requestType,
issueState,
filterByMilestone,
null,
labels,
mentionedBy);
}
private void getPinnedIssues(String repoOwner, String repoName) {
Call<List<Issue>> call =
RetrofitClient.getApiInterface(context).repoListPinnedIssues(repoOwner, repoName);
call.enqueue(
new Callback<>() {
@Override
public void onResponse(
@NonNull Call<List<Issue>> call,
@NonNull Response<List<Issue>> response) {
if (response.code() == 200) {
assert response.body() != null;
if (!response.body().isEmpty()) {
@@ -368,7 +393,9 @@ public class IssuesFragment extends Fragment {
String requestType,
String issueState,
String filterByMilestone,
String query) {
String query,
String labels,
String mentionedBy) {
Call<List<Issue>> call =
RetrofitClient.getApiInterface(context)
@@ -376,26 +403,24 @@ public class IssuesFragment extends Fragment {
repoOwner,
repoName,
issueState,
null,
labels,
query,
requestType,
filterByMilestone,
null,
null,
null,
null,
null,
null, // since
null, // before
null, // created_by
null, // assigned_by
mentionedBy, // mentioned_by
1,
resultLimit);
call.enqueue(
new Callback<>() {
@Override
public void onResponse(
@NonNull Call<List<Issue>> call,
@NonNull Response<List<Issue>> response) {
if (response.code() == 200) {
assert response.body() != null;
if (!response.body().isEmpty()) {
@@ -433,7 +458,9 @@ public class IssuesFragment extends Fragment {
int resultLimit,
String requestType,
String issueState,
String filterByMilestone) {
String filterByMilestone,
String labels,
String mentionedBy) {
fragmentIssuesBinding.progressBar.setVisibility(View.VISIBLE);
@@ -443,25 +470,24 @@ public class IssuesFragment extends Fragment {
repoOwner,
repoName,
issueState,
null,
labels,
null,
requestType,
filterByMilestone,
null,
null,
null,
null,
null,
null, // since
null, // before
null, // created_by
null, // assigned_by
mentionedBy, // mentioned_by
page,
resultLimit);
call.enqueue(
new Callback<>() {
@Override
public void onResponse(
@NonNull Call<List<Issue>> call,
@NonNull Response<List<Issue>> response) {
if (response.code() == 200) {
List<Issue> result = response.body();
assert result != null;

View File

@@ -4,6 +4,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import androidx.annotation.NonNull;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import org.gitnex.tea4j.v2.models.Permission;
@@ -34,6 +35,7 @@ public class RepositoryContext implements Serializable {
private boolean watched = false;
private int repositoryId = 0;
private Repository repositoryModel = null;
private String mentionedBy;
public RepositoryContext(org.gitnex.tea4j.v2.models.Repository repository, Context context) {
this.account = ((BaseActivity) context).getAccount();
@@ -57,37 +59,30 @@ public class RepositoryContext implements Serializable {
}
public State getIssueState() {
return issueState;
}
public void setIssueState(State issueState) {
this.issueState = issueState;
}
public State getMilestoneState() {
return milestoneState;
}
public void setMilestoneState(State milestoneState) {
this.milestoneState = milestoneState;
}
public State getPrState() {
return prState;
}
public void setPrState(State prState) {
this.prState = prState;
}
public org.gitnex.tea4j.v2.models.Repository getRepository() {
return repository;
}
@@ -99,12 +94,10 @@ public class RepositoryContext implements Serializable {
}
public String getBranchRef() {
return branchRef;
}
public void setBranchRef(String branchRef) {
this.branchRef = branchRef;
}
@@ -121,12 +114,10 @@ public class RepositoryContext implements Serializable {
}
public String getIssueMilestoneFilterName() {
return issueMilestoneFilterName;
}
public void setIssueMilestoneFilterName(String issueMilestoneFilterName) {
this.issueMilestoneFilterName = issueMilestoneFilterName;
}
@@ -151,45 +142,45 @@ public class RepositoryContext implements Serializable {
}
public boolean isStarred() {
return starred;
}
public void setStarred(boolean starred) {
this.starred = starred;
}
public boolean isWatched() {
return watched;
}
public void setWatched(boolean watched) {
this.watched = watched;
}
public int getRepositoryId() {
return repositoryId;
}
public void setRepositoryId(int repositoryId) {
this.repositoryId = repositoryId;
}
public Repository getRepositoryModel() {
return repositoryModel;
}
public void setRepositoryModel(Repository repositoryModel) {
this.repositoryModel = repositoryModel;
}
public String getMentionedBy() {
return mentionedBy;
}
public void setMentionedBy(String mentionedBy) {
this.mentionedBy = mentionedBy;
}
public Repository loadRepositoryModel(Context context) {
repositoryModel =
Objects.requireNonNull(BaseApi.getInstance(context, RepositoriesApi.class))
@@ -208,17 +199,14 @@ public class RepositoryContext implements Serializable {
}
public boolean isReleasesViewTypeIsTag() {
return releasesViewTypeIsTag;
}
public void setReleasesViewTypeIsTag(boolean releasesViewTypeIsTag) {
this.releasesViewTypeIsTag = releasesViewTypeIsTag;
}
public void removeRepository() {
repository = null;
}
@@ -258,4 +246,15 @@ public class RepositoryContext implements Serializable {
return "closed";
}
}
@Serial
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
out.defaultWriteObject();
}
@Serial
private void readObject(java.io.ObjectInputStream in)
throws java.io.IOException, ClassNotFoundException {
in.defaultReadObject();
}
}

View File

@@ -9,103 +9,95 @@
android:paddingTop="@dimen/dimen6dp"
android:paddingBottom="@dimen/dimen12dp">
<androidx.core.widget.NestedScrollView
<LinearLayout
android:id="@+id/issuesFilterHeadFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/dimen8dp">
<LinearLayout
<TextView
android:id="@+id/bottomSheetHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:gravity="center"
android:text="@string/strFilter"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp"/>
<LinearLayout
android:id="@+id/issuesFilterHeadFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/dimen8dp">
<com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewFilledStyle"
android:layout_width="@dimen/dimen28dp"
android:layout_height="@dimen/dimen4dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/dimen8dp"
android:layout_marginBottom="@dimen/dimen16dp"
app:cardCornerRadius="@dimen/dimen24dp"
app:cardElevation="@dimen/dimen0dp">
<TextView
android:id="@+id/bottomSheetHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/strFilter"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen16sp"/>
<com.google.android.material.card.MaterialCardView
style="?attr/materialCardViewFilledStyle"
android:layout_width="@dimen/dimen28dp"
android:layout_height="@dimen/dimen4dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="@dimen/dimen8dp"
android:layout_marginBottom="@dimen/dimen16dp"
app:cardCornerRadius="@dimen/dimen24dp"
app:cardElevation="@dimen/dimen0dp">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/fabColor" />
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/issuesFilterSection"
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/dimen4dp"
app:alignContent="center"
app:alignItems="flex_start"
app:flexWrap="wrap"
app:justifyContent="center">
android:background="?attr/fabColor" />
<TextView
android:id="@+id/filterByMilestone"
android:layout_width="@dimen/dimen132dp"
android:layout_height="@dimen/dimen100dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
android:padding="@dimen/dimen4dp"
android:text="@string/newIssueMilestoneTitle"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp"
app:drawableTopCompat="@drawable/ic_milestone"
app:layout_alignSelf="flex_start"/>
</com.google.android.material.card.MaterialCardView>
</LinearLayout>
<TextView
android:id="@+id/openIssues"
android:layout_width="@dimen/dimen132dp"
android:layout_height="@dimen/dimen100dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
android:padding="@dimen/dimen4dp"
android:text="@string/isOpen"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp"
app:drawableTopCompat="@drawable/ic_issue"
app:layout_alignSelf="flex_start"/>
<com.google.android.material.chip.ChipGroup
android:id="@+id/stateChipGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:singleSelection="true"
android:paddingStart="@dimen/dimen16dp"
android:paddingEnd="@dimen/dimen16dp"
android:paddingBottom="@dimen/dimen8dp">
<TextView
android:id="@+id/closedIssues"
android:layout_width="@dimen/dimen132dp"
android:layout_height="@dimen/dimen100dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
android:padding="@dimen/dimen4dp"
android:text="@string/isClosed"
android:textColor="?attr/primaryTextColor"
android:textSize="@dimen/dimen14sp"
app:drawableTopCompat="@drawable/ic_issue_closed"
app:layout_alignSelf="flex_start"/>
<com.google.android.material.chip.Chip
android:id="@+id/openChip"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/isOpen"
android:checked="true"/>
</com.google.android.flexbox.FlexboxLayout>
<com.google.android.material.chip.Chip
android:id="@+id/closedChip"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/isClosed"/>
</LinearLayout>
</com.google.android.material.chip.ChipGroup>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.chip.ChipGroup
android:id="@+id/filterChipGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:singleSelection="false"
android:padding="@dimen/dimen16dp">
<com.google.android.material.chip.Chip
android:id="@+id/mentionsChip"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/im_mentioned"/>
<com.google.android.material.chip.Chip
android:id="@+id/labelsChip"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/newIssueLabelsTitle"/>
<com.google.android.material.chip.Chip
android:id="@+id/milestoneChip"
style="@style/Widget.MaterialComponents.Chip.Filter"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/tabTextMl"
android:visibility="gone"/>
</com.google.android.material.chip.ChipGroup>
</LinearLayout>

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="@dimen/dimen16dp">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:maxHeight="@dimen/dimen320dp">
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/labelsContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:flexWrap="wrap"
app:justifyContent="flex_start"
app:alignItems="flex_start"
android:padding="@dimen/dimen4dp"/>
</androidx.core.widget.NestedScrollView>
<com.google.android.material.button.MaterialButton
android:id="@+id/filterButton"
android:layout_width="wrap_content"
android:layout_height="@dimen/dimen54dp"
android:layout_marginStart="@dimen/dimen16dp"
android:layout_marginTop="@dimen/dimen8dp"
android:layout_marginEnd="@dimen/dimen16dp"
android:layout_marginBottom="@dimen/dimen8dp"
android:layout_gravity="end"
android:text="@string/strFilter"
android:textColor="@color/colorWhite" />
</LinearLayout>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.chip.Chip
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/labelChip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="@dimen/dimen4dp"
app:chipStartPadding="@dimen/dimen8dp"
app:chipEndPadding="@dimen/dimen8dp"
app:chipIconSize="@dimen/dimen16dp"
app:chipIconVisible="true"
app:checkedIconEnabled="false"
app:chipMinHeight="@dimen/dimen32dp"
app:textEndPadding="@dimen/dimen4dp"
app:textStartPadding="@dimen/dimen4dp"
style="@style/Widget.MaterialComponents.Chip.Choice"/>

View File

@@ -946,4 +946,5 @@
<string name="search_matches_found">%1$d matches found</string>
<string name="search_no_matches">No matches found</string>
<string name="heatmap_contribution">%1$d contributions on %2$s</string>
<string name="im_mentioned">I\'m mentioned</string>
</resources>