diff --git a/README.md b/README.md index 7ec2af0d..79146187 100644 --- a/README.md +++ b/README.md @@ -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) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 1ec4a7c9..b2c79cef 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -82,7 +82,11 @@ + android:windowSoftInputMode="adjustResize"/> + labelsIds = new ArrayList<>(); private List assigneesListData = new ArrayList<>(); private boolean renderMd = false; @@ -84,6 +93,11 @@ public class CreateIssueActivity extends BaseActivity private static List attachmentsList; private AttachmentsAdapter attachmentsAdapter; private static final List contentUri = new ArrayList<>(); + private CustomInsertNoteBinding customInsertNoteBinding; + private NotesAdapter adapter; + private NotesApi notesApi; + private List 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 startActivityForResult = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), diff --git a/app/src/main/java/org/mian/gitnex/activities/CreatePullRequestActivity.java b/app/src/main/java/org/mian/gitnex/activities/CreatePullRequestActivity.java index 1aefe7cc..05ad2a65 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CreatePullRequestActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CreatePullRequestActivity.java @@ -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 attachmentsList; private AttachmentsAdapter attachmentsAdapter; private static final List contentUri = new ArrayList<>(); + private CustomInsertNoteBinding customInsertNoteBinding; + private NotesAdapter adapter; + private NotesApi notesApi; + private List 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_) { diff --git a/app/src/main/java/org/mian/gitnex/activities/CreateReleaseActivity.java b/app/src/main/java/org/mian/gitnex/activities/CreateReleaseActivity.java index 98a19715..04c381d6 100644 --- a/app/src/main/java/org/mian/gitnex/activities/CreateReleaseActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/CreateReleaseActivity.java @@ -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 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; diff --git a/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java b/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java index 34a56ebd..60070604 100644 --- a/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java +++ b/app/src/main/java/org/mian/gitnex/activities/IssueDetailActivity.java @@ -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