Hide actions if the user can't use them (#977)

closes #919

TODO

- [X] repo and file actions (create release, label...)
	- [X] allow for repo admins
- [x] label actions (edit, delete)
	- [x] allow for repo admins
- [X] issue/pr action that are available for creators (close...)
	- [X] allow for creator
    - [X] allow for repo admins
- [x] pr actions that are allowed when having push access to pr source (there was a bug in Gitea that makes that this was not working and these features were not accessible -> https://github.com/go-gitea/gitea/issues/17181)
    - [x] allow deleting of head branch/updates only if you can do this
- [x] issue/pr action that are available for repo admins (merge)
    - [x] allow for repo admins
- [x] milestone actions (close/reopen)
    - [x] allow for repo admins
- [x] comment actions (delete, edit...)
	- [X] allow for creators
    - [x] allow for repo admins
- [x] org actions (create label, team, repo; req gitea 1.16.0)
- [x] actions when creating/editing issues
- [x] delete head when merging
- [x] All actions available to instance admins? (handled through API)

Maybe as extras:
- [x] Allow close/reopen also for PRs
- [x] Improve handling of these (multiple btns for the same action)

Co-authored-by: qwerty287 <ndev@web.de>
Co-authored-by: M M Arif <mmarif@noreply.codeberg.org>
Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/977
Reviewed-by: M M Arif <mmarif@noreply.codeberg.org>
Co-authored-by: qwerty287 <qwerty287@noreply.codeberg.org>
Co-committed-by: qwerty287 <qwerty287@noreply.codeberg.org>
This commit is contained in:
qwerty287 2022-02-11 15:27:31 +01:00 committed by M M Arif
parent e444f8f729
commit 8cfd4b6a31
26 changed files with 340 additions and 85 deletions

View File

@ -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.24"
implementation "org.codeberg.gitnex:tea4j:1.0.29"
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'

View File

@ -138,6 +138,13 @@ public class CreateIssueActivity extends BaseActivity implements View.OnClickLis
viewBinding.createNewIssueButton.setOnClickListener(this);
}
if(!tinyDB.getBoolean("canPush")) {
viewBinding.newIssueAssigneesListLayout.setVisibility(View.GONE);
viewBinding.newIssueMilestoneSpinnerLayout.setVisibility(View.GONE);
viewBinding.newIssueLabelsLayout.setVisibility(View.GONE);
viewBinding.newIssueDueDateLayout.setVisibility(View.GONE);
}
}
@Override

View File

