Merge remote-tracking branch 'remotes/main/master' into manrope

# Conflicts:
#	app/src/main/java/org/mian/gitnex/activities/BaseActivity.java
This commit is contained in:
opyale
2020-04-12 12:24:57 +02:00
19 changed files with 736 additions and 320 deletions

View File

@ -0,0 +1,143 @@
package org.mian.gitnex.actions;
import android.content.Context;
import android.util.Log;
import androidx.annotation.NonNull;
import com.google.gson.JsonElement;
import org.mian.gitnex.R;
import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.models.Milestones;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.viewmodels.MilestonesViewModel;
import retrofit2.Call;
import retrofit2.Callback;
/**
* Author M M Arif
*/
public class MilestoneActions {
static final private String TAG = "MilestoneActions : ";
public static void closeMilestone(final Context ctx, int milestoneId_) {
final TinyDB tinyDB = new TinyDB(ctx);
final String instanceUrl = tinyDB.getString("instanceUrl");
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String loginUid = tinyDB.getString("loginUid");
final String token = "token " + tinyDB.getString(loginUid + "-token");
Milestones milestoneStateJson = new Milestones("closed");
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, ctx)
.getApiInterface()
.closeReopenMilestone(token, repoOwner, repoName, milestoneId_, milestoneStateJson);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
Toasty.info(ctx, ctx.getString(R.string.milestoneStatusUpdate));
MilestonesViewModel.loadMilestonesList(instanceUrl, Authorization.returnAuthentication(ctx, loginUid, token), repoOwner, repoName, "all", ctx);
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle),
ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
public static void openMilestone(final Context ctx, int milestoneId_) {
final TinyDB tinyDB = new TinyDB(ctx);
final String instanceUrl = tinyDB.getString("instanceUrl");
String repoFullName = tinyDB.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final String loginUid = tinyDB.getString("loginUid");
final String token = "token " + tinyDB.getString(loginUid + "-token");
Milestones milestoneStateJson = new Milestones("open");
Call<JsonElement> call;
call = RetrofitClient
.getInstance(instanceUrl, ctx)
.getApiInterface()
.closeReopenMilestone(token, repoOwner, repoName, milestoneId_, milestoneStateJson);
call.enqueue(new Callback<JsonElement>() {
@Override
public void onResponse(@NonNull Call<JsonElement> call, @NonNull retrofit2.Response<JsonElement> response) {
if(response.isSuccessful()) {
Toasty.info(ctx, ctx.getString(R.string.milestoneStatusUpdate));
MilestonesViewModel.loadMilestonesList(instanceUrl, Authorization.returnAuthentication(ctx, loginUid, token), repoOwner, repoName, "all", ctx);
}
else if(response.code() == 401) {
AlertDialogs.authorizationTokenRevokedDialog(ctx, ctx.getResources().getString(R.string.alertDialogTokenRevokedTitle),
ctx.getResources().getString(R.string.alertDialogTokenRevokedMessage),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
ctx.getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else {
Toasty.info(ctx, ctx.getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<JsonElement> call, @NonNull Throwable t) {
Log.e(TAG, t.toString());
}
});
}
}

View File

@ -4,6 +4,7 @@ import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import org.mian.gitnex.R;
import org.mian.gitnex.helpers.FontsOverride;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.util.TinyDB;
/**
@ -17,12 +18,24 @@ public abstract class BaseActivity extends AppCompatActivity {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(tinyDb.getInt("themeId") == 1) {
setTheme(R.style.AppThemeLight);
}
else {
setTheme(R.style.AppTheme);
}
if(tinyDb.getInt("themeId") == 1) {
setTheme(R.style.AppThemeLight);
}
else if(tinyDb.getInt("themeId") == 2) {
boolean timeSetterFlag = TimeHelper.timeBetweenHours(18, 6); // 6pm to 6am
if(timeSetterFlag) {
setTheme(R.style.AppTheme);
}
else {
setTheme(R.style.AppThemeLight);
}
}
else {
setTheme(R.style.AppTheme);
}
super.onCreate(savedInstanceState);
setContentView(getLayoutResourceId());

View File

@ -17,7 +17,6 @@ import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
@ -34,6 +33,7 @@ import android.graphics.Color;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.text.Html;
@ -68,7 +68,6 @@ import org.mian.gitnex.helpers.RoundedTransformation;
import org.mian.gitnex.util.TinyDB;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.viewmodels.IssueCommentsViewModel;
import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collection;
@ -153,56 +152,42 @@ public class IssueDetailActivity extends BaseActivity {
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(mRecyclerView.getContext(), DividerItemDecoration.VERTICAL);
mRecyclerView.addItemDecoration(dividerItemDecoration);
createNewComment = findViewById(R.id.addNewComment);
createNewComment.setOnClickListener(new View.OnClickListener() {
createNewComment.setOnClickListener(v -> startActivity(new Intent(ctx, ReplyToIssueActivity.class)));
@Override
public void onClick(View v) {
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
startActivity(new Intent(ctx, ReplyToIssueActivity.class));
scrollViewComments.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
}
});
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
if (dy > 0 && createNewComment.isShown()) {
if ((scrollY - oldScrollY) > 0 && createNewComment.isShown()) {
createNewComment.setVisibility(View.GONE);
} else if (dy < 0) {
}
else if ((scrollY - oldScrollY) < 0) {
createNewComment.setVisibility(View.VISIBLE);
}
}
if (!scrollViewComments.canScrollVertically(1)) { // bottom
createNewComment.setVisibility(View.GONE);
}
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
}
});
if (!scrollViewComments.canScrollVertically(-1)) { // top
createNewComment.setVisibility(View.VISIBLE);
}
swipeRefresh.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
@Override
public void onRefresh() {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
swipeRefresh.setRefreshing(false);
IssueCommentsViewModel.loadIssueComments(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, getApplicationContext());
}
}, 500);
}
});
});
}
swipeRefresh.setOnRefreshListener(() -> new Handler().postDelayed(() -> {
swipeRefresh.setRefreshing(false);
IssueCommentsViewModel.loadIssueComments(instanceUrl, Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, issueIndex, getApplicationContext());
}, 500));
Typeface myTypeface;
switch(tinyDb.getInt("customFontId")) {
case 0:
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/roboto.ttf");
break;
case 1:
myTypeface = Typeface.createFromAsset(Objects.requireNonNull(getApplicationContext()).getAssets(), "fonts/manroperegular.ttf");
break;
@ -357,44 +342,35 @@ public class IssueDetailActivity extends BaseActivity {
final Markwon markwon = Markwon.builder(Objects.requireNonNull(getApplicationContext()))
.usePlugin(CorePlugin.create())
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
.usePlugin(ImagesPlugin.create(plugin -> {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
final int resourceId = getApplicationContext().getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
getApplicationContext().getPackageName());
final int resourceId = getApplicationContext().getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
getApplicationContext().getPackageName());
final Drawable drawable = getApplicationContext().getDrawable(resourceId);
final Drawable drawable = getApplicationContext().getDrawable(resourceId);
assert drawable != null;
return ImageItem.withResult(drawable);
}
assert drawable != null;
return ImageItem.withResult(drawable);
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(getApplicationContext().getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(getApplicationContext().getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(drawable -> null);
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(getApplicationContext().getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(getApplicationContext().getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}))
.usePlugin(new AbstractMarkwonPlugin() {
@ -580,12 +556,7 @@ public class IssueDetailActivity extends BaseActivity {
}
private void initCloseListener() {
View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
View.OnClickListener onClickListener = view -> finish();
}
}

View File

@ -1,16 +1,20 @@
package org.mian.gitnex.activities;
import androidx.annotation.NonNull;
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.hendraanggrian.appcompat.socialview.Mention;
import com.hendraanggrian.appcompat.widget.MentionArrayAdapter;
import com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView;
@ -19,10 +23,13 @@ import org.mian.gitnex.clients.RetrofitClient;
import org.mian.gitnex.helpers.AlertDialogs;
import org.mian.gitnex.helpers.Authorization;
import org.mian.gitnex.helpers.Toasty;
import org.mian.gitnex.helpers.VersionCheck;
import org.mian.gitnex.models.Collaborators;
import org.mian.gitnex.models.MergePullRequest;
import org.mian.gitnex.models.MergePullRequestSpinner;
import org.mian.gitnex.util.AppUtil;
import org.mian.gitnex.util.TinyDB;
import java.util.ArrayList;
import java.util.List;
import okhttp3.ResponseBody;
import retrofit2.Call;
@ -35,234 +42,267 @@ import retrofit2.Response;
public class MergePullRequestActivity extends BaseActivity {
public ImageView closeActivity;
private View.OnClickListener onClickListener;
public ImageView closeActivity;
private View.OnClickListener onClickListener;
final Context ctx = this;
final Context ctx = this;
private SocialAutoCompleteTextView mergePR;
private ArrayAdapter<Mention> defaultMentionAdapter;
private Button mergeButton;
private SocialAutoCompleteTextView mergeDescription;
private EditText mergeTitle;
private Spinner mergeModeSpinner;
private ArrayAdapter<Mention> defaultMentionAdapter;
private Button mergeButton;
private String Do;
@Override
protected int getLayoutResourceId(){
return R.layout.activity_merge_pull_request;
}
@Override
protected int getLayoutResourceId() {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
return R.layout.activity_merge_pull_request;
}
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
@SuppressLint("SetTextI18n")
@Override
public void onCreate(Bundle savedInstanceState) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
super.onCreate(savedInstanceState);
mergePR = findViewById(R.id.mergePR);
mergePR.setShowSoftInputOnFocus(true);
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
TinyDB tinyDb = new TinyDB(getApplicationContext());
mergePR.requestFocus();
assert imm != null;
imm.showSoftInput(mergePR, InputMethodManager.SHOW_IMPLICIT);
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList();
mergeModeSpinner = findViewById(R.id.mergeSpinner);
mergeDescription = findViewById(R.id.mergeDescription);
mergeTitle = findViewById(R.id.mergeTitle);
mergePR.setMentionAdapter(defaultMentionAdapter);
mergeTitle.requestFocus();
assert imm != null;
imm.showSoftInput(mergeTitle, InputMethodManager.SHOW_IMPLICIT);
closeActivity = findViewById(R.id.close);
TextView toolbar_title = findViewById(R.id.toolbar_title);
setMergeAdapter();
if(!tinyDb.getString("issueTitle").isEmpty()) {
toolbar_title.setText(tinyDb.getString("issueTitle"));
}
mergeModeSpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
mergeButton = findViewById(R.id.mergeButton);
MergePullRequestSpinner mergeId = (MergePullRequestSpinner) parent.getSelectedItem();
Do = mergeId.getId();
if(!connToInternet) {
}
disableProcessButton();
@Override
public void onNothingSelected(AdapterView<?> parent) {
} else {
}
mergeButton.setOnClickListener(mergePullRequest);
});
}
defaultMentionAdapter = new MentionArrayAdapter<>(this);
loadCollaboratorsList();
}
mergeDescription.setMentionAdapter(defaultMentionAdapter);
public void loadCollaboratorsList() {
closeActivity = findViewById(R.id.close);
TextView toolbar_title = findViewById(R.id.toolbar_title);
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(!tinyDb.getString("issueTitle").isEmpty()) {
toolbar_title.setText(tinyDb.getString("issueTitle"));
mergeTitle.setText(tinyDb.getString("issueTitle") + " (#" + tinyDb.getString("issueNumber")+ ")");
}
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
initCloseListener();
closeActivity.setOnClickListener(onClickListener);
Call<List<Collaborators>> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
mergeButton = findViewById(R.id.mergeButton);
call.enqueue(new Callback<List<Collaborators>>() {
if(!connToInternet) {
@Override
public void onResponse(@NonNull Call<List<Collaborators>> call, @NonNull Response<List<Collaborators>> response) {
disableProcessButton();
if (response.isSuccessful()) {
}
else {
assert response.body() != null;
String fullName = "";
for (int i = 0; i < response.body().size(); i++) {
if(!response.body().get(i).getFull_name().equals("")) {
fullName = response.body().get(i).getFull_name();
}
defaultMentionAdapter.add(
new Mention(response.body().get(i).getUsername(), fullName, response.body().get(i).getAvatar_url()));
}
mergeButton.setOnClickListener(mergePullRequest);
}
else {
}
Log.i("onResponse", String.valueOf(response.code()));
}
}
private void setMergeAdapter() {
}
TinyDB tinyDb = new TinyDB(getApplicationContext());
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
Log.i("onFailure", t.toString());
}
ArrayList<MergePullRequestSpinner> mergeList = new ArrayList<>();
});
}
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.5 and higher due to a bug
if(VersionCheck.compareVersion("1.11.5", tinyDb.getString("giteaVersion")) < 1) {
mergeList.add(new MergePullRequestSpinner("squash", getResources().getString(R.string.mergeOptionSquash)));
}
private void initCloseListener() {
onClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
};
}
ArrayAdapter<MergePullRequestSpinner> adapter = new ArrayAdapter<>(ctx, R.layout.spinner_item, mergeList);
adapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
mergeModeSpinner.setAdapter(adapter);
private View.OnClickListener mergePullRequest = new View.OnClickListener() {
public void onClick(View v) {
processMergePullRequest();
}
};
}
private void processMergePullRequest() {
public void loadCollaboratorsList() {
String mergePRDT = mergePR.getText().toString();
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
final TinyDB tinyDb = new TinyDB(getApplicationContext());
if(!connToInternet) {
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
return;
Call<List<Collaborators>> call = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().getCollaborators(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName);
}
call.enqueue(new Callback<List<Collaborators>>() {
disableProcessButton();
String doWhat = "merge";
mergeFunction(doWhat, mergePRDT);
@Override
public void onResponse(@NonNull Call<List<Collaborators>> call, @NonNull Response<List<Collaborators>> response) {
}
if(response.isSuccessful()) {
private void mergeFunction(String doWhat, String mergePRDT) {
assert response.body() != null;
String fullName = "";
for(int i = 0; i < response.body().size(); i++) {
if(!response.body().get(i).getFull_name().equals("")) {
fullName = response.body().get(i).getFull_name();
}
defaultMentionAdapter.add(new Mention(response.body().get(i).getUsername(), fullName, response.body().get(i).getAvatar_url()));
}
final TinyDB tinyDb = new TinyDB(getApplicationContext());
}
else {
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final int prIndex = Integer.parseInt(tinyDb.getString("issueNumber"));
Log.i("onResponse", String.valueOf(response.code()));
MergePullRequest mergePR = new MergePullRequest(doWhat, mergePRDT, null);
}
Call<ResponseBody> call = RetrofitClient
.getInstance(instanceUrl, getApplicationContext())
.getApiInterface()
.mergePullRequest(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, prIndex, mergePR);
}
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onFailure(@NonNull Call<List<Collaborators>> call, @NonNull Throwable t) {
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
Log.i("onFailure", t.toString());
}
if(response.code() == 200) {
});
}
Toasty.info(getApplicationContext(), getString(R.string.mergePRSuccessMsg));
tinyDb.putBoolean("prMerged", true);
tinyDb.putBoolean("resumePullRequests", true);
finish();
private void initCloseListener() {
}
else if(response.code() == 401) {
onClickListener = view -> finish();
}
enableProcessButton();
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle),
getResources().getString(R.string.alertDialogTokenRevokedMessage),
getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton),
getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
private View.OnClickListener mergePullRequest = v -> processMergePullRequest();
}
else if(response.code() == 404) {
private void processMergePullRequest() {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.mergePR404ErrorMsg));
String mergePRDesc = mergeDescription.getText().toString();
String mergePRTitle = mergeTitle.getText().toString();
}
else {
boolean connToInternet = AppUtil.haveNetworkConnection(getApplicationContext());
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.genericError));
if(!connToInternet) {
}
Toasty.info(getApplicationContext(), getResources().getString(R.string.checkNetConnection));
return;
}
}
@Override
public void onFailure(@NonNull Call<ResponseBody> call, @NonNull Throwable t) {
Log.e("onFailure", t.toString());
enableProcessButton();
}
disableProcessButton();
mergeFunction(Do, mergePRDesc, mergePRTitle);
});
}
}
private void mergeFunction(String Do, String mergePRDT, String mergeTitle) {
private void disableProcessButton() {
final TinyDB tinyDb = new TinyDB(getApplicationContext());
mergeButton.setEnabled(false);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.hintColor));
mergeButton.setBackground(shape);
final String instanceUrl = tinyDb.getString("instanceUrl");
final String loginUid = tinyDb.getString("loginUid");
final String instanceToken = "token " + tinyDb.getString(loginUid + "-token");
String repoFullName = tinyDb.getString("repoFullName");
String[] parts = repoFullName.split("/");
final String repoOwner = parts[0];
final String repoName = parts[1];
final int prIndex = Integer.parseInt(tinyDb.getString("issueNumber"));
}
MergePullRequest mergePR = new MergePullRequest(Do, mergePRDT, mergeTitle);
private void enableProcessButton() {
Call<ResponseBody> call = RetrofitClient.getInstance(instanceUrl, getApplicationContext()).getApiInterface().mergePullRequest(Authorization.returnAuthentication(getApplicationContext(), loginUid, instanceToken), repoOwner, repoName, prIndex, mergePR);
mergeButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius( 8 );
shape.setColor(getResources().getColor(R.color.btnBackground));
mergeButton.setBackground(shape);
call.enqueue(new Callback<ResponseBody>() {
}
@Override
public void onResponse(@NonNull Call<ResponseBody> call, @NonNull retrofit2.Response<ResponseBody> response) {
if(response.code() == 200) {
Toasty.info(getApplicationContext(), getString(R.string.mergePRSuccessMsg));
tinyDb.putBoolean("prMerged", true);
tinyDb.putBoolean("resumePullRequests", true);
finish();
}
else if(response.code() == 401) {
enableProcessButton();
AlertDialogs.authorizationTokenRevokedDialog(ctx, getResources().getString(R.string.alertDialogTokenRevokedTitle), getResources().getString(R.string.alertDialogTokenRevokedMessage), getResources().getString(R.string.alertDialogTokenRevokedCopyNegativeButton), getResources().getString(R.string.alertDialogTokenRevokedCopyPositiveButton));
}
else if(response.code() == 404) {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.mergePR404ErrorMsg));
}
else {
enableProcessButton();
Toasty.info(getApplicationContext(), getString(R.string.genericError));
}
}
@Override
public void onFailure(@NonNull Call<ResponseBody> 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);
}
private void enableProcessButton() {
mergeButton.setEnabled(true);
GradientDrawable shape = new GradientDrawable();
shape.setCornerRadius(8);
shape.setColor(getResources().getColor(R.color.btnBackground));
mergeButton.setBackground(shape);
}
}

View File

@ -15,8 +15,10 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.amulyakhare.textdrawable.TextDrawable;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.vdurmont.emoji.EmojiParser;
import org.mian.gitnex.R;
import org.mian.gitnex.actions.MilestoneActions;
import org.mian.gitnex.helpers.ClickListener;
import org.mian.gitnex.helpers.TimeHelper;
import org.mian.gitnex.models.Milestones;
@ -32,7 +34,6 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import io.noties.markwon.AbstractMarkwonPlugin;
import io.noties.markwon.Markwon;
@ -42,7 +43,6 @@ import io.noties.markwon.ext.strikethrough.StrikethroughPlugin;
import io.noties.markwon.ext.tables.TablePlugin;
import io.noties.markwon.ext.tasklist.TaskListPlugin;
import io.noties.markwon.html.HtmlPlugin;
import io.noties.markwon.image.AsyncDrawable;
import io.noties.markwon.image.DefaultMediaDecoder;
import io.noties.markwon.image.ImageItem;
import io.noties.markwon.image.ImagesPlugin;
@ -63,6 +63,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
static class MilestonesViewHolder extends RecyclerView.ViewHolder {
private TextView milestoneId;
private TextView msTitle;
private TextView msDescription;
private TextView msOpenIssues;
@ -70,10 +71,12 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
private TextView msDueDate;
private ImageView msStatus;
private ProgressBar msProgress;
private TextView milestoneStatus;
private MilestonesViewHolder(View itemView) {
super(itemView);
milestoneId = itemView.findViewById(R.id.milestoneId);
msTitle = itemView.findViewById(R.id.milestoneTitle);
msStatus = itemView.findViewById(R.id.milestoneState);
msDescription = itemView.findViewById(R.id.milestoneDescription);
@ -81,23 +84,52 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
msClosedIssues = itemView.findViewById(R.id.milestoneIssuesClosed);
msDueDate = itemView.findViewById(R.id.milestoneDueDate);
msProgress = itemView.findViewById(R.id.milestoneProgress);
ImageView milestonesMenu = itemView.findViewById(R.id.milestonesMenu);
milestoneStatus = itemView.findViewById(R.id.milestoneStatus);
/*msTitle.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
milestonesMenu.setOnClickListener(v -> {
Context context = v.getContext();
Log.i("issueNumber", issueNumber.getText().toString());
Context ctx = v.getContext();
int milestoneId_ = Integer.parseInt(milestoneId.getText().toString());
Intent intent = new Intent(context, IssueDetailActivity.class);
intent.putExtra("issueNumber", issueNumber.getText());
@SuppressLint("InflateParams") View view = LayoutInflater.from(ctx).inflate(R.layout.bottom_sheet_milestones_in_list, null);
TinyDB tinyDb = new TinyDB(context);
tinyDb.putString("issueNumber", issueNumber.getText().toString());
context.startActivity(intent);
TextView closeMilestone = view.findViewById(R.id.closeMilestone);
TextView openMilestone = view.findViewById(R.id.openMilestone);
BottomSheetDialog dialog = new BottomSheetDialog(ctx);
dialog.setContentView(view);
dialog.show();
if(milestoneStatus.getText().toString().equals("open")) {
closeMilestone.setVisibility(View.VISIBLE);
openMilestone.setVisibility(View.GONE);
}
else {
closeMilestone.setVisibility(View.GONE);
openMilestone.setVisibility(View.VISIBLE);
}
closeMilestone.setOnClickListener(v12 -> {
MilestoneActions.closeMilestone(ctx, milestoneId_);
dialog.dismiss();
});
openMilestone.setOnClickListener(v12 -> {
MilestoneActions.openMilestone(ctx, milestoneId_);
dialog.dismiss();
});
});
}
});*/
}
}
@ -123,46 +155,40 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
Milestones currentItem = milestonesList.get(position);
holder.milestoneId.setText(String.valueOf(currentItem.getId()));
holder.milestoneStatus.setText(currentItem.getState());
final Markwon markwon = Markwon.builder(Objects.requireNonNull(mCtx))
.usePlugin(CorePlugin.create())
.usePlugin(ImagesPlugin.create(new ImagesPlugin.ImagesConfigure() {
@Override
public void configureImages(@NonNull ImagesPlugin plugin) {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
.usePlugin(ImagesPlugin.create(plugin -> {
plugin.addSchemeHandler(new SchemeHandler() {
@NonNull
@Override
public ImageItem handle(@NonNull String raw, @NonNull Uri uri) {
final int resourceId = mCtx.getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
mCtx.getPackageName());
final int resourceId = mCtx.getResources().getIdentifier(
raw.substring("drawable://".length()),
"drawable",
mCtx.getPackageName());
final Drawable drawable = mCtx.getDrawable(resourceId);
final Drawable drawable = mCtx.getDrawable(resourceId);
assert drawable != null;
return ImageItem.withResult(drawable);
}
assert drawable != null;
return ImageItem.withResult(drawable);
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(new ImagesPlugin.PlaceholderProvider() {
@Nullable
@Override
public Drawable providePlaceholder(@NonNull AsyncDrawable drawable) {
return null;
}
});
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(mCtx.getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}
@NonNull
@Override
public Collection<String> supportedSchemes() {
return Collections.singleton("drawable");
}
});
plugin.placeholderProvider(drawable -> null);
plugin.addMediaDecoder(GifMediaDecoder.create(false));
plugin.addMediaDecoder(SvgMediaDecoder.create(mCtx.getResources()));
plugin.addMediaDecoder(SvgMediaDecoder.create());
plugin.defaultMediaDecoder(DefaultMediaDecoder.create(mCtx.getResources()));
plugin.defaultMediaDecoder(DefaultMediaDecoder.create());
}))
.usePlugin(new AbstractMarkwonPlugin() {
@Override
@ -182,7 +208,6 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
Spanned msTitle = markwon.toMarkdown(currentItem.getTitle());
markwon.setParsedMarkdown(holder.msTitle, msTitle);
//holder.msStatus.setText(currentItem.getState());
if(currentItem.getState().equals("open")) {
@ -261,13 +286,14 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
} catch (ParseException e) {
e.printStackTrace();
}
String dueDate = formatter.format(date);
assert date != null;
String dueDate = formatter.format(date);
if(date.before(new Date())) {
holder.msDueDate.setTextColor(mCtx.getResources().getColor(R.color.darkRed));
}
holder.msDueDate.setText(dueDate);
holder.msDueDate.setText(mCtx.getResources().getString(R.string.dueDate, dueDate));
holder.msDueDate.setOnClickListener(new ClickListener(TimeHelper.customDateFormatForToast(currentItem.getDue_on()), mCtx));
} else if (timeFormat.equals("normal1")) {
@ -279,7 +305,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
e.printStackTrace();
}
String dueDate = formatter.format(date1);
holder.msDueDate.setText(dueDate);
holder.msDueDate.setText(mCtx.getResources().getString(R.string.dueDate, dueDate));
}
}
@ -300,6 +326,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
}
private Filter milestoneFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
List<Milestones> filteredList = new ArrayList<>();
@ -328,6 +355,7 @@ public class MilestonesAdapter extends RecyclerView.Adapter<MilestonesAdapter.Mi
milestonesList.addAll((List) results.values);
notifyDataSetChanged();
}
};
}

