mirror of
https://github.com/gitnex-org/gitnex.git
synced 2026-05-08 04:14:25 -05:00
Implement new UI for creating release/tag + can edit release. New content viewer
This commit is contained in:
@@ -39,9 +39,6 @@
|
||||
<activity
|
||||
android:name=".activities.AdminGetUsersActivity"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation"/>
|
||||
<activity
|
||||
android:name=".activities.CreateReleaseActivity"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation"/>
|
||||
<activity
|
||||
android:name=".activities.EditIssueActivity"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation"
|
||||
|
||||
@@ -1,482 +0,0 @@
|
||||
package org.mian.gitnex.activities;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.vdurmont.emoji.EmojiParser;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.gitnex.tea4j.v2.models.Branch;
|
||||
import org.gitnex.tea4j.v2.models.CreateReleaseOption;
|
||||
import org.gitnex.tea4j.v2.models.CreateTagOption;
|
||||
import org.gitnex.tea4j.v2.models.Release;
|
||||
import org.gitnex.tea4j.v2.models.Tag;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.adapters.BranchAdapter;
|
||||
import org.mian.gitnex.adapters.NotesAdapter;
|
||||
import org.mian.gitnex.clients.RetrofitClient;
|
||||
import org.mian.gitnex.database.api.BaseApi;
|
||||
import org.mian.gitnex.database.api.NotesApi;
|
||||
import org.mian.gitnex.database.models.Notes;
|
||||
import org.mian.gitnex.databinding.ActivityCreateReleaseBinding;
|
||||
import org.mian.gitnex.databinding.CustomInsertNoteBinding;
|
||||
import org.mian.gitnex.helpers.AlertDialogs;
|
||||
import org.mian.gitnex.helpers.Constants;
|
||||
import org.mian.gitnex.helpers.Markdown;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.helpers.contexts.RepositoryContext;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
|
||||
/**
|
||||
* @author mmarif
|
||||
*/
|
||||
public class CreateReleaseActivity extends BaseActivity {
|
||||
|
||||
private ActivityCreateReleaseBinding binding;
|
||||
List<String> branchesList = new ArrayList<>();
|
||||
private String selectedBranch;
|
||||
private RepositoryContext repository;
|
||||
private boolean renderMd = false;
|
||||
private MaterialAlertDialogBuilder materialAlertDialogBuilderNotes;
|
||||
private CustomInsertNoteBinding customInsertNoteBinding;
|
||||
private NotesAdapter adapter;
|
||||
private NotesApi notesApi;
|
||||
public AlertDialog dialogNotes;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
binding = ActivityCreateReleaseBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
repository = RepositoryContext.fromIntent(getIntent());
|
||||
|
||||
materialAlertDialogBuilderNotes =
|
||||
new MaterialAlertDialogBuilder(ctx, R.style.ThemeOverlay_Material3_Dialog_Alert);
|
||||
|
||||
binding.releaseContent.setOnTouchListener(
|
||||
(touchView, motionEvent) -> {
|
||||
touchView.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
|
||||
if ((motionEvent.getAction() & MotionEvent.ACTION_UP) != 0
|
||||
&& (motionEvent.getActionMasked() & MotionEvent.ACTION_UP) != 0) {
|
||||
|
||||
touchView.getParent().requestDisallowInterceptTouchEvent(false);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
binding.topAppBar.setNavigationOnClickListener(v -> finish());
|
||||
|
||||
binding.topAppBar.setOnMenuItemClickListener(
|
||||
menuItem -> {
|
||||
int id = menuItem.getItemId();
|
||||
|
||||
if (id == R.id.markdown) {
|
||||
|
||||
if (!renderMd) {
|
||||
Markdown.render(
|
||||
ctx,
|
||||
EmojiParser.parseToUnicode(
|
||||
Objects.requireNonNull(
|
||||
Objects.requireNonNull(
|
||||
binding.releaseContent
|
||||
.getText())
|
||||
.toString())),
|
||||
binding.markdownPreview);
|
||||
|
||||
binding.markdownPreview.setVisibility(View.VISIBLE);
|
||||
binding.releaseContentLayout.setVisibility(View.GONE);
|
||||
renderMd = true;
|
||||
} else {
|
||||
binding.markdownPreview.setVisibility(View.GONE);
|
||||
binding.releaseContentLayout.setVisibility(View.VISIBLE);
|
||||
renderMd = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if (id == R.id.create) {
|
||||
processNewRelease();
|
||||
return true;
|
||||
} else if (id == R.id.create_tag) {
|
||||
createNewTag();
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(menuItem);
|
||||
}
|
||||
});
|
||||
|
||||
binding.insertNote.setOnClickListener(insertNote -> showAllNotes());
|
||||
|
||||
binding.releaseBranch.setKeyListener(null);
|
||||
binding.releaseBranch.setCursorVisible(false);
|
||||
|
||||
binding.releaseBranch.setOnFocusChangeListener(
|
||||
(v, hasFocus) -> {
|
||||
if (hasFocus) {
|
||||
getBranches();
|
||||
binding.releaseBranch.clearFocus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void showAllNotes() {
|
||||
List<Notes> notesList = new ArrayList<>();
|
||||
notesApi = BaseApi.getInstance(ctx, NotesApi.class);
|
||||
customInsertNoteBinding = CustomInsertNoteBinding.inflate(LayoutInflater.from(ctx));
|
||||
|
||||
materialAlertDialogBuilderNotes.setView(customInsertNoteBinding.getRoot());
|
||||
|
||||
customInsertNoteBinding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
|
||||
adapter = new NotesAdapter(ctx, notesList, "insert", "release");
|
||||
customInsertNoteBinding.recyclerView.setAdapter(adapter);
|
||||
|
||||
if (notesApi.getCount() > 0) {
|
||||
fetchNotes();
|
||||
dialogNotes = materialAlertDialogBuilderNotes.show();
|
||||
} else {
|
||||
Toasty.show(ctx, getString(R.string.noNotes));
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchNotes() {
|
||||
customInsertNoteBinding.expressiveLoader.setVisibility(View.VISIBLE);
|
||||
|
||||
notesApi.fetchAllNotes()
|
||||
.observe(
|
||||
this,
|
||||
allNotes -> {
|
||||
customInsertNoteBinding.expressiveLoader.setVisibility(View.GONE);
|
||||
|
||||
if (allNotes != null && !allNotes.isEmpty()) {
|
||||
adapter.updateList(allNotes);
|
||||
customInsertNoteBinding
|
||||
.layoutEmpty
|
||||
.getRoot()
|
||||
.setVisibility(View.GONE);
|
||||
} else {
|
||||
adapter.updateList(new ArrayList<>());
|
||||
customInsertNoteBinding
|
||||
.layoutEmpty
|
||||
.getRoot()
|
||||
.setVisibility(View.VISIBLE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void createNewTag() {
|
||||
|
||||
String tagName = Objects.requireNonNull(binding.releaseTagName.getText()).toString();
|
||||
String message =
|
||||
Objects.requireNonNull(binding.releaseTitle.getText())
|
||||
+ "\n\n"
|
||||
+ Objects.requireNonNull(binding.releaseContent.getText());
|
||||
|
||||
if (tagName.isEmpty()) {
|
||||
Toasty.show(ctx, getString(R.string.tagNameErrorEmpty));
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedBranch == null) {
|
||||
Toasty.show(ctx, getString(R.string.selectBranchError));
|
||||
return;
|
||||
}
|
||||
|
||||
CreateTagOption createReleaseJson = new CreateTagOption();
|
||||
createReleaseJson.setMessage(message);
|
||||
createReleaseJson.setTagName(tagName);
|
||||
createReleaseJson.setTarget(selectedBranch);
|
||||
|
||||
Call<Tag> call =
|
||||
RetrofitClient.getApiInterface(ctx)
|
||||
.repoCreateTag(
|
||||
repository.getOwner(), repository.getName(), createReleaseJson);
|
||||
|
||||
call.enqueue(
|
||||
new Callback<>() {
|
||||
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<Tag> call, @NonNull retrofit2.Response<Tag> response) {
|
||||
|
||||
if (response.code() == 201) {
|
||||
|
||||
// RepoDetailActivity.updateFABActions = true;
|
||||
Toasty.show(ctx, getString(R.string.tagCreated));
|
||||
new Handler().postDelayed(() -> finish(), 3000);
|
||||
} else if (response.code() == 401) {
|
||||
AlertDialogs.authorizationTokenRevokedDialog(ctx);
|
||||
} else if (response.code() == 403) {
|
||||
Toasty.show(ctx, getString(R.string.authorizeError));
|
||||
} else if (response.code() == 404) {
|
||||
Toasty.show(ctx, getString(R.string.apiNotFound));
|
||||
} else {
|
||||
Toasty.show(ctx, getString(R.string.genericError));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Tag> call, @NonNull Throwable t) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void processNewRelease() {
|
||||
|
||||
String newReleaseTagName =
|
||||
Objects.requireNonNull(binding.releaseTagName.getText()).toString();
|
||||
String newReleaseTitle = Objects.requireNonNull(binding.releaseTitle.getText()).toString();
|
||||
String newReleaseContent =
|
||||
Objects.requireNonNull(binding.releaseContent.getText()).toString();
|
||||
String checkBranch = selectedBranch;
|
||||
boolean newReleaseType = binding.releaseType.isChecked();
|
||||
boolean newReleaseDraft = binding.releaseDraft.isChecked();
|
||||
|
||||
if (newReleaseTitle.isEmpty()) {
|
||||
Toasty.show(ctx, getString(R.string.titleErrorEmpty));
|
||||
return;
|
||||
}
|
||||
|
||||
if (newReleaseTagName.isEmpty()) {
|
||||
Toasty.show(ctx, getString(R.string.tagNameErrorEmpty));
|
||||
return;
|
||||
}
|
||||
|
||||
if (checkBranch == null) {
|
||||
Toasty.show(ctx, getString(R.string.selectBranchError));
|
||||
return;
|
||||
}
|
||||
|
||||
createNewReleaseFunc(
|
||||
repository.getOwner(),
|
||||
repository.getName(),
|
||||
newReleaseTagName,
|
||||
newReleaseTitle,
|
||||
newReleaseContent,
|
||||
selectedBranch,
|
||||
newReleaseType,
|
||||
newReleaseDraft);
|
||||
}
|
||||
|
||||
private void createNewReleaseFunc(
|
||||
String repoOwner,
|
||||
String repoName,
|
||||
String newReleaseTagName,
|
||||
String newReleaseTitle,
|
||||
String newReleaseContent,
|
||||
String selectedBranch,
|
||||
boolean newReleaseType,
|
||||
boolean newReleaseDraft) {
|
||||
|
||||
CreateReleaseOption createReleaseJson = new CreateReleaseOption();
|
||||
createReleaseJson.setName(newReleaseTitle);
|
||||
createReleaseJson.setTagName(newReleaseTagName);
|
||||
createReleaseJson.setBody(newReleaseContent);
|
||||
createReleaseJson.setDraft(newReleaseDraft);
|
||||
createReleaseJson.setPrerelease(newReleaseType);
|
||||
createReleaseJson.setTargetCommitish(selectedBranch);
|
||||
|
||||
Call<Release> call =
|
||||
RetrofitClient.getApiInterface(ctx)
|
||||
.repoCreateRelease(repoOwner, repoName, createReleaseJson);
|
||||
|
||||
call.enqueue(
|
||||
new Callback<>() {
|
||||
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<Release> call,
|
||||
@NonNull retrofit2.Response<Release> response) {
|
||||
|
||||
if (response.code() == 201) {
|
||||
|
||||
// RepoDetailActivity.updateFABActions = true;
|
||||
Toasty.show(ctx, getString(R.string.releaseCreatedText));
|
||||
new Handler().postDelayed(() -> finish(), 3000);
|
||||
} else if (response.code() == 401) {
|
||||
|
||||
AlertDialogs.authorizationTokenRevokedDialog(ctx);
|
||||
} else if (response.code() == 403) {
|
||||
|
||||
Toasty.show(ctx, getString(R.string.authorizeError));
|
||||
} else if (response.code() == 404) {
|
||||
|
||||
Toasty.show(ctx, getString(R.string.apiNotFound));
|
||||
} else {
|
||||
|
||||
Toasty.show(ctx, getString(R.string.genericError));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Release> call, @NonNull Throwable t) {}
|
||||
});
|
||||
}
|
||||
|
||||
private void getBranches() {
|
||||
|
||||
Dialog progressDialog = new Dialog(ctx);
|
||||
progressDialog.setCancelable(false);
|
||||
progressDialog.setContentView(R.layout.custom_progress_loader);
|
||||
progressDialog.show();
|
||||
|
||||
MaterialAlertDialogBuilder dialogBuilder = new MaterialAlertDialogBuilder(ctx);
|
||||
View dialogView = getLayoutInflater().inflate(R.layout.custom_branches_dialog, null);
|
||||
dialogBuilder.setView(dialogView);
|
||||
|
||||
RecyclerView recyclerView = dialogView.findViewById(R.id.recyclerView);
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
|
||||
|
||||
recyclerView.addItemDecoration(
|
||||
new RecyclerView.ItemDecoration() {
|
||||
@Override
|
||||
public void getItemOffsets(
|
||||
@NonNull Rect outRect,
|
||||
@NonNull View view,
|
||||
@NonNull RecyclerView parent,
|
||||
@NonNull RecyclerView.State state) {
|
||||
|
||||
int position = parent.getChildAdapterPosition(view);
|
||||
int spacingSides = (int) ctx.getResources().getDimension(R.dimen.dimen16dp);
|
||||
int spacingTop = (int) ctx.getResources().getDimension(R.dimen.dimen12dp);
|
||||
|
||||
outRect.right = spacingSides;
|
||||
outRect.left = spacingSides;
|
||||
|
||||
if (position > 0) {
|
||||
outRect.top = spacingTop;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialogBuilder.setNeutralButton(R.string.close, (dialog, which) -> dialog.dismiss());
|
||||
AlertDialog dialog = dialogBuilder.create();
|
||||
dialog.setCancelable(false);
|
||||
dialog.setCanceledOnTouchOutside(false);
|
||||
|
||||
final int[] page = {1};
|
||||
final int resultLimit = Constants.getCurrentResultLimit(ctx);
|
||||
final boolean[] isLoading = {false};
|
||||
final boolean[] isLastPage = {false};
|
||||
|
||||
BranchAdapter adapter =
|
||||
new BranchAdapter(
|
||||
branchName -> {
|
||||
binding.releaseBranch.setText(branchName);
|
||||
selectedBranch = branchName;
|
||||
dialog.dismiss();
|
||||
});
|
||||
recyclerView.setAdapter(adapter);
|
||||
|
||||
Runnable fetchBranches =
|
||||
() -> {
|
||||
if (isLoading[0] || isLastPage[0]) return;
|
||||
isLoading[0] = true;
|
||||
|
||||
Call<List<Branch>> call =
|
||||
RetrofitClient.getApiInterface(ctx)
|
||||
.repoListBranches(
|
||||
repository.getOwner(),
|
||||
repository.getName(),
|
||||
page[0],
|
||||
resultLimit);
|
||||
|
||||
call.enqueue(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<List<Branch>> call,
|
||||
@NonNull Response<List<Branch>> response) {
|
||||
|
||||
isLoading[0] = false;
|
||||
|
||||
if (response.code() == 200 && response.body() != null) {
|
||||
List<Branch> newBranches = response.body();
|
||||
adapter.addBranches(newBranches);
|
||||
|
||||
String totalCountStr =
|
||||
response.headers().get("X-Total-Count");
|
||||
|
||||
if (totalCountStr != null) {
|
||||
|
||||
int totalItems = Integer.parseInt(totalCountStr);
|
||||
int totalPages =
|
||||
(int)
|
||||
Math.ceil(
|
||||
(double) totalItems
|
||||
/ resultLimit);
|
||||
isLastPage[0] = page[0] >= totalPages;
|
||||
} else {
|
||||
isLastPage[0] = newBranches.size() < resultLimit;
|
||||
}
|
||||
page[0]++;
|
||||
|
||||
if (page[0] == 2 && !dialog.isShowing()) {
|
||||
progressDialog.dismiss();
|
||||
dialog.show();
|
||||
}
|
||||
} else {
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(
|
||||
@NonNull Call<List<Branch>> call, @NonNull Throwable t) {
|
||||
isLoading[0] = false;
|
||||
progressDialog.dismiss();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
recyclerView.addOnScrollListener(
|
||||
new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
|
||||
super.onScrolled(recyclerView, dx, dy);
|
||||
LinearLayoutManager layoutManager =
|
||||
(LinearLayoutManager) recyclerView.getLayoutManager();
|
||||
|
||||
if (layoutManager != null) {
|
||||
|
||||
int visibleItemCount = layoutManager.getChildCount();
|
||||
int totalItemCount = layoutManager.getItemCount();
|
||||
int firstVisibleItemPosition =
|
||||
layoutManager.findFirstVisibleItemPosition();
|
||||
|
||||
if (!isLoading[0]
|
||||
&& !isLastPage[0]
|
||||
&& (visibleItemCount + firstVisibleItemPosition)
|
||||
>= totalItemCount - 5) {
|
||||
fetchBranches.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// adapter.clear();
|
||||
fetchBranches.run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
repository.checkAccountSwitch(this);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.databinding.ActivityRepoDetailBinding;
|
||||
import org.mian.gitnex.fragments.BottomSheetCreateIssue;
|
||||
import org.mian.gitnex.fragments.BottomSheetCreateMilestone;
|
||||
import org.mian.gitnex.fragments.BottomSheetCreateRelease;
|
||||
import org.mian.gitnex.fragments.BottomsheetRepoMenu;
|
||||
import org.mian.gitnex.fragments.CollaboratorsFragment;
|
||||
import org.mian.gitnex.fragments.FilesFragment;
|
||||
@@ -625,7 +626,8 @@ public class RepoDetailActivity extends BaseActivity
|
||||
|
||||
case "newRelease":
|
||||
switchTab("releases", R.id.btn_nav_releases);
|
||||
startActivity(repository.getIntent(this, CreateReleaseActivity.class));
|
||||
BottomSheetCreateRelease.newInstance(repository, null)
|
||||
.show(getSupportFragmentManager(), "CREATE_RELEASE");
|
||||
break;
|
||||
|
||||
case "wiki":
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.activities.BaseActivity;
|
||||
import org.mian.gitnex.activities.CreateNoteActivity;
|
||||
import org.mian.gitnex.activities.CreatePullRequestActivity;
|
||||
import org.mian.gitnex.activities.CreateReleaseActivity;
|
||||
import org.mian.gitnex.database.api.BaseApi;
|
||||
import org.mian.gitnex.database.api.NotesApi;
|
||||
import org.mian.gitnex.database.models.Notes;
|
||||
@@ -107,10 +106,7 @@ public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NotesViewHol
|
||||
EditText targetField = null;
|
||||
AlertDialog dialogToDismiss = null;
|
||||
|
||||
if (activity instanceof CreateReleaseActivity releaseAct) {
|
||||
targetField = releaseAct.findViewById(R.id.releaseContent);
|
||||
dialogToDismiss = releaseAct.dialogNotes;
|
||||
} else if (activity instanceof CreatePullRequestActivity prAct) {
|
||||
if (activity instanceof CreatePullRequestActivity prAct) {
|
||||
targetField = prAct.findViewById(R.id.prBody);
|
||||
dialogToDismiss = prAct.dialogNotes;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.util.Locale;
|
||||
import org.gitnex.tea4j.v2.models.Release;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.databinding.ListReleasesBinding;
|
||||
import org.mian.gitnex.fragments.ReleasesFragment;
|
||||
import org.mian.gitnex.helpers.AvatarGenerator;
|
||||
import org.mian.gitnex.helpers.Markdown;
|
||||
import org.mian.gitnex.helpers.TimeHelper;
|
||||
@@ -33,13 +32,19 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
|
||||
private final Context context;
|
||||
private List<Release> releasesList;
|
||||
private final boolean canDelete;
|
||||
private final ReleasesFragment.OnReleaseItemClickListener listener;
|
||||
private final OnReleaseItemClickListener listener;
|
||||
|
||||
public interface OnReleaseItemClickListener {
|
||||
void onMenuClick(Release release, int position);
|
||||
|
||||
void onDownload(String url);
|
||||
}
|
||||
|
||||
public ReleasesAdapter(
|
||||
Context context,
|
||||
List<Release> releases,
|
||||
boolean canDelete,
|
||||
ReleasesFragment.OnReleaseItemClickListener listener) {
|
||||
OnReleaseItemClickListener listener) {
|
||||
this.context = context;
|
||||
this.releasesList = releases;
|
||||
this.canDelete = canDelete;
|
||||
@@ -71,14 +76,6 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void removeItem(int position) {
|
||||
if (position >= 0 && position < releasesList.size()) {
|
||||
releasesList.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
notifyItemRangeChanged(position, releasesList.size());
|
||||
}
|
||||
}
|
||||
|
||||
public class ReleasesViewHolder extends RecyclerView.ViewHolder {
|
||||
private final ListReleasesBinding binding;
|
||||
|
||||
@@ -137,7 +134,7 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
|
||||
if (release.getAssets() != null && !release.getAssets().isEmpty()) {
|
||||
binding.downloadList.setVisibility(View.VISIBLE);
|
||||
ReleasesDownloadsAdapter downloadsAdapter =
|
||||
new ReleasesDownloadsAdapter(release.getAssets(), listener);
|
||||
new ReleasesDownloadsAdapter(release.getAssets(), listener::onDownload);
|
||||
|
||||
binding.downloadList.setLayoutManager(new LinearLayoutManager(context));
|
||||
binding.downloadList.setAdapter(downloadsAdapter);
|
||||
@@ -148,7 +145,7 @@ public class ReleasesAdapter extends RecyclerView.Adapter<ReleasesAdapter.Releas
|
||||
|
||||
binding.itemMenu.setVisibility(canDelete ? View.VISIBLE : View.GONE);
|
||||
binding.itemMenu.setOnClickListener(
|
||||
v -> listener.onDelete(release, getBindingAdapterPosition()));
|
||||
v -> listener.onMenuClick(release, getBindingAdapterPosition()));
|
||||
|
||||
binding.btnAssets.setOnClickListener(
|
||||
v -> {
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
package org.mian.gitnex.fragments;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.text.Spannable;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.databinding.BottomsheetContentViewerBinding;
|
||||
import org.mian.gitnex.helpers.AppUtil;
|
||||
import org.mian.gitnex.helpers.Markdown;
|
||||
import org.mian.gitnex.helpers.contexts.RepositoryContext;
|
||||
|
||||
/**
|
||||
* @author mmarif
|
||||
*/
|
||||
public class BottomSheetContentViewer extends BottomSheetDialogFragment {
|
||||
|
||||
public enum Feature {
|
||||
MARKDOWN_PREVIEW, // Enable markdown preview toggle
|
||||
START_IN_MARKDOWN, // Start showing Markdown instead of raw content
|
||||
ALLOW_COPY, // Show copy button (always visible by default)
|
||||
ALLOW_SHARE, // Show share button (always visible by default)
|
||||
SYNTAX_HIGHLIGHT, // Use renderWithHighlights for code
|
||||
SHOW_TITLE, // Show title in header
|
||||
}
|
||||
|
||||
/*
|
||||
Spannable highlighted = SyntaxHighlighter.highlight(code, "java");
|
||||
BottomSheetContentViewer.newInstance(
|
||||
highlighted,
|
||||
"Main.java",
|
||||
repoContext,
|
||||
BottomSheetContentViewer.Feature.SYNTAX_HIGHLIGHT,
|
||||
ContentViewerBottomSheet.Feature.MARKDOWN_PREVIEW,
|
||||
ContentViewerBottomSheet.Feature.SHOW_TITLE
|
||||
).show(fm, "viewer");
|
||||
*/
|
||||
|
||||
private static final String ARG_CONTENT = "content";
|
||||
private static final String ARG_TITLE = "title";
|
||||
private static final String ARG_REPO_CONTEXT = "repo_context";
|
||||
private static final String ARG_FEATURES = "features";
|
||||
private static final String ARG_IS_SPANNABLE = "is_spannable";
|
||||
|
||||
private BottomsheetContentViewerBinding binding;
|
||||
private final Set<Feature> enabledFeatures = new HashSet<>();
|
||||
private RepositoryContext repoContext;
|
||||
private String rawContent;
|
||||
private String title;
|
||||
private Spannable spannableContent;
|
||||
private boolean isSpannable = false;
|
||||
private boolean isMarkdownMode = false;
|
||||
|
||||
public static BottomSheetContentViewer newInstance(
|
||||
String content,
|
||||
@Nullable String title,
|
||||
@Nullable RepositoryContext repoContext,
|
||||
Feature... features) {
|
||||
BottomSheetContentViewer fragment = new BottomSheetContentViewer();
|
||||
Bundle args = new Bundle();
|
||||
args.putString(ARG_CONTENT, content);
|
||||
args.putBoolean(ARG_IS_SPANNABLE, false);
|
||||
if (title != null) args.putString(ARG_TITLE, title);
|
||||
if (repoContext != null) args.putSerializable(ARG_REPO_CONTEXT, repoContext);
|
||||
args.putStringArrayList(ARG_FEATURES, featureNamesToList(features));
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public static BottomSheetContentViewer newInstance(
|
||||
Spannable spannable,
|
||||
@Nullable String title,
|
||||
@Nullable RepositoryContext repoContext,
|
||||
Feature... features) {
|
||||
BottomSheetContentViewer fragment = new BottomSheetContentViewer();
|
||||
Bundle args = new Bundle();
|
||||
args.putCharSequence(ARG_CONTENT, spannable);
|
||||
args.putBoolean(ARG_IS_SPANNABLE, true);
|
||||
if (title != null) args.putString(ARG_TITLE, title);
|
||||
if (repoContext != null) args.putSerializable(ARG_REPO_CONTEXT, repoContext);
|
||||
args.putStringArrayList(ARG_FEATURES, featureNamesToList(features));
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
private static ArrayList<String> featureNamesToList(Feature... features) {
|
||||
ArrayList<String> names = new ArrayList<>();
|
||||
for (Feature f : features) {
|
||||
names.add(f.name());
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
isSpannable = getArguments().getBoolean(ARG_IS_SPANNABLE, false);
|
||||
|
||||
if (isSpannable) {
|
||||
spannableContent = (Spannable) getArguments().getCharSequence(ARG_CONTENT);
|
||||
} else {
|
||||
rawContent = getArguments().getString(ARG_CONTENT, "");
|
||||
}
|
||||
|
||||
title = getArguments().getString(ARG_TITLE);
|
||||
repoContext = (RepositoryContext) getArguments().getSerializable(ARG_REPO_CONTEXT);
|
||||
|
||||
ArrayList<String> featureNames = getArguments().getStringArrayList(ARG_FEATURES);
|
||||
if (featureNames != null) {
|
||||
for (String name : featureNames) {
|
||||
try {
|
||||
enabledFeatures.add(Feature.valueOf(name));
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isMarkdownMode = enabledFeatures.contains(Feature.START_IN_MARKDOWN);
|
||||
}
|
||||
|
||||
@Nullable @Override
|
||||
public View onCreateView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
binding = BottomsheetContentViewerBinding.inflate(inflater, container, false);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
setupUI();
|
||||
renderContent();
|
||||
}
|
||||
|
||||
private void setupUI() {
|
||||
binding.btnClose.setOnClickListener(v -> dismiss());
|
||||
|
||||
if (enabledFeatures.contains(Feature.ALLOW_COPY)) {
|
||||
binding.btnCopy.setVisibility(View.VISIBLE);
|
||||
binding.btnCopy.setOnClickListener(v -> copyContent());
|
||||
}
|
||||
|
||||
if (enabledFeatures.contains(Feature.ALLOW_SHARE)) {
|
||||
binding.btnShare.setVisibility(View.VISIBLE);
|
||||
binding.btnShare.setOnClickListener(v -> shareContent());
|
||||
}
|
||||
|
||||
if (enabledFeatures.contains(Feature.MARKDOWN_PREVIEW)) {
|
||||
binding.btnMarkdown.setVisibility(View.VISIBLE);
|
||||
binding.btnMarkdown.setOnClickListener(v -> toggleMarkdownMode());
|
||||
updateMarkdownIcon();
|
||||
}
|
||||
|
||||
if (enabledFeatures.contains(Feature.SHOW_TITLE) && title != null) {
|
||||
binding.viewerTitle.setText(title);
|
||||
binding.viewerTitle.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void renderContent() {
|
||||
if (isMarkdownMode) {
|
||||
renderMarkdown();
|
||||
} else {
|
||||
renderRaw();
|
||||
}
|
||||
}
|
||||
|
||||
private void renderRaw() {
|
||||
binding.rawContentScroll.setVisibility(View.VISIBLE);
|
||||
binding.markdownPreviewScroll.setVisibility(View.GONE);
|
||||
binding.markdownPreview.setVisibility(View.GONE);
|
||||
binding.markdownPreviewText.setVisibility(View.GONE);
|
||||
|
||||
String content = getContentAsString();
|
||||
binding.rawContentText.setText(content);
|
||||
}
|
||||
|
||||
private void renderMarkdown() {
|
||||
binding.rawContentScroll.setVisibility(View.GONE);
|
||||
binding.markdownPreviewScroll.setVisibility(View.VISIBLE);
|
||||
|
||||
String content = getContentAsString();
|
||||
if (content == null) content = "";
|
||||
|
||||
if (enabledFeatures.contains(Feature.SYNTAX_HIGHLIGHT) && spannableContent != null) {
|
||||
binding.markdownPreview.setVisibility(View.VISIBLE);
|
||||
binding.markdownPreviewText.setVisibility(View.GONE);
|
||||
Markdown.renderWithHighlights(
|
||||
requireContext(), spannableContent, binding.markdownPreview, repoContext);
|
||||
} else if (repoContext != null) {
|
||||
binding.markdownPreview.setVisibility(View.VISIBLE);
|
||||
binding.markdownPreviewText.setVisibility(View.GONE);
|
||||
Markdown.render(requireContext(), content, binding.markdownPreview, repoContext);
|
||||
} else {
|
||||
binding.markdownPreview.setVisibility(View.GONE);
|
||||
binding.markdownPreviewText.setVisibility(View.VISIBLE);
|
||||
Markdown.render(requireContext(), content, binding.markdownPreviewText);
|
||||
}
|
||||
}
|
||||
|
||||
private String getContentAsString() {
|
||||
return isSpannable && spannableContent != null ? spannableContent.toString() : rawContent;
|
||||
}
|
||||
|
||||
private void toggleMarkdownMode() {
|
||||
isMarkdownMode = !isMarkdownMode;
|
||||
updateMarkdownIcon();
|
||||
renderContent();
|
||||
}
|
||||
|
||||
private void updateMarkdownIcon() {
|
||||
binding.btnMarkdown.setIconResource(
|
||||
isMarkdownMode ? R.drawable.ic_edit : R.drawable.ic_markdown);
|
||||
}
|
||||
|
||||
private void copyContent() {
|
||||
String content = getContentAsString();
|
||||
AppUtil.copyToClipboard(requireContext(), content, getString(R.string.copied_to_clipboard));
|
||||
}
|
||||
|
||||
private void shareContent() {
|
||||
String content = getContentAsString();
|
||||
AppUtil.sharingIntent(requireContext(), content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
Dialog dialog = getDialog();
|
||||
if (dialog instanceof BottomSheetDialog) {
|
||||
AppUtil.applyFullScreenSheetStyle((BottomSheetDialog) dialog, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,460 @@
|
||||
package org.mian.gitnex.fragments;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import java.util.Objects;
|
||||
import org.gitnex.tea4j.v2.models.CreateReleaseOption;
|
||||
import org.gitnex.tea4j.v2.models.CreateTagOption;
|
||||
import org.gitnex.tea4j.v2.models.Release;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.databinding.BottomsheetCreateReleaseBinding;
|
||||
import org.mian.gitnex.helpers.AlertDialogs;
|
||||
import org.mian.gitnex.helpers.AppUtil;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.helpers.contexts.RepositoryContext;
|
||||
import org.mian.gitnex.viewmodels.ReleasesViewModel;
|
||||
|
||||
/**
|
||||
* @author mmarif
|
||||
*/
|
||||
public class BottomSheetCreateRelease extends BottomSheetDialogFragment {
|
||||
|
||||
private BottomsheetCreateReleaseBinding binding;
|
||||
private ReleasesViewModel viewModel;
|
||||
private RepositoryContext repoContext;
|
||||
private Release releaseToEdit;
|
||||
private String selectedBranch = null;
|
||||
private boolean isReleaseMode = true;
|
||||
|
||||
public static BottomSheetCreateRelease newInstance(
|
||||
RepositoryContext repository, @Nullable Release release) {
|
||||
BottomSheetCreateRelease fragment = new BottomSheetCreateRelease();
|
||||
Bundle args = new Bundle();
|
||||
args.putSerializable("repo_context", repository);
|
||||
if (release != null) {
|
||||
args.putSerializable("release_item", release);
|
||||
}
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (getArguments() != null) {
|
||||
repoContext = (RepositoryContext) getArguments().getSerializable("repo_context");
|
||||
releaseToEdit = (Release) getArguments().getSerializable("release_item");
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable @Override
|
||||
public View onCreateView(
|
||||
@NonNull LayoutInflater inflater,
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
binding = BottomsheetCreateReleaseBinding.inflate(inflater, container, false);
|
||||
return binding.getRoot();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
viewModel = new ViewModelProvider(requireActivity()).get(ReleasesViewModel.class);
|
||||
|
||||
viewModel.clearCreatedRelease();
|
||||
viewModel.clearCreatedTag();
|
||||
viewModel.clearUpdatedRelease();
|
||||
|
||||
setupUI();
|
||||
setupListeners();
|
||||
observeViewModel();
|
||||
|
||||
ViewGroup.LayoutParams editTextParams = binding.releaseContent.getLayoutParams();
|
||||
editTextParams.height = (int) (224 * getResources().getDisplayMetrics().density);
|
||||
binding.releaseContent.setLayoutParams(editTextParams);
|
||||
}
|
||||
|
||||
private void setupUI() {
|
||||
boolean hasWriteAccess =
|
||||
repoContext.getPermissions() != null && repoContext.getPermissions().isPush();
|
||||
|
||||
binding.cardBranch.cardIcon.setImageResource(R.drawable.ic_branch);
|
||||
binding.cardBranch.tvCardLabel.setText(R.string.pageTitleChooseBranch);
|
||||
binding.cardBranch.getRoot().setVisibility(hasWriteAccess ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (releaseToEdit != null) {
|
||||
binding.sheetTitle.setText(R.string.editRelease);
|
||||
binding.createTypeToggle.setVisibility(View.GONE);
|
||||
binding.releaseTagNameLayout.setVisibility(View.GONE);
|
||||
binding.switchDraft.setVisibility(View.GONE);
|
||||
binding.descriptionContainer.setVisibility(View.VISIBLE);
|
||||
binding.switchPrerelease.setVisibility(View.VISIBLE);
|
||||
|
||||
binding.releaseTitle.setText(releaseToEdit.getName());
|
||||
binding.releaseContent.setText(releaseToEdit.getBody());
|
||||
binding.switchPrerelease.setChecked(releaseToEdit.isPrerelease());
|
||||
|
||||
binding.cardBranch.getRoot().setVisibility(View.GONE);
|
||||
|
||||
binding.btnSubmit.setText(R.string.update);
|
||||
} else {
|
||||
binding.sheetTitle.setText(R.string.createRelease);
|
||||
binding.descriptionContainer.setVisibility(View.VISIBLE);
|
||||
binding.switchPrerelease.setVisibility(View.VISIBLE);
|
||||
binding.switchDraft.setVisibility(View.VISIBLE);
|
||||
|
||||
if (hasWriteAccess) {
|
||||
updateBranchDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
updateBranchClearButtonVisibility();
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
binding.btnClose.setOnClickListener(v -> dismiss());
|
||||
binding.btnExpand.setOnClickListener(v -> openFullScreenEditor());
|
||||
binding.btnSubmit.setOnClickListener(v -> submitAction());
|
||||
|
||||
boolean hasWriteAccess =
|
||||
repoContext.getPermissions() != null && repoContext.getPermissions().isPush();
|
||||
|
||||
if (hasWriteAccess) {
|
||||
binding.cardBranch.getRoot().setOnClickListener(v -> openBranchPicker());
|
||||
binding.cardBranch.btnClear.setOnClickListener(
|
||||
v -> {
|
||||
selectedBranch = null;
|
||||
updateBranchDisplay();
|
||||
updateBranchClearButtonVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
binding.createTypeToggle.addOnButtonCheckedListener(
|
||||
(group, checkedId, isChecked) -> {
|
||||
if (isChecked) {
|
||||
isReleaseMode = checkedId == R.id.btn_create_release;
|
||||
updateUIForMode();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void updateUIForMode() {
|
||||
if (releaseToEdit == null) {
|
||||
if (isReleaseMode) {
|
||||
binding.releaseTitleLayout.setHint(R.string.releaseTitleText);
|
||||
binding.descriptionContainer.setVisibility(View.VISIBLE);
|
||||
binding.switchPrerelease.setVisibility(View.VISIBLE);
|
||||
binding.switchDraft.setVisibility(View.VISIBLE);
|
||||
binding.btnSubmit.setText(R.string.createRelease);
|
||||
} else {
|
||||
binding.releaseTitleLayout.setHint(R.string.description);
|
||||
binding.descriptionContainer.setVisibility(View.GONE);
|
||||
binding.switchPrerelease.setVisibility(View.GONE);
|
||||
binding.switchDraft.setVisibility(View.GONE);
|
||||
binding.btnSubmit.setText(R.string.createTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void openBranchPicker() {
|
||||
BottomsheetBranchPicker branchPicker =
|
||||
BottomsheetBranchPicker.newInstance(
|
||||
repoContext.getOwner(),
|
||||
repoContext.getName(),
|
||||
selectedBranch != null ? selectedBranch : repoContext.getBranchRef());
|
||||
|
||||
branchPicker.setOnBranchSelectedListener(
|
||||
branchName -> {
|
||||
selectedBranch = branchName;
|
||||
updateBranchDisplay();
|
||||
updateBranchClearButtonVisibility();
|
||||
});
|
||||
|
||||
branchPicker.show(getParentFragmentManager(), "BRANCH_PICKER");
|
||||
}
|
||||
|
||||
private void updateBranchDisplay() {
|
||||
if (selectedBranch == null || selectedBranch.isEmpty()) {
|
||||
binding.cardBranch.tvSelectedText.setText(R.string.add_release_branch);
|
||||
} else {
|
||||
binding.cardBranch.tvSelectedText.setText(selectedBranch);
|
||||
}
|
||||
}
|
||||
|
||||
private void updateBranchClearButtonVisibility() {
|
||||
binding.cardBranch.btnClear.setVisibility(
|
||||
selectedBranch == null || selectedBranch.isEmpty() ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
|
||||
private void openFullScreenEditor() {
|
||||
BottomSheetFullScreenEditor editorBottomSheet =
|
||||
BottomSheetFullScreenEditor.newInstance(
|
||||
Objects.requireNonNull(binding.releaseContent.getText()).toString(),
|
||||
repoContext,
|
||||
true,
|
||||
true);
|
||||
|
||||
editorBottomSheet.setEditorListener(
|
||||
newContent -> {
|
||||
binding.releaseContent.setText(newContent);
|
||||
binding.releaseContent.setSelection(
|
||||
newContent != null ? newContent.length() : 0);
|
||||
});
|
||||
|
||||
editorBottomSheet.show(getParentFragmentManager(), "FULLSCREEN_EDITOR");
|
||||
}
|
||||
|
||||
private void submitAction() {
|
||||
if (releaseToEdit != null) {
|
||||
submitUpdateRelease();
|
||||
} else if (isReleaseMode) {
|
||||
submitCreateRelease();
|
||||
} else {
|
||||
submitCreateTag();
|
||||
}
|
||||
}
|
||||
|
||||
private void submitCreateRelease() {
|
||||
String tagName =
|
||||
binding.releaseTagName.getText() != null
|
||||
? binding.releaseTagName.getText().toString().trim()
|
||||
: "";
|
||||
String title =
|
||||
binding.releaseTitle.getText() != null
|
||||
? binding.releaseTitle.getText().toString().trim()
|
||||
: "";
|
||||
String content =
|
||||
binding.releaseContent.getText() != null
|
||||
? binding.releaseContent.getText().toString().trim()
|
||||
: "";
|
||||
|
||||
if (tagName.isEmpty()) {
|
||||
Toasty.show(requireContext(), R.string.tagNameErrorEmpty);
|
||||
return;
|
||||
}
|
||||
|
||||
if (title.isEmpty()) {
|
||||
Toasty.show(requireContext(), R.string.titleErrorEmpty);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedBranch == null || selectedBranch.isEmpty()) {
|
||||
Toasty.show(requireContext(), R.string.selectBranchError);
|
||||
return;
|
||||
}
|
||||
|
||||
CreateReleaseOption releaseData = new CreateReleaseOption();
|
||||
releaseData.setTagName(tagName);
|
||||
releaseData.setName(title);
|
||||
releaseData.setName(title);
|
||||
releaseData.setBody(content);
|
||||
releaseData.setTargetCommitish(selectedBranch);
|
||||
releaseData.setDraft(binding.switchDraft.isChecked());
|
||||
releaseData.setPrerelease(binding.switchPrerelease.isChecked());
|
||||
|
||||
viewModel.createRelease(
|
||||
requireContext(), repoContext.getOwner(), repoContext.getName(), releaseData);
|
||||
}
|
||||
|
||||
private void submitCreateTag() {
|
||||
String tagName =
|
||||
binding.releaseTagName.getText() != null
|
||||
? binding.releaseTagName.getText().toString().trim()
|
||||
: "";
|
||||
String message =
|
||||
binding.releaseTitle.getText() != null
|
||||
? binding.releaseTitle.getText().toString().trim()
|
||||
: "";
|
||||
|
||||
if (tagName.isEmpty()) {
|
||||
Toasty.show(requireContext(), R.string.tagNameErrorEmpty);
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedBranch == null || selectedBranch.isEmpty()) {
|
||||
Toasty.show(requireContext(), R.string.selectBranchError);
|
||||
return;
|
||||
}
|
||||
|
||||
CreateTagOption tagData = new CreateTagOption();
|
||||
tagData.setTagName(tagName);
|
||||
tagData.setMessage(message);
|
||||
tagData.setTarget(selectedBranch);
|
||||
|
||||
viewModel.createTag(
|
||||
requireContext(), repoContext.getOwner(), repoContext.getName(), tagData);
|
||||
}
|
||||
|
||||
private void submitUpdateRelease() {
|
||||
String title =
|
||||
binding.releaseTitle.getText() != null
|
||||
? binding.releaseTitle.getText().toString().trim()
|
||||
: "";
|
||||
String content =
|
||||
binding.releaseContent.getText() != null
|
||||
? binding.releaseContent.getText().toString().trim()
|
||||
: "";
|
||||
|
||||
if (title.isEmpty()) {
|
||||
Toasty.show(requireContext(), R.string.titleErrorEmpty);
|
||||
return;
|
||||
}
|
||||
|
||||
viewModel.updateRelease(
|
||||
requireContext(),
|
||||
repoContext.getOwner(),
|
||||
repoContext.getName(),
|
||||
releaseToEdit.getId(),
|
||||
title,
|
||||
content,
|
||||
binding.switchPrerelease.isChecked());
|
||||
}
|
||||
|
||||
private void observeViewModel() {
|
||||
viewModel
|
||||
.getIsCreatingRelease()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
isCreating -> {
|
||||
binding.loadingIndicator.setVisibility(
|
||||
isCreating ? View.VISIBLE : View.GONE);
|
||||
binding.btnSubmit.setEnabled(!isCreating);
|
||||
binding.btnSubmit.setText(
|
||||
isCreating
|
||||
? ""
|
||||
: getString(
|
||||
releaseToEdit != null
|
||||
? R.string.update
|
||||
: (isReleaseMode
|
||||
? R.string.createRelease
|
||||
: R.string.createTag)));
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getCreatedRelease()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
release -> {
|
||||
if (release != null) {
|
||||
Toasty.show(requireContext(), R.string.releaseCreatedText);
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getCreateReleaseError()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
handleError(error);
|
||||
viewModel.clearCreateReleaseError();
|
||||
}
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getIsCreatingTag()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
isCreating -> {
|
||||
if (!isReleaseMode) {
|
||||
binding.loadingIndicator.setVisibility(
|
||||
isCreating ? View.VISIBLE : View.GONE);
|
||||
binding.btnSubmit.setEnabled(!isCreating);
|
||||
binding.btnSubmit.setText(
|
||||
isCreating ? "" : getString(R.string.createTag));
|
||||
}
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getCreatedTag()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
tag -> {
|
||||
if (tag != null) {
|
||||
Toasty.show(requireContext(), R.string.tagCreated);
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getCreateTagError()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
handleError(error);
|
||||
viewModel.clearCreateTagError();
|
||||
}
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getIsUpdatingRelease()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
isUpdating -> {
|
||||
if (releaseToEdit != null) {
|
||||
binding.loadingIndicator.setVisibility(
|
||||
isUpdating ? View.VISIBLE : View.GONE);
|
||||
binding.btnSubmit.setEnabled(!isUpdating);
|
||||
binding.btnSubmit.setText(
|
||||
isUpdating ? "" : getString(R.string.update));
|
||||
}
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getUpdatedRelease()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
release -> {
|
||||
if (release != null) {
|
||||
Toasty.show(requireContext(), R.string.editReleaseSuccessMessage);
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getUpdateReleaseError()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
handleError(error);
|
||||
viewModel.clearUpdateReleaseError();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void handleError(String error) {
|
||||
if (error.equals("UNAUTHORIZED")) {
|
||||
AlertDialogs.authorizationTokenRevokedDialog(requireContext());
|
||||
} else if (error.equals(getString(R.string.tagNameConflictError))) {
|
||||
Toasty.show(requireContext(), R.string.tagNameConflictError);
|
||||
} else {
|
||||
Toasty.show(requireContext(), error);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
Dialog dialog = getDialog();
|
||||
if (dialog instanceof BottomSheetDialog) {
|
||||
AppUtil.applyFullScreenSheetStyle((BottomSheetDialog) dialog, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
binding = null;
|
||||
}
|
||||
}
|
||||
@@ -122,8 +122,6 @@ public class BottomSheetFullScreenEditor extends BottomSheetDialogFragment {
|
||||
isMarkdownMode = !isMarkdownMode;
|
||||
binding.fullscreenBtnMarkdown.setIconResource(
|
||||
isMarkdownMode ? R.drawable.ic_edit : R.drawable.ic_markdown);
|
||||
binding.fullscreenBtnMarkdown.setText(
|
||||
isMarkdownMode ? R.string.menuEditText : R.string.strMarkdown);
|
||||
binding.fullscreenBtnMarkdown.setIconSize(52);
|
||||
|
||||
if (isMarkdownMode) {
|
||||
|
||||
@@ -39,7 +39,6 @@ import org.gitnex.tea4j.v2.models.Release;
|
||||
import org.gitnex.tea4j.v2.models.Tag;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.activities.BaseActivity;
|
||||
import org.mian.gitnex.activities.CreateReleaseActivity;
|
||||
import org.mian.gitnex.activities.RepoDetailActivity;
|
||||
import org.mian.gitnex.adapters.ReleasesAdapter;
|
||||
import org.mian.gitnex.adapters.TagsAdapter;
|
||||
@@ -108,7 +107,7 @@ public class ReleasesFragment extends Fragment implements RepoDetailActivity.Rep
|
||||
@Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
binding = FragmentReleasesBinding.inflate(inflater, container, false);
|
||||
viewModel = new ViewModelProvider(this).get(ReleasesViewModel.class);
|
||||
viewModel = new ViewModelProvider(requireActivity()).get(ReleasesViewModel.class);
|
||||
|
||||
resultLimit = Constants.getCurrentResultLimit(requireContext());
|
||||
|
||||
@@ -138,7 +137,7 @@ public class ReleasesFragment extends Fragment implements RepoDetailActivity.Rep
|
||||
items.add(
|
||||
new RepositoryMenuItemModel(
|
||||
"RELEASE_CREATE_NEW",
|
||||
R.string.createRelease,
|
||||
R.string.create_release_tag,
|
||||
R.drawable.ic_add,
|
||||
R.attr.colorPrimaryContainer,
|
||||
R.attr.colorOnPrimaryContainer));
|
||||
@@ -156,7 +155,8 @@ public class ReleasesFragment extends Fragment implements RepoDetailActivity.Rep
|
||||
break;
|
||||
|
||||
case "RELEASE_CREATE_NEW":
|
||||
startActivity(repository.getIntent(requireContext(), CreateReleaseActivity.class));
|
||||
BottomSheetCreateRelease.newInstance(repository, null)
|
||||
.show(getChildFragmentManager(), "CREATE_RELEASE");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -295,14 +295,17 @@ public class ReleasesFragment extends Fragment implements RepoDetailActivity.Rep
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
code -> {
|
||||
if (code == -1) return;
|
||||
if (code == null || code == -1) return;
|
||||
|
||||
if (code == 204) {
|
||||
int messageRes =
|
||||
repository.isReleasesViewTypeIsTag()
|
||||
? R.string.tagDeleted
|
||||
: R.string.releaseDeleted;
|
||||
|
||||
Toasty.show(requireContext(), messageRes);
|
||||
refreshData();
|
||||
} else if (code == 200 || code == 201) {
|
||||
refreshData();
|
||||
} else {
|
||||
Toasty.show(requireContext(), R.string.genericError);
|
||||
}
|
||||
@@ -334,10 +337,9 @@ public class ReleasesFragment extends Fragment implements RepoDetailActivity.Rep
|
||||
requireContext(),
|
||||
list,
|
||||
canDelete,
|
||||
new OnReleaseItemClickListener() {
|
||||
new ReleasesAdapter.OnReleaseItemClickListener() {
|
||||
@Override
|
||||
public void onDelete(Object item, int position) {
|
||||
Release release = (Release) item;
|
||||
public void onMenuClick(Release release, int position) {
|
||||
showReleaseOptionsBottomSheet(release, position);
|
||||
}
|
||||
|
||||
@@ -382,6 +384,13 @@ public class ReleasesFragment extends Fragment implements RepoDetailActivity.Rep
|
||||
.show();
|
||||
});
|
||||
|
||||
menuBinding.editRelease.setOnClickListener(
|
||||
v -> {
|
||||
dialog.dismiss();
|
||||
BottomSheetCreateRelease.newInstance(repository, release)
|
||||
.show(getParentFragmentManager(), "EDIT_RELEASE");
|
||||
});
|
||||
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package org.mian.gitnex.fragments;
|
||||
|
||||
import static android.view.View.GONE;
|
||||
import static android.view.View.VISIBLE;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -22,6 +25,7 @@ import org.mian.gitnex.activities.WikiActivity;
|
||||
import org.mian.gitnex.adapters.WikiListAdapter;
|
||||
import org.mian.gitnex.databinding.BottomsheetWikiItemMenuBinding;
|
||||
import org.mian.gitnex.databinding.FragmentWikiBinding;
|
||||
import org.mian.gitnex.helpers.AlertDialogs;
|
||||
import org.mian.gitnex.helpers.AppUtil;
|
||||
import org.mian.gitnex.helpers.Constants;
|
||||
import org.mian.gitnex.helpers.EndlessRecyclerViewScrollListener;
|
||||
@@ -43,6 +47,7 @@ public class WikiFragment extends Fragment implements RepoDetailActivity.RepoHub
|
||||
private RepositoryContext repository;
|
||||
private int resultLimit;
|
||||
private boolean isFirstLoad = true;
|
||||
private String pendingPageName = null;
|
||||
|
||||
public static WikiFragment newInstance(RepositoryContext repository) {
|
||||
WikiFragment fragment = new WikiFragment();
|
||||
@@ -197,14 +202,73 @@ public class WikiFragment extends Fragment implements RepoDetailActivity.RepoHub
|
||||
err -> {
|
||||
if (err != null) Toasty.show(requireContext(), err);
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getIsLoadingPage()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
isLoading -> {
|
||||
binding.expressiveLoader.setVisibility(VISIBLE);
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getPageContent()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
content -> {
|
||||
if (content != null && pendingPageName != null) {
|
||||
showContentViewer(pendingPageName, content);
|
||||
pendingPageName = null;
|
||||
viewModel.clearPageContent();
|
||||
binding.expressiveLoader.setVisibility(GONE);
|
||||
}
|
||||
});
|
||||
|
||||
viewModel
|
||||
.getPageError()
|
||||
.observe(
|
||||
getViewLifecycleOwner(),
|
||||
error -> {
|
||||
if (error != null && !error.isEmpty()) {
|
||||
if (error.equals("UNAUTHORIZED")) {
|
||||
AlertDialogs.authorizationTokenRevokedDialog(requireContext());
|
||||
} else {
|
||||
Toasty.show(requireContext(), error);
|
||||
}
|
||||
pendingPageName = null;
|
||||
viewModel.clearPageError();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void openWiki(WikiPageMetaData wikiPage, String action) {
|
||||
Intent intent = new Intent(requireContext(), WikiActivity.class);
|
||||
intent.putExtra("pageName", wikiPage.getTitle());
|
||||
if (action != null) intent.putExtra("action", action);
|
||||
intent.putExtra(RepositoryContext.INTENT_EXTRA, repository);
|
||||
startActivity(intent);
|
||||
if (action != null && action.equals("edit")) {
|
||||
Intent intent = new Intent(requireContext(), WikiActivity.class);
|
||||
intent.putExtra("pageName", wikiPage.getSubUrl());
|
||||
intent.putExtra("action", action);
|
||||
intent.putExtra(RepositoryContext.INTENT_EXTRA, repository);
|
||||
startActivity(intent);
|
||||
} else {
|
||||
pendingPageName = wikiPage.getTitle();
|
||||
viewModel.fetchWikiPageContent(
|
||||
requireContext(),
|
||||
repository.getOwner(),
|
||||
repository.getName(),
|
||||
wikiPage.getSubUrl());
|
||||
}
|
||||
}
|
||||
|
||||
private void showContentViewer(String title, String content) {
|
||||
BottomSheetContentViewer.newInstance(
|
||||
content,
|
||||
title,
|
||||
repository,
|
||||
BottomSheetContentViewer.Feature.ALLOW_COPY,
|
||||
BottomSheetContentViewer.Feature.ALLOW_SHARE,
|
||||
BottomSheetContentViewer.Feature.MARKDOWN_PREVIEW,
|
||||
BottomSheetContentViewer.Feature.START_IN_MARKDOWN,
|
||||
BottomSheetContentViewer.Feature.SHOW_TITLE)
|
||||
.show(getParentFragmentManager(), "WIKI_VIEWER");
|
||||
}
|
||||
|
||||
private void showDeleteDialog(WikiPageMetaData wikiPage) {
|
||||
@@ -219,7 +283,7 @@ public class WikiFragment extends Fragment implements RepoDetailActivity.RepoHub
|
||||
requireContext(),
|
||||
repository.getOwner(),
|
||||
repository.getName(),
|
||||
wikiPage.getTitle());
|
||||
wikiPage.getSubUrl());
|
||||
})
|
||||
.setNegativeButton(R.string.cancelButton, null)
|
||||
.show();
|
||||
@@ -253,14 +317,12 @@ public class WikiFragment extends Fragment implements RepoDetailActivity.RepoHub
|
||||
boolean hasData = adapter != null && adapter.getItemCount() > 0;
|
||||
boolean hasLoadedOnce = Boolean.TRUE.equals(viewModel.getHasLoadedOnce().getValue());
|
||||
|
||||
binding.expressiveLoader.setVisibility(isLoading && !hasData ? View.VISIBLE : View.GONE);
|
||||
binding.expressiveLoader.setVisibility(isLoading && !hasData ? VISIBLE : GONE);
|
||||
|
||||
if (isLoading) {
|
||||
binding.layoutEmpty.getRoot().setVisibility(View.GONE);
|
||||
binding.layoutEmpty.getRoot().setVisibility(GONE);
|
||||
} else {
|
||||
binding.layoutEmpty
|
||||
.getRoot()
|
||||
.setVisibility(!hasData && hasLoadedOnce ? View.VISIBLE : View.GONE);
|
||||
binding.layoutEmpty.getRoot().setVisibility(!hasData && hasLoadedOnce ? VISIBLE : GONE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,12 @@ import androidx.lifecycle.ViewModel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.gitnex.tea4j.v2.models.CreateReleaseOption;
|
||||
import org.gitnex.tea4j.v2.models.CreateTagOption;
|
||||
import org.gitnex.tea4j.v2.models.EditReleaseOption;
|
||||
import org.gitnex.tea4j.v2.models.Release;
|
||||
import org.gitnex.tea4j.v2.models.Tag;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.clients.RetrofitClient;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
@@ -28,6 +32,15 @@ public class ReleasesViewModel extends ViewModel {
|
||||
private final MutableLiveData<Boolean> isTagsLoading = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Integer> actionResult = new MutableLiveData<>(-1);
|
||||
private final MutableLiveData<Integer> repoReleasesCountLiveData = new MutableLiveData<>(-1);
|
||||
private final MutableLiveData<Boolean> isCreatingRelease = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Boolean> isCreatingTag = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Boolean> isUpdatingRelease = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<Release> createdRelease = new MutableLiveData<>();
|
||||
private final MutableLiveData<Tag> createdTag = new MutableLiveData<>();
|
||||
private final MutableLiveData<Release> updatedRelease = new MutableLiveData<>();
|
||||
private final MutableLiveData<String> createReleaseError = new MutableLiveData<>();
|
||||
private final MutableLiveData<String> createTagError = new MutableLiveData<>();
|
||||
private final MutableLiveData<String> updateReleaseError = new MutableLiveData<>();
|
||||
|
||||
private int totalCount = -1;
|
||||
private boolean isLastPage = false;
|
||||
@@ -62,6 +75,42 @@ public class ReleasesViewModel extends ViewModel {
|
||||
return repoReleasesCountLiveData;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getIsCreatingRelease() {
|
||||
return isCreatingRelease;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getIsCreatingTag() {
|
||||
return isCreatingTag;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getIsUpdatingRelease() {
|
||||
return isUpdatingRelease;
|
||||
}
|
||||
|
||||
public LiveData<Release> getCreatedRelease() {
|
||||
return createdRelease;
|
||||
}
|
||||
|
||||
public LiveData<Tag> getCreatedTag() {
|
||||
return createdTag;
|
||||
}
|
||||
|
||||
public LiveData<Release> getUpdatedRelease() {
|
||||
return updatedRelease;
|
||||
}
|
||||
|
||||
public LiveData<String> getCreateReleaseError() {
|
||||
return createReleaseError;
|
||||
}
|
||||
|
||||
public LiveData<String> getCreateTagError() {
|
||||
return createTagError;
|
||||
}
|
||||
|
||||
public LiveData<String> getUpdateReleaseError() {
|
||||
return updateReleaseError;
|
||||
}
|
||||
|
||||
public void resetPagination() {
|
||||
this.isLastPage = false;
|
||||
this.totalCount = -1;
|
||||
@@ -75,6 +124,30 @@ public class ReleasesViewModel extends ViewModel {
|
||||
this.tags.setValue(null);
|
||||
}
|
||||
|
||||
public void clearCreatedRelease() {
|
||||
createdRelease.setValue(null);
|
||||
}
|
||||
|
||||
public void clearCreatedTag() {
|
||||
createdTag.setValue(null);
|
||||
}
|
||||
|
||||
public void clearUpdatedRelease() {
|
||||
updatedRelease.setValue(null);
|
||||
}
|
||||
|
||||
public void clearCreateReleaseError() {
|
||||
createReleaseError.setValue(null);
|
||||
}
|
||||
|
||||
public void clearCreateTagError() {
|
||||
createTagError.setValue(null);
|
||||
}
|
||||
|
||||
public void clearUpdateReleaseError() {
|
||||
updateReleaseError.setValue(null);
|
||||
}
|
||||
|
||||
public void resetActionResult() {
|
||||
actionResult.setValue(-1);
|
||||
}
|
||||
@@ -266,4 +339,124 @@ public class ReleasesViewModel extends ViewModel {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void createRelease(
|
||||
Context ctx, String owner, String repo, CreateReleaseOption releaseData) {
|
||||
isCreatingRelease.setValue(true);
|
||||
|
||||
Call<Release> call =
|
||||
RetrofitClient.getApiInterface(ctx).repoCreateRelease(owner, repo, releaseData);
|
||||
|
||||
call.enqueue(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<Release> call, @NonNull Response<Release> response) {
|
||||
isCreatingRelease.setValue(false);
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
createdRelease.setValue(response.body());
|
||||
actionResult.setValue(201);
|
||||
} else if (response.code() == 401) {
|
||||
createReleaseError.setValue("UNAUTHORIZED");
|
||||
} else if (response.code() == 403) {
|
||||
createReleaseError.setValue(ctx.getString(R.string.authorizeError));
|
||||
} else if (response.code() == 404) {
|
||||
createReleaseError.setValue(ctx.getString(R.string.apiNotFound));
|
||||
} else if (response.code() == 409) {
|
||||
createReleaseError.setValue(
|
||||
ctx.getString(R.string.tagNameConflictError));
|
||||
} else {
|
||||
createReleaseError.setValue(ctx.getString(R.string.genericError));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Release> call, @NonNull Throwable t) {
|
||||
isCreatingRelease.setValue(false);
|
||||
createReleaseError.setValue(t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void createTag(Context ctx, String owner, String repo, CreateTagOption tagData) {
|
||||
isCreatingTag.setValue(true);
|
||||
|
||||
Call<Tag> call = RetrofitClient.getApiInterface(ctx).repoCreateTag(owner, repo, tagData);
|
||||
|
||||
call.enqueue(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<Tag> call, @NonNull Response<Tag> response) {
|
||||
isCreatingTag.setValue(false);
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
createdTag.setValue(response.body());
|
||||
actionResult.setValue(201);
|
||||
} else if (response.code() == 401) {
|
||||
createTagError.setValue("UNAUTHORIZED");
|
||||
} else if (response.code() == 403) {
|
||||
createTagError.setValue(ctx.getString(R.string.authorizeError));
|
||||
} else if (response.code() == 404) {
|
||||
createTagError.setValue(ctx.getString(R.string.apiNotFound));
|
||||
} else if (response.code() == 409) {
|
||||
createTagError.setValue(ctx.getString(R.string.tagNameConflictError));
|
||||
} else {
|
||||
createTagError.setValue(ctx.getString(R.string.genericError));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Tag> call, @NonNull Throwable t) {
|
||||
isCreatingTag.setValue(false);
|
||||
createTagError.setValue(t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void updateRelease(
|
||||
Context ctx,
|
||||
String owner,
|
||||
String repo,
|
||||
long releaseId,
|
||||
String name,
|
||||
String body,
|
||||
boolean prerelease) {
|
||||
isUpdatingRelease.setValue(true);
|
||||
|
||||
EditReleaseOption editData = new EditReleaseOption();
|
||||
editData.setName(name);
|
||||
editData.setBody(body);
|
||||
editData.setPrerelease(prerelease);
|
||||
|
||||
Call<Release> call =
|
||||
RetrofitClient.getApiInterface(ctx)
|
||||
.repoEditRelease(owner, repo, releaseId, editData);
|
||||
|
||||
call.enqueue(
|
||||
new Callback<Release>() {
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<Release> call, @NonNull Response<Release> response) {
|
||||
isUpdatingRelease.setValue(false);
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
updatedRelease.setValue(response.body());
|
||||
actionResult.setValue(200);
|
||||
} else if (response.code() == 401) {
|
||||
updateReleaseError.setValue("UNAUTHORIZED");
|
||||
} else if (response.code() == 403) {
|
||||
updateReleaseError.setValue(ctx.getString(R.string.authorizeError));
|
||||
} else if (response.code() == 404) {
|
||||
updateReleaseError.setValue(ctx.getString(R.string.apiNotFound));
|
||||
} else {
|
||||
updateReleaseError.setValue(ctx.getString(R.string.genericError));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<Release> call, @NonNull Throwable t) {
|
||||
isUpdatingRelease.setValue(false);
|
||||
updateReleaseError.setValue(t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,8 +7,11 @@ import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import org.gitnex.tea4j.v2.models.WikiPage;
|
||||
import org.gitnex.tea4j.v2.models.WikiPageMetaData;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.clients.RetrofitClient;
|
||||
import org.mian.gitnex.helpers.AppUtil;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
import retrofit2.Response;
|
||||
@@ -23,6 +26,9 @@ public class WikiViewModel extends ViewModel {
|
||||
private final MutableLiveData<Boolean> hasLoadedOnce = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<String> error = new MutableLiveData<>();
|
||||
private final MutableLiveData<Integer> actionResult = new MutableLiveData<>(-1);
|
||||
private final MutableLiveData<Boolean> isLoadingPage = new MutableLiveData<>(false);
|
||||
private final MutableLiveData<String> pageContent = new MutableLiveData<>();
|
||||
private final MutableLiveData<String> pageError = new MutableLiveData<>();
|
||||
|
||||
private final List<WikiPageMetaData> fullList = new ArrayList<>();
|
||||
|
||||
@@ -49,6 +55,18 @@ public class WikiViewModel extends ViewModel {
|
||||
return actionResult;
|
||||
}
|
||||
|
||||
public LiveData<Boolean> getIsLoadingPage() {
|
||||
return isLoadingPage;
|
||||
}
|
||||
|
||||
public LiveData<String> getPageContent() {
|
||||
return pageContent;
|
||||
}
|
||||
|
||||
public LiveData<String> getPageError() {
|
||||
return pageError;
|
||||
}
|
||||
|
||||
public void resetPagination() {
|
||||
fullList.clear();
|
||||
isLastPage = false;
|
||||
@@ -57,6 +75,14 @@ public class WikiViewModel extends ViewModel {
|
||||
hasLoadedOnce.setValue(false);
|
||||
}
|
||||
|
||||
public void clearPageContent() {
|
||||
pageContent.setValue(null);
|
||||
}
|
||||
|
||||
public void clearPageError() {
|
||||
pageError.setValue(null);
|
||||
}
|
||||
|
||||
public void fetchWikiPages(
|
||||
Context ctx, String owner, String repo, int page, int limit, boolean isRefresh) {
|
||||
if (Boolean.TRUE.equals(isLoading.getValue()) && !isRefresh) return;
|
||||
@@ -120,6 +146,50 @@ public class WikiViewModel extends ViewModel {
|
||||
});
|
||||
}
|
||||
|
||||
public void fetchWikiPageContent(Context ctx, String owner, String repo, String pageName) {
|
||||
isLoadingPage.setValue(true);
|
||||
pageError.setValue(null);
|
||||
|
||||
Call<WikiPage> call =
|
||||
RetrofitClient.getApiInterface(ctx).repoGetWikiPage(owner, repo, pageName);
|
||||
|
||||
call.enqueue(
|
||||
new Callback<>() {
|
||||
@Override
|
||||
public void onResponse(
|
||||
@NonNull Call<WikiPage> call, @NonNull Response<WikiPage> response) {
|
||||
isLoadingPage.setValue(false);
|
||||
|
||||
if (response.isSuccessful() && response.body() != null) {
|
||||
WikiPage wikiPage = response.body();
|
||||
String decodedContent =
|
||||
AppUtil.decodeBase64(wikiPage.getContentBase64());
|
||||
pageContent.setValue(decodedContent);
|
||||
} else {
|
||||
switch (response.code()) {
|
||||
case 401:
|
||||
pageError.setValue("UNAUTHORIZED");
|
||||
break;
|
||||
case 403:
|
||||
pageError.setValue(ctx.getString(R.string.authorizeError));
|
||||
break;
|
||||
case 404:
|
||||
pageError.setValue(ctx.getString(R.string.apiNotFound));
|
||||
break;
|
||||
default:
|
||||
pageError.setValue(ctx.getString(R.string.genericError));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(@NonNull Call<WikiPage> call, @NonNull Throwable t) {
|
||||
isLoadingPage.setValue(false);
|
||||
pageError.setValue(t.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void deleteWikiPage(Context ctx, String owner, String repo, String pageName) {
|
||||
isLoading.setValue(true);
|
||||
RetrofitClient.getApiInterface(ctx)
|
||||
|
||||
@@ -1,196 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/primaryBackgroundColor"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:id="@+id/appBarLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/primaryBackgroundColor">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
style="?attr/collapsingToolbarLayoutLargeStyle"
|
||||
android:layout_width="match_parent"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed|snap"
|
||||
android:background="?attr/primaryBackgroundColor"
|
||||
app:contentScrim="?attr/primaryBackgroundColor"
|
||||
android:layout_height="?attr/collapsingToolbarLayoutLargeSize">
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/topAppBar"
|
||||
android:layout_width="match_parent"
|
||||
android:elevation="0dp"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
app:title="@string/createRelease"
|
||||
app:layout_collapseMode="pin"
|
||||
app:menu="@menu/create_release_tag_menu"
|
||||
app:popupTheme="@style/Widget.Material3.PopupMenu"
|
||||
app:navigationIcon="@drawable/ic_close" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="@dimen/dimen16dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/releaseTitleLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginBottom="@dimen/dimen8dp"
|
||||
android:hint="@string/releaseTitleText"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
app:boxStrokeErrorColor="@color/darkRed"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?attr/iconsColor"
|
||||
app:hintTextColor="?attr/hintColor">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/releaseTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textCapSentences"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/inputTextColor"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
android:textSize="@dimen/dimen16sp"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/releaseTagNameLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginBottom="@dimen/dimen8dp"
|
||||
android:hint="@string/releaseTagNameText"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
app:boxStrokeErrorColor="@color/darkRed"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?attr/iconsColor"
|
||||
app:hintTextColor="?attr/hintColor">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/releaseTagName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="textCapSentences"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/inputTextColor"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
android:textSize="@dimen/dimen16sp"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insertNote"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginBottom="@dimen/dimen0dp"
|
||||
android:text="@string/insertNote"
|
||||
android:textColor="?attr/primaryTextColor"
|
||||
android:textSize="@dimen/dimen14sp"/>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/releaseContentLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginBottom="@dimen/dimen8dp"
|
||||
android:hint="@string/releaseContentText"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
app:boxStrokeErrorColor="@color/darkRed"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?attr/iconsColor"
|
||||
app:hintTextColor="?attr/hintColor">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/releaseContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen180dp"
|
||||
android:gravity="top|start"
|
||||
android:inputType="textCapSentences|textMultiLine"
|
||||
android:scrollbars="vertical"
|
||||
android:textColor="?attr/inputTextColor"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
android:textSize="@dimen/dimen16sp"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/markdown_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:minHeight="@dimen/dimen186dp"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginBottom="@dimen/dimen8dp"
|
||||
android:textColor="?attr/primaryTextColor"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/dimen14sp"
|
||||
android:visibility="gone" />
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/releaseBranchLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginBottom="@dimen/dimen8dp"
|
||||
android:hint="@string/pageTitleChooseBranch"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
app:hintTextColor="?attr/hintColor">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/releaseBranch"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:singleLine="true"
|
||||
android:textColor="?attr/inputTextColor"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
android:textSize="@dimen/dimen16sp"/>
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/releaseType"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen10dp"
|
||||
android:checked="false"
|
||||
android:text="@string/releaseTypeText"
|
||||
android:textColor="?attr/primaryTextColor"
|
||||
android:textSize="@dimen/dimen16sp"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/releaseDraft"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen10dp"
|
||||
android:checked="false"
|
||||
android:text="@string/releaseDraftText"
|
||||
android:textColor="?attr/primaryTextColor"
|
||||
android:textSize="@dimen/dimen16sp"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
151
app/src/main/res/layout/bottomsheet_content_viewer.xml
Normal file
151
app/src/main/res/layout/bottomsheet_content_viewer.xml
Normal file
@@ -0,0 +1,151 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<!-- Header Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/header_card"
|
||||
style="@style/Widget.Material3.CardView.Filled"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginHorizontal="@dimen/dimen12dp"
|
||||
app:cardBackgroundColor="?attr/colorSurfaceContainerHigh"
|
||||
app:cardElevation="@dimen/dimen0dp"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.ExtraLargeIncreased"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="@dimen/dimen2dp"
|
||||
android:paddingHorizontal="@dimen/dimen8dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_close"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/close"
|
||||
app:icon="@drawable/ic_close"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_copy"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/menuCopyText"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_copy"
|
||||
app:layout_constraintStart_toEndOf="@id/btn_close"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_share"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/share"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_share"
|
||||
app:layout_constraintStart_toEndOf="@id/btn_copy"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_markdown"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/strMarkdown"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_markdown"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/viewer_title"
|
||||
style="@style/TextAppearance.Material3.TitleSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/dimen8dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center"
|
||||
android:maxLines="1"
|
||||
android:textColor="?attr/colorOnSurfaceVariant"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/btn_markdown"
|
||||
app:layout_constraintStart_toEndOf="@id/btn_share"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/dimen12dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/header_card"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/raw_content_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingHorizontal="@dimen/dimen16dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/raw_content_text"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dimen16dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textColor="?attr/colorOnSurface" />
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/markdown_preview_scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingHorizontal="@dimen/dimen16dp"
|
||||
android:visibility="gone">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/markdown_preview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dimen16dp"
|
||||
android:nestedScrollingEnabled="false"
|
||||
android:visibility="gone" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/markdown_preview_text"
|
||||
style="@style/TextAppearance.Material3.BodyLarge"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="@dimen/dimen16dp"
|
||||
android:textIsSelectable="true"
|
||||
android:textColor="?attr/colorOnSurface"
|
||||
android:visibility="gone" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
252
app/src/main/res/layout/bottomsheet_create_release.xml
Normal file
252
app/src/main/res/layout/bottomsheet_create_release.xml
Normal file
@@ -0,0 +1,252 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/root_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||
android:id="@+id/drag_handle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/header_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingHorizontal="@dimen/dimen24dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/drag_handle">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/sheet_title"
|
||||
style="@style/TextAppearance.Material3.HeadlineSmall"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/createRelease"
|
||||
android:textStyle="bold"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/btn_close"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_close"
|
||||
style="@style/Widget.Material3Expressive.Button.IconButton.Tonal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/close"
|
||||
app:icon="@drawable/ic_close"
|
||||
app:layout_constraintBottom_toBottomOf="@id/sheet_title"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/sheet_title" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/scroll_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/dimen16dp"
|
||||
android:clipToPadding="false"
|
||||
android:paddingHorizontal="@dimen/dimen24dp"
|
||||
android:paddingBottom="@dimen/dimen32dp"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintTop_toBottomOf="@id/header_layout"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/form_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<!-- Type Label + Segmented Buttons -->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen12dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.Material3.LabelLarge"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="@dimen/dimen4dp"
|
||||
android:layout_marginBottom="@dimen/dimen4dp"
|
||||
android:text="@string/type" />
|
||||
|
||||
<com.google.android.material.button.MaterialButtonToggleGroup
|
||||
android:id="@+id/create_type_toggle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:checkedButton="@id/btn_create_release"
|
||||
app:selectionRequired="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_create_release"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/release"
|
||||
app:cornerRadius="0dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_create_tag"
|
||||
style="?attr/materialButtonOutlinedStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:text="@string/create_tag"
|
||||
app:cornerRadius="0dp" />
|
||||
|
||||
</com.google.android.material.button.MaterialButtonToggleGroup>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Tag Name -->
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/releaseTagNameLayout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen12dp"
|
||||
android:hint="@string/releaseTagNameText"
|
||||
app:counterEnabled="true"
|
||||
app:counterMaxLength="24"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?attr/iconsColor"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/releaseTagName"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/releaseTitleLayout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen12dp"
|
||||
android:hint="@string/releaseTitleText"
|
||||
app:counterEnabled="true"
|
||||
app:counterMaxLength="255"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?attr/iconsColor"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/releaseTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:imeOptions="actionNext"
|
||||
android:inputType="text" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<!-- Description Container with Expand Button -->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/description_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen12dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputLayout
|
||||
android:id="@+id/releaseContentLayout"
|
||||
style="@style/Widget.Material3.TextInputLayout.OutlinedBox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/releaseContentText"
|
||||
app:endIconMode="clear_text"
|
||||
app:endIconTint="?attr/iconsColor"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/releaseContent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen224dp"
|
||||
android:gravity="top"
|
||||
android:scrollbars="vertical"
|
||||
android:paddingTop="@dimen/dimen48dp"
|
||||
android:inputType="textMultiLine" />
|
||||
|
||||
</com.google.android.material.textfield.TextInputLayout>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_expand"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginEnd="@dimen/dimen8dp"
|
||||
android:text="@string/fullscreen"
|
||||
app:icon="@drawable/ic_maximize"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<!-- Branch Selector Card -->
|
||||
<include
|
||||
android:id="@+id/card_branch"
|
||||
layout="@layout/item_metadata_card"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen16dp" />
|
||||
|
||||
<!-- Pre-release Switch -->
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/switch_prerelease"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen16dp"
|
||||
android:text="@string/releaseTypeText"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Draft Switch -->
|
||||
<com.google.android.material.materialswitch.MaterialSwitch
|
||||
android:id="@+id/switch_draft"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:text="@string/releaseDraftText"
|
||||
android:visibility="gone" />
|
||||
|
||||
<!-- Submit Button -->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen32dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_submit"
|
||||
style="@style/Widget.Material3.Button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/dimen56dp"
|
||||
android:text="@string/createRelease"
|
||||
app:cornerRadius="@dimen/dimen32dp" />
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:id="@+id/loading_indicator"
|
||||
android:layout_width="@dimen/dimen24dp"
|
||||
android:layout_height="@dimen/dimen24dp"
|
||||
android:layout_gravity="center"
|
||||
android:indeterminate="true"
|
||||
android:visibility="gone"
|
||||
app:indicatorSize="@dimen/dimen24dp" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -2,62 +2,84 @@
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingHorizontal="@dimen/dimen12dp">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/fullscreen_toolbar"
|
||||
<!-- Header Card -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/header_card"
|
||||
style="@style/Widget.Material3.CardView.Filled"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="end"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:layout_marginHorizontal="@dimen/dimen12dp"
|
||||
app:cardBackgroundColor="?attr/colorSurfaceContainerHigh"
|
||||
app:cardElevation="@dimen/dimen0dp"
|
||||
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.ExtraLargeIncreased"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fullscreen_btn_clear"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/clear"
|
||||
app:iconSize="@dimen/dimen20dp"
|
||||
app:icon="@drawable/ic_delete" />
|
||||
android:paddingVertical="@dimen/dimen2dp"
|
||||
android:paddingHorizontal="@dimen/dimen8dp">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fullscreen_btn_notes"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/navNotes"
|
||||
android:visibility="gone"
|
||||
app:iconSize="@dimen/dimen20dp"
|
||||
app:icon="@drawable/ic_file" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fullscreen_btn_collapse"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/collapse"
|
||||
app:icon="@drawable/ic_minimize"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fullscreen_btn_markdown"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:text="@string/strMarkdown"
|
||||
app:iconSize="@dimen/dimen20dp"
|
||||
app:icon="@drawable/ic_markdown" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fullscreen_btn_clear"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/clear"
|
||||
app:icon="@drawable/ic_delete"
|
||||
app:layout_constraintStart_toEndOf="@id/fullscreen_btn_collapse"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fullscreen_btn_collapse"
|
||||
style="@style/Widget.Material3.Button.TextButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/collapse"
|
||||
app:iconSize="@dimen/dimen20dp"
|
||||
app:icon="@drawable/ic_minimize" />
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fullscreen_btn_notes"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/navNotes"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_file"
|
||||
app:layout_constraintStart_toEndOf="@id/fullscreen_btn_clear"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/fullscreen_btn_markdown"
|
||||
style="@style/Widget.Material3.Button.IconButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/strMarkdown"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_markdown"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- Content Area -->
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/fullscreen_toolbar"
|
||||
android:layout_marginTop="@dimen/dimen12dp"
|
||||
android:paddingHorizontal="@dimen/dimen12dp"
|
||||
app:layout_constraintTop_toBottomOf="@id/header_card"
|
||||
app:layout_constraintBottom_toBottomOf="parent">
|
||||
|
||||
<EditText
|
||||
@@ -70,7 +92,7 @@
|
||||
android:hint="@string/description"
|
||||
android:background="@null"
|
||||
android:padding="@dimen/dimen8dp"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyMedium" />
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodyLarge" />
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:id="@+id/fullscreen_markdown_scroll"
|
||||
|
||||
@@ -47,6 +47,54 @@
|
||||
android:weightSum="3"
|
||||
tools:ignore="UselessParent">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/edit_card"
|
||||
style="?attr/materialCardViewFilledStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_margin="@dimen/dimen4dp"
|
||||
app:cardCornerRadius="@dimen/dimen24dp"
|
||||
app:cardBackgroundColor="?attr/colorPrimarySurface"
|
||||
app:strokeWidth="0dp">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/edit_release"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="?attr/selectableItemBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingVertical="@dimen/dimen16dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/edit_icon"
|
||||
android:layout_width="@dimen/dimen24dp"
|
||||
android:layout_height="@dimen/dimen24dp"
|
||||
app:srcCompat="@drawable/ic_edit"
|
||||
app:tint="?attr/colorOnPrimarySurface"
|
||||
android:contentDescription="@string/menuEditText" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen8dp"
|
||||
android:fontFamily="sans-serif-medium"
|
||||
android:gravity="center"
|
||||
android:text="@string/menuEditText"
|
||||
android:paddingHorizontal="@dimen/dimen6dp"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?attr/colorOnPrimarySurface"
|
||||
android:textAppearance="@style/TextAppearance.Material3.BodySmall" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/delete_release_card"
|
||||
style="?attr/materialCardViewFilledStyle"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/markdown"
|
||||
android:icon="@drawable/ic_markdown"
|
||||
android:orderInCategory="0"
|
||||
android:title="@string/strMarkdown"
|
||||
app:showAsAction="ifRoom" />
|
||||
|
||||
<item
|
||||
android:id="@+id/create"
|
||||
android:orderInCategory="1"
|
||||
android:title="@string/newCreateButtonCopy"
|
||||
android:contentDescription="@string/newCreateButtonCopy" />
|
||||
|
||||
<item
|
||||
android:id="@+id/create_tag"
|
||||
android:orderInCategory="2"
|
||||
android:title="@string/create_tag"
|
||||
android:contentDescription="@string/create_tag" />
|
||||
|
||||
</menu>
|
||||
@@ -321,8 +321,6 @@
|
||||
<string name="labelMenuContentDesc">Desc</string>
|
||||
<string name="labelDeleteText">Label deleted</string>
|
||||
|
||||
<string name="selectBranchError">Select a branch for release</string>
|
||||
|
||||
<string name="alertDialogTokenRevokedTitle">Authorization Error</string>
|
||||
<string name="alertDialogTokenRevokedMessage">It seems that the Access Token is revoked OR you are not allowed to see these contents.\n\nIn case of revoked Token, please update the account.</string>
|
||||
<string name="labelDeleteMessage">Do you really want to delete this label?</string>
|
||||
@@ -465,7 +463,6 @@
|
||||
<!-- edit issue -->
|
||||
|
||||
<!-- release -->
|
||||
<string name="createRelease">New Release</string>
|
||||
<string name="releaseTagNameText">Tag Name</string>
|
||||
<string name="releaseTitleText">Title</string>
|
||||
<string name="releaseContentText">Content</string>
|
||||
@@ -476,6 +473,14 @@
|
||||
<string name="releaseCreatedText">New release created</string>
|
||||
<string name="deleteReleaseConfirmation">Do you really want to delete this release?</string>
|
||||
<string name="releaseDeleted">Release deleted</string>
|
||||
<string name="tagNameConflictError">Tag name already exists</string>
|
||||
<string name="editReleaseSuccessMessage">Release updated successfully</string>
|
||||
<string name="createRelease">Create Release</string>
|
||||
<string name="createTag">Create Tag</string>
|
||||
<string name="editRelease">Edit Release</string>
|
||||
<string name="selectBranchError">Select a branch for release/tag</string>
|
||||
<string name="add_release_branch">Tap to select a branch</string>
|
||||
<string name="create_release_tag">Create Release/Tag</string>
|
||||
<!-- release -->
|
||||
|
||||
<string name="openWebRepo">Open in Browser</string>
|
||||
@@ -655,6 +660,7 @@
|
||||
<string name="select">Select</string>
|
||||
<string name="collapse">Collapse</string>
|
||||
<string name="fullscreen">Fullscreen</string>
|
||||
<string name="type">Type</string>
|
||||
<!-- generic copy -->
|
||||
|
||||
<string name="exploreUsers">Explore users</string>
|
||||
@@ -908,7 +914,7 @@
|
||||
<string name="userAvatar">Avatar</string>
|
||||
<string name="tags">Tags</string>
|
||||
<string name="releasesTags">Releases/Tags</string>
|
||||
<string name="create_tag">Create Tag Only</string>
|
||||
<string name="create_tag">Tag Only</string>
|
||||
<string name="tagCreated">Tag created</string>
|
||||
<string name="asRef">Use as reference</string>
|
||||
<string name="deleteTagConfirmation">Do you really want to delete this tag?</string>
|
||||
|
||||
Reference in New Issue
Block a user