@ -112,6 +112,11 @@ public class CreatePullRequestActivity extends BaseActivity implements LabelsLis
viewBinding.prLabels.setOnClickListener(prLabels -> showLabels());
viewBinding.createPr.setOnClickListener(createPr -> processPullRequest());
if(!tinyDB.getBoolean("canPush")) {
viewBinding.prDueDateLayout.setVisibility(View.GONE);
viewBinding.prLabelsLayout.setVisibility(View.GONE);
}
}
private void processPullRequest() {

View File

@ -479,6 +479,7 @@ public class DeepLinksActivity extends BaseActivity {
tinyDB.putString("repoType", getResources().getString(R.string.strPublic));
}
tinyDB.putBoolean("isRepoAdmin", repoInfo.getPermissions().isAdmin());
tinyDB.putBoolean("canPush", repoInfo.getPermissions().canPush());
tinyDB.putString("repoBranch", repoInfo.getDefault_branch());
int currentActiveAccountId = tinyDB.getInt("currentActiveAccountId");

View File

@ -133,6 +133,11 @@ public class EditIssueActivity extends BaseActivity implements View.OnClickListe
disableProcessButton();
getIssue(instanceToken, loginUid, repoOwner, repoName, issueIndex, resultLimit);
if(!tinyDB.getBoolean("canPush")) {
findViewById(R.id.editIssueMilestoneSpinnerLayout).setVisibility(View.GONE);
findViewById(R.id.editIssueDueDateLayout).setVisibility(View.GONE);
}
}
private void initCloseListener() {

View File

@ -114,11 +114,17 @@ public class FileDiffActivity extends BaseActivity {
break;
case 403:
runOnUiThread(() -> Toasty.error(ctx, ctx.getString(R.string.authorizeError)));
runOnUiThread(() -> {
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
finish();
});
break;
case 404:
runOnUiThread(() -> Toasty.warning(ctx, ctx.getString(R.string.apiNotFound)));
runOnUiThread(() -> {
Toasty.warning(ctx, ctx.getString(R.string.apiNotFound));
finish();
});
break;
default:

View File

@ -33,7 +33,9 @@ import com.vdurmont.emoji.EmojiParser;
import org.gitnex.tea4j.models.Collaborators;
import org.gitnex.tea4j.models.Issues;
import org.gitnex.tea4j.models.Labels;
import org.gitnex.tea4j.models.PullRequests;
import org.gitnex.tea4j.models.UpdateIssueAssignees;
import org.gitnex.tea4j.models.UserRepositories;
import org.gitnex.tea4j.models.WatchInfo;
import org.mian.gitnex.R;
import org.mian.gitnex.actions.AssigneesActions;
@ -86,6 +88,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
private String repoOwner;
private String repoName;
private int issueIndex;
private String issueCreator;
private LabelsListAdapter labelsAdapter;
private AssigneesListAdapter assigneesAdapter;
@ -450,7 +453,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
}
else if(id == R.id.genericMenu) {
BottomSheetSingleIssueFragment bottomSheet = new BottomSheetSingleIssueFragment();
BottomSheetSingleIssueFragment bottomSheet = new BottomSheetSingleIssueFragment(issueCreator);
bottomSheet.show(getSupportFragmentManager(), "singleIssueBottomSheet");
return true;
}
@ -542,6 +545,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
}
private void getSingleIssue(String repoOwner, String repoName, int issueIndex) {
updateTinyDBPermissionValues();
final TinyDB tinyDb = TinyDB.getInstance(appCtx);
Call<Issues> call = RetrofitClient.getApiInterface(ctx)
@ -560,7 +564,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
viewBinding.issuePrState.setVisibility(View.VISIBLE);
if(singleIssue.getPull_request() != null) {
getPullSourceRepo();
if(singleIssue.getPull_request().isMerged()) { // merged
viewBinding.issuePrState.setImageResource(R.drawable.ic_pull_request_merged);
@ -585,6 +589,7 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
tinyDb.putString("issueState", singleIssue.getState());
tinyDb.putString("issueTitle", singleIssue.getTitle());
tinyDb.putString("singleIssueHtmlUrl", singleIssue.getHtml_url());
issueCreator = singleIssue.getUser().getLogin();
PicassoService.getInstance(ctx).get().load(singleIssue.getUser().getAvatar_url()).placeholder(R.drawable.loader_animated)
.transform(new RoundedTransformation(8, 0)).resize(120, 120).centerCrop().into(viewBinding.assigneeAvatar);
@ -864,4 +869,56 @@ public class IssueDetailActivity extends BaseActivity implements LabelsListAdapt
}
private void updateTinyDBPermissionValues() {
RetrofitClient.getApiInterface(this).getUserRepository(Authorization.get(this), repoOwner, repoName).enqueue(new Callback<UserRepositories>() {
@Override
public void onResponse(@NonNull Call<UserRepositories> call, @NonNull Response<UserRepositories> response) {
if(response.isSuccessful()) {
assert response.body() != null;
tinyDB.putBoolean("isArchived", response.body().isArchived());
if(response.body().isArchived()) {
viewBinding.addNewComment.setVisibility(View.GONE);
}
tinyDB.putBoolean("isRepoAdmin", response.body().getPermissions().isAdmin());
tinyDB.putBoolean("canPush", response.body().getPermissions().canPush());
}
else {
onFailure(call, new Throwable());
}
}
@Override
public void onFailure(@NonNull Call<UserRepositories> call, @NonNull Throwable t) {
tinyDB.putBoolean("isRepoAdmin", false);
tinyDB.putBoolean("canPush", false);
}
});
}
private void getPullSourceRepo() {
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.15.4")) {
RetrofitClient.getApiInterface(this).getPullRequestByIndex(Authorization.get(this), repoOwner, repoName, issueIndex).enqueue(new Callback<PullRequests>() {
@Override
public void onResponse(@NonNull Call<PullRequests> call, @NonNull Response<PullRequests> response) {
if(response.isSuccessful() && response.body() != null) {
tinyDB.putBoolean("canPushPullSource", response.body().getHead().getRepo().getPermissions().isPush());
}
else {
tinyDB.putBoolean("canPushPullSource", false);
}
}
@Override
public void onFailure(@NonNull Call<PullRequests> call, @NonNull Throwable t) {
tinyDB.putBoolean("canPushPullSource", false);
}
});
}
else {
tinyDB.putBoolean("canPushPullSource", true);
}
}
}

View File

