Delete release (#1120)

Closes #1072

Co-authored-by: M M Arif <mmarif@swatian.com>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1120
Reviewed-by: qwerty287 <qwerty287@noreply.codeberg.org>
This commit is contained in:
M M Arif 2022-05-01 12:00:02 +02:00
parent bdfbbf31ef
commit 656ca5073e
27 changed files with 271 additions and 75 deletions

View File

@ -4,7 +4,7 @@ android {
compileSdkVersion 31 compileSdkVersion 31
defaultConfig { defaultConfig {
applicationId "org.mian.gitnex" applicationId "org.mian.gitnex"
minSdkVersion 22 minSdkVersion 23
targetSdkVersion 31 targetSdkVersion 31
versionCode 425 versionCode 425
versionName "4.3.0" versionName "4.3.0"

View File

@ -32,7 +32,7 @@ public class RepositoryActions {
if(response.isSuccessful()) { if(response.isSuccessful()) {
if(response.code() == 204) { if(response.code() == 204) {
MainActivity.repoCreated = true; MainActivity.reloadRepos = true;
Toasty.success(context, context.getString(R.string.starRepositorySuccess)); Toasty.success(context, context.getString(R.string.starRepositorySuccess));
} }
} }
@ -78,7 +78,7 @@ public class RepositoryActions {
if(response.isSuccessful()) { if(response.isSuccessful()) {
if(response.code() == 204) { if(response.code() == 204) {
MainActivity.repoCreated = true; MainActivity.reloadRepos = true;
Toasty.success(context, context.getString(R.string.unStarRepositorySuccess)); Toasty.success(context, context.getString(R.string.unStarRepositorySuccess));
} }
} }

View File

@ -91,7 +91,7 @@ public class CreateFileActivity extends BaseActivity {
filePath = getIntent().getStringExtra("filePath"); filePath = getIntent().getStringExtra("filePath");
fileSha = getIntent().getStringExtra("fileSha"); fileSha = getIntent().getStringExtra("fileSha");
toolbarTitle.setText(getString(R.string.deleteFileText, filePath)); toolbarTitle.setText(getString(R.string.deleteGenericTitle, filePath));
binding.newFileCreate.setText(R.string.deleteFile); binding.newFileCreate.setText(R.string.deleteFile);

View File

@ -256,7 +256,7 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
Toasty.success(ctx, getString(R.string.issueCreated)); Toasty.success(ctx, getString(R.string.issueCreated));
enableProcessButton(); enableProcessButton();
RepoDetailActivity.updateRepo = true; RepoDetailActivity.updateRepo = true;
MainActivity.repoCreated = true; MainActivity.reloadRepos = true;
finish(); finish();
} }
else if(response2.code() == 401) { else if(response2.code() == 401) {

View File

@ -180,7 +180,7 @@ public class CreatePullRequestActivity extends BaseActivity implements LabelsLis
Toasty.success(ctx, getString(R.string.prCreateSuccess)); Toasty.success(ctx, getString(R.string.prCreateSuccess));
RepoDetailActivity.updateRepo = true; RepoDetailActivity.updateRepo = true;
PullRequestsFragment.resumePullRequests = true; PullRequestsFragment.resumePullRequests = true;
MainActivity.repoCreated = true; MainActivity.reloadRepos = true;
finish(); finish();
} }
else if(response.code() == 409 || response.message().equals("Conflict")) { else if(response.code() == 409 || response.message().equals("Conflict")) {

View File

@ -178,7 +178,7 @@ public class CreateRepoActivity extends BaseActivity {
if(response.code() == 201) { if(response.code() == 201) {
MainActivity.repoCreated = true; MainActivity.reloadRepos = true;
Toasty.success(ctx, getString(R.string.repoCreated)); Toasty.success(ctx, getString(R.string.repoCreated));
enableProcessButton(); enableProcessButton();
finish(); finish();

View File

@ -69,7 +69,7 @@ import retrofit2.Callback;
public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener, BottomSheetListener { public class MainActivity extends BaseActivity implements NavigationView.OnNavigationItemSelectedListener, BottomSheetListener {
public static boolean refActivity = false; public static boolean refActivity = false;
public static boolean repoCreated = false; public static boolean reloadRepos = false;
private DrawerLayout drawer; private DrawerLayout drawer;
private TextView toolbarTitle; private TextView toolbarTitle;

View File

@ -23,11 +23,12 @@ import org.mian.gitnex.databinding.CustomRepositoryEditPropertiesDialogBinding;
import org.mian.gitnex.databinding.CustomRepositoryTransferDialogBinding; import org.mian.gitnex.databinding.CustomRepositoryTransferDialogBinding;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.contexts.RepositoryContext; import org.mian.gitnex.helpers.contexts.RepositoryContext;
import java.util.Objects;
import retrofit2.Call; import retrofit2.Call;
import retrofit2.Callback; import retrofit2.Callback;
/** /**
* Author M M Arif * @author M M Arif
*/ */
public class RepositorySettingsActivity extends BaseActivity { public class RepositorySettingsActivity extends BaseActivity {
@ -58,15 +59,9 @@ public class RepositorySettingsActivity extends BaseActivity {
initCloseListener(); initCloseListener();
closeActivity.setOnClickListener(onClickListener); closeActivity.setOnClickListener(onClickListener);
// require gitea 1.12 or higher
if(getAccount().requiresVersion("1.12.0")) {
viewBinding.transferOwnerFrame.setVisibility(View.VISIBLE);
}
viewBinding.editProperties.setOnClickListener(editProperties -> showRepositoryProperties()); viewBinding.editProperties.setOnClickListener(editProperties -> showRepositoryProperties());
viewBinding.deleteRepository.setOnClickListener(deleteRepository -> showDeleteRepository()); viewBinding.deleteRepositoryFrame.setOnClickListener(deleteRepository -> showDeleteRepository());
viewBinding.transferOwnerFrame.setOnClickListener(transferRepositoryOwnership -> showTransferRepository()); viewBinding.transferOwnerFrame.setOnClickListener(transferRepositoryOwnership -> showTransferRepository());
} }
@ -133,7 +128,7 @@ public class RepositorySettingsActivity extends BaseActivity {
Toasty.success(ctx, getString(R.string.repoTransferSuccess)); Toasty.success(ctx, getString(R.string.repoTransferSuccess));
finish(); finish();
BaseApi.getInstance(ctx, RepositoriesApi.class).deleteRepository(repository.getRepositoryId()); Objects.requireNonNull(BaseApi.getInstance(ctx, RepositoriesApi.class)).deleteRepository(repository.getRepositoryId());
Intent intent = new Intent(RepositorySettingsActivity.this, MainActivity.class); Intent intent = new Intent(RepositorySettingsActivity.this, MainActivity.class);
RepositorySettingsActivity.this.startActivity(intent); RepositorySettingsActivity.this.startActivity(intent);
} }
@ -214,7 +209,7 @@ public class RepositorySettingsActivity extends BaseActivity {
Toasty.success(ctx, getString(R.string.repoDeletionSuccess)); Toasty.success(ctx, getString(R.string.repoDeletionSuccess));
finish(); finish();
BaseApi.getInstance(ctx, RepositoriesApi.class).deleteRepository(repository.getRepositoryId()); Objects.requireNonNull(BaseApi.getInstance(ctx, RepositoriesApi.class)).deleteRepository(repository.getRepositoryId());
Intent intent = new Intent(RepositorySettingsActivity.this, MainActivity.class); Intent intent = new Intent(RepositorySettingsActivity.this, MainActivity.class);
RepositorySettingsActivity.this.startActivity(intent); RepositorySettingsActivity.this.startActivity(intent);
} }
@ -346,7 +341,8 @@ public class RepositorySettingsActivity extends BaseActivity {
repository.setRepository(response.body()); repository.setRepository(response.body());
if(!repository.getName().equals(repoName)) { if(!repository.getName().equals(repoName)) {
BaseApi.getInstance(ctx, RepositoriesApi.class).updateRepositoryOwnerAndName(repository.getOwner(), repoName, repository.getRepositoryId()); Objects.requireNonNull(BaseApi.getInstance(ctx, RepositoriesApi.class))
.updateRepositoryOwnerAndName(repository.getOwner(), repoName, repository.getRepositoryId());
Intent result = new Intent(); Intent result = new Intent();
result.putExtra("nameChanged", true); result.putExtra("nameChanged", true);
setResult(200, result); setResult(200, result);

View File

@ -10,21 +10,31 @@ import android.widget.ImageView;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.TextView; import android.widget.TextView;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.gitnex.tea4j.v2.models.Release; import org.gitnex.tea4j.v2.models.Release;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.activities.ProfileActivity; import org.mian.gitnex.activities.ProfileActivity;
import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.clients.PicassoService; import org.mian.gitnex.clients.PicassoService;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentReleasesBinding;
import org.mian.gitnex.helpers.AppUtil; import org.mian.gitnex.helpers.AppUtil;
import org.mian.gitnex.helpers.ClickListener; import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.Markdown; import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.RoundedTransformation; import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.helpers.TimeHelper; import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.helpers.TinyDB; import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.structs.FragmentRefreshListener; import org.mian.gitnex.structs.FragmentRefreshListener;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/** /**
* @author M M Arif * @author M M Arif
@ -34,12 +44,15 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
private List<Release> releasesList; private List<Release> releasesList;
private final Context context; private final Context context;
private final String repoOwner;
private final String repoName;
private OnLoadMoreListener loadMoreListener; private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true; private boolean isLoading = false, isMoreDataAvailable = true;
private final FragmentRefreshListener startDownload; private final FragmentRefreshListener startDownload;
private final FragmentReleasesBinding fragmentReleasesBinding;
static class ReleasesViewHolder extends RecyclerView.ViewHolder { protected class ReleasesViewHolder extends RecyclerView.ViewHolder {
private Release releases; private Release releases;
@ -56,6 +69,7 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
private final LinearLayout releaseTarDownloadFrame; private final LinearLayout releaseTarDownloadFrame;
private final ImageView downloadDropdownIcon; private final ImageView downloadDropdownIcon;
private final RecyclerView downloadList; private final RecyclerView downloadList;
private final ImageView optionsMenu;
private ReleasesViewHolder(View itemView) { private ReleasesViewHolder(View itemView) {
@ -75,6 +89,7 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
releaseTarDownloadFrame = itemView.findViewById(R.id.releaseTarDownloadFrame); releaseTarDownloadFrame = itemView.findViewById(R.id.releaseTarDownloadFrame);
downloadDropdownIcon = itemView.findViewById(R.id.downloadDropdownIcon); downloadDropdownIcon = itemView.findViewById(R.id.downloadDropdownIcon);
downloadList = itemView.findViewById(R.id.downloadList); downloadList = itemView.findViewById(R.id.downloadList);
optionsMenu = itemView.findViewById(R.id.releasesOptionsMenu);
downloadList.setHasFixedSize(true); downloadList.setHasFixedSize(true);
downloadList.setLayoutManager(new LinearLayoutManager(itemView.getContext())); downloadList.setLayoutManager(new LinearLayoutManager(itemView.getContext()));
@ -86,13 +101,34 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
intent.putExtra("username", releases.getAuthor().getLogin()); intent.putExtra("username", releases.getAuthor().getLogin());
context.startActivity(intent); context.startActivity(intent);
}); });
optionsMenu.setOnClickListener(v -> {
final Context context = v.getContext();
@SuppressLint("InflateParams")
View view = LayoutInflater.from(context).inflate(R.layout.bottom_sheet_release_in_list, null);
TextView deleteRelease = view.findViewById(R.id.deleteRelease);
BottomSheetDialog dialog = new BottomSheetDialog(context);
dialog.setContentView(view);
dialog.show();
deleteRelease.setOnClickListener(v1 -> {
deleteRelease(context, releases.getName(), releases.getId(), repoOwner, repoName, getBindingAdapterPosition());
dialog.dismiss();
});
});
} }
} }
public ReleasesAdapter(Context ctx, List<Release> releasesMain, FragmentRefreshListener startDownload) { public ReleasesAdapter(Context ctx, List<Release> releasesMain, FragmentRefreshListener startDownload, String repoOwner, String repoName, FragmentReleasesBinding fragmentReleasesBinding) {
this.context = ctx; this.context = ctx;
this.releasesList = releasesMain; this.releasesList = releasesMain;
this.startDownload = startDownload; this.startDownload = startDownload;
this.repoOwner = repoOwner;
this.repoName = repoName;
this.fragmentReleasesBinding = fragmentReleasesBinding;
} }
@NonNull @NonNull
@ -178,6 +214,10 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
isLoading = true; isLoading = true;
loadMoreListener.onLoadMore(); loadMoreListener.onLoadMore();
} }
if(!((RepoDetailActivity) context).repository.getPermissions().isPush()) {
holder.optionsMenu.setVisibility(View.GONE);
}
} }
@Override @Override
@ -213,4 +253,47 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
releasesList = list; releasesList = list;
notifyDataChanged(); notifyDataChanged();
} }
private void updateAdapter(int position) {
releasesList.remove(position);
notifyItemRemoved(position);
notifyItemRangeChanged(position, releasesList.size());
}
private void deleteRelease(final Context context, final String releaseName, final Long releaseId, final String owner, final String repo, int position) {
new AlertDialog.Builder(context)
.setTitle(String.format(context.getString(R.string.deleteGenericTitle), releaseName))
.setMessage(R.string.deleteReleaseConfirmation)
.setIcon(R.drawable.ic_delete)
.setPositiveButton(R.string.menuDeleteText, (dialog, whichButton) -> RetrofitClient
.getApiInterface(context).repoDeleteRelease(owner, repo, releaseId).enqueue(new Callback<>() {
@Override
public void onResponse(@NonNull Call<Void> call, @NonNull Response<Void> response) {
if(response.isSuccessful()) {
updateAdapter(position);
Toasty.success(context, context.getString(R.string.releaseDeleted));
MainActivity.reloadRepos = true;
if(getItemCount() == 0) {
fragmentReleasesBinding.noDataReleases.setVisibility(View.VISIBLE);
}
}
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<Void> call, @NonNull Throwable t) {
Toasty.error(context, context.getString(R.string.genericError));
}
}))
.setNeutralButton(R.string.cancelButton, null).show();
}
} }

View File

@ -16,6 +16,7 @@ import org.gitnex.tea4j.v2.models.Tag;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.RepoDetailActivity; import org.mian.gitnex.activities.RepoDetailActivity;
import org.mian.gitnex.clients.RetrofitClient; import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.FragmentReleasesBinding;
import org.mian.gitnex.helpers.Markdown; import org.mian.gitnex.helpers.Markdown;
import org.mian.gitnex.helpers.Toasty; import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.structs.FragmentRefreshListener; import org.mian.gitnex.structs.FragmentRefreshListener;
@ -35,11 +36,11 @@ public class TagsAdapter extends RecyclerView.Adapter<TagsAdapter.TagsViewHolder
private final String repo; private final String repo;
private final String owner; private final String owner;
private final FragmentRefreshListener startDownload; private final FragmentRefreshListener startDownload;
private final FragmentReleasesBinding fragmentReleasesBinding;
private OnLoadMoreListener loadMoreListener; private OnLoadMoreListener loadMoreListener;
private boolean isLoading = false, isMoreDataAvailable = true; private boolean isLoading = false, isMoreDataAvailable = true;
class TagsViewHolder extends RecyclerView.ViewHolder { protected class TagsViewHolder extends RecyclerView.ViewHolder {
private Tag tagsHolder; private Tag tagsHolder;
private final TextView tagName; private final TextView tagName;
@ -84,12 +85,13 @@ public class TagsAdapter extends RecyclerView.Adapter<TagsAdapter.TagsViewHolder
} }
} }
public TagsAdapter(Context ctx, List<Tag> releasesMain, String repoOwner, String repoName, FragmentRefreshListener startDownload) { public TagsAdapter(Context ctx, List<Tag> releasesMain, String repoOwner, String repoName, FragmentRefreshListener startDownload, FragmentReleasesBinding fragmentReleasesBinding) {
this.context = ctx; this.context = ctx;
this.tags = releasesMain; this.tags = releasesMain;
owner = repoOwner; owner = repoOwner;
repo = repoName; repo = repoName;
this.startDownload = startDownload; this.startDownload = startDownload;
this.fragmentReleasesBinding = fragmentReleasesBinding;
} }
@NonNull @NonNull
@ -180,10 +182,10 @@ public class TagsAdapter extends RecyclerView.Adapter<TagsAdapter.TagsViewHolder
notifyItemRangeChanged(position, tags.size()); notifyItemRangeChanged(position, tags.size());
} }
public void tagDeleteDialog(final Context context, final String tagName, final String owner, final String repo, int position) { private void tagDeleteDialog(final Context context, final String tagName, final String owner, final String repo, int position) {
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
.setTitle(String.format(context.getString(R.string.deleteTagTitle), tagName)) .setTitle(String.format(context.getString(R.string.deleteGenericTitle), tagName))
.setMessage(R.string.deleteTagConfirmation) .setMessage(R.string.deleteTagConfirmation)
.setIcon(R.drawable.ic_delete) .setIcon(R.drawable.ic_delete)
.setPositiveButton(R.string.menuDeleteText, (dialog, whichButton) -> RetrofitClient .setPositiveButton(R.string.menuDeleteText, (dialog, whichButton) -> RetrofitClient
@ -195,6 +197,9 @@ public class TagsAdapter extends RecyclerView.Adapter<TagsAdapter.TagsViewHolder
if(response.isSuccessful()) { if(response.isSuccessful()) {
updateAdapter(position); updateAdapter(position);
Toasty.success(context, context.getString(R.string.tagDeleted)); Toasty.success(context, context.getString(R.string.tagDeleted));
if(getItemCount() == 0) {
fragmentReleasesBinding.noDataReleases.setVisibility(View.VISIBLE);
}
} }
else if(response.code() == 403) { else if(response.code() == 403) {
Toasty.error(context, context.getString(R.string.authorizeError)); Toasty.error(context, context.getString(R.string.authorizeError));

View File

@ -1,16 +1,13 @@
package org.mian.gitnex.fragments; package org.mian.gitnex.fragments;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.appcompat.content.res.AppCompatResources;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment; import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.R;
import org.mian.gitnex.databinding.BottomSheetUserProfileBinding; import org.mian.gitnex.databinding.BottomSheetUserProfileBinding;
import org.mian.gitnex.structs.BottomSheetListener; import org.mian.gitnex.structs.BottomSheetListener;
@ -36,19 +33,22 @@ public class BottomSheetUserProfileFragment extends BottomSheetDialogFragment {
BottomSheetUserProfileBinding bottomSheetUserProfileBinding = BottomSheetUserProfileBinding.inflate(inflater, container, false); BottomSheetUserProfileBinding bottomSheetUserProfileBinding = BottomSheetUserProfileBinding.inflate(inflater, container, false);
if(following) { if(following) {
bottomSheetUserProfileBinding.followUnfollowUser.setText(R.string.unfollowUser); bottomSheetUserProfileBinding.unfollowUser.setVisibility(View.VISIBLE);
Drawable drawable = AppCompatResources.getDrawable(requireContext(), R.drawable.ic_person_remove); assert drawable != null; bottomSheetUserProfileBinding.followUser.setVisibility(View.GONE);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
bottomSheetUserProfileBinding.followUnfollowUser.setCompoundDrawablesRelative(drawable, null, null, null);
} }
bottomSheetUserProfileBinding.followUnfollowUser.setOnClickListener(v1 -> { bottomSheetUserProfileBinding.followUser.setOnClickListener(v1 -> {
bmListener.onButtonClicked("follow"); bmListener.onButtonClicked("follow");
dismiss(); dismiss();
}); });
bottomSheetUserProfileBinding.unfollowUser.setOnClickListener(v1 -> {
bmListener.onButtonClicked("follow");
dismiss();
});
return bottomSheetUserProfileBinding.getRoot(); return bottomSheetUserProfileBinding.getRoot();
} }
@ -60,8 +60,7 @@ public class BottomSheetUserProfileFragment extends BottomSheetDialogFragment {
bmListener = (BottomSheetListener) context; bmListener = (BottomSheetListener) context;
} }
catch (ClassCastException e) { catch (ClassCastException e) {
throw new ClassCastException(context.toString() + " must implement BottomSheetListener"); throw new ClassCastException(context + " must implement BottomSheetListener");
} }
} }
} }

View File

@ -252,10 +252,10 @@ public class ExploreRepositoriesFragment extends Fragment {
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
if(MainActivity.repoCreated) { if(MainActivity.reloadRepos) {
dataList.clear(); dataList.clear();
loadInitial(searchQuery, resultLimit); loadInitial(searchQuery, resultLimit);
MainActivity.repoCreated = false; MainActivity.reloadRepos = false;
} }
} }

View File

@ -12,10 +12,11 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.BaseActivity; import org.mian.gitnex.activities.BaseActivity;
import org.mian.gitnex.activities.CreateRepoActivity; import org.mian.gitnex.activities.CreateRepoActivity;
@ -23,6 +24,7 @@ import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.adapters.ReposListAdapter; import org.mian.gitnex.adapters.ReposListAdapter;
import org.mian.gitnex.databinding.FragmentRepositoriesBinding; import org.mian.gitnex.databinding.FragmentRepositoriesBinding;
import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.DividerItemDecorator;
import org.mian.gitnex.viewmodels.RepositoriesViewModel; import org.mian.gitnex.viewmodels.RepositoriesViewModel;
/** /**
@ -56,10 +58,13 @@ public class MyRepositoriesFragment extends Fragment {
fragmentRepositoriesBinding.recyclerView.setHasFixedSize(true); fragmentRepositoriesBinding.recyclerView.setHasFixedSize(true);
fragmentRepositoriesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); fragmentRepositoriesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(fragmentRepositoriesBinding.recyclerView.getContext(),
DividerItemDecoration.VERTICAL); RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(requireContext(), R.drawable.shape_list_divider));
fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration); fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration);
fragmentRepositoriesBinding.recyclerView.setPadding(0, 0, 0, 200);
fragmentRepositoriesBinding.recyclerView.setClipToPadding(false);
fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
page = 1; page = 1;
@ -114,10 +119,10 @@ public class MyRepositoriesFragment extends Fragment {
super.onResume(); super.onResume();
final String userLogin = ((BaseActivity) requireActivity()).getAccount().getAccount().getUserName(); final String userLogin = ((BaseActivity) requireActivity()).getAccount().getAccount().getUserName();
if(MainActivity.repoCreated) { if(MainActivity.reloadRepos) {
page = 1; page = 1;
fetchDataAsync(userLogin); fetchDataAsync(userLogin);
MainActivity.repoCreated = false; MainActivity.reloadRepos = false;
} }
} }

View File

@ -126,7 +126,7 @@ public class OrganizationTeamInfoReposFragment extends Fragment {
if(repoAdded) { if(repoAdded) {
page = 1; page = 1;
fetchDataAsync(); fetchDataAsync();
MainActivity.repoCreated = false; MainActivity.reloadRepos = false;
} }
} }

View File

@ -61,6 +61,9 @@ public class OrganizationsFragment extends Fragment {
RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(requireContext(), R.drawable.shape_list_divider)); RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(requireContext(), R.drawable.shape_list_divider));
fragmentOrganizationsBinding.recyclerView.addItemDecoration(dividerItemDecoration); fragmentOrganizationsBinding.recyclerView.addItemDecoration(dividerItemDecoration);
fragmentOrganizationsBinding.recyclerView.setPadding(0, 0, 0, 200);
fragmentOrganizationsBinding.recyclerView.setClipToPadding(false);
fragmentOrganizationsBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { fragmentOrganizationsBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
page = 1; page = 1;

View File

@ -41,6 +41,7 @@ import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom; import java.security.SecureRandom;
import java.util.List; import java.util.List;
import java.util.Objects;
import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager; import javax.net.ssl.X509TrustManager;
@ -128,7 +129,7 @@ public class ReleasesFragment extends Fragment {
releasesModel.getReleasesList(owner, repo, getContext()).observe(getViewLifecycleOwner(), releasesListMain -> { releasesModel.getReleasesList(owner, repo, getContext()).observe(getViewLifecycleOwner(), releasesListMain -> {
if(!repository.isReleasesViewTypeIsTag()) { if(!repository.isReleasesViewTypeIsTag()) {
adapter = new ReleasesAdapter(getContext(), releasesListMain, this::requestFileDownload); adapter = new ReleasesAdapter(getContext(), releasesListMain, this::requestFileDownload, repository.getOwner(), repository.getName(), fragmentReleasesBinding);
adapter.setLoadMoreListener(new ReleasesAdapter.OnLoadMoreListener() { adapter.setLoadMoreListener(new ReleasesAdapter.OnLoadMoreListener() {
@Override @Override
@ -165,7 +166,7 @@ public class ReleasesFragment extends Fragment {
releasesModel.getTagsList(owner, repo, getContext()).observe(getViewLifecycleOwner(), tagList -> { releasesModel.getTagsList(owner, repo, getContext()).observe(getViewLifecycleOwner(), tagList -> {
if(repository.isReleasesViewTypeIsTag()) { if(repository.isReleasesViewTypeIsTag()) {
tagsAdapter = new TagsAdapter(getContext(), tagList, owner, repo, this::requestFileDownload); tagsAdapter = new TagsAdapter(getContext(), tagList, owner, repo, this::requestFileDownload, fragmentReleasesBinding);
tagsAdapter.setLoadMoreListener(new TagsAdapter.OnLoadMoreListener() { tagsAdapter.setLoadMoreListener(new TagsAdapter.OnLoadMoreListener() {
@Override @Override
@ -270,7 +271,7 @@ public class ReleasesFragment extends Fragment {
OutputStream outputStream = requireContext().getContentResolver().openOutputStream(result.getData().getData()); OutputStream outputStream = requireContext().getContentResolver().openOutputStream(result.getData().getData());
AppUtil.copyProgress(response.body().byteStream(), outputStream, 0, p -> {}); AppUtil.copyProgress(Objects.requireNonNull(response.body()).byteStream(), outputStream, 0, p -> {});
builder.setContentTitle(getString(R.string.fileViewerNotificationTitleFinished)) builder.setContentTitle(getString(R.string.fileViewerNotificationTitleFinished))
.setContentText(getString(R.string.fileViewerNotificationDescriptionFinished, .setContentText(getString(R.string.fileViewerNotificationDescriptionFinished,
Uri.parse(currentDownloadUrl).getLastPathSegment())).setOngoing(false); Uri.parse(currentDownloadUrl).getLastPathSegment())).setOngoing(false);

View File

@ -126,9 +126,9 @@ public class RepositoriesByOrgFragment extends Fragment {
super.onResume(); super.onResume();
if(MainActivity.repoCreated) { if(MainActivity.reloadRepos) {
repositoriesViewModel.loadReposList(page, resultLimit, null, "org", orgName, getContext()); repositoriesViewModel.loadReposList(page, resultLimit, null, "org", orgName, getContext());
MainActivity.repoCreated = false; MainActivity.reloadRepos = false;
} }
} }

View File

@ -59,6 +59,9 @@ public class RepositoriesFragment extends Fragment {
RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(requireContext(), R.drawable.shape_list_divider)); RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(requireContext(), R.drawable.shape_list_divider));
fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration); fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration);
fragmentRepositoriesBinding.recyclerView.setPadding(0, 0, 0, 200);
fragmentRepositoriesBinding.recyclerView.setClipToPadding(false);
fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
page = 1; page = 1;
@ -112,10 +115,10 @@ public class RepositoriesFragment extends Fragment {
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
if(MainActivity.repoCreated) { if(MainActivity.reloadRepos) {
page = 1; page = 1;
fetchDataAsync(); fetchDataAsync();
MainActivity.repoCreated = false; MainActivity.reloadRepos = false;
} }
} }

View File

@ -12,16 +12,18 @@ import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.EditorInfo; import android.view.inputmethod.EditorInfo;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment; import androidx.fragment.app.Fragment;
import androidx.lifecycle.ViewModelProvider; import androidx.lifecycle.ViewModelProvider;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.mian.gitnex.R; import org.mian.gitnex.R;
import org.mian.gitnex.activities.CreateRepoActivity; import org.mian.gitnex.activities.CreateRepoActivity;
import org.mian.gitnex.activities.MainActivity; import org.mian.gitnex.activities.MainActivity;
import org.mian.gitnex.adapters.ReposListAdapter; import org.mian.gitnex.adapters.ReposListAdapter;
import org.mian.gitnex.databinding.FragmentRepositoriesBinding; import org.mian.gitnex.databinding.FragmentRepositoriesBinding;
import org.mian.gitnex.helpers.Constants; import org.mian.gitnex.helpers.Constants;
import org.mian.gitnex.helpers.DividerItemDecorator;
import org.mian.gitnex.viewmodels.RepositoriesViewModel; import org.mian.gitnex.viewmodels.RepositoriesViewModel;
/** /**
@ -53,10 +55,13 @@ public class StarredRepositoriesFragment extends Fragment {
fragmentRepositoriesBinding.recyclerView.setHasFixedSize(true); fragmentRepositoriesBinding.recyclerView.setHasFixedSize(true);
fragmentRepositoriesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); fragmentRepositoriesBinding.recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(fragmentRepositoriesBinding.recyclerView.getContext(),
DividerItemDecoration.VERTICAL); RecyclerView.ItemDecoration dividerItemDecoration = new DividerItemDecorator(ContextCompat.getDrawable(requireContext(), R.drawable.shape_list_divider));
fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration); fragmentRepositoriesBinding.recyclerView.addItemDecoration(dividerItemDecoration);
fragmentRepositoriesBinding.recyclerView.setPadding(0, 0, 0, 200);
fragmentRepositoriesBinding.recyclerView.setClipToPadding(false);
fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> { fragmentRepositoriesBinding.pullToRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
page = 1; page = 1;
@ -137,10 +142,10 @@ public class StarredRepositoriesFragment extends Fragment {
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
if(MainActivity.repoCreated) { if(MainActivity.reloadRepos) {
page = 1; page = 1;
fetchDataAsync(); fetchDataAsync();
MainActivity.repoCreated = false; MainActivity.reloadRepos = false;
} }
} }

View File

@ -57,7 +57,7 @@ public class AlertDialogs {
RepositoryContext repository) { RepositoryContext repository) {
new AlertDialog.Builder(context) new AlertDialog.Builder(context)
.setTitle(context.getString(R.string.deleteLabelTitle, labelTitle)) .setTitle(context.getString(R.string.deleteGenericTitle, labelTitle))
.setMessage(R.string.labelDeleteMessage) .setMessage(R.string.labelDeleteMessage)
.setIcon(R.drawable.ic_delete) .setIcon(R.drawable.ic_delete)
.setPositiveButton(R.string.menuDeleteText, (dialog, whichButton) -> { .setPositiveButton(R.string.menuDeleteText, (dialog, whichButton) -> {

View File

@ -85,7 +85,6 @@
android:orientation="vertical" android:orientation="vertical"
android:focusable="true" android:focusable="true"
android:clickable="true" android:clickable="true"
android:visibility="gone"
tools:visibility="visible"> tools:visibility="visible">
<TextView <TextView
@ -122,6 +121,7 @@
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/deleteRepositoryFrame"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"

View File

@ -0,0 +1,67 @@
<?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:paddingTop="6dp"
android:paddingBottom="12dp"
android:background="?attr/primaryBackgroundColor">
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/releasesListHeadFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:orientation="vertical">
<TextView
android:id="@+id/bottomSheetHeader"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="@string/release"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp" />
</LinearLayout>
<com.google.android.flexbox.FlexboxLayout
android:id="@+id/releasesListSection"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:flexWrap="wrap"
app:alignItems="stretch"
android:padding="8dp"
app:alignContent="stretch" >
<TextView
android:id="@+id/deleteRelease"
android:layout_width="98dp"
android:layout_height="100dp"
android:padding="8dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
app:layout_alignSelf="flex_start"
app:drawableTopCompat="@drawable/ic_delete"
android:text="@string/menuDeleteText"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp" />
</com.google.android.flexbox.FlexboxLayout>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View File

@ -46,7 +46,7 @@
app:alignContent="stretch" > app:alignContent="stretch" >
<TextView <TextView
android:id="@+id/followUnfollowUser" android:id="@+id/followUser"
android:layout_width="98dp" android:layout_width="98dp"
android:layout_height="100dp" android:layout_height="100dp"
android:padding="8dp" android:padding="8dp"
@ -58,6 +58,20 @@
android:textColor="?attr/primaryTextColor" android:textColor="?attr/primaryTextColor"
android:textSize="16sp" /> android:textSize="16sp" />
<TextView
android:id="@+id/unfollowUser"
android:layout_width="98dp"
android:layout_height="100dp"
android:padding="8dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:gravity="center"
app:layout_alignSelf="flex_start"
app:drawableTopCompat="@drawable/ic_person_remove"
android:text="@string/unfollowUser"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:visibility="gone" />
</com.google.android.flexbox.FlexboxLayout> </com.google.android.flexbox.FlexboxLayout>
</LinearLayout> </LinearLayout>

View File

@ -15,8 +15,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/primaryBackgroundColor" android:background="?attr/primaryBackgroundColor"
android:paddingBottom="64dp"
android:clipToPadding="false"
android:scrollbars="vertical" /> android:scrollbars="vertical" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -17,8 +17,6 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?attr/primaryBackgroundColor" android:background="?attr/primaryBackgroundColor"
android:paddingBottom="64dp"
android:clipToPadding="false"
android:scrollbars="vertical" /> android:scrollbars="vertical" />
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout> </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

View File

@ -29,16 +29,15 @@
android:textSize="16sp" android:textSize="16sp"
android:textStyle="bold" /> android:textStyle="bold" />
<TextView <ImageView
android:id="@+id/releaseType" android:id="@+id/releasesOptionsMenu"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_weight="0" android:layout_weight="0"
android:background="@drawable/shape_stable_release" android:layout_gravity="center_vertical|end"
android:paddingLeft="8dp" android:contentDescription="@string/labelMenuContentDesc"
android:paddingRight="8dp" android:background="?android:attr/selectableItemBackgroundBorderless"
android:textColor="@color/colorWhite" android:src="@drawable/ic_dotted_menu_horizontal" />
android:textSize="14sp" />
</LinearLayout> </LinearLayout>
@ -77,6 +76,25 @@
android:gravity="end" android:gravity="end"
android:orientation="vertical"> android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="end|center_vertical"
android:layout_marginBottom="6dp"
android:orientation="horizontal">
<TextView
android:id="@+id/releaseType"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_stable_release"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:textColor="@color/colorWhite"
android:textSize="14sp" />
</LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"

View File

@ -270,7 +270,6 @@
<string name="alertDialogTokenRevokedTitle">Authorization Error</string> <string name="alertDialogTokenRevokedTitle">Authorization Error</string>
<string name="alertDialogTokenRevokedMessage">It seems that the Access Token is revoked OR your are not allowed to see these contents.\n\nIn case of revoked Token, please logout and login again</string> <string name="alertDialogTokenRevokedMessage">It seems that the Access Token is revoked OR your are not allowed to see these contents.\n\nIn case of revoked Token, please logout and login again</string>
<string name="deleteLabelTitle">Delete %s</string>
<string name="labelDeleteMessage">Do you really want to delete this label?</string> <string name="labelDeleteMessage">Do you really want to delete this label?</string>
<!-- org tabbed layout str --> <!-- org tabbed layout str -->
@ -404,6 +403,8 @@
<string name="tagNameErrorEmpty">Tag name is empty</string> <string name="tagNameErrorEmpty">Tag name is empty</string>
<string name="titleErrorEmpty">Title is empty</string> <string name="titleErrorEmpty">Title is empty</string>
<string name="releaseCreatedText">New release created</string> <string name="releaseCreatedText">New release created</string>
<string name="deleteReleaseConfirmation">Do you really want to delete this release?</string>
<string name="releaseDeleted">Release deleted</string>
<!-- release --> <!-- release -->
<string name="loginOTPTypeError">OTP code should be numbers</string> <string name="loginOTPTypeError">OTP code should be numbers</string>
@ -469,7 +470,7 @@
<string name="menuEditText">Edit</string> <string name="menuEditText">Edit</string>
<string name="menuDeleteText">Delete</string> <string name="menuDeleteText">Delete</string>
<string name="menuCopyText">Copy</string> <string name="menuCopyText">Copy</string>
<string name="menuQuoteText">Quote and Reply</string> <string name="menuQuoteText">Quote Reply</string>
<string name="colorfulBulletSpan" translatable="false">\u0020\u0020\u0020\u25CF\u0020\u0020\u0020</string> <string name="colorfulBulletSpan" translatable="false">\u0020\u0020\u0020\u25CF\u0020\u0020\u0020</string>
<string name="modifiedText">edited</string> <string name="modifiedText">edited</string>
<string name="saveButton">Save</string> <string name="saveButton">Save</string>
@ -506,6 +507,7 @@
<string name="download">Download</string> <string name="download">Download</string>
<string name="reopen">Reopen</string> <string name="reopen">Reopen</string>
<string name="openInBrowser">Open in Browser</string> <string name="openInBrowser">Open in Browser</string>
<string name="deleteGenericTitle">Delete %s</string>
<!-- generic copy --> <!-- generic copy -->
<string name="exploreUsers">Explore users</string> <string name="exploreUsers">Explore users</string>
@ -561,7 +563,6 @@
<string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string> <string name="excludeFilesInFileViewer">This file type/size is not supported in file viewer. You can download it from the menu.</string>
<string name="deleteFile">Delete This File</string> <string name="deleteFile">Delete This File</string>
<string name="editFile">Edit This File</string> <string name="editFile">Edit This File</string>
<string name="deleteFileText">Delete %1$s</string>
<string name="deleteFileMessage">File is set for deletion by branch %1$s</string> <string name="deleteFileMessage">File is set for deletion by branch %1$s</string>
<string name="editFileText">Edit %1$s</string> <string name="editFileText">Edit %1$s</string>
<string name="editFileMessage">File is modified by branch %1$s</string> <string name="editFileMessage">File is modified by branch %1$s</string>
@ -750,7 +751,7 @@
<string name="tagCreated">Tag created</string> <string name="tagCreated">Tag created</string>
<string name="asRef">Use as reference</string> <string name="asRef">Use as reference</string>
<string name="deleteTagConfirmation">Do you really want to delete this tag?</string> <string name="deleteTagConfirmation">Do you really want to delete this tag?</string>
<string name="deleteTagTitle">Delete tag %s</string>
<string name="tagDeleted">Tag deleted</string> <string name="tagDeleted">Tag deleted</string>
<string name="tagDeleteError">A tag attached to a release cannot be deleted directly</string> <string name="tagDeleteError">A tag attached to a release cannot be deleted directly</string>
<string name="useCustomTabs">Use Custom Tabs</string> <string name="useCustomTabs">Use Custom Tabs</string>