mirror of
https://codeberg.org/gitnex/GitNex.git
synced 2024-12-16 15:48:13 +08:00
Improve biometric lock, new comment UI, create issue/pr from a note (#1356)
This PR will also remove Draft feature from the app. Closes #1270 Closes #1346 Closes #750 Reviewed-on: https://codeberg.org/gitnex/GitNex/pulls/1356 Co-authored-by: M M Arif <mmarif@swatian.com> Co-committed-by: M M Arif <mmarif@swatian.com>
This commit is contained in:
parent
36b45df849
commit
4ccaeba2aa
@ -36,7 +36,7 @@ Option 2 - Open the terminal (Linux) and navigate to the project directory. Then
|
||||
- Pull requests
|
||||
- Files diff for PRs
|
||||
- Notifications
|
||||
- Drafts
|
||||
- Notes
|
||||
- Repositories / issues list
|
||||
- [& more...](https://codeberg.org/gitnex/GitNex/wiki/Features)
|
||||
|
||||
|
@ -82,7 +82,11 @@
|
||||
<activity
|
||||
android:name=".activities.IssueDetailActivity"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation"
|
||||
android:windowSoftInputMode="adjustNothing"/>
|
||||
android:windowSoftInputMode="adjustResize"/>
|
||||
<activity
|
||||
android:name=".activities.BiometricUnlock"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation"
|
||||
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar"/>
|
||||
<activity
|
||||
android:name=".activities.RepoDetailActivity"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|density|screenLayout|keyboard|keyboardHidden|navigation"
|
||||
|
@ -1,13 +1,10 @@
|
||||
package org.mian.gitnex.activities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Executor;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.core.MainApplication;
|
||||
import org.mian.gitnex.helpers.AppDatabaseSettings;
|
||||
@ -128,50 +125,8 @@ public abstract class BaseActivity extends AppCompatActivity {
|
||||
AppDatabaseSettings.getSettingsValue(
|
||||
ctx, AppDatabaseSettings.APP_BIOMETRIC_LIFE_CYCLE_KEY))) {
|
||||
|
||||
Executor executor = ContextCompat.getMainExecutor(this);
|
||||
|
||||
BiometricPrompt biometricPrompt =
|
||||
new BiometricPrompt(
|
||||
this,
|
||||
executor,
|
||||
new BiometricPrompt.AuthenticationCallback() {
|
||||
|
||||
@Override
|
||||
public void onAuthenticationError(
|
||||
int errorCode, @NonNull CharSequence errString) {
|
||||
|
||||
super.onAuthenticationError(errorCode, errString);
|
||||
|
||||
// Authentication error, close the app
|
||||
finish();
|
||||
}
|
||||
|
||||
// Authentication succeeded, continue to app
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(
|
||||
@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||
super.onAuthenticationSucceeded(result);
|
||||
AppDatabaseSettings.updateSettingsValue(
|
||||
getApplicationContext(),
|
||||
"true",
|
||||
AppDatabaseSettings.APP_BIOMETRIC_LIFE_CYCLE_KEY);
|
||||
}
|
||||
|
||||
// Authentication failed, close the app
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed();
|
||||
}
|
||||
});
|
||||
|
||||
BiometricPrompt.PromptInfo biometricPromptBuilder =
|
||||
new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.biometricAuthTitle))
|
||||
.setSubtitle(getString(R.string.biometricAuthSubTitle))
|
||||
.setNegativeButtonText(getString(R.string.cancelButton))
|
||||
.build();
|
||||
|
||||
biometricPrompt.authenticate(biometricPromptBuilder);
|
||||
Intent unlockIntent = new Intent(ctx, BiometricUnlock.class);
|
||||
ctx.startActivity(unlockIntent);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,80 @@
|
||||
package org.mian.gitnex.activities;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.biometric.BiometricPrompt;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import java.util.concurrent.Executor;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.databinding.ActivityUnlockBinding;
|
||||
import org.mian.gitnex.helpers.AppDatabaseSettings;
|
||||
|
||||
/**
|
||||
* @author M M Arif
|
||||
*/
|
||||
public class BiometricUnlock extends AppCompatActivity {
|
||||
|
||||
protected Context ctx = this;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
ActivityUnlockBinding activityUnlockBinding =
|
||||
ActivityUnlockBinding.inflate(getLayoutInflater());
|
||||
setContentView(activityUnlockBinding.getRoot());
|
||||
}
|
||||
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
Executor executor = ContextCompat.getMainExecutor(this);
|
||||
|
||||
BiometricPrompt biometricPrompt =
|
||||
new BiometricPrompt(
|
||||
this,
|
||||
executor,
|
||||
new BiometricPrompt.AuthenticationCallback() {
|
||||
|
||||
@Override
|
||||
public void onAuthenticationError(
|
||||
int errorCode, @NonNull CharSequence errString) {
|
||||
|
||||
super.onAuthenticationError(errorCode, errString);
|
||||
|
||||
// Authentication error, close the app
|
||||
finish();
|
||||
}
|
||||
|
||||
// Authentication succeeded, continue to app
|
||||
@Override
|
||||
public void onAuthenticationSucceeded(
|
||||
@NonNull BiometricPrompt.AuthenticationResult result) {
|
||||
super.onAuthenticationSucceeded(result);
|
||||
AppDatabaseSettings.updateSettingsValue(
|
||||
getApplicationContext(),
|
||||
"true",
|
||||
AppDatabaseSettings.APP_BIOMETRIC_LIFE_CYCLE_KEY);
|
||||
finish();
|
||||
}
|
||||
|
||||
// Authentication failed, close the app
|
||||
@Override
|
||||
public void onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed();
|
||||
}
|
||||
});
|
||||
|
||||
BiometricPrompt.PromptInfo biometricPromptBuilder =
|
||||
new BiometricPrompt.PromptInfo.Builder()
|
||||
.setTitle(getString(R.string.biometricAuthTitle))
|
||||
.setSubtitle(getString(R.string.biometricAuthSubTitle))
|
||||
.setNegativeButtonText(getString(R.string.cancelButton))
|
||||
.build();
|
||||
|
||||
biometricPrompt.authenticate(biometricPromptBuilder);
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@ -14,6 +15,7 @@ import android.widget.TextView;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.google.android.material.datepicker.MaterialDatePicker;
|
||||
@ -43,10 +45,15 @@ import org.mian.gitnex.actions.LabelsActions;
|
||||
import org.mian.gitnex.adapters.AssigneesListAdapter;
|
||||
import org.mian.gitnex.adapters.AttachmentsAdapter;
|
||||
import org.mian.gitnex.adapters.LabelsListAdapter;
|
||||
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.ActivityCreateIssueBinding;
|
||||
import org.mian.gitnex.databinding.BottomSheetAttachmentsBinding;
|
||||
import org.mian.gitnex.databinding.CustomAssigneesSelectionDialogBinding;
|
||||
import org.mian.gitnex.databinding.CustomInsertNoteBinding;
|
||||
import org.mian.gitnex.databinding.CustomLabelsSelectionDialogBinding;
|
||||
import org.mian.gitnex.fragments.IssuesFragment;
|
||||
import org.mian.gitnex.helpers.AlertDialogs;
|
||||
@ -54,6 +61,7 @@ import org.mian.gitnex.helpers.AppDatabaseSettings;
|
||||
import org.mian.gitnex.helpers.Constants;
|
||||
import org.mian.gitnex.helpers.Markdown;
|
||||
import org.mian.gitnex.helpers.SnackBar;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.helpers.attachments.AttachmentUtils;
|
||||
import org.mian.gitnex.helpers.attachments.AttachmentsModel;
|
||||
import org.mian.gitnex.helpers.contexts.RepositoryContext;
|
||||
@ -77,6 +85,7 @@ public class CreateIssueActivity extends BaseActivity
|
||||
private LabelsListAdapter labelsAdapter;
|
||||
private AssigneesListAdapter assigneesAdapter;
|
||||
private MaterialAlertDialogBuilder materialAlertDialogBuilder;
|
||||
private MaterialAlertDialogBuilder materialAlertDialogBuilderNotes;
|
||||
private List<Integer> labelsIds = new ArrayList<>();
|
||||
private List<String> assigneesListData = new ArrayList<>();
|
||||
private boolean renderMd = false;
|
||||
@ -84,6 +93,11 @@ public class CreateIssueActivity extends BaseActivity
|
||||
private static List<AttachmentsModel> attachmentsList;
|
||||
private AttachmentsAdapter attachmentsAdapter;
|
||||
private static final List<Uri> contentUri = new ArrayList<>();
|
||||
private CustomInsertNoteBinding customInsertNoteBinding;
|
||||
private NotesAdapter adapter;
|
||||
private NotesApi notesApi;
|
||||
private List<Notes> notesList;
|
||||
public AlertDialog dialogNotes;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
@ -98,6 +112,8 @@ public class CreateIssueActivity extends BaseActivity
|
||||
|
||||
materialAlertDialogBuilder =
|
||||
new MaterialAlertDialogBuilder(ctx, R.style.ThemeOverlay_Material3_Dialog_Alert);
|
||||
materialAlertDialogBuilderNotes =
|
||||
new MaterialAlertDialogBuilder(ctx, R.style.ThemeOverlay_Material3_Dialog_Alert);
|
||||
|
||||
repository = RepositoryContext.fromIntent(getIntent());
|
||||
|
||||
@ -174,6 +190,8 @@ public class CreateIssueActivity extends BaseActivity
|
||||
}
|
||||
});
|
||||
|
||||
viewBinding.insertNote.setOnClickListener(insertNote -> showAllNotes());
|
||||
|
||||
getMilestones(repository.getOwner(), repository.getName(), resultLimit);
|
||||
|
||||
viewBinding.newIssueLabels.setOnClickListener(newIssueLabels -> showLabels());
|
||||
@ -189,6 +207,62 @@ public class CreateIssueActivity extends BaseActivity
|
||||
}
|
||||
}
|
||||
|
||||
private void showAllNotes() {
|
||||
|
||||
notesList = new ArrayList<>();
|
||||
notesApi = BaseApi.getInstance(ctx, NotesApi.class);
|
||||
|
||||
customInsertNoteBinding = CustomInsertNoteBinding.inflate(LayoutInflater.from(ctx));
|
||||
|
||||
View view = customInsertNoteBinding.getRoot();
|
||||
materialAlertDialogBuilderNotes.setView(view);
|
||||
|
||||
customInsertNoteBinding.recyclerView.setHasFixedSize(true);
|
||||
customInsertNoteBinding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
|
||||
|
||||
adapter = new NotesAdapter(ctx, notesList, "insert", "issue");
|
||||
|
||||
customInsertNoteBinding.pullToRefresh.setOnRefreshListener(
|
||||
() ->
|
||||
new Handler(Looper.getMainLooper())
|
||||
.postDelayed(
|
||||
() -> {
|
||||
notesList.clear();
|
||||
customInsertNoteBinding.pullToRefresh.setRefreshing(
|
||||
false);
|
||||
customInsertNoteBinding.progressBar.setVisibility(
|
||||
View.VISIBLE);
|
||||
fetchNotes();
|
||||
},
|
||||
250));
|
||||
|
||||
if (notesApi.getCount() > 0) {
|
||||
fetchNotes();
|
||||
dialogNotes = materialAlertDialogBuilderNotes.show();
|
||||
} else {
|
||||
Toasty.warning(ctx, getResources().getString(R.string.noNotes));
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchNotes() {
|
||||
|
||||
notesApi.fetchAllNotes()
|
||||
.observe(
|
||||
this,
|
||||
allNotes -> {
|
||||
assert allNotes != null;
|
||||
if (!allNotes.isEmpty()) {
|
||||
|
||||
notesList.clear();
|
||||
|
||||
notesList.addAll(allNotes);
|
||||
adapter.notifyDataChanged();
|
||||
customInsertNoteBinding.recyclerView.setAdapter(adapter);
|
||||
}
|
||||
customInsertNoteBinding.progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
|
||||
ActivityResultLauncher<Intent> startActivityForResult =
|
||||
registerForActivityResult(
|
||||
new ActivityResultContracts.StartActivityForResult(),
|
||||
|
@ -6,6 +6,7 @@ import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
@ -14,6 +15,7 @@ import android.widget.TextView;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
import com.google.android.material.datepicker.MaterialDatePicker;
|
||||
@ -41,9 +43,14 @@ import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.actions.LabelsActions;
|
||||
import org.mian.gitnex.adapters.AttachmentsAdapter;
|
||||
import org.mian.gitnex.adapters.LabelsListAdapter;
|
||||
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.ActivityCreatePrBinding;
|
||||
import org.mian.gitnex.databinding.BottomSheetAttachmentsBinding;
|
||||
import org.mian.gitnex.databinding.CustomInsertNoteBinding;
|
||||
import org.mian.gitnex.databinding.CustomLabelsSelectionDialogBinding;
|
||||
import org.mian.gitnex.fragments.PullRequestsFragment;
|
||||
import org.mian.gitnex.helpers.AlertDialogs;
|
||||
@ -51,6 +58,7 @@ import org.mian.gitnex.helpers.AppDatabaseSettings;
|
||||
import org.mian.gitnex.helpers.Constants;
|
||||
import org.mian.gitnex.helpers.Markdown;
|
||||
import org.mian.gitnex.helpers.SnackBar;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.helpers.attachments.AttachmentUtils;
|
||||
import org.mian.gitnex.helpers.attachments.AttachmentsModel;
|
||||
import org.mian.gitnex.helpers.contexts.RepositoryContext;
|
||||
@ -74,11 +82,17 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
private RepositoryContext repository;
|
||||
private LabelsListAdapter labelsAdapter;
|
||||
private MaterialAlertDialogBuilder materialAlertDialogBuilder;
|
||||
private MaterialAlertDialogBuilder materialAlertDialogBuilderNotes;
|
||||
private boolean renderMd = false;
|
||||
private RepositoryContext repositoryContext;
|
||||
private static List<AttachmentsModel> attachmentsList;
|
||||
private AttachmentsAdapter attachmentsAdapter;
|
||||
private static final List<Uri> contentUri = new ArrayList<>();
|
||||
private CustomInsertNoteBinding customInsertNoteBinding;
|
||||
private NotesAdapter adapter;
|
||||
private NotesApi notesApi;
|
||||
private List<Notes> notesList;
|
||||
public AlertDialog dialogNotes;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
@ -93,6 +107,8 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
|
||||
materialAlertDialogBuilder =
|
||||
new MaterialAlertDialogBuilder(ctx, R.style.ThemeOverlay_Material3_Dialog_Alert);
|
||||
materialAlertDialogBuilderNotes =
|
||||
new MaterialAlertDialogBuilder(ctx, R.style.ThemeOverlay_Material3_Dialog_Alert);
|
||||
|
||||
repository = RepositoryContext.fromIntent(getIntent());
|
||||
|
||||
@ -162,6 +178,8 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
}
|
||||
});
|
||||
|
||||
viewBinding.insertNote.setOnClickListener(insertNote -> showAllNotes());
|
||||
|
||||
getMilestones(repository.getOwner(), repository.getName(), resultLimit);
|
||||
getBranches(repository.getOwner(), repository.getName());
|
||||
|
||||
@ -190,6 +208,62 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
}
|
||||
});
|
||||
|
||||
private void showAllNotes() {
|
||||
|
||||
notesList = new ArrayList<>();
|
||||
notesApi = BaseApi.getInstance(ctx, NotesApi.class);
|
||||
|
||||
customInsertNoteBinding = CustomInsertNoteBinding.inflate(LayoutInflater.from(ctx));
|
||||
|
||||
View view = customInsertNoteBinding.getRoot();
|
||||
materialAlertDialogBuilderNotes.setView(view);
|
||||
|
||||
customInsertNoteBinding.recyclerView.setHasFixedSize(true);
|
||||
customInsertNoteBinding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
|
||||
|
||||
adapter = new NotesAdapter(ctx, notesList, "insert", "pr");
|
||||
|
||||
customInsertNoteBinding.pullToRefresh.setOnRefreshListener(
|
||||
() ->
|
||||
new Handler(Looper.getMainLooper())
|
||||
.postDelayed(
|
||||
() -> {
|
||||
notesList.clear();
|
||||
customInsertNoteBinding.pullToRefresh.setRefreshing(
|
||||
false);
|
||||
customInsertNoteBinding.progressBar.setVisibility(
|
||||
View.VISIBLE);
|
||||
fetchNotes();
|
||||
},
|
||||
250));
|
||||
|
||||
if (notesApi.getCount() > 0) {
|
||||
fetchNotes();
|
||||
dialogNotes = materialAlertDialogBuilderNotes.show();
|
||||
} else {
|
||||
Toasty.warning(ctx, getResources().getString(R.string.noNotes));
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchNotes() {
|
||||
|
||||
notesApi.fetchAllNotes()
|
||||
.observe(
|
||||
this,
|
||||
allNotes -> {
|
||||
assert allNotes != null;
|
||||
if (!allNotes.isEmpty()) {
|
||||
|
||||
notesList.clear();
|
||||
|
||||
notesList.addAll(allNotes);
|
||||
adapter.notifyDataChanged();
|
||||
customInsertNoteBinding.recyclerView.setAdapter(adapter);
|
||||
}
|
||||
customInsertNoteBinding.progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
|
||||
public void onDestroy() {
|
||||
AttachmentsAdapter.setAttachmentsReceiveListener(null);
|
||||
super.onDestroy();
|
||||
@ -202,7 +276,7 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
|
||||
private void checkForAttachments() {
|
||||
|
||||
if (contentUri.size() > 0) {
|
||||
if (!contentUri.isEmpty()) {
|
||||
|
||||
BottomSheetAttachmentsBinding bottomSheetAttachmentsBinding =
|
||||
BottomSheetAttachmentsBinding.inflate(getLayoutInflater());
|
||||
@ -241,7 +315,10 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
|
||||
RequestBody requestFile =
|
||||
RequestBody.create(
|
||||
file, MediaType.parse(getContentResolver().getType(contentUri.get(i))));
|
||||
file,
|
||||
MediaType.parse(
|
||||
Objects.requireNonNull(
|
||||
getContentResolver().getType(contentUri.get(i)))));
|
||||
|
||||
uploadAttachments(requestFile, issueIndex, file.getName());
|
||||
}
|
||||
@ -301,7 +378,7 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
|
||||
assignees.add("");
|
||||
|
||||
if (labelsIds.size() == 0) {
|
||||
if (labelsIds.isEmpty()) {
|
||||
|
||||
labelsIds.add(0);
|
||||
}
|
||||
@ -383,7 +460,7 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
PullRequestsFragment.resumePullRequests = true;
|
||||
MainActivity.reloadRepos = true;
|
||||
|
||||
if (contentUri.size() > 0) {
|
||||
if (!contentUri.isEmpty()) {
|
||||
assert response.body() != null;
|
||||
processAttachments(response.body().getNumber());
|
||||
contentUri.clear();
|
||||
@ -555,7 +632,7 @@ public class CreatePullRequestActivity extends BaseActivity
|
||||
.title(getString(R.string.issueCreatedNoMilestone)));
|
||||
assert milestonesList_ != null;
|
||||
|
||||
if (milestonesList_.size() > 0) {
|
||||
if (!milestonesList_.isEmpty()) {
|
||||
|
||||
for (Milestone milestone : milestonesList_) {
|
||||
|
||||
|
@ -3,10 +3,15 @@ package org.mian.gitnex.activities;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.ArrayAdapter;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
import com.vdurmont.emoji.EmojiParser;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@ -17,11 +22,17 @@ 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.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.Markdown;
|
||||
import org.mian.gitnex.helpers.SnackBar;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.helpers.contexts.RepositoryContext;
|
||||
import retrofit2.Call;
|
||||
import retrofit2.Callback;
|
||||
@ -36,6 +47,12 @@ public class CreateReleaseActivity extends BaseActivity {
|
||||
private String selectedBranch;
|
||||
private RepositoryContext repository;
|
||||
private boolean renderMd = false;
|
||||
private MaterialAlertDialogBuilder materialAlertDialogBuilder;
|
||||
private CustomInsertNoteBinding customInsertNoteBinding;
|
||||
private NotesAdapter adapter;
|
||||
private NotesApi notesApi;
|
||||
private List<Notes> notesList;
|
||||
public AlertDialog dialogNotes;
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
@Override
|
||||
@ -48,6 +65,9 @@ public class CreateReleaseActivity extends BaseActivity {
|
||||
|
||||
repository = RepositoryContext.fromIntent(getIntent());
|
||||
|
||||
materialAlertDialogBuilder =
|
||||
new MaterialAlertDialogBuilder(ctx, R.style.ThemeOverlay_Material3_Dialog_Alert);
|
||||
|
||||
binding.releaseContent.setOnTouchListener(
|
||||
(touchView, motionEvent) -> {
|
||||
touchView.getParent().requestDisallowInterceptTouchEvent(true);
|
||||
@ -60,10 +80,7 @@ public class CreateReleaseActivity extends BaseActivity {
|
||||
return false;
|
||||
});
|
||||
|
||||
binding.topAppBar.setNavigationOnClickListener(
|
||||
v -> {
|
||||
finish();
|
||||
});
|
||||
binding.topAppBar.setNavigationOnClickListener(v -> finish());
|
||||
|
||||
binding.topAppBar.setOnMenuItemClickListener(
|
||||
menuItem -> {
|
||||
@ -103,9 +120,67 @@ public class CreateReleaseActivity extends BaseActivity {
|
||||
}
|
||||
});
|
||||
|
||||
binding.insertNote.setOnClickListener(insertNote -> showAllNotes());
|
||||
|
||||
getBranches(repository.getOwner(), repository.getName());
|
||||
}
|
||||
|
||||
private void showAllNotes() {
|
||||
|
||||
notesList = new ArrayList<>();
|
||||
notesApi = BaseApi.getInstance(ctx, NotesApi.class);
|
||||
|
||||
customInsertNoteBinding = CustomInsertNoteBinding.inflate(LayoutInflater.from(ctx));
|
||||
|
||||
View view = customInsertNoteBinding.getRoot();
|
||||
materialAlertDialogBuilder.setView(view);
|
||||
|
||||
customInsertNoteBinding.recyclerView.setHasFixedSize(true);
|
||||
customInsertNoteBinding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
|
||||
|
||||
adapter = new NotesAdapter(ctx, notesList, "insert", "release");
|
||||
|
||||
customInsertNoteBinding.pullToRefresh.setOnRefreshListener(
|
||||
() ->
|
||||
new Handler(Looper.getMainLooper())
|
||||
.postDelayed(
|
||||
() -> {
|
||||
notesList.clear();
|
||||
customInsertNoteBinding.pullToRefresh.setRefreshing(
|
||||
false);
|
||||
customInsertNoteBinding.progressBar.setVisibility(
|
||||
View.VISIBLE);
|
||||
fetchNotes();
|
||||
},
|
||||
250));
|
||||
|
||||
if (notesApi.getCount() > 0) {
|
||||
fetchNotes();
|
||||
dialogNotes = materialAlertDialogBuilder.show();
|
||||
} else {
|
||||
Toasty.warning(ctx, getResources().getString(R.string.noNotes));
|
||||
}
|
||||
}
|
||||
|
||||
private void fetchNotes() {
|
||||
|
||||
notesApi.fetchAllNotes()
|
||||
.observe(
|
||||
this,
|
||||
allNotes -> {
|
||||
assert allNotes != null;
|
||||
if (!allNotes.isEmpty()) {
|
||||
|
||||
notesList.clear();
|
||||
|
||||
notesList.addAll(allNotes);
|
||||
adapter.notifyDataChanged();
|
||||
customInsertNoteBinding.recyclerView.setAdapter(adapter);
|
||||
}
|
||||
customInsertNoteBinding.progressBar.setVisibility(View.GONE);
|
||||
});
|
||||
}
|
||||
|
||||
private void createNewTag() {
|
||||
|
||||
String tagName = Objects.requireNonNull(binding.releaseTagName.getText()).toString();
|
||||
@ -114,7 +189,7 @@ public class CreateReleaseActivity extends BaseActivity {
|
||||
+ "\n\n"
|
||||
+ Objects.requireNonNull(binding.releaseContent.getText());
|
||||
|
||||
if (tagName.equals("")) {
|
||||
if (tagName.isEmpty()) {
|
||||
SnackBar.error(
|
||||
ctx, findViewById(android.R.id.content), getString(R.string.tagNameErrorEmpty));
|
||||
return;
|
||||
@ -187,13 +262,13 @@ public class CreateReleaseActivity extends BaseActivity {
|
||||
boolean newReleaseType = binding.releaseType.isChecked();
|
||||
boolean newReleaseDraft = binding.releaseDraft.isChecked();
|
||||
|
||||
if (newReleaseTitle.equals("")) {
|
||||
if (newReleaseTitle.isEmpty()) {
|
||||
SnackBar.error(
|
||||
ctx, findViewById(android.R.id.content), getString(R.string.titleErrorEmpty));
|
||||
return;
|
||||
}
|
||||
|
||||
if (newReleaseTagName.equals("")) {
|
||||
if (newReleaseTagName.isEmpty()) {
|
||||
SnackBar.error(
|
||||
ctx, findViewById(android.R.id.content), getString(R.string.tagNameErrorEmpty));
|
||||
return;
|
||||
|
@ -11,6 +11,8 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
@ -18,6 +20,8 @@ import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ScrollView;
|
||||
@ -57,7 +61,9 @@ import org.gitnex.tea4j.v2.models.Repository;
|
||||
import org.gitnex.tea4j.v2.models.User;
|
||||
import org.gitnex.tea4j.v2.models.WatchInfo;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.actions.ActionResult;
|
||||
import org.mian.gitnex.actions.AssigneesActions;
|
||||
import org.mian.gitnex.actions.IssueActions;
|
||||
import org.mian.gitnex.actions.LabelsActions;
|
||||
import org.mian.gitnex.adapters.AssigneesListAdapter;
|
||||
import org.mian.gitnex.adapters.IssueCommentsAdapter;
|
||||
@ -82,6 +88,7 @@ import org.mian.gitnex.helpers.LabelWidthCalculator;
|
||||
import org.mian.gitnex.helpers.Markdown;
|
||||
import org.mian.gitnex.helpers.RoundedTransformation;
|
||||
import org.mian.gitnex.helpers.TimeHelper;
|
||||
import org.mian.gitnex.helpers.TinyDB;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.helpers.contexts.IssueContext;
|
||||
import org.mian.gitnex.notifications.Notifications;
|
||||
@ -105,7 +112,7 @@ public class IssueDetailActivity extends BaseActivity
|
||||
public static boolean commentPosted = false;
|
||||
private final List<Label> labelsList = new ArrayList<>();
|
||||
private final List<User> assigneesList = new ArrayList<>();
|
||||
public boolean commentEdited = false;
|
||||
public static boolean commentEdited = false;
|
||||
private IssueCommentsAdapter adapter;
|
||||
private String repoOwner;
|
||||
private String repoName;
|
||||
@ -131,6 +138,13 @@ public class IssueDetailActivity extends BaseActivity
|
||||
private String instanceUrlOnly;
|
||||
private String token;
|
||||
private int page = 1;
|
||||
private TinyDB tinyDB;
|
||||
private Mode mode = Mode.SEND;
|
||||
|
||||
private enum Mode {
|
||||
EDIT,
|
||||
SEND
|
||||
}
|
||||
|
||||
public ActivityResultLauncher<Intent> editIssueLauncher =
|
||||
registerForActivityResult(
|
||||
@ -275,10 +289,15 @@ public class IssueDetailActivity extends BaseActivity
|
||||
repoName = issue.getRepository().getName();
|
||||
issueIndex = issue.getIssueIndex();
|
||||
|
||||
tinyDB = TinyDB.getInstance(ctx);
|
||||
|
||||
setSupportActionBar(viewBinding.toolbar);
|
||||
Objects.requireNonNull(getSupportActionBar()).setTitle(repoName);
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
|
||||
InputMethodManager imm =
|
||||
(InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
|
||||
|
||||
String instanceUrl = ((BaseActivity) ctx).getAccount().getAccount().getInstanceUrl();
|
||||
instanceUrlOnly = instanceUrl.substring(0, instanceUrl.lastIndexOf("api/v1/"));
|
||||
|
||||
@ -293,31 +312,11 @@ public class IssueDetailActivity extends BaseActivity
|
||||
viewBinding.recyclerView.setNestedScrollingEnabled(false);
|
||||
viewBinding.recyclerView.setLayoutManager(new LinearLayoutManager(ctx));
|
||||
|
||||
new Handler()
|
||||
.postDelayed(
|
||||
() -> {
|
||||
if (issue.getIssue() != null) {
|
||||
if (issue.getIssue().isIsLocked() != null) {
|
||||
if (issue.getIssue().isIsLocked()) {
|
||||
if (issue.getRepository().getPermissions() != null
|
||||
&& issue.getRepository().getPermissions().isAdmin()
|
||||
!= null) {
|
||||
if (issue.getRepository().getPermissions().isAdmin()) {
|
||||
viewBinding.addNewComment.setVisibility(
|
||||
View.VISIBLE);
|
||||
} else {
|
||||
viewBinding.addNewComment.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
viewBinding.addNewComment.setVisibility(View.GONE);
|
||||
}
|
||||
} else {
|
||||
viewBinding.addNewComment.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
50);
|
||||
float buttonAlphaStatDisabled = .5F;
|
||||
float buttonAlphaStatEnabled = 1F;
|
||||
|
||||
viewBinding.send.setAlpha(buttonAlphaStatDisabled);
|
||||
viewBinding.send.setEnabled(false);
|
||||
|
||||
viewBinding.addNewComment.setOnClickListener(
|
||||
v -> {
|
||||
@ -360,6 +359,166 @@ public class IssueDetailActivity extends BaseActivity
|
||||
&& Objects.equals(getIntent().getStringExtra("openPrDiff"), "true")) {
|
||||
startActivity(issue.getIntent(ctx, DiffActivity.class));
|
||||
}
|
||||
|
||||
viewBinding.commentReply.addTextChangedListener(
|
||||
new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence chr, int i, int i1, int i2) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence chr, int i, int i1, int i2) {
|
||||
if (chr.length() > 0) {
|
||||
viewBinding.commentReply.requestFocus();
|
||||
getWindow()
|
||||
.setSoftInputMode(
|
||||
WindowManager.LayoutParams
|
||||
.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
|
||||
viewBinding.commentReply.setSelection(
|
||||
viewBinding.commentReply.length());
|
||||
viewBinding.send.setAlpha(buttonAlphaStatEnabled);
|
||||
viewBinding.send.setEnabled(true);
|
||||
} else {
|
||||
viewBinding.send.setAlpha(buttonAlphaStatDisabled);
|
||||
viewBinding.send.setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable editable) {
|
||||
|
||||
if (editable.length() > 0) {
|
||||
new Handler()
|
||||
.postDelayed(
|
||||
() -> {
|
||||
if (issue.getIssue() != null) {
|
||||
if (issue.getIssue().isIsLocked() != null) {
|
||||
if (issue.getIssue().isIsLocked()) {
|
||||
if (issue.getRepository()
|
||||
.getPermissions()
|
||||
!= null
|
||||
&& issue.getRepository()
|
||||
.getPermissions()
|
||||
.isAdmin()
|
||||
!= null) {
|
||||
if (issue.getRepository()
|
||||
.getPermissions()
|
||||
.isAdmin()) {
|
||||
viewBinding.send.setEnabled(
|
||||
true);
|
||||
viewBinding.send.setAlpha(
|
||||
buttonAlphaStatEnabled);
|
||||
} else {
|
||||
viewBinding.send.setAlpha(
|
||||
buttonAlphaStatDisabled);
|
||||
viewBinding.send.setEnabled(
|
||||
false);
|
||||
}
|
||||
} else {
|
||||
viewBinding.send.setAlpha(
|
||||
buttonAlphaStatDisabled);
|
||||
viewBinding.send.setEnabled(false);
|
||||
}
|
||||
} else {
|
||||
viewBinding.send.setEnabled(true);
|
||||
viewBinding.send.setAlpha(
|
||||
buttonAlphaStatEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
50);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
viewBinding.send.setOnClickListener(
|
||||
v -> {
|
||||
if (Objects.requireNonNull(tinyDB.getString("commentAction"))
|
||||
.equalsIgnoreCase("edit")) {
|
||||
mode = Mode.EDIT;
|
||||
} else {
|
||||
mode = Mode.SEND;
|
||||
}
|
||||
|
||||
if (mode == Mode.SEND) {
|
||||
|
||||
IssueActions.reply(
|
||||
ctx, viewBinding.commentReply.getText().toString(), issue)
|
||||
.accept(
|
||||
(status, result) -> {
|
||||
if (status == ActionResult.Status.SUCCESS) {
|
||||
|
||||
viewBinding.scrollViewComments.post(
|
||||
() ->
|
||||
issueCommentsModel
|
||||
.loadIssueComments(
|
||||
repoOwner,
|
||||
repoName,
|
||||
issueIndex,
|
||||
ctx,
|
||||
() ->
|
||||
viewBinding
|
||||
.scrollViewComments
|
||||
.fullScroll(
|
||||
ScrollView
|
||||
.FOCUS_DOWN)));
|
||||
|
||||
Toasty.success(
|
||||
ctx, getString(R.string.commentSuccess));
|
||||
|
||||
viewBinding.send.setAlpha(buttonAlphaStatDisabled);
|
||||
viewBinding.send.setEnabled(false);
|
||||
viewBinding.commentReply.setText(null);
|
||||
viewBinding.commentReply.clearFocus();
|
||||
imm.toggleSoftInput(
|
||||
InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
|
||||
} else {
|
||||
|
||||
Toasty.error(ctx, getString(R.string.genericError));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
||||
IssueActions.edit(
|
||||
ctx,
|
||||
viewBinding.commentReply.getText().toString(),
|
||||
tinyDB.getInt("commentId"),
|
||||
issue)
|
||||
.accept(
|
||||
(status, result) -> {
|
||||
if (status == ActionResult.Status.SUCCESS) {
|
||||
|
||||
tinyDB.remove("commentId");
|
||||
tinyDB.remove("commentAction");
|
||||
|
||||
viewBinding.scrollViewComments.post(
|
||||
() ->
|
||||
issueCommentsModel
|
||||
.loadIssueComments(
|
||||
repoOwner,
|
||||
repoName,
|
||||
issueIndex,
|
||||
ctx,
|
||||
null));
|
||||
|
||||
Toasty.success(
|
||||
ctx,
|
||||
getString(R.string.editCommentUpdatedText));
|
||||
|
||||
mode = Mode.SEND;
|
||||
viewBinding.send.setAlpha(buttonAlphaStatDisabled);
|
||||
viewBinding.send.setEnabled(false);
|
||||
viewBinding.commentReply.setText(null);
|
||||
viewBinding.commentReply.clearFocus();
|
||||
imm.toggleSoftInput(
|
||||
InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
|
||||
} else {
|
||||
|
||||
Toasty.error(ctx, getString(R.string.genericError));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -708,6 +867,10 @@ public class IssueDetailActivity extends BaseActivity
|
||||
},
|
||||
500);
|
||||
}
|
||||
|
||||
tinyDB.remove("commentId");
|
||||
tinyDB.remove("commentAction");
|
||||
mode = Mode.SEND;
|
||||
}
|
||||
|
||||
private void fetchDataAsync(String owner, String repo, int index) {
|
||||
@ -724,12 +887,7 @@ public class IssueDetailActivity extends BaseActivity
|
||||
|
||||
adapter =
|
||||
new IssueCommentsAdapter(
|
||||
ctx,
|
||||
bundle,
|
||||
issueCommentsMain,
|
||||
getSupportFragmentManager(),
|
||||
this::onResume,
|
||||
issue);
|
||||
ctx, bundle, issueCommentsMain, this::onResume, issue);
|
||||
adapter.setLoadMoreListener(
|
||||
new IssueCommentsAdapter.OnLoadMoreListener() {
|
||||
|
||||
|
@ -18,6 +18,7 @@ import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
@ -27,7 +28,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
import androidx.core.text.HtmlCompat;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import com.amulyakhare.textdrawable.TextDrawable;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog;
|
||||
@ -52,7 +52,6 @@ import org.mian.gitnex.activities.ProfileActivity;
|
||||
import org.mian.gitnex.clients.PicassoService;
|
||||
import org.mian.gitnex.clients.RetrofitClient;
|
||||
import org.mian.gitnex.databinding.CustomImageViewDialogBinding;
|
||||
import org.mian.gitnex.fragments.BottomSheetReplyFragment;
|
||||
import org.mian.gitnex.fragments.IssuesFragment;
|
||||
import org.mian.gitnex.helpers.AlertDialogs;
|
||||
import org.mian.gitnex.helpers.AppDatabaseSettings;
|
||||
@ -79,7 +78,6 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
|
||||
private final Context context;
|
||||
private final TinyDB tinyDB;
|
||||
private final Bundle bundle;
|
||||
private final FragmentManager fragmentManager;
|
||||
private final Runnable onInteractedListener;
|
||||
private final Locale locale;
|
||||
private final IssueContext issue;
|
||||
@ -92,14 +90,12 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
|
||||
Context ctx,
|
||||
Bundle bundle,
|
||||
List<TimelineComment> issuesCommentsMain,
|
||||
FragmentManager fragmentManager,
|
||||
Runnable onInteractedListener,
|
||||
IssueContext issue) {
|
||||
|
||||
this.context = ctx;
|
||||
this.bundle = bundle;
|
||||
this.issuesComments = issuesCommentsMain;
|
||||
this.fragmentManager = fragmentManager;
|
||||
this.onInteractedListener = onInteractedListener;
|
||||
tinyDB = TinyDB.getInstance(ctx);
|
||||
locale = ctx.getResources().getConfiguration().locale;
|
||||
@ -266,11 +262,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
|
||||
|
||||
if (issueComment != null) {
|
||||
new Handler()
|
||||
.postDelayed(
|
||||
() -> {
|
||||
getAttachments(issueComment.getId(), view, token);
|
||||
},
|
||||
250);
|
||||
.postDelayed(() -> getAttachments(issueComment.getId(), view, token), 250);
|
||||
}
|
||||
|
||||
menu.setOnClickListener(
|
||||
@ -343,18 +335,14 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
|
||||
|
||||
commentMenuEdit.setOnClickListener(
|
||||
v1 -> {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putInt(
|
||||
"commentId", Math.toIntExact(issueComment.getId()));
|
||||
bundle.putString("commentAction", "edit");
|
||||
bundle.putString("commentBody", issueComment.getBody());
|
||||
IssueDetailActivity parentActivity =
|
||||
(IssueDetailActivity) context;
|
||||
EditText text = parentActivity.findViewById(R.id.comment_reply);
|
||||
text.append(issueComment.getBody());
|
||||
|
||||
BottomSheetReplyFragment bottomSheetReplyFragment =
|
||||
BottomSheetReplyFragment.newInstance(bundle, issue);
|
||||
bottomSheetReplyFragment.setOnInteractedListener(
|
||||
onInteractedListener);
|
||||
bottomSheetReplyFragment.show(
|
||||
fragmentManager, "replyBottomSheet");
|
||||
tinyDB.putString("commentAction", "edit");
|
||||
tinyDB.putInt(
|
||||
"commentId", Math.toIntExact(issueComment.getId()));
|
||||
|
||||
dialog.dismiss();
|
||||
});
|
||||
@ -402,15 +390,14 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
|
||||
stringBuilder.append(">").append(line).append("\n");
|
||||
}
|
||||
|
||||
stringBuilder.append("\n");
|
||||
String comment = String.valueOf(stringBuilder.append("\n"));
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString("commentBody", stringBuilder.toString());
|
||||
bundle.putBoolean("cursorToEnd", true);
|
||||
IssueDetailActivity parentActivity =
|
||||
(IssueDetailActivity) context;
|
||||
EditText text = parentActivity.findViewById(R.id.comment_reply);
|
||||
text.setText(comment);
|
||||
|
||||
dialog.dismiss();
|
||||
BottomSheetReplyFragment.newInstance(bundle, issue)
|
||||
.show(fragmentManager, "replyBottomSheet");
|
||||
});
|
||||
|
||||
commentMenuCopy.setOnClickListener(
|
||||
@ -1489,7 +1476,7 @@ public class IssueCommentsAdapter extends RecyclerView.Adapter<RecyclerView.View
|
||||
attachmentView.setLayoutParams(paramsAttachment);
|
||||
materialCardView.addView(attachmentView);
|
||||
|
||||
int finalI = i;
|
||||
// int finalI = i;
|
||||
materialCardView.setOnClickListener(
|
||||
v1 -> {
|
||||
// filesize = attachment.get(finalI).getSize();
|
||||
|
@ -6,6 +6,7 @@ import android.content.Intent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
@ -19,7 +20,10 @@ import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.mian.gitnex.R;
|
||||
import org.mian.gitnex.activities.CreateIssueActivity;
|
||||
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;
|
||||
@ -35,14 +39,18 @@ public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NotesViewHol
|
||||
private List<Notes> notesList;
|
||||
private final Context ctx;
|
||||
private final Intent noteIntent;
|
||||
private final String insert;
|
||||
private final String source;
|
||||
|
||||
public NotesAdapter(Context ctx, List<Notes> notesListMain) {
|
||||
public NotesAdapter(Context ctx, List<Notes> notesListMain, String insert, String source) {
|
||||
this.ctx = ctx;
|
||||
this.notesList = notesListMain;
|
||||
noteIntent = new Intent(ctx, CreateNoteActivity.class);
|
||||
this.insert = insert;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
class NotesViewHolder extends RecyclerView.ViewHolder {
|
||||
public class NotesViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private Notes notes;
|
||||
|
||||
@ -82,6 +90,49 @@ public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NotesViewHol
|
||||
.setNeutralButton(R.string.cancelButton, null)
|
||||
.show();
|
||||
});
|
||||
|
||||
if (insert.equalsIgnoreCase("insert") && source.equalsIgnoreCase("issue")) {
|
||||
|
||||
deleteNote.setVisibility(View.GONE);
|
||||
|
||||
itemView.setOnClickListener(
|
||||
view -> {
|
||||
CreateIssueActivity parentActivity = (CreateIssueActivity) ctx;
|
||||
EditText text = parentActivity.findViewById(R.id.newIssueDescription);
|
||||
text.append(notes.getContent());
|
||||
|
||||
parentActivity.dialogNotes.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
if (insert.equalsIgnoreCase("insert") && source.equalsIgnoreCase("release")) {
|
||||
|
||||
deleteNote.setVisibility(View.GONE);
|
||||
|
||||
itemView.setOnClickListener(
|
||||
view -> {
|
||||
CreateReleaseActivity parentActivity = (CreateReleaseActivity) ctx;
|
||||
EditText text = parentActivity.findViewById(R.id.releaseContent);
|
||||
text.append(notes.getContent());
|
||||
|
||||
parentActivity.dialogNotes.dismiss();
|
||||
});
|
||||
}
|
||||
|
||||
if (insert.equalsIgnoreCase("insert") && source.equalsIgnoreCase("pr")) {
|
||||
|
||||
deleteNote.setVisibility(View.GONE);
|
||||
|
||||
itemView.setOnClickListener(
|
||||
view -> {
|
||||
CreatePullRequestActivity parentActivity =
|
||||
(CreatePullRequestActivity) ctx;
|
||||
EditText text = parentActivity.findViewById(R.id.prBody);
|
||||
text.append(notes.getContent());
|
||||
|
||||
parentActivity.dialogNotes.dismiss();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,10 @@ public class NotesApi extends BaseApi {
|
||||
return notesDao.fetchAllNotes();
|
||||
}
|
||||
|
||||
public Integer getCount() {
|
||||
return notesDao.getCount();
|
||||
}
|
||||
|
||||
public Notes fetchNoteById(int noteId) {
|
||||
return notesDao.fetchNoteById(noteId);
|
||||
}
|
||||
|
@ -33,4 +33,7 @@ public interface NotesDao {
|
||||
|
||||
@Query("DELETE FROM Notes WHERE noteId = :noteId")
|
||||
void deleteNote(int noteId);
|
||||
|
||||
@Query("SELECT COUNT(noteId) FROM Notes")
|
||||
Integer getCount();
|
||||
}
|
||||
|
@ -33,7 +33,6 @@ import org.mian.gitnex.database.api.DraftsApi;
|
||||
import org.mian.gitnex.databinding.BottomSheetReplyLayoutBinding;
|
||||
import org.mian.gitnex.helpers.AppDatabaseSettings;
|
||||
import org.mian.gitnex.helpers.Constants;
|
||||
import org.mian.gitnex.helpers.TinyDB;
|
||||
import org.mian.gitnex.helpers.Toasty;
|
||||
import org.mian.gitnex.helpers.contexts.IssueContext;
|
||||
|
||||
@ -43,7 +42,6 @@ import org.mian.gitnex.helpers.contexts.IssueContext;
|
||||
public class BottomSheetReplyFragment extends BottomSheetDialogFragment {
|
||||
|
||||
private Mode mode = Mode.SEND;
|
||||
private TinyDB tinyDB;
|
||||
private DraftsApi draftsApi;
|
||||
private int currentActiveAccountId;
|
||||
private IssueContext issue;
|
||||
@ -65,7 +63,6 @@ public class BottomSheetReplyFragment extends BottomSheetDialogFragment {
|
||||
|
||||
super.onAttach(context);
|
||||
|
||||
tinyDB = TinyDB.getInstance(context);
|
||||
draftsApi = BaseApi.getInstance(context, DraftsApi.class);
|
||||
|
||||
currentActiveAccountId =
|
||||
@ -103,7 +100,7 @@ public class BottomSheetReplyFragment extends BottomSheetDialogFragment {
|
||||
|
||||
if (arguments.getString("draftId") != null) {
|
||||
|
||||
draftId = Long.parseLong(arguments.getString("draftId"));
|
||||
draftId = Long.parseLong(Objects.requireNonNull(arguments.getString("draftId")));
|
||||
}
|
||||
|
||||
if (issue.getIssue() != null && !issue.getIssue().getTitle().isEmpty()) {
|
||||
@ -235,8 +232,7 @@ public class BottomSheetReplyFragment extends BottomSheetDialogFragment {
|
||||
(status, result) -> {
|
||||
FragmentActivity activity = requireActivity();
|
||||
if (activity instanceof IssueDetailActivity) {
|
||||
((IssueDetailActivity) activity).commentEdited =
|
||||
true;
|
||||
IssueDetailActivity.commentEdited = true;
|
||||
}
|
||||
|
||||
if (status == ActionResult.Status.SUCCESS) {
|
||||
@ -271,6 +267,7 @@ public class BottomSheetReplyFragment extends BottomSheetDialogFragment {
|
||||
|
||||
private void saveDraft(String text, boolean remove) {
|
||||
|
||||
@SuppressLint("Recycle")
|
||||
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0f, 1f);
|
||||
valueAnimator.setDuration(500);
|
||||
valueAnimator.addUpdateListener(
|
||||
|
@ -70,7 +70,7 @@ public class NotesFragment extends Fragment {
|
||||
binding.recyclerView.setPadding(0, 0, 0, 220);
|
||||
binding.recyclerView.setClipToPadding(false);
|
||||
|
||||
adapter = new NotesAdapter(ctx, notesList);
|
||||
adapter = new NotesAdapter(ctx, notesList, "", "");
|
||||
|
||||
binding.pullToRefresh.setOnRefreshListener(
|
||||
() ->
|
||||
@ -103,7 +103,7 @@ public class NotesFragment extends Fragment {
|
||||
allNotes -> {
|
||||
binding.pullToRefresh.setRefreshing(false);
|
||||
assert allNotes != null;
|
||||
if (allNotes.size() > 0) {
|
||||
if (!allNotes.isEmpty()) {
|
||||
|
||||
notesList.clear();
|
||||
binding.noData.setVisibility(View.GONE);
|
||||
@ -138,7 +138,7 @@ public class NotesFragment extends Fragment {
|
||||
|
||||
public void deleteAllNotes() {
|
||||
|
||||
if (notesList.size() > 0) {
|
||||
if (!notesList.isEmpty()) {
|
||||
|
||||
notesApi.deleteAllNotes();
|
||||
notesList.clear();
|
||||
@ -159,6 +159,7 @@ public class NotesFragment extends Fragment {
|
||||
|
||||
MenuItem searchItem = menu.findItem(R.id.action_search);
|
||||
SearchView searchView = (SearchView) searchItem.getActionView();
|
||||
assert searchView != null;
|
||||
searchView.setImeOptions(EditorInfo.IME_ACTION_DONE);
|
||||
|
||||
searchView.setOnQueryTextListener(
|
||||
@ -184,7 +185,7 @@ public class NotesFragment extends Fragment {
|
||||
|
||||
if (item.getItemId() == R.id.reset_menu_item) {
|
||||
|
||||
if (notesList.size() == 0) {
|
||||
if (notesList.isEmpty()) {
|
||||
Toasty.warning(ctx, getResources().getString(R.string.noDataFound));
|
||||
} else {
|
||||
new MaterialAlertDialogBuilder(ctx)
|
||||
|
@ -4,17 +4,17 @@
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M22,2L11,13"
|
||||
android:pathData="M4.698,4.034l16.302,7.966l-16.302,7.966a0.503,0.503 0,0 1,-0.546 -0.124a0.555,0.555 0,0 1,-0.12 -0.568l2.468,-7.274l-2.468,-7.274a0.555,0.555 0,0 1,0.12 -0.568a0.503,0.503 0,0 1,0.546 -0.124z"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="?attr/iconsColor"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"/>
|
||||
android:strokeLineCap="round"/>
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M22,2l-7,20l-4,-9l-9,-4l20,-7z"
|
||||
android:pathData="M6.5,12h14.5"
|
||||
android:strokeLineJoin="round"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="?attr/iconsColor"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeLineJoin="round"/>
|
||||
android:strokeLineCap="round"/>
|
||||
</vector>
|
||||
|
@ -4,11 +4,11 @@
|
||||
android:shape="rectangle">
|
||||
|
||||
<solid
|
||||
android:color="?attr/inputBackgroundColor">
|
||||
android:color="?attr/materialCardBackgroundColor">
|
||||
</solid>
|
||||
|
||||
<corners
|
||||
android:radius="3dp">
|
||||
android:radius="32dp">
|
||||
</corners>
|
||||
|
||||
<padding
|
||||
|
@ -84,6 +84,17 @@
|
||||
|
||||
</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/newIssueDescriptionLayout"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -84,6 +84,17 @@
|
||||
|
||||
</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/prBodyLayout"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -99,6 +99,17 @@
|
||||
|
||||
</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"
|
||||
|
@ -63,6 +63,7 @@
|
||||
android:text="@string/commentButtonText"
|
||||
android:textColor="?attr/materialCardBackgroundColor"
|
||||
app:iconTint="?attr/materialCardBackgroundColor"
|
||||
android:visibility="gone"
|
||||
app:icon="@drawable/ic_reply" />
|
||||
|
||||
<RelativeLayout
|
||||
@ -89,7 +90,7 @@
|
||||
android:paddingStart="@dimen/dimen8dp"
|
||||
android:paddingTop="@dimen/dimen2dp"
|
||||
android:paddingEnd="@dimen/dimen8dp"
|
||||
android:paddingBottom="@dimen/dimen8dp">
|
||||
android:paddingBottom="@dimen/dimen104dp">
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:id="@+id/titleCard"
|
||||
@ -153,7 +154,8 @@
|
||||
android:layout_width="@dimen/dimen24dp"
|
||||
android:layout_height="@dimen/dimen24dp"
|
||||
app:cardCornerRadius="@dimen/dimen12dp"
|
||||
app:cardElevation="@dimen/dimen0dp">
|
||||
app:cardElevation="@dimen/dimen0dp"
|
||||
tools:ignore="TooDeepLayout">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/assigneeAvatar"
|
||||
@ -371,9 +373,7 @@
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:paddingBottom="@dimen/dimen72dp" />
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
@ -383,6 +383,56 @@
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:background="?attr/primaryBackgroundColor"
|
||||
android:padding="@dimen/dimen8dp">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/comment_reply"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:autofillHints="@string/commentButtonText"
|
||||
android:background="@drawable/shape_inputs"
|
||||
android:inputType="textMultiLine|textImeMultiLine|textCapSentences"
|
||||
android:labelFor="@+id/comment_reply"
|
||||
android:layout_weight="1"
|
||||
android:maxLines="4"
|
||||
android:paddingStart="@dimen/dimen16dp"
|
||||
android:paddingEnd="@dimen/dimen16dp"
|
||||
android:paddingTop="@dimen/dimen8dp"
|
||||
android:paddingBottom="@dimen/dimen8dp"
|
||||
android:textColor="?attr/inputTextColor"
|
||||
android:layout_marginEnd="@dimen/dimen12dp"
|
||||
android:textSize="@dimen/dimen14sp" />
|
||||
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
style="?attr/materialCardViewFilledStyle"
|
||||
android:id="@+id/send_button"
|
||||
android:layout_width="@dimen/dimen36dp"
|
||||
android:layout_height="@dimen/dimen36dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:backgroundTint="?attr/fabColor"
|
||||
app:cardCornerRadius="@dimen/dimen36dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/send"
|
||||
android:layout_width="@dimen/dimen24dp"
|
||||
android:layout_height="@dimen/dimen24dp"
|
||||
android:layout_gravity="center_vertical|center_horizontal"
|
||||
android:contentDescription="@string/generalImgContentText"
|
||||
app:tint="?attr/materialCardBackgroundColor"
|
||||
android:clickable="true"
|
||||
android:src="@drawable/ic_send"
|
||||
android:focusable="true" />
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
@ -138,6 +138,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/dimen32dp"
|
||||
android:visibility="gone"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
|
7
app/src/main/res/layout/activity_unlock.xml
Normal file
7
app/src/main/res/layout/activity_unlock.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -29,7 +29,6 @@
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hint="@string/title"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
app:boxBackgroundColor="?attr/inputBackgroundColor"
|
||||
app:boxStrokeErrorColor="@color/darkRed"
|
||||
app:hintTextColor="?attr/hintColor">
|
||||
|
||||
@ -51,7 +50,6 @@
|
||||
android:layout_marginBottom="8dp"
|
||||
android:hint="@string/sshKey"
|
||||
android:textColorHint="?attr/hintColor"
|
||||
app:boxBackgroundColor="?attr/inputBackgroundColor"
|
||||
app:boxStrokeErrorColor="@color/darkRed"
|
||||
app:hintTextColor="?attr/hintColor">
|
||||
|
||||
|
35
app/src/main/res/layout/custom_insert_note.xml
Normal file
35
app/src/main/res/layout/custom_insert_note.xml
Normal file
@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:padding="@dimen/dimen16dp">
|
||||
|
||||
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
||||
android:id="@+id/pullToRefresh"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
|
||||
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
<com.google.android.material.progressindicator.LinearProgressIndicator
|
||||
android:id="@+id/progressBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true"
|
||||
style="@style/Widget.Material3.LinearProgressIndicator"
|
||||
app:indicatorColor="?attr/progressIndicatorColor" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
@ -58,6 +58,7 @@
|
||||
|
||||
<item android:id="@+id/nav_comments_draft"
|
||||
android:icon="@drawable/ic_drafts"
|
||||
android:visible="false"
|
||||
android:title="@string/titleDrafts"/>
|
||||
|
||||
<item android:id="@+id/nav_profile"
|
||||
|
@ -853,6 +853,8 @@
|
||||
<item quantity="other">Notes deleted successfully</item>
|
||||
</plurals>
|
||||
<string name="notesAllDeletionMessage">This will delete all of your notes. This action cannot be undone.</string>
|
||||
<string name="insertNote">Insert a Note</string>
|
||||
<string name="noNotes">No notes found</string>
|
||||
|
||||
<!-- timeline -->
|
||||
<string name="commitsText">commit</string>
|
||||
|
Loading…
Reference in New Issue
Block a user