@ -108,6 +108,11 @@ public class MergePullRequestActivity extends BaseActivity {
viewBinding.mergeButton.setOnClickListener(mergePullRequest);
}
if(!tinyDB.getBoolean("canPushPullSource")) {
viewBinding.deleteBranch.setVisibility(View.GONE);
viewBinding.deleteBranchForkInfo.setVisibility(View.GONE);
}
}
private void setMergeAdapter() {

View File

@ -19,17 +19,25 @@ import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.tabs.TabLayout;
import org.gitnex.tea4j.models.OrgPermissions;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.fragments.BottomSheetOrganizationFragment;
import org.mian.gitnex.fragments.MembersByOrgFragment;
import org.mian.gitnex.fragments.OrganizationInfoFragment;
import org.mian.gitnex.fragments.OrganizationLabelsFragment;
import org.mian.gitnex.fragments.RepositoriesByOrgFragment;
import org.mian.gitnex.fragments.TeamsByOrgFragment;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.structs.BottomSheetListener;
import org.mian.gitnex.helpers.Version;
import java.util.List;
import java.util.Objects;
import io.mikael.urlbuilder.UrlBuilder;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -37,6 +45,8 @@ import io.mikael.urlbuilder.UrlBuilder;
public class OrganizationDetailActivity extends BaseActivity implements BottomSheetListener {
public OrgPermissions permissions;
@Override
public void onCreate(Bundle savedInstanceState) {
@ -44,7 +54,7 @@ public class OrganizationDetailActivity extends BaseActivity implements BottomSh
setContentView(R.layout.activity_org_detail);
String orgName = tinyDB.getString("orgName");
String orgName = tinyDB.getString("orgName");
Toolbar toolbar = findViewById(R.id.toolbar);
TextView toolbarTitle = findViewById(R.id.toolbar_title);
@ -102,6 +112,29 @@ public class OrganizationDetailActivity extends BaseActivity implements BottomSh
mViewPager.addOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
tabLayout.addOnTabSelectedListener(new TabLayout.ViewPagerOnTabSelectedListener(mViewPager));
if(new Version(tinyDB.getString("giteaVersion")).higherOrEqual("1.16.0")) {
RetrofitClient.getApiInterface(this)
.getOrgPermissions(Authorization.get(this), tinyDB.getString("loginUid"), orgName).enqueue(new Callback<OrgPermissions>() {
@Override
public void onResponse(@NonNull Call<OrgPermissions> call, @NonNull Response<OrgPermissions> response) {
if(response.isSuccessful()) {
permissions = response.body();
}
else {
permissions = null;
}
}
@Override
public void onFailure(@NonNull Call<OrgPermissions> call, @NonNull Throwable t) {
permissions = null;
}
});
} else {
permissions = null;
}
}
@ -125,7 +158,7 @@ public class OrganizationDetailActivity extends BaseActivity implements BottomSh
}
else if(id == R.id.repoMenu) {
BottomSheetOrganizationFragment bottomSheet = new BottomSheetOrganizationFragment();
BottomSheetOrganizationFragment bottomSheet = new BottomSheetOrganizationFragment(permissions);
bottomSheet.show(getSupportFragmentManager(), "orgBottomSheet");
return true;
}
@ -203,7 +236,7 @@ public class OrganizationDetailActivity extends BaseActivity implements BottomSh
return OrganizationLabelsFragment.newInstance(orgName);
case 3: // teams
return TeamsByOrgFragment.newInstance(orgName);
return TeamsByOrgFragment.newInstance(orgName, permissions);
case 4: // members
return MembersByOrgFragment.newInstance(orgName);

View File

@ -12,6 +12,7 @@ import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.widget.Toolbar;
import androidx.lifecycle.ViewModelProvider;
import org.gitnex.tea4j.models.OrgPermissions;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.UserGridAdapter;
import org.mian.gitnex.databinding.ActivityOrgTeamMembersBinding;
@ -95,7 +96,7 @@ public class OrganizationTeamMembersActivity extends BaseActivity implements Bot
TeamMembersByOrgViewModel teamMembersModel = new ViewModelProvider(this).get(TeamMembersByOrgViewModel.class);
teamMembersModel.getMembersByOrgList(instanceToken, teamId, ctx).observe(this, teamMembersListMain -> {
teamMembersModel.getMembersByOrgList(instanceToken, teamId, ctx, noDataMembers, progressBar).observe(this, teamMembersListMain -> {
adapter = new UserGridAdapter(ctx, teamMembersListMain);
@ -117,9 +118,10 @@ public class OrganizationTeamMembersActivity extends BaseActivity implements Bot
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.generic_nav_dotted_menu, menu);
if(((OrgPermissions) getIntent().getSerializableExtra("permissions")).isOwner()) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.generic_nav_dotted_menu, menu);
}
return true;
}

View File

@ -100,8 +100,16 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
TextView commentMenuCopy = vw.findViewById(R.id.commentMenuCopy);
TextView commentMenuDelete = vw.findViewById(R.id.commentMenuDelete);
TextView issueCommentCopyUrl = vw.findViewById(R.id.issueCommentCopyUrl);
LinearLayout linearLayout = vw.findViewById(R.id.commentReactionButtons);
if(!loginUid.contentEquals(issueComment.getUser().getUsername())) {
if(tinyDB.getBoolean("isArchived")) {
commentMenuEdit.setVisibility(View.GONE);
commentMenuDelete.setVisibility(View.GONE);
commentMenuQuote.setVisibility(View.GONE);
linearLayout.setVisibility(View.GONE);
}
if(!loginUid.contentEquals(issueComment.getUser().getUsername()) && !tinyDB.getBoolean("canPush")) {
commentMenuEdit.setVisibility(View.GONE);
commentMenuDelete.setVisibility(View.GONE);
}
@ -114,7 +122,6 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<IssueCommentsAdap
dialog.setContentView(vw);
dialog.show();
LinearLayout linearLayout = vw.findViewById(R.id.commentReactionButtons);
TextView loadReactions = new TextView(context);
loadReactions.setText(context.getString(R.string.genericWaitFor));
loadReactions.setGravity(Gravity.CENTER);

View File

@ -18,8 +18,10 @@ import com.google.android.material.bottomsheet.BottomSheetDialog;
import org.gitnex.tea4j.models.Labels;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.CreateLabelActivity;
import org.mian.gitnex.activities.OrganizationDetailActivity;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.ColorInverter;
import org.mian.gitnex.helpers.TinyDB;
import java.util.List;
/**
@ -48,6 +50,10 @@ public class LabelsAdapter extends RecyclerView.Adapter<LabelsAdapter.LabelsView
labelName = itemView.findViewById(R.id.labelName);
ImageView labelsOptionsMenu = itemView.findViewById(R.id.labelsOptionsMenu);
if((type.equals("repo") && !TinyDB.getInstance(itemView.getContext()).getBoolean("isRepoAdmin")) ||
(type.equals("org") && !((OrganizationDetailActivity) itemView.getContext()).permissions.isOwner())) {
labelsOptionsMenu.setVisibility(View.GONE);
}
labelsOptionsMenu.setOnClickListener(v -> {
final Context context = v.getContext();

View File

@ -100,6 +100,9 @@ public class MilestonesAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
msProgress = itemView.findViewById(R.id.milestoneProgress);
ImageView milestonesMenu = itemView.findViewById(R.id.milestonesMenu);
if(!TinyDB.getInstance(itemView.getContext()).getBoolean("isRepoAdmin")) {
milestonesMenu.setVisibility(View.GONE);
}
milestonesMenu.setOnClickListener(v -> {
Context ctx = v.getContext();

View File

@ -10,6 +10,7 @@ import android.widget.Filterable;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import org.gitnex.tea4j.models.OrgPermissions;
import org.gitnex.tea4j.models.Teams;
import org.mian.gitnex.R;
import org.mian.gitnex.activities.OrganizationTeamMembersActivity;
@ -25,11 +26,13 @@ public class TeamsByOrgAdapter extends RecyclerView.Adapter<TeamsByOrgAdapter.Or
private final List<Teams> teamList;
private final Context context;
private final List<Teams> teamListFull;
private final OrgPermissions permissions;
static class OrgTeamsViewHolder extends RecyclerView.ViewHolder {
private Teams teams;
private OrgPermissions permissions;
private final TextView teamTitle;
private final TextView teamDescription;
private final TextView teamPermission;
@ -48,6 +51,7 @@ public class TeamsByOrgAdapter extends RecyclerView.Adapter<TeamsByOrgAdapter.Or
Intent intent = new Intent(context, OrganizationTeamMembersActivity.class);
intent.putExtra("teamTitle", teams.getName());
intent.putExtra("teamId", String.valueOf(teams.getId()));
intent.putExtra("permissions", permissions);
context.startActivity(intent);
});
@ -55,9 +59,10 @@ public class TeamsByOrgAdapter extends RecyclerView.Adapter<TeamsByOrgAdapter.Or
}
public TeamsByOrgAdapter(Context ctx, List<Teams> teamListMain) {
public TeamsByOrgAdapter(Context ctx, List<Teams> teamListMain, OrgPermissions permissions) {
this.context = ctx;
this.teamList = teamListMain;
this.permissions = permissions;
teamListFull = new ArrayList<>(teamList);
}
@ -75,6 +80,7 @@ public class TeamsByOrgAdapter extends RecyclerView.Adapter<TeamsByOrgAdapter.Or
holder.teams = currentItem;
holder.teamTitle.setText(currentItem.getName());
holder.permissions = permissions;
if (!currentItem.getDescription().equals("")) {
holder.teamDescription.setVisibility(View.VISIBLE);

View File

@ -10,6 +10,7 @@ import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.mian.gitnex.databinding.BottomSheetFileViewerBinding;
import org.mian.gitnex.structs.BottomSheetListener;
import org.mian.gitnex.helpers.TinyDB;
/**
* Author M M Arif
@ -25,6 +26,11 @@ public class BottomSheetFileViewerFragment extends BottomSheetDialogFragment {
BottomSheetFileViewerBinding bottomSheetFileViewerBinding = BottomSheetFileViewerBinding.inflate(inflater, container, false);
if(!TinyDB.getInstance(requireContext()).getBoolean("canPush")) {
bottomSheetFileViewerBinding.deleteFile.setVisibility(View.GONE);
bottomSheetFileViewerBinding.editFile.setVisibility(View.GONE);
}
bottomSheetFileViewerBinding.downloadFile.setOnClickListener(v1 -> {
bmListener.onButtonClicked("downloadFile");

View File

@ -8,8 +8,17 @@ import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import org.gitnex.tea4j.models.OrgPermissions;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.BottomSheetOrganizationBinding;
import org.mian.gitnex.structs.BottomSheetListener;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.TinyDB;
import org.mian.gitnex.helpers.Version;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
/**
* Author M M Arif
@ -18,6 +27,11 @@ import org.mian.gitnex.structs.BottomSheetListener;
public class BottomSheetOrganizationFragment extends BottomSheetDialogFragment {
private BottomSheetListener bmListener;
private final OrgPermissions permissions;
public BottomSheetOrganizationFragment(OrgPermissions org) {
permissions = org;
}
@Nullable
@Override
@ -25,6 +39,16 @@ public class BottomSheetOrganizationFragment extends BottomSheetDialogFragment {
BottomSheetOrganizationBinding bottomSheetOrganizationBinding = BottomSheetOrganizationBinding.inflate(inflater, container, false);
if(permissions != null) {
if(!permissions.canCreateRepositories()) {
bottomSheetOrganizationBinding.createRepository.setVisibility(View.GONE);
}
if(!permissions.isOwner()) {
bottomSheetOrganizationBinding.createLabel.setVisibility(View.GONE);
bottomSheetOrganizationBinding.createTeam.setVisibility(View.GONE);
}
}
bottomSheetOrganizationBinding.createTeam.setOnClickListener(v1 -> {
bmListener.onButtonClicked("team");

View File

@ -47,13 +47,32 @@ public class BottomSheetRepoFragment extends BottomSheetDialogFragment {
TextView repoSettings = bottomSheetRepoBinding.repoSettings;
TextView createPullRequest = bottomSheetRepoBinding.createPullRequest;
boolean canPush = tinyDb.getBoolean("canPush");
if(!canPush) {
createMilestone.setVisibility(View.GONE);
createLabel.setVisibility(View.GONE);
createRelease.setVisibility(View.GONE);
newFile.setVisibility(View.GONE);
}
boolean archived = tinyDb.getBoolean("isArchived");
if(archived) {
createIssue.setVisibility(View.GONE);
createPullRequest.setVisibility(View.GONE);
createMilestone.setVisibility(View.GONE);
createLabel.setVisibility(View.GONE);
createRelease.setVisibility(View.GONE);
newFile.setVisibility(View.GONE);
bottomSheetRepoBinding.createDivider.setVisibility(View.GONE);
}
createLabel.setOnClickListener(v112 -> {
bmListener.onButtonClicked("label");
dismiss();
});
if(tinyDb.getBoolean("hasIssues")) {
if(tinyDb.getBoolean("hasIssues") && !archived) {
createIssue.setVisibility(View.VISIBLE);
createIssue.setOnClickListener(v12 -> {
@ -67,7 +86,7 @@ public class BottomSheetRepoFragment extends BottomSheetDialogFragment {
createIssue.setVisibility(View.GONE);
}
if(tinyDb.getBoolean("hasPullRequests")) {
if(tinyDb.getBoolean("hasPullRequests") && !archived) {
createPullRequest.setVisibility(View.VISIBLE);
createPullRequest.setOnClickListener(vPr -> {

View File

@ -37,6 +37,11 @@ import java.util.Objects;
public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
private BottomSheetListener bmListener;
private final String issueCreator;
public BottomSheetSingleIssueFragment(String username) {
issueCreator = username;
}
@Nullable
@Override
@ -47,10 +52,14 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
final Context ctx = getContext();
final TinyDB tinyDB = TinyDB.getInstance(ctx);
boolean userIsCreator = issueCreator.equals(tinyDB.getString("loginUid"));
boolean isRepoAdmin = tinyDB.getBoolean("isRepoAdmin");
boolean canPush = tinyDB.getBoolean("canPush");
boolean archived = tinyDB.getBoolean("isArchived");
TextView editIssue = bottomSheetSingleIssueBinding.editIssue;
TextView editLabels = bottomSheetSingleIssueBinding.editLabels;
TextView closeIssue = bottomSheetSingleIssueBinding.closeIssue;
TextView reOpenIssue = bottomSheetSingleIssueBinding.reOpenIssue;
TextView addRemoveAssignees = bottomSheetSingleIssueBinding.addRemoveAssignees;
TextView copyIssueUrl = bottomSheetSingleIssueBinding.copyIssueUrl;
TextView openFilesDiff = bottomSheetSingleIssueBinding.openFilesDiff;
@ -60,6 +69,7 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
TextView shareIssue = bottomSheetSingleIssueBinding.shareIssue;
TextView subscribeIssue = bottomSheetSingleIssueBinding.subscribeIssue;
TextView unsubscribeIssue = bottomSheetSingleIssueBinding.unsubscribeIssue;
View closeReopenDivider = bottomSheetSingleIssueBinding.dividerCloseReopenIssue;
LinearLayout linearLayout = bottomSheetSingleIssueBinding.commentReactionButtons;
@ -100,14 +110,36 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
copyIssueUrl.setText(R.string.copyPrUrlText);
shareIssue.setText(R.string.sharePr);
boolean canPushPullSource = tinyDB.getBoolean("canPushPullSource");
if(tinyDB.getBoolean("prMerged") || tinyDB.getString("repoPrState").equals("closed")) {
updatePullRequest.setVisibility(View.GONE);
mergePullRequest.setVisibility(View.GONE);
deletePullRequestBranch.setVisibility(View.VISIBLE);
if(canPushPullSource) {
deletePullRequestBranch.setVisibility(View.VISIBLE);
}
else {
if(!canPush) {
editIssue.setVisibility(View.GONE);
}
deletePullRequestBranch.setVisibility(View.GONE);
}
}
else {
updatePullRequest.setVisibility(View.VISIBLE);
mergePullRequest.setVisibility(View.VISIBLE);
if(canPushPullSource) {
updatePullRequest.setVisibility(View.VISIBLE);
}
else {
updatePullRequest.setVisibility(View.GONE);
}
if(!userIsCreator && !canPush) {
editIssue.setVisibility(View.GONE);
}
if(canPush && !tinyDB.getString("prMergeable").equals("false")) {
mergePullRequest.setVisibility(View.VISIBLE);
}
else {
mergePullRequest.setVisibility(View.GONE);
}
deletePullRequestBranch.setVisibility(View.GONE);
}
@ -123,7 +155,9 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
}
else {
if(!userIsCreator && !canPush) {
editIssue.setVisibility(View.GONE);
}
updatePullRequest.setVisibility(View.GONE);
mergePullRequest.setVisibility(View.GONE);
deletePullRequestBranch.setVisibility(View.GONE);
@ -199,41 +233,36 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
dismiss();
});
if(tinyDB.getString("issueType").equalsIgnoreCase("Issue")) {
if(tinyDB.getString("issueState").equals("open")) { // close issue
reOpenIssue.setVisibility(View.GONE);
closeIssue.setVisibility(View.VISIBLE);
closeIssue.setOnClickListener(closeSingleIssue -> {
IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "closed");
dismiss();
});
}
else if(tinyDB.getString("issueState").equals("closed")) {
if(tinyDB.getString("issueState").equals("open")) { // close issue
if(!userIsCreator && !canPush) {
closeIssue.setVisibility(View.GONE);
reOpenIssue.setVisibility(View.VISIBLE);
reOpenIssue.setOnClickListener(reOpenSingleIssue -> {
IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "open");
dismiss();
});
closeReopenDivider.setVisibility(View.GONE);
}
else if(tinyDB.getString("issueType").equalsIgnoreCase("Pull")) {
closeIssue.setText(R.string.closePr);
}
closeIssue.setOnClickListener(closeSingleIssue -> {
IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "closed");
dismiss();
});
}
else {
reOpenIssue.setVisibility(View.GONE);
closeIssue.setVisibility(View.GONE);
else if(tinyDB.getString("issueState").equals("closed")) {
if(userIsCreator || canPush) {
if(tinyDB.getString("issueType").equalsIgnoreCase("Pull")) {
closeIssue.setText(R.string.reopenPr);
}
else {
closeIssue.setText(R.string.reOpenIssue);
}
}
else {
closeIssue.setVisibility(View.GONE);
closeReopenDivider.setVisibility(View.GONE);
}
closeIssue.setOnClickListener(closeSingleIssue -> {
IssueActions.closeReopenIssue(ctx, Integer.parseInt(tinyDB.getString("issueNumber")), "open");
dismiss();
});
}
subscribeIssue.setOnClickListener(subscribeToIssue -> {
@ -261,6 +290,18 @@ public class BottomSheetSingleIssueFragment extends BottomSheetDialogFragment {
unsubscribeIssue.setVisibility(View.GONE);
}
if(archived) {
subscribeIssue.setVisibility(View.GONE);
unsubscribeIssue.setVisibility(View.GONE);
editIssue.setVisibility(View.GONE);
editLabels.setVisibility(View.GONE);
closeIssue.setVisibility(View.GONE);
closeReopenDivider.setVisibility(View.GONE);
addRemoveAssignees.setVisibility(View.GONE);
linearLayout.setVisibility(View.GONE);
bottomSheetSingleIssueBinding.shareDivider.setVisibility(View.GONE);
}
return bottomSheetSingleIssueBinding.getRoot();
}

View File

@ -283,6 +283,7 @@ public class RepoInfoFragment extends Fragment {
tinyDb.putBoolean("hasPullRequests", false);
}
tinyDb.putBoolean("isArchived", repoInfo.isArchived());
if(repoInfo.isArchived()) {
binding.repoIsArchived.setVisibility(View.VISIBLE);
}
@ -291,6 +292,7 @@ public class RepoInfoFragment extends Fragment {
}
tinyDb.putString("repoHtmlUrl", repoInfo.getHtml_url());
tinyDb.putBoolean("canPush", repoInfo.getPermissions().canPush());
binding.progressBar.setVisibility(View.GONE);
pageContent.setVisibility(View.VISIBLE);

View File

@ -22,6 +22,7 @@ import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import org.gitnex.tea4j.models.OrgPermissions;
import org.gitnex.tea4j.models.Teams;
import org.mian.gitnex.R;
import org.mian.gitnex.adapters.TeamsByOrgAdapter;
@ -44,15 +45,17 @@ public class TeamsByOrgFragment extends Fragment {
private TextView noDataTeams;
private static String orgNameF = "param2";
private String orgName;
private OrgPermissions permissions;
private TeamsByOrgAdapter adapter;
public TeamsByOrgFragment() {
}
public static TeamsByOrgFragment newInstance(String param1) {
public static TeamsByOrgFragment newInstance(String param1, OrgPermissions permissions) {
TeamsByOrgFragment fragment = new TeamsByOrgFragment();
Bundle args = new Bundle();
args.putString(orgNameF, param1);
args.putSerializable("permissions", permissions);
fragment.setArguments(args);
return fragment;
}
@ -62,6 +65,7 @@ public class TeamsByOrgFragment extends Fragment {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
orgName = getArguments().getString(orgNameF);
permissions = (OrgPermissions) getArguments().getSerializable("permissions");
}
}
@ -89,7 +93,7 @@ public class TeamsByOrgFragment extends Fragment {
swipeRefresh.setOnRefreshListener(() -> new Handler(Looper.getMainLooper()).postDelayed(() -> {
swipeRefresh.setRefreshing(false);
TeamsByOrgViewModel.loadTeamsByOrgList(Authorization.get(getContext()), orgName, getContext());
TeamsByOrgViewModel.loadTeamsByOrgList(Authorization.get(getContext()), orgName, getContext(), noDataTeams, mProgressBar);
}, 200));
@ -104,7 +108,7 @@ public class TeamsByOrgFragment extends Fragment {
TinyDB tinyDb = TinyDB.getInstance(getContext());
if(tinyDb.getBoolean("resumeTeams")) {
TeamsByOrgViewModel.loadTeamsByOrgList(Authorization.get(getContext()), orgName, getContext());
TeamsByOrgViewModel.loadTeamsByOrgList(Authorization.get(getContext()), orgName, getContext(), noDataTeams, mProgressBar);
tinyDb.putBoolean("resumeTeams", false);
}
}
@ -113,10 +117,10 @@ public class TeamsByOrgFragment extends Fragment {
TeamsByOrgViewModel teamModel = new ViewModelProvider(this).get(TeamsByOrgViewModel.class);
teamModel.getTeamsByOrg(instanceToken, owner, getContext()).observe(getViewLifecycleOwner(), new Observer<List<Teams>>() {
teamModel.getTeamsByOrg(instanceToken, owner, getContext(), noDataTeams, mProgressBar).observe(getViewLifecycleOwner(), new Observer<List<Teams>>() {
@Override
public void onChanged(@Nullable List<Teams> orgTeamsListMain) {
adapter = new TeamsByOrgAdapter(getContext(), orgTeamsListMain);
adapter = new TeamsByOrgAdapter(getContext(), orgTeamsListMain, permissions);
if(adapter.getItemCount() > 0) {
mRecyclerView.setAdapter(adapter);
noDataTeams.setVisibility(View.GONE);

View File

@ -2,11 +2,15 @@ package org.mian.gitnex.viewmodels;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.gitnex.tea4j.models.UserInfo;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import java.util.List;
import retrofit2.Call;
@ -21,15 +25,15 @@ public class TeamMembersByOrgViewModel extends ViewModel {
private static MutableLiveData<List<UserInfo>> teamMembersList;
public LiveData<List<UserInfo>> getMembersByOrgList(String token, int teamId, Context ctx) {
public LiveData<List<UserInfo>> getMembersByOrgList(String token, int teamId, Context ctx, TextView noDataMembers, ProgressBar progressBar) {
teamMembersList = new MutableLiveData<>();
loadMembersByOrgList(token, teamId, ctx);
loadMembersByOrgList(token, teamId, ctx, noDataMembers, progressBar);
return teamMembersList;
}
private static void loadMembersByOrgList(String token, int teamId, Context ctx) {
private static void loadMembersByOrgList(String token, int teamId, Context ctx, TextView noDataMembers, ProgressBar progressBar) {
Call<List<UserInfo>> call = RetrofitClient
.getApiInterface(ctx)
@ -44,13 +48,21 @@ public class TeamMembersByOrgViewModel extends ViewModel {
teamMembersList.postValue(response.body());
} else {
Log.i("onResponse", String.valueOf(response.code()));
progressBar.setVisibility(View.GONE);
if(response.code() == 403) {
noDataMembers.setText(R.string.authorizeError);
} else {
noDataMembers.setText(R.string.genericError);
}
}
}
@Override
public void onFailure(@NonNull Call<List<UserInfo>> call, Throwable t) {
public void onFailure(@NonNull Call<List<UserInfo>> call, @NonNull Throwable t) {
Log.i("onFailure", t.toString());
progressBar.setVisibility(View.GONE);
noDataMembers.setText(R.string.genericError);
}
});

View File

@ -2,12 +2,17 @@ package org.mian.gitnex.viewmodels;
import android.content.Context;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import org.gitnex.tea4j.models.Teams;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.Toasty;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
@ -21,15 +26,15 @@ public class TeamsByOrgViewModel extends ViewModel {
private static MutableLiveData<List<Teams>> teamsList;
public LiveData<List<Teams>> getTeamsByOrg(String token, String orgName, Context ctx) {
public LiveData<List<Teams>> getTeamsByOrg(String token, String orgName, Context ctx, TextView noDataTeams, ProgressBar mProgressBar) {
teamsList = new MutableLiveData<>();
loadTeamsByOrgList(token, orgName, ctx);
loadTeamsByOrgList(token, orgName, ctx, noDataTeams, mProgressBar);
return teamsList;
}
public static void loadTeamsByOrgList(String token, String orgName, Context ctx) {
public static void loadTeamsByOrgList(String token, String orgName, Context ctx, TextView noDataTeams, ProgressBar mProgressBar) {
Call<List<Teams>> call = RetrofitClient
.getApiInterface(ctx)
@ -46,12 +51,23 @@ public class TeamsByOrgViewModel extends ViewModel {
}
}
else if(response.code() == 403) {
Toasty.error(ctx, ctx.getString(R.string.authorizeError));
mProgressBar.setVisibility(View.GONE);
noDataTeams.setText(R.string.authorizeError);
}
else {
mProgressBar.setVisibility(View.GONE);
noDataTeams.setText(R.string.genericError);
}
}
@Override
public void onFailure(@NonNull Call<List<Teams>> call, Throwable t) {
public void onFailure(@NonNull Call<List<Teams>> call, @NonNull Throwable t) {
Log.i("onFailure", t.toString());
mProgressBar.setVisibility(View.GONE);
noDataTeams.setText(R.string.genericError);
}
});

View File

@ -149,7 +149,6 @@
android:layout_marginBottom="8dp"
app:endIconMode="clear_text"
app:endIconTint="?attr/iconsColor"
android:visibility="gone"
android:hint="@string/newIssueDueDateTitle">
<com.google.android.material.textfield.TextInputEditText

View File

@ -109,6 +109,7 @@
app:drawableStartCompat="@drawable/ic_release" />
<View
android:id="@+id/createDivider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="12dp"

View File

@ -166,6 +166,7 @@
tools:visibility="visible" />
<View
android:id="@+id/shareDivider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="12dp"
@ -204,6 +205,7 @@
app:drawableStartCompat="@drawable/ic_copy" />
<View
android:id="@+id/dividerCloseReopenIssue"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="12dp"
@ -226,23 +228,6 @@
android:textSize="16sp"
app:drawableStartCompat="@drawable/ic_issue_closed" />
<TextView
android:id="@+id/reOpenIssue"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="?android:attr/selectableItemBackground"
android:focusable="true"
android:clickable="true"
android:drawablePadding="24dp"
android:padding="12dp"
android:text="@string/reOpenIssue"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:visibility="gone"
app:drawableStartCompat="@drawable/ic_reopen"
tools:visibility="visible" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>

View File

@ -749,6 +749,9 @@
<string name="updateStrategyMerge">Merge</string>
<string name="updateStrategyRebase">Rebase</string>
<string name="selectUpdateStrategy">Select Update Strategy</string>
<string name="closePr">Close Pull Request</string>
<string name="reopenPr">Reopen Pull Request</string>
<string name="userAvatar">Avatar</string>
<string name="useCustomTabs">Use Custom Tabs</string>
<string name="browserOpenFailed">No application found to open this link. SSH URLs and URLs with another prefix the http:// or https:// are not supported by most browser</string>