From f79d227bff3d16ae759fbd9b0ab3892da09d8660 Mon Sep 17 00:00:00 2001 From: qwerty287 Date: Sat, 12 Feb 2022 14:41:11 +0100 Subject: [PATCH] Add support for tags (#1002) Closes #983 TODO - [x] create tags - [x] view tags - [x] apply pagination - [x] delete tags Co-authored-by: qwerty287 Co-authored-by: M M Arif Co-authored-by: M M Arif Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1002 Reviewed-by: M M Arif Co-authored-by: qwerty287 Co-committed-by: qwerty287 --- app/build.gradle | 2 +- .../activities/CreateReleaseActivity.java | 81 +++++++- .../gitnex/activities/RepoDetailActivity.java | 22 +++ .../mian/gitnex/adapters/ReleasesAdapter.java | 38 +++- .../org/mian/gitnex/adapters/TagsAdapter.java | 174 ++++++++++++++++++ .../BottomSheetReleasesTagsFragment.java | 55 ++++++ .../gitnex/fragments/ReleasesFragment.java | 129 ++++++++++--- .../org/mian/gitnex/helpers/AlertDialogs.java | 33 ++++ .../gitnex/viewmodels/ReleasesViewModel.java | 133 ++++++++++++- .../res/layout/activity_create_release.xml | 8 + .../res/layout/bottom_sheet_releases_tags.xml | 53 ++++++ .../res/layout/bottom_sheet_tag_in_list.xml | 40 ++++ app/src/main/res/layout/list_tags.xml | 150 +++++++++++++++ .../main/res/menu/filter_menu_releases.xml | 12 ++ app/src/main/res/values/strings.xml | 8 + 15 files changed, 908 insertions(+), 30 deletions(-) create mode 100644 app/src/main/java/org/mian/gitnex/adapters/TagsAdapter.java create mode 100644 app/src/main/java/org/mian/gitnex/fragments/BottomSheetReleasesTagsFragment.java create mode 100644 app/src/main/res/layout/bottom_sheet_releases_tags.xml create mode 100644 app/src/main/res/layout/bottom_sheet_tag_in_list.xml create mode 100644 app/src/main/res/layout/list_tags.xml create mode 100644 app/src/main/res/menu/filter_menu_releases.xml diff --git a/app/build.gradle b/app/build.gradle index 3480e2d8..8c2c58a8 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.29" + implementation "org.codeberg.gitnex:tea4j:1.0.30" 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/CreateReleaseActivity.java b/app/src/main/java/org/mian/gitnex/activities/CreateReleaseActivity.java index 2de79fd6..d8a3b82a 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CreateReleaseActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CreateReleaseActivity.java @@ -15,6 +15,8 @@ import android.widget.EditText; import android.widget.ImageView; import androidx.annotation.NonNull; import org.gitnex.tea4j.models.Branches; +import org.gitnex.tea4j.models.CreateTagOptions; +import org.gitnex.tea4j.models.GitTag; import org.gitnex.tea4j.models.Releases; import org.mian.gitnex.R; import org.mian.gitnex.clients.RetrofitClient; @@ -44,6 +46,7 @@ public class CreateReleaseActivity extends BaseActivity { private CheckBox releaseDraft; private Button createNewRelease; private String selectedBranch; + private Button createNewTag; private String repoOwner; private String repoName; @@ -97,6 +100,7 @@ public class CreateReleaseActivity extends BaseActivity { getBranches(Authorization.get(ctx), repoOwner, repoName); createNewRelease = activityCreateReleaseBinding.createNewRelease; + createNewTag = activityCreateReleaseBinding.createNewTag; disableProcessButton(); if(!connToInternet) { @@ -108,6 +112,79 @@ public class CreateReleaseActivity extends BaseActivity { createNewRelease.setOnClickListener(createReleaseListener); } + createNewTag.setOnClickListener(v -> createNewTag()); + + } + + private void createNewTag() { + boolean connToInternet = AppUtil.hasNetworkConnection(appCtx); + + String tagName = releaseTagName.getText().toString(); + String message = releaseTitle.getText().toString() + "\n\n" + releaseContent.getText().toString(); + + if(!connToInternet) { + Toasty.error(ctx, getResources().getString(R.string.checkNetConnection)); + return; + } + + if(tagName.equals("")) { + Toasty.error(ctx, getString(R.string.tagNameErrorEmpty)); + return; + } + + if(selectedBranch == null) { + Toasty.error(ctx, getString(R.string.selectBranchError)); + return; + } + + disableProcessButton(); + + CreateTagOptions createReleaseJson = new CreateTagOptions(message, tagName, selectedBranch); + + Call call = RetrofitClient + .getApiInterface(ctx) + .createTag(Authorization.get(ctx), repoOwner, repoName, createReleaseJson); + + call.enqueue(new Callback() { + + @Override + public void onResponse(@NonNull Call call, @NonNull retrofit2.Response response) { + + if (response.code() == 201) { + tinyDB.putBoolean("updateReleases", true); + Toasty.success(ctx, getString(R.string.tagCreated)); + finish(); + } + else if(response.code() == 401) { + enableProcessButton(); + AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle), + ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage), + ctx.getResources().getString(R.string.cancelButton), + ctx.getResources().getString(R.string.navLogout)); + } + else if(response.code() == 403) { + enableProcessButton(); + Toasty.error(ctx, ctx.getString(R.string.authorizeError)); + } + else if(response.code() == 404) { + enableProcessButton(); + Toasty.warning(ctx, ctx.getString(R.string.apiNotFound)); + } + else { + enableProcessButton(); + Toasty.error(ctx, ctx.getString(R.string.genericError)); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Log.e("onFailure", t.toString()); + enableProcessButton(); + } + }); + + + } private final View.OnClickListener createReleaseListener = v -> processNewRelease(); @@ -268,12 +345,12 @@ public class CreateReleaseActivity extends BaseActivity { } private void disableProcessButton() { - + createNewTag.setEnabled(false); createNewRelease.setEnabled(false); } private void enableProcessButton() { - + createNewTag.setEnabled(true); createNewRelease.setEnabled(true); } 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 09166f2e..edc2a39d 100644 --- a/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/RepoDetailActivity.java @@ -39,6 +39,7 @@ import org.mian.gitnex.database.models.UserAccount; import org.mian.gitnex.fragments.BottomSheetIssuesFilterFragment; import org.mian.gitnex.fragments.BottomSheetMilestonesFilterFragment; import org.mian.gitnex.fragments.BottomSheetPullRequestFilterFragment; +import org.mian.gitnex.fragments.BottomSheetReleasesTagsFragment; import org.mian.gitnex.fragments.BottomSheetRepoFragment; import org.mian.gitnex.fragments.CollaboratorsFragment; import org.mian.gitnex.fragments.FilesFragment; @@ -76,6 +77,7 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe private FragmentRefreshListener fragmentRefreshListenerMilestone; private FragmentRefreshListener fragmentRefreshListenerFiles; private FragmentRefreshListener fragmentRefreshListenerFilterIssuesByMilestone; + private FragmentRefreshListener fragmentRefreshListenerReleases; private String repositoryOwner; private String repositoryName; @@ -388,6 +390,11 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe ctx.startActivity(intent); return true; } + else if(id == R.id.filterReleases && new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.15.0")) { + BottomSheetReleasesTagsFragment bottomSheetReleasesTagsFragment = new BottomSheetReleasesTagsFragment(); + bottomSheetReleasesTagsFragment.show(getSupportFragmentManager(), "repoFilterReleasesMenuBottomSheet"); + return true; + } return super.onOptionsItemSelected(item); @@ -498,6 +505,16 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe startActivity(new Intent(RepoDetailActivity.this, CreatePullRequestActivity.class)); break; + case "tags": + if(getFragmentRefreshListenerReleases() != null) { + getFragmentRefreshListenerReleases().onRefresh("tags"); + } + break; + case "releases": + if(getFragmentRefreshListenerReleases() != null) { + getFragmentRefreshListenerReleases().onRefresh("releases"); + } + break; } } @@ -819,4 +836,9 @@ public class RepoDetailActivity extends BaseActivity implements BottomSheetListe public void setFragmentRefreshListenerFiles(FragmentRefreshListener fragmentRefreshListenerFiles) { this.fragmentRefreshListenerFiles = fragmentRefreshListenerFiles; } + //Releases interface + public FragmentRefreshListener getFragmentRefreshListenerReleases() { return fragmentRefreshListenerReleases; } + + public void setFragmentRefreshListenerReleases(FragmentRefreshListener fragmentRefreshListener) { this.fragmentRefreshListenerReleases = fragmentRefreshListener; } + } diff --git a/app/src/main/java/org/mian/gitnex/adapters/ReleasesAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/ReleasesAdapter.java index 279b420f..c13e2dad 100644 --- a/app/src/main/java/org/mian/gitnex/adapters/ReleasesAdapter.java +++ b/app/src/main/java/org/mian/gitnex/adapters/ReleasesAdapter.java @@ -32,9 +32,12 @@ import java.util.Locale; public class ReleasesAdapter extends RecyclerView.Adapter { - private final List releasesList; + private List releasesList; private final Context context; + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + static class ReleasesViewHolder extends RecyclerView.ViewHolder { private Releases releases; @@ -172,6 +175,11 @@ public class ReleasesAdapter extends RecyclerView.Adapter= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } } @Override @@ -179,4 +187,32 @@ public class ReleasesAdapter extends RecyclerView.Adapter list) { + releasesList = list; + notifyDataChanged(); + } + } diff --git a/app/src/main/java/org/mian/gitnex/adapters/TagsAdapter.java b/app/src/main/java/org/mian/gitnex/adapters/TagsAdapter.java new file mode 100644 index 00000000..075f9312 --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/adapters/TagsAdapter.java @@ -0,0 +1,174 @@ +package org.mian.gitnex.adapters; + +import android.annotation.SuppressLint; +import android.content.Context; +import android.text.method.LinkMovementMethod; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.core.text.HtmlCompat; +import androidx.recyclerview.widget.RecyclerView; +import com.google.android.material.bottomsheet.BottomSheetDialog; +import org.gitnex.tea4j.models.GitTag; +import org.mian.gitnex.R; +import org.mian.gitnex.helpers.AlertDialogs; +import org.mian.gitnex.helpers.Markdown; +import org.mian.gitnex.helpers.TinyDB; +import java.util.List; + +/** + * Author qwerty287 + */ + +public class TagsAdapter extends RecyclerView.Adapter { + + private List tags; + private final Context context; + private final String repo; + private final String owner; + private Context ctx; + + private OnLoadMoreListener loadMoreListener; + private boolean isLoading = false, isMoreDataAvailable = true; + + static class TagsViewHolder extends RecyclerView.ViewHolder { + + private final TextView tagName; + private final TextView tagBody; + private final LinearLayout downloadFrame; + private final LinearLayout downloads; + private final TextView releaseZipDownload; + private final TextView releaseTarDownload; + private final ImageView downloadDropdownIcon; + private final ImageView options; + + private TagsViewHolder(View itemView) { + + super(itemView); + + tagName = itemView.findViewById(R.id.tagName); + tagBody = itemView.findViewById(R.id.tagBodyContent); + downloadFrame = itemView.findViewById(R.id.downloadFrame); + downloads = itemView.findViewById(R.id.downloads); + releaseZipDownload = itemView.findViewById(R.id.releaseZipDownload); + releaseTarDownload = itemView.findViewById(R.id.releaseTarDownload); + downloadDropdownIcon = itemView.findViewById(R.id.downloadDropdownIcon); + options = itemView.findViewById(R.id.tagsOptionsMenu); + } + } + + public TagsAdapter(Context ctx, List releasesMain, String repoOwner, String repoName) { + this.context = ctx; + this.tags = releasesMain; + owner = repoOwner; + repo = repoName; + } + + @NonNull + @Override + public TagsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_tags, parent, false); + return new TagsViewHolder(v); + } + + @Override + public void onBindViewHolder(@NonNull TagsViewHolder holder, int position) { + + GitTag currentItem = tags.get(position); + + holder.tagName.setText(currentItem.getName()); + + if(!currentItem.getMessage().equals("")) { + Markdown.render(context, currentItem.getMessage(), holder.tagBody); + } + else { + holder.tagBody.setVisibility(View.GONE); + } + + holder.downloadFrame.setOnClickListener(v -> { + + if(holder.downloads.getVisibility() == View.GONE) { + + holder.downloadDropdownIcon.setImageResource(R.drawable.ic_chevron_down); + holder.downloads.setVisibility(View.VISIBLE); + } + else { + + holder.downloadDropdownIcon.setImageResource(R.drawable.ic_chevron_right); + holder.downloads.setVisibility(View.GONE); + } + }); + + if(!TinyDB.getInstance(ctx).getBoolean("isRepoAdmin")) { + holder.options.setVisibility(View.GONE); + } + + holder.options.setOnClickListener(v -> { + final Context context = v.getContext(); + + @SuppressLint("InflateParams") + View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_tag_in_list, null); + + TextView delete = view.findViewById(R.id.tagMenuDelete); + + BottomSheetDialog dialog = new BottomSheetDialog(context); + dialog.setContentView(view); + dialog.show(); + + delete.setOnClickListener(v1 -> { + AlertDialogs.tagDeleteDialog(context, currentItem.getName(), owner, repo); + dialog.dismiss(); + }); + }); + + holder.releaseZipDownload.setText( + HtmlCompat.fromHtml("" + context.getResources().getString(R.string.zipArchiveDownloadReleasesTab) + " ", HtmlCompat.FROM_HTML_MODE_LEGACY)); + holder.releaseZipDownload.setMovementMethod(LinkMovementMethod.getInstance()); + + holder.releaseTarDownload.setText( + HtmlCompat.fromHtml("" + context.getResources().getString(R.string.tarArchiveDownloadReleasesTab) + " ", HtmlCompat.FROM_HTML_MODE_LEGACY)); + holder.releaseTarDownload.setMovementMethod(LinkMovementMethod.getInstance()); + + if(position >= getItemCount() - 1 && isMoreDataAvailable && !isLoading && loadMoreListener != null) { + isLoading = true; + loadMoreListener.onLoadMore(); + } + } + + @Override + public int getItemCount() { + return tags.size(); + } + + public void setMoreDataAvailable(boolean moreDataAvailable) { + isMoreDataAvailable = moreDataAvailable; + if(!isMoreDataAvailable) { + loadMoreListener.onLoadFinished(); + } + } + + public void notifyDataChanged() { + notifyDataSetChanged(); + isLoading = false; + loadMoreListener.onLoadFinished(); + } + + public interface OnLoadMoreListener { + void onLoadMore(); + void onLoadFinished(); + } + + public void setLoadMoreListener(OnLoadMoreListener loadMoreListener) { + this.loadMoreListener = loadMoreListener; + } + + public void updateList(List list) { + tags = list; + notifyDataChanged(); + } + +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/BottomSheetReleasesTagsFragment.java b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetReleasesTagsFragment.java new file mode 100644 index 00000000..912eaf2a --- /dev/null +++ b/app/src/main/java/org/mian/gitnex/fragments/BottomSheetReleasesTagsFragment.java @@ -0,0 +1,55 @@ +package org.mian.gitnex.fragments; + +import android.content.Context; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.material.bottomsheet.BottomSheetDialogFragment; +import org.mian.gitnex.databinding.BottomSheetReleasesTagsBinding; +import org.mian.gitnex.structs.BottomSheetListener; + +/** + * Author opyale + */ + +public class BottomSheetReleasesTagsFragment extends BottomSheetDialogFragment { + + private BottomSheetListener bmListener; + + @Override + public void onAttach(@NonNull Context context) { + + super.onAttach(context); + + try { + bmListener = (BottomSheetListener) context; + } + catch(ClassCastException e) { + throw new ClassCastException(context.toString() + " must implement BottomSheetListener"); + } + } + + @Nullable + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + + BottomSheetReleasesTagsBinding binding = BottomSheetReleasesTagsBinding.inflate(inflater, container, false); + + binding.tags.setOnClickListener(v1 -> { + + bmListener.onButtonClicked("tags"); + dismiss(); + }); + + binding.releases.setOnClickListener(v12 -> { + + bmListener.onButtonClicked("releases"); + dismiss(); + }); + + return binding.getRoot(); + } +} diff --git a/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java b/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java index af6ce998..c1fff529 100644 --- a/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java +++ b/app/src/main/java/org/mian/gitnex/fragments/ReleasesFragment.java @@ -5,6 +5,8 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ProgressBar; @@ -19,10 +21,14 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import org.gitnex.tea4j.models.Releases; +import org.mian.gitnex.R; +import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.adapters.ReleasesAdapter; +import org.mian.gitnex.adapters.TagsAdapter; import org.mian.gitnex.databinding.FragmentReleasesBinding; import org.mian.gitnex.helpers.Authorization; import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Version; import org.mian.gitnex.viewmodels.ReleasesViewModel; import java.util.List; @@ -34,6 +40,7 @@ public class ReleasesFragment extends Fragment { private ProgressBar mProgressBar; private ReleasesAdapter adapter; + private TagsAdapter tagsAdapter; private RecyclerView mRecyclerView; private TextView noDataReleases; private static String repoNameF = "param2"; @@ -42,6 +49,9 @@ public class ReleasesFragment extends Fragment { private String repoName; private String repoOwner; private String releaseTag; + private boolean viewTypeIsTags = false; + private int page = 1; + private int pageReleases = 1; private OnFragmentInteractionListener mListener; @@ -90,12 +100,30 @@ public class ReleasesFragment extends Fragment { swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { swipeRefresh.setRefreshing(false); - ReleasesViewModel.loadReleasesList(Authorization.get(getContext()), repoOwner, repoName, getContext()); + if(viewTypeIsTags) { + ReleasesViewModel.loadTagsList(Authorization.get(getContext()), repoOwner, repoName, getContext()); + } else { + ReleasesViewModel.loadReleasesList(Authorization.get(getContext()), repoOwner, repoName, getContext()); + } + mProgressBar.setVisibility(View.VISIBLE); }, 50)); fetchDataAsync(Authorization.get(getContext()), repoOwner, repoName); + setHasOptionsMenu(true); + ((RepoDetailActivity) requireActivity()).setFragmentRefreshListenerReleases(type -> { + viewTypeIsTags = type.equals("tags"); + page = 1; + pageReleases = 1; + if(viewTypeIsTags) { + ReleasesViewModel.loadTagsList(Authorization.get(getContext()), repoOwner, repoName, getContext()); + } else { + ReleasesViewModel.loadReleasesList(Authorization.get(getContext()), repoOwner, repoName, getContext()); + } + mProgressBar.setVisibility(View.VISIBLE); + }); + return fragmentReleasesBinding.getRoot(); } @@ -107,10 +135,14 @@ public class ReleasesFragment extends Fragment { TinyDB tinyDb = TinyDB.getInstance(getContext()); if(tinyDb.getBoolean("updateReleases")) { - ReleasesViewModel.loadReleasesList(Authorization.get(getContext()), repoOwner, repoName, getContext()); - tinyDb.putBoolean("updateReleases", false); + if(viewTypeIsTags) { + ReleasesViewModel.loadTagsList(Authorization.get(getContext()), repoOwner, repoName, getContext()); + } else { + ReleasesViewModel.loadReleasesList(Authorization.get(getContext()), repoOwner, repoName, getContext()); + } + mProgressBar.setVisibility(View.VISIBLE); + tinyDb.putBoolean("updateReleases", false); } - } public void onButtonPressed(Uri uri) { @@ -136,27 +168,73 @@ public class ReleasesFragment extends Fragment { releasesModel.getReleasesList(instanceToken, owner, repo, getContext()).observe(getViewLifecycleOwner(), new Observer>() { @Override public void onChanged(@Nullable List releasesListMain) { - adapter = new ReleasesAdapter(getContext(), releasesListMain); - if(adapter.getItemCount() > 0) { - mRecyclerView.setAdapter(adapter); - if(releasesListMain != null && releaseTag != null) { - int index = getReleaseIndex(releaseTag, releasesListMain); - releaseTag = null; - if(index != -1) { - mRecyclerView.scrollToPosition(index); - } - } - noDataReleases.setVisibility(View.GONE); - } - else { - adapter.notifyDataSetChanged(); - mRecyclerView.setAdapter(adapter); - noDataReleases.setVisibility(View.VISIBLE); - } - mProgressBar.setVisibility(View.GONE); + if(!viewTypeIsTags) { + adapter = new ReleasesAdapter(getContext(), releasesListMain); + adapter.setLoadMoreListener(new ReleasesAdapter.OnLoadMoreListener() { + + @Override + public void onLoadMore() { + pageReleases += 1; + ReleasesViewModel.loadMoreReleases(instanceToken, owner, repo , pageReleases, getContext(), adapter); + mProgressBar.setVisibility(View.VISIBLE); + } + + @Override + public void onLoadFinished() { + mProgressBar.setVisibility(View.GONE); + } + }); + if(adapter.getItemCount() > 0) { + mRecyclerView.setAdapter(adapter); + if(releasesListMain != null && releaseTag != null) { + int index = getReleaseIndex(releaseTag, releasesListMain); + releaseTag = null; + if(index != -1) { + mRecyclerView.scrollToPosition(index); + } + } + noDataReleases.setVisibility(View.GONE); + } + else { + adapter.notifyDataSetChanged(); + mRecyclerView.setAdapter(adapter); + noDataReleases.setVisibility(View.VISIBLE); + } + mProgressBar.setVisibility(View.GONE); + } } }); + releasesModel.getTagsList(instanceToken, owner, repo, getContext()).observe(getViewLifecycleOwner(), tagList -> { + if(viewTypeIsTags) { + tagsAdapter = new TagsAdapter(getContext(), tagList, owner, repo); + tagsAdapter.setLoadMoreListener(new TagsAdapter.OnLoadMoreListener() { + + @Override + public void onLoadMore() { + page += 1; + ReleasesViewModel.loadMoreTags(instanceToken, owner, repo , page, getContext(), tagsAdapter); + mProgressBar.setVisibility(View.VISIBLE); + } + + @Override + public void onLoadFinished() { + mProgressBar.setVisibility(View.GONE); + } + }); + if(tagsAdapter.getItemCount() > 0) { + mRecyclerView.setAdapter(tagsAdapter); + noDataReleases.setVisibility(View.GONE); + } + else { + tagsAdapter.notifyDataSetChanged(); + mRecyclerView.setAdapter(tagsAdapter); + noDataReleases.setVisibility(View.VISIBLE); + } + mProgressBar.setVisibility(View.GONE); + } + }); + } private static int getReleaseIndex(String tag, List releases) { @@ -168,4 +246,11 @@ public class ReleasesFragment extends Fragment { return -1; } + @Override + public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) { + if(new Version(TinyDB.getInstance(requireContext()).getString("giteaVersion")).less("1.15.0")) + return; + inflater.inflate(R.menu.filter_menu_releases, menu); + super.onCreateOptionsMenu(menu, inflater); + } } diff --git a/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java b/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java index 091ddbec..f561336a 100644 --- a/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java +++ b/app/src/main/java/org/mian/gitnex/helpers/AlertDialogs.java @@ -6,6 +6,7 @@ import android.content.Intent; import android.graphics.Color; import android.graphics.drawable.ColorDrawable; import android.widget.Button; +import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import org.mian.gitnex.R; import org.mian.gitnex.actions.CollaboratorActions; @@ -13,6 +14,10 @@ import org.mian.gitnex.actions.PullRequestActions; import org.mian.gitnex.actions.TeamActions; import org.mian.gitnex.activities.CreateLabelActivity; import org.mian.gitnex.activities.LoginActivity; +import org.mian.gitnex.clients.RetrofitClient; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; /** * Author M M Arif @@ -87,6 +92,34 @@ public class AlertDialogs { } + public static void tagDeleteDialog(final Context context, final String tagName, final String owner, final String repo) { + new AlertDialog.Builder(context) + .setTitle(String.format(context.getString(R.string.deleteTagTitle), tagName)) + .setMessage(R.string.deleteTagConfirmation) + .setIcon(R.drawable.ic_delete) + .setPositiveButton(R.string.menuDeleteText, (dialog, whichButton) -> RetrofitClient.getApiInterface(context).deleteTag(Authorization.get(context), owner, repo, tagName).enqueue(new Callback() { + + @Override + public void onResponse(@NonNull Call call, @NonNull Response response) { + if(response.isSuccessful()) { + Toasty.success(context, context.getString(R.string.tagDeleted)); + } + else if(response.code() == 403) { + Toasty.error(context, context.getString(R.string.authorizeError)); + } + else { + Toasty.error(context, context.getString(R.string.genericError)); + } + } + + @Override + public void onFailure(@NonNull Call call, @NonNull Throwable t) { + Toasty.error(context, context.getString(R.string.genericError)); + } + })) + .setNeutralButton(R.string.cancelButton, null).show(); + } + public static void collaboratorRemoveDialog(final Context context, final String userNameMain, String title, String message, String positiveButton, String negativeButton, final String searchKeyword) { new AlertDialog.Builder(context) diff --git a/app/src/main/java/org/mian/gitnex/viewmodels/ReleasesViewModel.java b/app/src/main/java/org/mian/gitnex/viewmodels/ReleasesViewModel.java index ea7de358..5dbbbfff 100644 --- a/app/src/main/java/org/mian/gitnex/viewmodels/ReleasesViewModel.java +++ b/app/src/main/java/org/mian/gitnex/viewmodels/ReleasesViewModel.java @@ -6,8 +6,14 @@ import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; import androidx.lifecycle.MutableLiveData; import androidx.lifecycle.ViewModel; +import org.gitnex.tea4j.models.GitTag; import org.gitnex.tea4j.models.Releases; +import org.mian.gitnex.adapters.ReleasesAdapter; +import org.mian.gitnex.adapters.TagsAdapter; import org.mian.gitnex.clients.RetrofitClient; +import org.mian.gitnex.helpers.Constants; +import org.mian.gitnex.helpers.TinyDB; +import org.mian.gitnex.helpers.Version; import java.util.List; import retrofit2.Call; import retrofit2.Callback; @@ -20,10 +26,17 @@ import retrofit2.Response; public class ReleasesViewModel extends ViewModel { private static MutableLiveData> releasesList; + private static int resultLimit = Constants.resultLimitOldGiteaInstances; public LiveData> getReleasesList(String token, String owner, String repo, Context ctx) { releasesList = new MutableLiveData<>(); + + // if gitea is 1.12 or higher use the new limit + if(new Version(TinyDB.getInstance(ctx).getString("giteaVersion")).higherOrEqual("1.12.0")) { + resultLimit = Constants.resultLimitNewGiteaInstances; + } + loadReleasesList(token, owner, repo, ctx); return releasesList; @@ -33,7 +46,7 @@ public class ReleasesViewModel extends ViewModel { Call> call = RetrofitClient .getApiInterface(ctx) - .getReleases(token, owner, repo); + .getReleases(token, owner, repo, 1, resultLimit); call.enqueue(new Callback>() { @@ -42,18 +55,130 @@ public class ReleasesViewModel extends ViewModel { if (response.isSuccessful()) { releasesList.postValue(response.body()); - } else { + } + else { Log.i("onResponse", String.valueOf(response.code())); } - } @Override public void onFailure(@NonNull Call> call, Throwable t) { Log.i("onFailure", t.toString()); } - }); } + public static void loadMoreReleases(String token, String owner, String repo, int page, Context ctx, ReleasesAdapter adapter) { + + Call> call = RetrofitClient + .getApiInterface(ctx) + .getReleases(token, owner, repo, page, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if (response.isSuccessful()) { + List list = releasesList.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 { + Log.i("onResponse", String.valueOf(response.code())); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.i("onFailure", t.toString()); + } + }); + } + + private static MutableLiveData> tagsList; + + public LiveData> getTagsList(String token, String owner, String repo, Context ctx) { + + tagsList = new MutableLiveData<>(); + + // if gitea is 1.12 or higher use the new limit + if(new Version(TinyDB.getInstance(ctx).getString("giteaVersion")).higherOrEqual("1.12.0")) { + resultLimit = Constants.resultLimitNewGiteaInstances; + } + + loadTagsList(token, owner, repo, ctx); + + return tagsList; + } + + public static void loadTagsList(String token, String owner, String repo, Context ctx) { + + Call> call = RetrofitClient + .getApiInterface(ctx) + .getTags(token, owner, repo, 1, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if (response.isSuccessful()) { + tagsList.postValue(response.body()); + } + else { + Log.i("onResponse", String.valueOf(response.code())); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.i("onFailure", t.toString()); + } + }); + } + public static void loadMoreTags(String token, String owner, String repo, int page, Context ctx, TagsAdapter adapter) { + + Call> call = RetrofitClient + .getApiInterface(ctx) + .getTags(token, owner, repo, page, resultLimit); + + call.enqueue(new Callback>() { + + @Override + public void onResponse(@NonNull Call> call, @NonNull Response> response) { + + if (response.isSuccessful()) { + + List list = tagsList.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 { + Log.i("onResponse", String.valueOf(response.code())); + } + } + + @Override + public void onFailure(@NonNull Call> call, @NonNull Throwable t) { + Log.i("onFailure", t.toString()); + } + }); + } } diff --git a/app/src/main/res/layout/activity_create_release.xml b/app/src/main/res/layout/activity_create_release.xml index 4e90105a..cd26b21d 100644 --- a/app/src/main/res/layout/activity_create_release.xml +++ b/app/src/main/res/layout/activity_create_release.xml @@ -193,6 +193,14 @@ android:text="@string/newCreateButtonCopy" android:textColor="@color/btnTextColor" /> +