View File

@ -151,6 +151,7 @@ public class PullRequestsFragment extends Fragment {
loadInitial(Authorization.returnAuthentication(getContext(), loginUid, instanceToken), repoOwner, repoName, pageSize, prState, resultLimit);
tinyDb.putBoolean("resumePullRequests", false);
tinyDb.putBoolean("prMerged", false);
}

View File

@ -44,7 +44,7 @@ public class SettingsFragment extends Fragment {
private static String[] customFontList = {"Roboto", "Manrope", "Source Code Pro"};
private static int customFontSelectedChoice = 0;
private static String[] themeList = {"Dark", "Light"};
private static String[] themeList = {"Dark", "Light", "Auto (Day/Night)"};
private static int themeSelectedChoice = 0;
@Nullable

View File

@ -6,9 +6,14 @@ import org.ocpsoft.prettytime.PrettyTime;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
/**
* Author M M Arif
*/
public class TimeHelper {
public static String customDateFormatForToast(String customDate) {
@ -59,4 +64,29 @@ public class TimeHelper {
}
public static boolean timeBetweenHours(int fromHour, int toHour) {
Calendar cal = Calendar.getInstance();
Calendar from = Calendar.getInstance();
from.set(Calendar.HOUR_OF_DAY, fromHour);
from.set(Calendar.MINUTE, 0);
Calendar to = Calendar.getInstance();
to.set(Calendar.HOUR_OF_DAY, toHour);
to.set(Calendar.MINUTE, 0);
if(to.before(from)) {
if (cal.after(to)) {
to.add(Calendar.DATE, 1);
}
else {
from.add(Calendar.DATE, -1);
}
}
return cal.after(from) && cal.before(to);
}
}

View File

@ -266,4 +266,7 @@ public interface ApiInterface {
@GET("repos/{owner}/{repo}/commits") // get all commits
Call<List<Commits>> getRepositoryCommits(@Header("Authorization") String token, @Path("owner") String owner, @Path("repo") String repo, @Query("page") int page, @Query("sha") String branchName);
@PATCH("repos/{owner}/{repo}/milestones/{index}") // close / reopen milestone
Call<JsonElement> closeReopenMilestone(@Header("Authorization") String token, @Path("owner") String ownerName, @Path("repo") String repoName, @Path("index") int index, @Body Milestones jsonStr);
}

View File

@ -11,9 +11,11 @@ public class MergePullRequest {
private String MergeTitleField;
public MergePullRequest(String Do, String MergeMessageField, String MergeTitleField) {
this.Do = Do;
this.MergeMessageField = MergeMessageField;
this.MergeTitleField = MergeTitleField;
}
}

View File

@ -0,0 +1,55 @@
package org.mian.gitnex.models;
import androidx.annotation.NonNull;
/**
* Author M M Arif
*/
public class MergePullRequestSpinner {
private String id;
private String mergerMethod;
public MergePullRequestSpinner(String id, String mergerMethod) {
this.id = id;
this.mergerMethod = mergerMethod;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
private String getMergerMethod() {
return mergerMethod;
}
public void setName(String mergerMethod) {
this.mergerMethod = mergerMethod;
}
@NonNull
@Override
public String toString() {
return mergerMethod;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof MergePullRequestSpinner){
MergePullRequestSpinner spinner = (MergePullRequestSpinner )obj;
return spinner.getMergerMethod().equals(mergerMethod) && spinner.getId().equals(id);
}
return false;
}
}

View File

@ -25,6 +25,10 @@ public class Milestones {
this.title = title;
}
public Milestones(String state) {
this.state = state;
}
public int getId() {
return id;
}

View File

@ -68,32 +68,67 @@
android:paddingBottom="30dp"
android:orientation="vertical">
<com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView
android:id="@+id/mergePR"
<EditText
android:id="@+id/mergeTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20dp"
android:padding="10dp"
android:textSize="14sp"
tools:ignore="Autofill"
android:background="@drawable/shape_inputs"
android:textColor="?attr/inputTextColor"
android:textColorHint="?attr/hintColor"
android:textColorHighlight="?attr/primaryTextColor"
android:inputType="textCapSentences|text" />
<com.hendraanggrian.appcompat.widget.SocialAutoCompleteTextView
android:id="@+id/mergeDescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:padding="10dp"
android:completionThreshold="1"
android:background="@drawable/shape_inputs"
android:maxLines="12"
android:minLines="10"
tools:ignore="Autofill"
android:labelFor="@+id/mergePR"
android:labelFor="@+id/mergeDescription"
android:scrollbars="vertical"
android:gravity="top|start"
android:textSize="14sp"
android:textColor="@color/white"
android:textColor="?attr/inputTextColor"
android:hint="@string/mergeCommentText"
android:textColorHint="@color/colorAccent"
android:textColorHint="?attr/hintColor"
android:inputType="textCapSentences|textMultiLine"
android:textColorHighlight="@color/white" />
android:textColorHighlight="?attr/primaryTextColor" />
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/shape_dropdown"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp" >
<Spinner
android:id="@+id/mergeSpinner"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:spinnerMode="dropdown"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingStart="5dp" />
</RelativeLayout>
<TextView
android:id="@+id/mergeInfo"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/mergeNoteText"
android:textColor="?attr/primaryTextColor"
android:textColor="?attr/hintColor"
android:textSize="12sp"
android:gravity="start"
android:layout_marginTop="10dp" />

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingBottom="8dp"
android:background="?attr/primaryBackgroundColor"
android:paddingTop="8dp">
<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">
<TextView
android:id="@+id/closeMilestone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/closeMilestone"
android:drawableStart="@drawable/ic_close"
android:drawablePadding="24dp"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:padding="16dp" />
<TextView
android:id="@+id/openMilestone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:text="@string/openMilestone"
android:drawableStart="@drawable/ic_check"
android:drawablePadding="24dp"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp"
android:padding="16dp" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</LinearLayout>

View File

@ -23,14 +23,15 @@
android:id="@+id/pdfMode"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal">
android:layout_marginTop="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/pdfModeHeader"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:layout_marginTop="10dp"
android:layout_marginStart="44dp"
android:layout_marginEnd="4dp"
android:text="@string/settingsPdfModeHeaderText"

View File

@ -22,7 +22,7 @@
android:id="@+id/langFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginTop="10dp"
android:orientation="vertical">
<TextView

View File

@ -23,8 +23,8 @@
android:id="@+id/certsFrame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
android:orientation="horizontal">
android:layout_marginTop="10dp"
android:orientation="vertical">
<TextView
android:id="@+id/tvCertHeader"

View File

@ -8,6 +8,18 @@
android:background="?attr/primaryBackgroundColor"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:id="@+id/milestoneId" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
android:id="@+id/milestoneStatus" />
<LinearLayout
android:id="@+id/frameTitle"
android:layout_width="match_parent"
@ -31,6 +43,7 @@
android:layout_weight=".15"
android:layout_gravity="end"
android:gravity="end"
android:scaleType="fitEnd"
android:contentDescription="@string/pageTitleCreateMilestone"
android:layout_marginBottom="5dp" />
@ -87,18 +100,39 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
android:id="@+id/milestoneDateMenuFrame"
android:layout_marginTop="8dp"
android:orientation="horizontal">
<TextView
android:id="@+id/milestoneDueDate"
android:layout_width="wrap_content"
<RelativeLayout
android:layout_width="0dp"
android:layout_weight=".90"
android:layout_height="wrap_content"
android:text="@string/repoWatchers"
android:gravity="start"
android:layout_marginTop="5dp"
android:textColor="?attr/primaryTextColor"
android:textSize="16sp" />
android:id="@+id/dueDateFrame"
android:orientation="horizontal"
android:layout_marginTop="3dp">
<TextView
android:id="@+id/milestoneDueDate"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/dueDate"
android:gravity="start"
android:textColor="?attr/primaryTextColor"
android:textSize="12sp" />
</RelativeLayout>
<ImageView
android:id="@+id/milestonesMenu"
android:layout_width="0dp"
android:layout_weight=".10"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:scaleType="fitEnd"
android:src="@drawable/ic_dotted_menu_horizontal"
android:contentDescription="@string/menuContentDesc" />
</LinearLayout>

View File

@ -183,7 +183,7 @@
<string name="issueCommenter">Commenter:\u0020</string>
<string name="issueTitleWithId" translatable="false">#%1$d %2$s</string>
<string name="issueMilestone">Milestone %1$s</string>
<string name="dueDate">Due %1$s</string>
<string name="dueDate">Due on %1$s</string>
<string name="createdTime">Opened %1$s</string>
<string name="assignedTo">Assigned to: %1$s</string>
<string name="commentButtonText">Comment</string>
@ -566,6 +566,10 @@
<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>
<string name="mergeOptionMerge">Merge Pull Request</string>
<string name="mergeOptionRebase">Rebase and Merge</string>
<string name="mergeOptionRebaseCommit">Rebase and Merge (&#45;&#45;no-ff)</string>
<string name="mergeOptionSquash">Squash and Merge</string>
<string name="downloadFile">Download This File</string>
<string name="waitLoadingDownloadFile">Please wait for the file to load to memory</string>
@ -602,4 +606,8 @@
<string name="issueSubscribtionError">Issue Subscription failed</string>
<string name="issueUnsubscribtion">Issue Unsubscribed</string>
<string name="issueUnsubscribtionError">Issue Un-Subscription failed</string>
<string name="closeMilestone">Close Milestone</string>
<string name="openMilestone">Open Milestone</string>
<string name="milestoneStatusUpdate">Milestone status updated successfully</string>
</resources>