Delete branch after merge (#496)

delete branch API call

Add fork repo info for branch

Check if pr is mergeable, show message if not.

Use checkbox instead of button

make ripple effects work for buttons with enable/disable

introduce viewbinding

Co-authored-by: 6543 <6543@noreply.gitea.io>
Reviewed-on: https://gitea.com/gitnex/GitNex/pulls/496
Reviewed-by: 6543 <6543@noreply.gitea.io>
This commit is contained in:
M M Arif 2020-05-21 22:49:09 +00:00 committed by 6543
parent 1b213783bc
commit d06f5353c6
10 changed files with 338 additions and 83 deletions

View File

@ -10,6 +10,9 @@ android {
versionName "3.0.0-dev"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
viewBinding {
enabled = true
}
buildTypes {
release {
minifyEnabled false
@ -38,7 +41,7 @@ dependencies {
def acra = "5.5.0"
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "androidx.appcompat:appcompat:1.2.0-beta01"
implementation "androidx.appcompat:appcompat:1.2.0-rc01"
implementation "com.google.android.material:material:1.2.0-alpha06"
implementation "androidx.constraintlayout:constraintlayout:1.1.3"
implementation "androidx.legacy:legacy-support-v4:1.0.0"
@ -46,15 +49,15 @@ dependencies {
androidTestImplementation "androidx.test:runner:1.2.0"
androidTestImplementation "androidx.test.espresso:espresso-core:3.2.0"
implementation "com.github.vihtarb:tooltip:0.2.0"
implementation 'com.squareup.okhttp3:okhttp:4.5.0'
implementation 'com.squareup.okhttp3:okhttp:4.7.0'
implementation "com.google.code.gson:gson:2.8.6"
implementation "com.squareup.picasso:picasso:2.71828"
implementation "com.amulyakhare:com.amulyakhare.textdrawable:1.0.1"
implementation 'com.squareup.retrofit2:retrofit:2.8.1'
implementation 'com.squareup.retrofit2:converter-gson:2.8.1'
implementation 'com.squareup.retrofit2:converter-scalars:2.8.1'
implementation 'com.squareup.okhttp3:logging-interceptor:4.5.0'
implementation 'org.ocpsoft.prettytime:prettytime:4.0.4.Final'
implementation 'com.squareup.okhttp3:logging-interceptor:4.7.0'
implementation 'org.ocpsoft.prettytime:prettytime:4.0.5.Final'
implementation "com.vdurmont:emoji-java:5.1.1"
implementation "com.pes.materialcolorpicker:library:1.2.5"
implementation "io.noties.markwon:core:$markwon_version"

View File

@ -2,24 +2,19 @@ package org.mian.gitnex.activities;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.drawable.GradientDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import com.hendraanggrian.appcompat.socialview.Mention;
import com.hendraanggrian.appcompat.widget.MentionArrayAdapter;
import com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.databinding.ActivityMergePullRequestBinding;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
@ -42,17 +37,12 @@ import retrofit2.Response;
public class MergePullRequestActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
final Context ctx = this;
private Context appCtx;
private ActivityMergePullRequestBinding viewBinding;
private SocialAutoCompleteTextView mergeDescription;
private EditText mergeTitle;
private Spinner mergeModeSpinner;
private ArrayAdapter<Mention> defaultMentionAdapter;
private Button mergeButton;
private String Do;
@Override
@ -68,22 +58,22 @@ public class MergePullRequestActivity extends BaseActivity {
super.onCreate(savedInstanceState);
appCtx = getApplicationContext();
viewBinding = ActivityMergePullRequestBinding.inflate(getLayoutInflater());
View view = viewBinding.getRoot();
setContentView(view);
boolean connToInternet = AppUtil.haveNetworkConnection(appCtx);
TinyDB tinyDb = new TinyDB(appCtx);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
mergeModeSpinner = findViewById(R.id.mergeSpinner);
mergeDescription = findViewById(R.id.mergeDescription);
mergeTitle = findViewById(R.id.mergeTitle);
mergeTitle.requestFocus();
viewBinding.mergeTitle.requestFocus();
assert imm != null;
imm.showSoftInput(mergeTitle, InputMethodManager.SHOW_IMPLICIT);
imm.showSoftInput(viewBinding.mergeTitle, InputMethodManager.SHOW_IMPLICIT);
setMergeAdapter();
mergeModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
viewBinding.mergeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
@ -103,20 +93,35 @@ public class MergePullRequestActivity extends BaseActivity {
defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList();
mergeDescription.setMentionAdapter(defaultMentionAdapter);
closeActivity = findViewById(R.id.close);
TextView toolbar_title = findViewById(R.id.toolbar_title);
viewBinding.mergeDescription.setMentionAdapter(defaultMentionAdapter);
if(!tinyDb.getString("issueTitle").isEmpty()) {
toolbar_title.setText(tinyDb.getString("issueTitle"));
mergeTitle.setText(tinyDb.getString("issueTitle") + " (#" + tinyDb.getString("issueNumber") + ")");
viewBinding.toolbarTitle.setText(tinyDb.getString("issueTitle"));
viewBinding.mergeTitle.setText(tinyDb.getString("issueTitle") + " (#" + tinyDb.getString("issueNumber") + ")");
}
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
viewBinding.close.setOnClickListener(onClickListener);
mergeButton = findViewById(R.id.mergeButton);
// if gitea version is greater/equal(1.12.0) than user installed version (installed.higherOrEqual(compareVer))
if(new Version(tinyDb.getString("giteaVersion")).higherOrEqual("1.12.0")) {
viewBinding.deleteBranch.setVisibility(View.VISIBLE);
}
if(tinyDb.getString("prMergeable").equals("false")) {
disableProcessButton();
viewBinding.mergeInfoDisabledMessage.setVisibility(View.VISIBLE);
}
else {
viewBinding.mergeInfoDisabledMessage.setVisibility(View.GONE);
}
if(tinyDb.getString("prIsFork").equals("true")) {
viewBinding.deleteBranchForkInfo.setVisibility(View.VISIBLE);
}
else {
viewBinding.deleteBranchForkInfo.setVisibility(View.GONE);
}
if(!connToInternet) {
@ -125,7 +130,7 @@ public class MergePullRequestActivity extends BaseActivity {
}
else {
mergeButton.setOnClickListener(mergePullRequest);
viewBinding.mergeButton.setOnClickListener(mergePullRequest);
}
@ -140,14 +145,14 @@ public class MergePullRequestActivity extends BaseActivity {
mergeList.add(new MergePullRequestSpinner("merge", getResources().getString(R.string.mergeOptionMerge)));
mergeList.add(new MergePullRequestSpinner("rebase", getResources().getString(R.string.mergeOptionRebase)));
mergeList.add(new MergePullRequestSpinner("rebase-merge", getResources().getString(R.string.mergeOptionRebaseCommit)));
//squash merge works only on gitea > v1.11.4 due to a bug
// squash merge works only on gitea > v1.11.4 due to a bug
if(new Version(tinyDb.getString("giteaVersion")).higher("1.11.4")) {
mergeList.add(new MergePullRequestSpinner("squash", getResources().getString(R.string.mergeOptionSquash)));
}
ArrayAdapter<MergePullRequestSpinner> adapter = new ArrayAdapter<>(MergePullRequestActivity.this, R.layout.spinner_item, mergeList);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
mergeModeSpinner.setAdapter(adapter);
viewBinding.mergeSpinner.setAdapter(adapter);
}
@ -208,8 +213,9 @@ public class MergePullRequestActivity extends BaseActivity {
private void processMergePullRequest() {
String mergePRDesc = mergeDescription.getText().toString();
String mergePRTitle = mergeTitle.getText().toString();
String mergePRDesc = viewBinding.mergeDescription.getText().toString();
String mergePRTitle = viewBinding.mergeTitle.getText().toString();
boolean deleteBranch = viewBinding.deleteBranch.isChecked();
boolean connToInternet = AppUtil.haveNetworkConnection(appCtx);
@ -221,11 +227,11 @@ public class MergePullRequestActivity extends BaseActivity {
}
disableProcessButton();
mergeFunction(Do, mergePRDesc, mergePRTitle);
mergeFunction(Do, mergePRDesc, mergePRTitle, deleteBranch);
}
private void mergeFunction(String Do, String mergePRDT, String mergeTitle) {
private void mergeFunction(String Do, String mergePRDT, String mergeTitle, boolean deleteBranch) {
final TinyDB tinyDb = new TinyDB(appCtx);
@ -249,10 +255,48 @@ public class MergePullRequestActivity extends BaseActivity {
if(response.code() == 200) {
Toasty.info(ctx, getString(R.string.mergePRSuccessMsg));
tinyDb.putBoolean("prMerged", true);
tinyDb.putBoolean("resumePullRequests", true);
finish();
if(deleteBranch) {
if(tinyDb.getString("prIsFork").equals("true")) {
String repoFullName = tinyDb.getString("prForkFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
deleteBranchFunction(repoOwner, repoName);
Toasty.info(ctx, getString(R.string.mergePRSuccessMsg));
tinyDb.putBoolean("prMerged", true);
tinyDb.putBoolean("resumePullRequests", true);
finish();
}
else {
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
deleteBranchFunction(repoOwner, repoName);
Toasty.info(ctx, getString(R.string.mergePRSuccessMsg));
tinyDb.putBoolean("prMerged", true);
tinyDb.putBoolean("resumePullRequests", true);
finish();
}
}
else {
Toasty.info(ctx, getString(R.string.mergePRSuccessMsg));
tinyDb.putBoolean("prMerged", true);
tinyDb.putBoolean("resumePullRequests", true);
finish();
}
}
else if(response.code() == 401) {
@ -287,23 +331,56 @@ public class MergePullRequestActivity extends BaseActivity {
}
private void deleteBranchFunction(String repoOwner, String repoName) {
TinyDB tinyDb = new TinyDB(appCtx);
String instanceUrl = tinyDb.getString("instanceUrl");
String loginUid = tinyDb.getString("loginUid");
String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String branchName = tinyDb.getString("prHeadBranch");
Call<JsonElement> call = RetrofitClient
.getInstance(instanceUrl, ctx)
.getApiInterface()
.deleteBranch(Authorization.returnAuthentication(ctx, loginUid, instanceToken), repoOwner, repoName, branchName);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.code() == 204) {
Log.i("deleteBranch", "Branch deleted successfully");
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
});
}
private void disableProcessButton() {
mergeButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(8);
shape.setColor(getResources().getColor(R.color.hintColor));
mergeButton.setBackground(shape);
viewBinding.mergeButton.setEnabled(false);
viewBinding.mergeButton.setBackground(getResources().getDrawable(R.drawable.shape_buttons_disabled));
}
private void enableProcessButton() {
mergeButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(8);
shape.setColor(getResources().getColor(R.color.btnBackground));
mergeButton.setBackground(shape);
viewBinding.mergeButton.setEnabled(true);
viewBinding.mergeButton.setBackground(getResources().getDrawable(R.drawable.shape_buttons));
}

View File

@ -97,6 +97,10 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
class PullRequestsHolder extends RecyclerView.ViewHolder {
private TextView prNumber;
private TextView prMergeable;
private TextView prHeadBranch;
private TextView prIsFork;
private TextView prForkFullName;
private ImageView assigneeAvatar;
private TextView prTitle;
private TextView prCreatedTime;
@ -107,6 +111,10 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
super(itemView);
prNumber = itemView.findViewById(R.id.prNumber);
prMergeable = itemView.findViewById(R.id.prMergeable);
prHeadBranch = itemView.findViewById(R.id.prHeadBranch);
prIsFork = itemView.findViewById(R.id.prIsFork);
prForkFullName = itemView.findViewById(R.id.prForkFullName);
assigneeAvatar = itemView.findViewById(R.id.assigneeAvatar);
prTitle = itemView.findViewById(R.id.prTitle);
prCommentsCount = itemView.findViewById(R.id.prCommentsCount);
@ -119,9 +127,15 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", prNumber.getText());
intent.putExtra("prMergeable", prMergeable.getText());
intent.putExtra("prHeadBranch", prHeadBranch.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", prNumber.getText().toString());
tinyDb.putString("prMergeable", prMergeable.getText().toString());
tinyDb.putString("prHeadBranch", prHeadBranch.getText().toString());
tinyDb.putString("prIsFork", prIsFork.getText().toString());
tinyDb.putString("prForkFullName", prForkFullName.getText().toString());
tinyDb.putString("issueType", "pr");
context.startActivity(intent);
@ -132,9 +146,15 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", prNumber.getText());
intent.putExtra("prMergeable", prMergeable.getText());
intent.putExtra("prHeadBranch", prHeadBranch.getText());
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", prNumber.getText().toString());
tinyDb.putString("prMergeable", prMergeable.getText().toString());
tinyDb.putString("prHeadBranch", prHeadBranch.getText().toString());
tinyDb.putString("prIsFork", prIsFork.getText().toString());
tinyDb.putString("prForkFullName", prForkFullName.getText().toString());
tinyDb.putString("issueType", "pr");
context.startActivity(intent);
@ -167,6 +187,10 @@ public class PullRequestsAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
prTitle.setText(Html.fromHtml(prNumber_ + " " + prModel.getTitle()));
prNumber.setText(String.valueOf(prModel.getNumber()));
prMergeable.setText(String.valueOf(prModel.isMergeable()));
prHeadBranch.setText(prModel.getHead().getRef());
prIsFork.setText(String.valueOf(prModel.getHead().getRepo().isFork()));
prForkFullName.setText(prModel.getHead().getRepo().getFull_name());
prCommentsCount.setText(String.valueOf(prModel.getComments()));
prCreatedTime.setText(TimeHelper.formatTime(prModel.getCreated_at(), new Locale(locale), timeFormat, context));

View File

@ -287,4 +287,7 @@ public interface ApiInterface {
@DELETE("teams/{teamId}/members/{username}") // remove team member
Call<JsonElement> removeTeamMember(@Header("Authorization") String token, @Path("teamId") int teamId, @Path("username") String username);
@DELETE("repos/{owner}/{repo}/branches/{branch}") // delete branch
Call<JsonElement> deleteBranch(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("branch") String branchName);
}

View File

@ -42,7 +42,7 @@ public class PullRequests {
this.body = body;
}
public class headObject {
public static class headObject {
private int repo_id;
private String label;
@ -51,7 +51,7 @@ public class PullRequests {
private repoObject repo;
public class repoObject {
public static class repoObject {
private int repo_id;
private boolean allow_merge_commits;
@ -91,7 +91,7 @@ public class PullRequests {
private ownerObject owner;
private permissionsObject permissions;
public class ownerObject {
public static class ownerObject {
private int repo_id;
private boolean is_admin;
@ -135,7 +135,7 @@ public class PullRequests {
}
}
public class permissionsObject {
public static class permissionsObject {
private boolean admin;
private boolean pull;
@ -295,9 +295,34 @@ public class PullRequests {
}
}
public int getRepo_id() {
return repo_id;
}
public String getLabel() {
return label;
}
public String getRef() {
return ref;
}
public String getSha() {
return sha;
}
public repoObject getRepo() {
return repo;
}
}
public class baseObject {
public static class baseObject {
private int repo_id;
private String label;
@ -306,7 +331,7 @@ public class PullRequests {
private repoObject repo;
public class repoObject {
public static class repoObject {
private int repo_id;
private boolean allow_merge_commits;
@ -344,7 +369,7 @@ public class PullRequests {
private ownerObject owner;
private permissionsObject permissions;
public class ownerObject {
public static class ownerObject {
private int repo_id;
private boolean is_admin;
@ -388,7 +413,7 @@ public class PullRequests {
}
}
public class permissionsObject {
public static class permissionsObject {
private boolean admin;
private boolean pull;
@ -540,9 +565,34 @@ public class PullRequests {
}
}
public int getRepo_id() {
return repo_id;
}
public String getLabel() {
return label;
}
public String getRef() {
return ref;
}
public String getSha() {
return sha;
}
public repoObject getRepo() {
return repo;
}
}
public class userObject {
public static class userObject {
private int id;
private String login;
@ -581,7 +631,7 @@ public class PullRequests {
}
}
public class labelsObject {
public static class labelsObject {
private int id;
private String name;
@ -605,7 +655,7 @@ public class PullRequests {
}
}
public class assigneesObject {
public static class assigneesObject {
private int id;
private String login;
@ -644,7 +694,7 @@ public class PullRequests {
}
}
public class mergedByObject {
public static class mergedByObject {
private int id;
private String login;
@ -683,7 +733,7 @@ public class PullRequests {
}
}
public class milestoneObject {
public static class milestoneObject {
private int id;
private String title;

View File

@ -1,21 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="@color/colorPrimaryDark">
<solid
android:color="@color/btnBackground">
</solid>
<item android:id="@android:id/mask">
<corners
android:radius="3dp">
</corners>
<shape android:shape="rectangle">
<padding
android:top="0dp"
android:right="10dp"
android:left="10dp"
android:bottom="0dp">
</padding>
<solid android:color="@color/btnBackground" />
<corners android:radius="3dp" />
</shape>
</shape>
</item>
<item android:id="@android:id/background">
<shape android:shape="rectangle">
<gradient
android:angle="90"
android:endColor="@color/btnBackground"
android:startColor="@color/btnBackground"
android:type="linear" />
<corners android:radius="3dp" />
<padding
android:top="0dp"
android:bottom="0dp"
android:left="10dp"
android:right="10dp"
/>
</shape>
</item>
</ripple>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="@color/hintColor">
</solid>
<corners
android:radius="3dp">
</corners>
<padding
android:top="0dp"
android:right="10dp"
android:left="10dp"
android:bottom="0dp">
</padding>
</shape>

View File

@ -123,6 +123,27 @@
</RelativeLayout>
<CheckBox
android:id="@+id/deleteBranch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/deleteBranchAfterMerge"
android:checked="false"
android:textSize="16sp"
android:layout_marginTop="10dp"
android:visibility="gone"
android:textColor="?attr/primaryTextColor"/>
<TextView
android:id="@+id/deleteBranchForkInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/deleteBranchForkInfo"
android:textColor="?attr/hintColor"
android:textSize="12sp"
android:gravity="start"
android:layout_marginTop="0dp" />
<TextView
android:id="@+id/mergeInfo"
android:layout_width="match_parent"
@ -131,7 +152,7 @@
android:textColor="?attr/hintColor"
android:textSize="12sp"
android:gravity="start"
android:layout_marginTop="10dp" />
android:layout_marginTop="15dp" />
<Button
android:id="@+id/mergeButton"
@ -144,6 +165,17 @@
android:background="@drawable/shape_buttons"
android:textColor="@color/btnTextColor" />
<TextView
android:id="@+id/mergeInfoDisabledMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/mergeInfoDisabledMessage"
android:textColor="?attr/hintColor"
android:textSize="12sp"
android:gravity="start"
android:visibility="gone"
android:layout_marginTop="10dp" />
</LinearLayout>
</ScrollView>

View File

@ -14,6 +14,30 @@
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/prMergeable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/prHeadBranch"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/prIsFork"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<TextView
android:id="@+id/prForkFullName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="invisible"/>
<ImageView
android:id="@+id/assigneeAvatar"
android:layout_width="48dp"

View File

@ -594,7 +594,10 @@
<string name="openFileDiffText">Files Changed</string>
<string name="mergePullRequestText">Merge Pull Request</string>
<string name="mergePullRequestButtonText">Merge</string>
<string name="deleteBranchAfterMerge">Delete branch after merge</string>
<string name="mergeNoteText">Merge may fail if you are not authorized to merge this Pull Request.</string>
<string name="mergeInfoDisabledMessage">Disabled Merge button means that there are conflicts OR other things to fix before Merge.</string>
<string name="deleteBranchForkInfo">This branch belong to a forked repository</string>
<string name="mergeCommentText">Merge comment</string>
<string name="mergePRSuccessMsg">Pull Request was merged successfully</string>
<string name="mergePR404ErrorMsg">Pull Request is not available for merge</string>