Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-notes.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2021-06-23 17:02:46 +0300
committerStefan Niedermann <info@niedermann.it>2021-06-23 17:02:46 +0300
commitbbf1a7da50e9b9fc4a5749bf6af1799afa511f87 (patch)
treef0166360b9d022ec03119c60d2dfb925b83ad747
parentfc8bacaa1be4bd7ce17dff5e8f8b416bf1809650 (diff)
#1277 Redesign note details1277-redesign-note-details
Signed-off-by: Stefan Niedermann <info@niedermann.it>
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java13
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java22
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java4
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryAdapter.java134
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryDialogFragment.java2
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/details/CategoryAdapter.java110
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/details/CategoryViewModel.java (renamed from app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryViewModel.java)5
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsDialogFragment.java148
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsViewModel.java43
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/edit/title/EditTitleDialogFragment.java96
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java4
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java35
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java13
-rw-r--r--app/src/main/res/layout/dialog_note_details.xml118
-rw-r--r--app/src/main/res/values/strings.xml1
15 files changed, 386 insertions, 362 deletions
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java
index bc0faca7..ae44f4b3 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/branding/BrandingUtil.java
@@ -21,6 +21,8 @@ import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.preference.PreferenceManager;
+import com.google.android.material.textfield.TextInputLayout;
+
import it.niedermann.android.sharedpreferences.SharedPreferenceIntLiveData;
import it.niedermann.owncloud.notes.NotesApplication;
import it.niedermann.owncloud.notes.R;
@@ -161,4 +163,15 @@ public class BrandingUtil {
DrawableCompat.setTint(drawable, mainColor);
}
}
+
+ public static void applyBrandToEditTextInputLayout(@ColorInt int color, @NonNull TextInputLayout til) {
+ final int colorPrimary = ContextCompat.getColor(til.getContext(), R.color.primary);
+ final int colorAccent = ContextCompat.getColor(til.getContext(), R.color.accent);
+ final ColorStateList colorDanger = ColorStateList.valueOf(ContextCompat.getColor(til.getContext(), R.color.design_default_color_error));
+ til.setBoxStrokeColor(contrastRatioIsSufficient(color, colorPrimary) ? color : colorAccent);
+ til.setHintTextColor(ColorStateList.valueOf(contrastRatioIsSufficient(color, colorPrimary) ? color : colorAccent));
+ til.setErrorTextColor(colorDanger);
+ til.setBoxStrokeErrorColor(colorDanger);
+ til.setErrorIconTintList(colorDanger);
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java
index 3f0dff69..c5e6a9f6 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/BaseNoteFragment.java
@@ -35,11 +35,7 @@ import it.niedermann.android.util.ColorUtil;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.accountpicker.AccountPickerDialogFragment;
import it.niedermann.owncloud.notes.branding.BrandedFragment;
-import it.niedermann.owncloud.notes.edit.category.CategoryDialogFragment;
-import it.niedermann.owncloud.notes.edit.category.CategoryDialogFragment.CategoryDialogListener;
import it.niedermann.owncloud.notes.edit.details.NoteDetailsDialogFragment;
-import it.niedermann.owncloud.notes.edit.title.EditTitleDialogFragment;
-import it.niedermann.owncloud.notes.edit.title.EditTitleDialogFragment.EditTitleListener;
import it.niedermann.owncloud.notes.persistence.NotesRepository;
import it.niedermann.owncloud.notes.persistence.entity.Account;
import it.niedermann.owncloud.notes.persistence.entity.Note;
@@ -47,11 +43,10 @@ import it.niedermann.owncloud.notes.shared.model.DBStatus;
import it.niedermann.owncloud.notes.shared.model.ISyncCallback;
import it.niedermann.owncloud.notes.shared.util.NoteUtil;
import it.niedermann.owncloud.notes.shared.util.NotesColorUtil;
-import it.niedermann.owncloud.notes.shared.util.ShareUtil;
import static it.niedermann.owncloud.notes.NotesApplication.isDarkThemeActive;
-public abstract class BaseNoteFragment extends BrandedFragment implements CategoryDialogListener, EditTitleListener {
+public abstract class BaseNoteFragment extends BrandedFragment implements NoteDetailsDialogFragment.NoteDetailsListener {
private static final String TAG = BaseNoteFragment.class.getSimpleName();
protected final ExecutorService executor = Executors.newCachedThreadPool();
@@ -284,22 +279,13 @@ public abstract class BaseNoteFragment extends BrandedFragment implements Catego
}
@Override
- public void onCategoryChosen(String category) {
- repo.setCategory(localAccount, note.getId(), category);
+ public void onNoteDetailsEdited(String title, String category) {
+ titleModified = true;
+ note.setTitle(title);
note.setCategory(category);
listener.onNoteUpdated(note);
}
- @Override
- public void onTitleEdited(String newTitle) {
- titleModified = true;
- note.setTitle(newTitle);
- executor.submit(() -> {
- note = repo.updateNoteAndSync(localAccount, note, note.getContent(), newTitle, null);
- requireActivity().runOnUiThread(() -> listener.onNoteUpdated(note));
- });
- }
-
public void moveNote(Account account) {
final LiveData<Note> moveLiveData = repo.moveNoteToAnotherAccount(account, note);
moveLiveData.observe(this, (v) -> moveLiveData.removeObservers(this));
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java
index a1eb8d68..4b54c53c 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/EditNoteActivity.java
@@ -29,11 +29,9 @@ import it.niedermann.owncloud.notes.LockedActivity;
import it.niedermann.owncloud.notes.R;
import it.niedermann.owncloud.notes.accountpicker.AccountPickerListener;
import it.niedermann.owncloud.notes.databinding.ActivityEditBinding;
-import it.niedermann.owncloud.notes.databinding.ActivityEditBinding;
-import it.niedermann.owncloud.notes.edit.category.CategoryViewModel;
+import it.niedermann.owncloud.notes.edit.details.CategoryViewModel;
import it.niedermann.owncloud.notes.persistence.entity.Account;
import it.niedermann.owncloud.notes.persistence.entity.Note;
-import it.niedermann.owncloud.notes.shared.model.DBStatus;
import it.niedermann.owncloud.notes.shared.model.NavigationCategory;
import it.niedermann.owncloud.notes.shared.util.NoteUtil;
import it.niedermann.owncloud.notes.shared.util.ShareUtil;
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryAdapter.java
deleted file mode 100644
index 4b3bb9ba..00000000
--- a/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryAdapter.java
+++ /dev/null
@@ -1,134 +0,0 @@
-package it.niedermann.owncloud.notes.edit.category;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.appcompat.widget.AppCompatImageView;
-import androidx.core.content.ContextCompat;
-import androidx.core.graphics.drawable.DrawableCompat;
-import androidx.recyclerview.widget.RecyclerView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import it.niedermann.owncloud.notes.R;
-import it.niedermann.owncloud.notes.databinding.ItemCategoryBinding;
-import it.niedermann.owncloud.notes.main.navigation.NavigationItem;
-import it.niedermann.owncloud.notes.shared.util.NoteUtil;
-
-public class CategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
-
- private static final String clearItemId = "clear_item";
- private static final String addItemId = "add_item";
- @NonNull
- private List<NavigationItem> categories = new ArrayList<>();
- @NonNull
- private final CategoryListener listener;
- private final Context context;
-
- CategoryAdapter(@NonNull Context context, @NonNull CategoryListener categoryListener) {
- this.context = context;
- this.listener = categoryListener;
- }
-
- @NonNull
- @Override
- public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
- View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_category, parent, false);
- return new CategoryViewHolder(v);
- }
-
- @Override
- public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
- NavigationItem category = categories.get(position);
- CategoryViewHolder categoryViewHolder = (CategoryViewHolder) holder;
-
- switch (category.id) {
- case addItemId:
- Drawable wrapDrawable = DrawableCompat.wrap(ContextCompat.getDrawable(context, category.icon));
- DrawableCompat.setTint(wrapDrawable, ContextCompat.getColor(context, R.color.icon_color_default));
- categoryViewHolder.getIcon().setImageDrawable(wrapDrawable);
- categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryAdded());
- break;
- case clearItemId:
- categoryViewHolder.getIcon().setImageDrawable(ContextCompat.getDrawable(context, category.icon));
- categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryCleared());
- break;
- default:
- categoryViewHolder.getIcon().setImageDrawable(ContextCompat.getDrawable(context, category.icon));
- categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryChosen(category.label));
- break;
- }
- categoryViewHolder.getCategory().setText(NoteUtil.extendCategory(category.label));
- if (category.count != null && category.count > 0) {
- categoryViewHolder.getCount().setText(String.valueOf(category.count));
- } else {
- categoryViewHolder.getCount().setVisibility(View.GONE);
- }
- }
-
- @Override
- public int getItemCount() {
- return categories.size();
- }
-
- static class CategoryViewHolder extends RecyclerView.ViewHolder {
- private final ItemCategoryBinding binding;
-
- private CategoryViewHolder(View view) {
- super(view);
- binding = ItemCategoryBinding.bind(view);
- }
-
- private View getCategoryWrapper() {
- return binding.categoryWrapper;
- }
-
- private AppCompatImageView getIcon() {
- return binding.icon;
- }
-
- private TextView getCategory() {
- return binding.category;
- }
-
- private TextView getCount() {
- return binding.count;
- }
- }
-
- void setCategoryList(List<NavigationItem.CategoryNavigationItem> categories, @Nullable String currentSearchString) {
- this.categories.clear();
- this.categories.addAll(categories);
- final NavigationItem clearItem = new NavigationItem(clearItemId, context.getString(R.string.no_category), 0, R.drawable.ic_clear_grey_24dp);
- this.categories.add(0, clearItem);
- if (currentSearchString != null && currentSearchString.trim().length() > 0) {
- boolean currentSearchStringIsInCategories = false;
- for (NavigationItem category : categories) {
- if (currentSearchString.equals(category.label)) {
- currentSearchStringIsInCategories = true;
- break;
- }
- }
- if (!currentSearchStringIsInCategories) {
- NavigationItem addItem = new NavigationItem(addItemId, context.getString(R.string.add_category, currentSearchString.trim()), 0, R.drawable.ic_add_blue_24dp);
- this.categories.add(addItem);
- }
- }
- notifyDataSetChanged();
- }
-
- public interface CategoryListener {
- void onCategoryChosen(String category);
-
- void onCategoryAdded();
-
- void onCategoryCleared();
- }
-}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryDialogFragment.java
index 648578d4..c283ae72 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryDialogFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryDialogFragment.java
@@ -24,6 +24,8 @@ import it.niedermann.owncloud.notes.branding.BrandedAlertDialogBuilder;
import it.niedermann.owncloud.notes.branding.BrandedDialogFragment;
import it.niedermann.owncloud.notes.branding.BrandingUtil;
import it.niedermann.owncloud.notes.databinding.DialogChangeCategoryBinding;
+import it.niedermann.owncloud.notes.edit.details.CategoryAdapter;
+import it.niedermann.owncloud.notes.edit.details.CategoryViewModel;
import it.niedermann.owncloud.notes.main.navigation.NavigationItem;
/**
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/details/CategoryAdapter.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/details/CategoryAdapter.java
new file mode 100644
index 00000000..1f64a0f5
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/details/CategoryAdapter.java
@@ -0,0 +1,110 @@
+package it.niedermann.owncloud.notes.edit.details;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.appcompat.widget.AppCompatImageView;
+import androidx.core.content.ContextCompat;
+import androidx.recyclerview.widget.RecyclerView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.databinding.ItemCategoryBinding;
+import it.niedermann.owncloud.notes.main.navigation.NavigationItem;
+import it.niedermann.owncloud.notes.shared.util.NoteUtil;
+
+public class CategoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+
+ @NonNull
+ private final List<NavigationItem> categories = new ArrayList<>();
+ @NonNull
+ private final CategoryListener listener;
+ private final Context context;
+
+
+ public CategoryAdapter(@NonNull Context context, @NonNull CategoryListener categoryListener) {
+ this.context = context;
+ this.listener = categoryListener;
+ }
+
+ @NonNull
+ @Override
+ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
+ View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_category, parent, false);
+ return new CategoryViewHolder(v);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
+ final NavigationItem category = categories.get(position);
+ final CategoryViewHolder categoryViewHolder = (CategoryViewHolder) holder;
+ categoryViewHolder.getIcon().setImageDrawable(ContextCompat.getDrawable(context, category.icon));
+ categoryViewHolder.getCategoryWrapper().setOnClickListener((v) -> listener.onCategoryChosen(category.label));
+ categoryViewHolder.getCategory().setText(NoteUtil.extendCategory(category.label));
+ if (category.count != null && category.count > 0) {
+ categoryViewHolder.getCount().setText(String.valueOf(category.count));
+ } else {
+ categoryViewHolder.getCount().setVisibility(View.GONE);
+ }
+ }
+
+ @Override
+ public int getItemCount() {
+ return categories.size();
+ }
+
+ static class CategoryViewHolder extends RecyclerView.ViewHolder {
+ private final ItemCategoryBinding binding;
+
+ private CategoryViewHolder(View view) {
+ super(view);
+ binding = ItemCategoryBinding.bind(view);
+ }
+
+ private View getCategoryWrapper() {
+ return binding.categoryWrapper;
+ }
+
+ private AppCompatImageView getIcon() {
+ return binding.icon;
+ }
+
+ private TextView getCategory() {
+ return binding.category;
+ }
+
+ private TextView getCount() {
+ return binding.count;
+ }
+ }
+
+ /**
+ * @deprecated use {@link #setCategoryList(List)}
+ */
+ public void setCategoryList(List<NavigationItem.CategoryNavigationItem> categories, @Nullable String currentSearchString) {
+ setCategoryList(categories);
+ }
+
+ public void setCategoryList(@NonNull List<NavigationItem.CategoryNavigationItem> categories) {
+ this.categories.clear();
+ this.categories.addAll(categories);
+ notifyDataSetChanged();
+ }
+
+ public interface CategoryListener {
+ void onCategoryChosen(String category);
+
+ default void onCategoryAdded() {
+ }
+
+ default void onCategoryCleared() {
+ }
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/details/CategoryViewModel.java
index ea5efd37..4a18026e 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/edit/category/CategoryViewModel.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/details/CategoryViewModel.java
@@ -1,4 +1,4 @@
-package it.niedermann.owncloud.notes.edit.category;
+package it.niedermann.owncloud.notes.edit.details;
import android.app.Application;
import android.text.TextUtils;
@@ -13,6 +13,7 @@ import java.util.List;
import it.niedermann.owncloud.notes.main.navigation.NavigationItem;
import it.niedermann.owncloud.notes.persistence.NotesRepository;
+import static androidx.lifecycle.Transformations.distinctUntilChanged;
import static androidx.lifecycle.Transformations.map;
import static androidx.lifecycle.Transformations.switchMap;
import static it.niedermann.owncloud.notes.shared.util.DisplayUtils.convertToCategoryNavigationItem;
@@ -35,7 +36,7 @@ public class CategoryViewModel extends AndroidViewModel {
@NonNull
public LiveData<List<NavigationItem.CategoryNavigationItem>> getCategories(long accountId) {
- return switchMap(this.searchTerm, searchTerm ->
+ return switchMap(distinctUntilChanged(this.searchTerm), searchTerm ->
map(repo.searchCategories$(accountId, TextUtils.isEmpty(searchTerm) ? "%" : "%" + searchTerm + "%"),
categories -> convertToCategoryNavigationItem(getApplication(), categories)));
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsDialogFragment.java
index 285e72af..b6bf96c3 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsDialogFragment.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsDialogFragment.java
@@ -10,6 +10,9 @@ import android.content.pm.ShortcutManager;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextUtils;
+import android.text.TextWatcher;
import android.text.format.DateUtils;
import android.util.Log;
import android.view.View;
@@ -19,11 +22,16 @@ import androidx.annotation.Nullable;
import androidx.fragment.app.DialogFragment;
import androidx.lifecycle.ViewModelProvider;
+import java.util.stream.Collectors;
+
import it.niedermann.owncloud.notes.R;
+import it.niedermann.owncloud.notes.branding.BrandingUtil;
import it.niedermann.owncloud.notes.databinding.DialogNoteDetailsBinding;
import it.niedermann.owncloud.notes.edit.EditNoteActivity;
import it.niedermann.owncloud.notes.persistence.entity.Account;
+import it.niedermann.owncloud.notes.persistence.entity.Note;
import it.niedermann.owncloud.notes.shared.model.ApiVersion;
+import it.niedermann.owncloud.notes.shared.model.IResponseCallback;
import it.niedermann.owncloud.notes.shared.util.ApiVersionUtil;
import it.niedermann.owncloud.notes.shared.util.ShareUtil;
@@ -34,14 +42,17 @@ import static java.lang.Boolean.TRUE;
public class NoteDetailsDialogFragment extends DialogFragment {
private static final String TAG = NoteDetailsDialogFragment.class.getSimpleName();
- static final String PARAM_ACCOUNT = "account";
- static final String PARAM_NOTE_ID = "noteId";
+ private static final String PARAM_ACCOUNT = "account";
+ private static final String PARAM_NOTE_ID = "noteId";
+
private DialogNoteDetailsBinding binding;
+ private NoteDetailsViewModel viewModel;
+ private CategoryViewModel categoryViewModel;
+ private NoteDetailsListener listener;
private Account account;
private long noteId;
- private NoteDetailsViewModel viewModel;
@Override
public void onAttach(@NonNull Context context) {
@@ -49,7 +60,17 @@ public class NoteDetailsDialogFragment extends DialogFragment {
final Bundle args = requireArguments();
account = (Account) args.getSerializable(PARAM_ACCOUNT);
noteId = args.getLong(PARAM_NOTE_ID);
+
+ if (getTargetFragment() instanceof NoteDetailsListener) {
+ listener = (NoteDetailsListener) getTargetFragment();
+ } else if (getActivity() instanceof NoteDetailsListener) {
+ listener = (NoteDetailsListener) getActivity();
+ } else {
+ throw new IllegalArgumentException("Calling activity or target fragment must implement " + NoteDetailsListener.class.getSimpleName());
+ }
+
viewModel = new ViewModelProvider(requireActivity()).get(NoteDetailsViewModel.class);
+ categoryViewModel = new ViewModelProvider(requireActivity()).get(CategoryViewModel.class);
}
@NonNull
@@ -60,10 +81,16 @@ public class NoteDetailsDialogFragment extends DialogFragment {
final Dialog dialog = new AlertDialog.Builder(getActivity())
.setView(binding.getRoot())
.setCancelable(true)
- .setNegativeButton(R.string.simple_close, null)
+ .setPositiveButton(R.string.action_edit_save, (d, w) -> {
+ listener.onNoteDetailsEdited(binding.title.getText().toString(), binding.category.getText().toString());
+ viewModel.commit(account, noteId, binding.title.getText().toString(), binding.category.getText().toString());
+ })
+ .setNeutralButton(android.R.string.cancel, null)
.create();
dialog.setOnShowListener((d) -> {
- if (!(isRequestPinShortcutSupported(requireActivity()) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)) {
+ BrandingUtil.applyBrandToEditTextInputLayout(account.getColor(), binding.titleWrapper);
+ BrandingUtil.applyBrandToEditTextInputLayout(account.getColor(), binding.categoryWrapper);
+ if (!isRequestPinShortcutSupported(requireContext()) || Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
binding.pin.setVisibility(View.GONE);
}
final ApiVersion preferredApiVersion = ApiVersionUtil.getPreferredApiVersion(account.getApiVersion());
@@ -71,44 +98,89 @@ public class NoteDetailsDialogFragment extends DialogFragment {
if (!supportsTitle) {
binding.titleWrapper.setVisibility(View.GONE);
}
+ binding.category.addTextChangedListener(new TextWatcher() {
+ @Override
+ public void beforeTextChanged(CharSequence s, int start, int count, int after) {
+ // Nothing to do here...
+ }
+
+ @Override
+ public void onTextChanged(CharSequence s, int start, int before, int count) {
+ categoryViewModel.postSearchTerm(s.toString());
+ }
+
+ @Override
+ public void afterTextChanged(Editable s) {
+ // Nothing to do here...
+ }
+ });
- viewModel.getNote$(noteId).observe(this, (note) -> {
- binding.favorite.setImageResource(note.getFavorite() ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp);
- if (supportsTitle) {
- binding.title.setText(note.getTitle());
+ final CategoryAdapter adapter = new CategoryAdapter(requireContext(), category -> binding.category.setText(category));
+ binding.categories.setAdapter(adapter);
+
+ viewModel.isFavorite$(noteId).observe(this, (isFavorite) -> binding.favorite.setImageResource(isFavorite ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp));
+ viewModel.getCategory$(noteId).observe(this, (category) -> {
+ if (!TextUtils.equals(binding.category.getText(), category)) {
+ binding.category.setText(category);
+ }
+ categoryViewModel.postSearchTerm(category);
+ });
+ categoryViewModel.getCategories(account.getId()).observe(this, categories -> adapter.setCategoryList(categories.stream().filter(category -> !TextUtils.equals(category.category, binding.category.getText())).collect(Collectors.toList())));
+ viewModel.getTitle$(noteId).observe(this, (title) -> {
+ if (!TextUtils.equals(binding.title.getText(), title)) {
+ binding.title.setText(title);
}
- binding.category.setText(note.getCategory());
- binding.modified.setText(DateUtils.getRelativeDateTimeString(
- getContext(),
- note.getModified().getTimeInMillis(),
- DateUtils.SECOND_IN_MILLIS,
- DateUtils.WEEK_IN_MILLIS,
- 0
- ));
-
- binding.pin.setOnClickListener((v) -> {
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- final ShortcutManager shortcutManager = requireActivity().getSystemService(ShortcutManager.class);
- if (shortcutManager != null) {
- if (shortcutManager.isRequestPinShortcutSupported()) {
- final ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder(getActivity(), String.valueOf(note.getId()))
- .setShortLabel(note.getTitle())
- .setIcon(Icon.createWithResource(requireActivity().getApplicationContext(), TRUE.equals(note.getFavorite()) ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp))
- .setIntent(new Intent(getActivity(), EditNoteActivity.class).putExtra(EditNoteActivity.PARAM_NOTE_ID, note.getId()).setAction(ACTION_SHORTCUT))
- .build();
-
- shortcutManager.requestPinShortcut(pinShortcutInfo, PendingIntent.getBroadcast(getActivity(), 0, shortcutManager.createShortcutResultIntent(pinShortcutInfo), 0).getIntentSender());
- } else {
- Log.i(TAG, "RequestPinShortcut is not supported");
- }
+ });
+ viewModel.getModified$(noteId).observe(this, (modified) -> binding.modified.setText(DateUtils.getRelativeDateTimeString(
+ getContext(),
+ modified.getTimeInMillis(),
+ DateUtils.SECOND_IN_MILLIS,
+ DateUtils.WEEK_IN_MILLIS,
+ 0
+ )));
+ binding.pin.setOnClickListener((v) -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ final ShortcutManager shortcutManager = requireActivity().getSystemService(ShortcutManager.class);
+ if (shortcutManager != null) {
+ if (shortcutManager.isRequestPinShortcutSupported()) {
+ viewModel.getNoteById(noteId, new IResponseCallback<Note>() {
+ @Override
+ public void onSuccess(Note note) {
+ final ShortcutInfo pinShortcutInfo = new ShortcutInfo.Builder(getActivity(), String.valueOf(note.getId()))
+ .setShortLabel(note.getTitle())
+ .setIcon(Icon.createWithResource(requireActivity().getApplicationContext(), TRUE.equals(note.getFavorite()) ? R.drawable.ic_star_yellow_24dp : R.drawable.ic_star_grey_ccc_24dp))
+ .setIntent(new Intent(getActivity(), EditNoteActivity.class).putExtra(EditNoteActivity.PARAM_NOTE_ID, note.getId()).setAction(ACTION_SHORTCUT))
+ .build();
+ shortcutManager.requestPinShortcut(pinShortcutInfo, PendingIntent.getBroadcast(getActivity(), 0, shortcutManager.createShortcutResultIntent(pinShortcutInfo), 0).getIntentSender());
+ }
+
+ @Override
+ public void onError(@NonNull Throwable t) {
+ requireActivity().runOnUiThread(NoteDetailsDialogFragment.this::dismiss);
+ }
+ });
} else {
- Log.e(TAG, ShortcutManager.class.getSimpleName() + " is null");
+ Log.i(TAG, "RequestPinShortcut is not supported");
}
+ } else {
+ Log.e(TAG, ShortcutManager.class.getSimpleName() + " is null");
+ }
+ }
+ });
+ binding.share.setOnClickListener((v) -> {
+ viewModel.getNoteById(noteId, new IResponseCallback<Note>() {
+ @Override
+ public void onSuccess(Note note) {
+ ShareUtil.openShareDialog(requireContext(), note.getTitle(), note.getContent());
+ }
+
+ @Override
+ public void onError(@NonNull Throwable t) {
+ requireActivity().runOnUiThread(NoteDetailsDialogFragment.this::dismiss);
}
});
- binding.share.setOnClickListener((v) -> ShareUtil.openShareDialog(requireContext(), note.getTitle(), note.getContent()));
- binding.favorite.setOnClickListener((v) -> viewModel.toggleFavorite(noteId));
});
+ binding.favorite.setOnClickListener((v) -> viewModel.toggleFavorite(account, noteId));
});
return dialog;
}
@@ -121,4 +193,8 @@ public class NoteDetailsDialogFragment extends DialogFragment {
fragment.setArguments(args);
return fragment;
}
+
+ public interface NoteDetailsListener {
+ void onNoteDetailsEdited(String title, String category);
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsViewModel.java
index 5306bf0d..028ff0fd 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsViewModel.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/edit/details/NoteDetailsViewModel.java
@@ -8,37 +8,58 @@ import androidx.lifecycle.AndroidViewModel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.SavedStateHandle;
+import java.time.Instant;
+import java.util.Calendar;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import it.niedermann.owncloud.notes.persistence.NotesRepository;
import it.niedermann.owncloud.notes.persistence.entity.Account;
import it.niedermann.owncloud.notes.persistence.entity.Note;
+import it.niedermann.owncloud.notes.shared.model.IResponseCallback;
public class NoteDetailsViewModel extends AndroidViewModel {
- private static final String TAG = NoteDetailsViewModel.class.getSimpleName();
-
private final ExecutorService executor = Executors.newCachedThreadPool();
- private final SavedStateHandle state;
-
@NonNull
private final NotesRepository repo;
-
- public NoteDetailsViewModel(@NonNull Application application, @NonNull SavedStateHandle savedStateHandle) {
+ public NoteDetailsViewModel(@NonNull Application application) {
super(application);
this.repo = NotesRepository.getInstance(application);
- this.state = savedStateHandle;
}
- public LiveData<Note> getNote$(long noteId) {
- return repo.getNoteById$(noteId);
+ public void getNoteById(long noteId, @NonNull IResponseCallback<Note> callback) {
+ executor.submit(() -> callback.onSuccess(repo.getNoteById(noteId)));
+ }
+
+ public LiveData<String> getTitle$(long noteId) {
+ return repo.getTitle$(noteId);
+ }
+
+ public LiveData<Calendar> getModified$(long noteId) {
+ return repo.getModified$(noteId);
+ }
+
+ public LiveData<String> getCategory$(long noteId) {
+ return repo.getCategory$(noteId);
+ }
+
+ public LiveData<Boolean> isFavorite$(long noteId) {
+ return repo.isFavorite$(noteId);
}
@AnyThread
- public void toggleFavorite(long noteId) {
- repo.toggleFavorite(noteId);
+ public void toggleFavorite(@NonNull Account account, long noteId) {
+ repo.toggleFavoriteAndSync(account, noteId);
+ }
+
+ public void commit(@NonNull Account account, long noteId, String title, String category) {
+ executor.submit(() -> {
+ final Note note = repo.getNoteById(noteId);
+ note.setCategory(category);
+ repo.updateNoteAndSync(account, note, note.getContent(), title, null);
+ });
}
} \ No newline at end of file
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/edit/title/EditTitleDialogFragment.java b/app/src/main/java/it/niedermann/owncloud/notes/edit/title/EditTitleDialogFragment.java
deleted file mode 100644
index e9473399..00000000
--- a/app/src/main/java/it/niedermann/owncloud/notes/edit/title/EditTitleDialogFragment.java
+++ /dev/null
@@ -1,96 +0,0 @@
-package it.niedermann.owncloud.notes.edit.title;
-
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.content.Context;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.DialogFragment;
-
-import it.niedermann.owncloud.notes.R;
-import it.niedermann.owncloud.notes.databinding.DialogEditTitleBinding;
-
-public class EditTitleDialogFragment extends DialogFragment {
-
- private static final String TAG = EditTitleDialogFragment.class.getSimpleName();
- static final String PARAM_OLD_TITLE = "old_title";
- private DialogEditTitleBinding binding;
-
- private String oldTitle;
- private EditTitleListener listener;
-
- @Override
- public void onAttach(@NonNull Context context) {
- super.onAttach(context);
- final Bundle args = getArguments();
- if (args == null) {
- throw new IllegalArgumentException("Provide at least " + PARAM_OLD_TITLE);
- }
- oldTitle = args.getString(PARAM_OLD_TITLE);
-
- if (getTargetFragment() instanceof EditTitleListener) {
- listener = (EditTitleListener) getTargetFragment();
- } else if (getActivity() instanceof EditTitleListener) {
- listener = (EditTitleListener) getActivity();
- } else {
- throw new IllegalArgumentException("Calling activity or target fragment must implement " + EditTitleListener.class.getSimpleName());
- }
- }
-
- @NonNull
- @Override
- public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
- View dialogView = View.inflate(getContext(), R.layout.dialog_edit_title, null);
- binding = DialogEditTitleBinding.bind(dialogView);
-
- if (savedInstanceState == null) {
- binding.title.setText(oldTitle);
- }
-
- return new AlertDialog.Builder(getActivity())
- .setTitle(R.string.change_note_title)
- .setView(dialogView)
- .setCancelable(true)
- .setPositiveButton(R.string.action_edit_save, (dialog, which) -> listener.onTitleEdited(binding.title.getText().toString()))
- .setNegativeButton(R.string.simple_cancel, null)
- .create();
- }
-
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- binding.title.requestFocus();
- Window window = requireDialog().getWindow();
- if (window != null) {
- window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
- } else {
- Log.w(TAG, "can not enable soft keyboard because " + Window.class.getSimpleName() + " is null.");
- }
- }
-
- public static DialogFragment newInstance(String title) {
- final DialogFragment fragment = new EditTitleDialogFragment();
- final Bundle args = new Bundle();
- args.putString(PARAM_OLD_TITLE, title);
- fragment.setArguments(args);
- return fragment;
- }
-
- /**
- * Interface that must be implemented by the calling Activity.
- */
- public interface EditTitleListener {
- /**
- * This method is called after the user has changed the title of a note manually.
- *
- * @param newTitle the new title that a user submitted
- */
- void onTitleEdited(String newTitle);
- }
-}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java
index 23e2ea42..baa159f5 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java
@@ -15,7 +15,6 @@ import android.util.Log;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.LinearLayout;
-import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -56,7 +55,6 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-import java.util.function.Function;
import java.util.stream.Collectors;
import it.niedermann.owncloud.notes.LockedActivity;
@@ -69,7 +67,7 @@ import it.niedermann.owncloud.notes.databinding.ActivityNotesListViewBinding;
import it.niedermann.owncloud.notes.databinding.DrawerLayoutBinding;
import it.niedermann.owncloud.notes.edit.EditNoteActivity;
import it.niedermann.owncloud.notes.edit.category.CategoryDialogFragment;
-import it.niedermann.owncloud.notes.edit.category.CategoryViewModel;
+import it.niedermann.owncloud.notes.edit.details.CategoryViewModel;
import it.niedermann.owncloud.notes.exception.ExceptionDialogFragment;
import it.niedermann.owncloud.notes.exception.IntendedOfflineException;
import it.niedermann.owncloud.notes.importaccount.ImportAccountActivity;
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java
index 00b6928d..b52e59cb 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesRepository.java
@@ -30,6 +30,7 @@ import com.nextcloud.android.sso.exceptions.NoCurrentAccountSelectedException;
import com.nextcloud.android.sso.helper.SingleAccountHelper;
import com.nextcloud.android.sso.model.SingleSignOnAccount;
+import java.time.Instant;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
@@ -231,6 +232,22 @@ public class NotesRepository {
return db.getNoteDao().getNoteById$(id);
}
+ public LiveData<String> getTitle$(long noteId) {
+ return distinctUntilChanged(db.getNoteDao().getTitle$(noteId));
+ }
+
+ public LiveData<String> getCategory$(long noteId) {
+ return distinctUntilChanged(db.getNoteDao().getCategory$(noteId));
+ }
+
+ public LiveData<Boolean> isFavorite$(long noteId) {
+ return distinctUntilChanged(db.getNoteDao().isFavorite$(noteId));
+ }
+
+ public LiveData<Calendar> getModified$(long noteId) {
+ return distinctUntilChanged(db.getNoteDao().getModified$(noteId));
+ }
+
public Note getNoteById(long id) {
return db.getNoteDao().getNoteById(id);
}
@@ -426,12 +443,10 @@ public class NotesRepository {
@AnyThread
public void toggleFavoriteAndSync(Account account, long noteId) {
- toggleFavorite(noteId);
- executor.submit(() -> scheduleSync(account, true));
- }
-
- public void toggleFavorite(long noteId) {
- executor.submit(() -> db.getNoteDao().toggleFavorite(noteId));
+ executor.submit(() -> {
+ db.getNoteDao().toggleFavorite(noteId);
+ scheduleSync(account, true);
+ });
}
/**
@@ -452,6 +467,14 @@ public class NotesRepository {
});
}
+ @AnyThread
+ public void setTitle(@NonNull Account account, long noteId, @NonNull String title) {
+ executor.submit(() -> {
+ final Note note = getNoteById(noteId);
+ updateNoteAndSync(account, note, note.getContent(), title, null);
+ });
+ }
+
/**
* Updates a single Note with a new content.
* The title is derived from the new content automatically, and modified date as well as DBStatus are updated, too -- if the content differs to the state in the database.
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java
index ca111727..a86b93bf 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/dao/NoteDao.java
@@ -7,6 +7,7 @@ import androidx.room.OnConflictStrategy;
import androidx.room.Query;
import androidx.room.Update;
+import java.util.Calendar;
import java.util.List;
import java.util.Set;
@@ -53,6 +54,12 @@ public interface NoteDao {
@Query(count)
LiveData<Integer> count$(long accountId);
+ @Query("SELECT title FROM NOTE WHERE id = :noteId")
+ LiveData<String> getTitle$(long noteId);
+
+ @Query("SELECT modified FROM NOTE WHERE id = :noteId")
+ LiveData<Calendar> getModified$(long noteId);
+
@Query(count)
Integer count(long accountId);
@@ -62,6 +69,9 @@ public interface NoteDao {
@Query(countFavorites)
Integer countFavorites(long accountId);
+ @Query("SELECT favorite FROM NOTE WHERE id = :noteId")
+ LiveData<Boolean> isFavorite$(long noteId);
+
@Query(searchRecentByModified)
LiveData<List<Note>> searchRecentByModified$(long accountId, String query);
@@ -188,6 +198,9 @@ public interface NoteDao {
@Query("SELECT accountId, category, COUNT(*) as 'totalNotes' FROM NOTE WHERE STATUS != 'LOCAL_DELETED' AND accountId = :accountId GROUP BY category")
LiveData<List<CategoryWithNotesCount>> getCategories$(Long accountId);
+ @Query("SELECT category FROM NOTE WHERE id = :noteId")
+ LiveData<String> getCategory$(long noteId);
+
@Query("SELECT accountId, category, COUNT(*) as 'totalNotes' FROM NOTE WHERE STATUS != 'LOCAL_DELETED' AND accountId = :accountId AND category != '' AND category LIKE :searchTerm GROUP BY category")
LiveData<List<CategoryWithNotesCount>> searchCategories$(Long accountId, String searchTerm);
diff --git a/app/src/main/res/layout/dialog_note_details.xml b/app/src/main/res/layout/dialog_note_details.xml
index d5d97d08..5c62aea9 100644
--- a/app/src/main/res/layout/dialog_note_details.xml
+++ b/app/src/main/res/layout/dialog_note_details.xml
@@ -5,62 +5,18 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <TextView
- android:id="@+id/details"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:padding="@dimen/spacer_2x"
- android:text="@string/simple_details"
- android:textSize="25sp"
- app:layout_constraintEnd_toStartOf="@id/pin"
- app:layout_constraintHorizontal_weight="1"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toTopOf="parent" />
-
- <ImageButton
- android:id="@+id/pin"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:background="@null"
- android:src="@drawable/ic_baseline_push_pin_24"
- app:layout_constraintBottom_toBottomOf="@id/details"
- app:layout_constraintEnd_toStartOf="@id/share"
- app:layout_constraintStart_toEndOf="@id/details"
- app:layout_constraintTop_toTopOf="@id/details" />
-
- <ImageButton
- android:id="@+id/share"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:background="@null"
- android:src="@drawable/ic_share_white_24dp"
- app:layout_constraintBottom_toBottomOf="@id/details"
- app:layout_constraintEnd_toStartOf="@id/favorite"
- app:layout_constraintStart_toEndOf="@id/pin"
- app:layout_constraintTop_toTopOf="@id/details"
- app:tint="@color/fg_default_low" />
-
- <ImageButton
- android:id="@+id/favorite"
- android:layout_width="0dp"
- android:layout_height="0dp"
- android:background="@null"
- android:src="@drawable/ic_star_grey_ccc_24dp"
- app:layout_constraintBottom_toBottomOf="@id/details"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toEndOf="@id/share"
- app:layout_constraintTop_toTopOf="@id/details" />
-
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/titleWrapper"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:hint="@string/change_note_title"
- android:padding="@dimen/spacer_2x"
+ android:hint="@string/simple_title"
+ android:paddingStart="@dimen/spacer_2x"
+ android:paddingEnd="@dimen/spacer_2x"
+ android:paddingTop="@dimen/spacer_2x"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/barrier">
+ app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/title"
@@ -89,20 +45,76 @@
android:inputType="text" />
</com.google.android.material.textfield.TextInputLayout>
+ <androidx.recyclerview.widget.RecyclerView
+ android:id="@+id/categories"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:paddingStart="@dimen/spacer_1x"
+ android:paddingEnd="@dimen/spacer_1x"
+ android:scrollbars="vertical"
+ app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
+ app:layout_constrainedHeight="true"
+ app:layout_constraintBottom_toTopOf="@id/modified"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/categoryWrapper"
+ tools:listitem="@layout/item_category" />
+
<TextView
android:id="@+id/modified"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/spacer_2x"
- app:layout_constraintBottom_toBottomOf="parent"
+ android:layout_marginBottom="@dimen/spacer_2x"
+ app:layout_constraintBottom_toTopOf="@id/barrier"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/categories"
tools:text="Last modified: Yesterday" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier"
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ app:barrierDirection="top"
+ app:constraint_referenced_ids="share,pin,favorite" />
+
+ <ImageButton
+ android:id="@+id/pin"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/pin_to_homescreen"
+ android:padding="@dimen/spacer_2x"
+ android:src="@drawable/ic_baseline_push_pin_24"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toStartOf="@id/share"
+ app:layout_constraintStart_toStartOf="parent" />
+
+ <ImageButton
+ android:id="@+id/share"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/menu_share"
+ android:padding="@dimen/spacer_2x"
+ android:src="@drawable/ic_share_white_24dp"
+ app:layout_constraintBottom_toBottomOf="@id/pin"
+ app:layout_constraintEnd_toStartOf="@id/favorite"
+ app:layout_constraintStart_toEndOf="@id/pin"
+ app:layout_constraintTop_toTopOf="@id/pin"
+ app:tint="@color/fg_default_low" />
+
+ <ImageButton
+ android:id="@+id/favorite"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
- app:barrierDirection="bottom"
- app:constraint_referenced_ids="details,share,pin,favorite" />
+ android:background="?attr/selectableItemBackground"
+ android:contentDescription="@string/label_favorites"
+ android:padding="@dimen/spacer_2x"
+ android:src="@drawable/ic_star_grey_ccc_24dp"
+ app:layout_constraintBottom_toBottomOf="@id/pin"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toEndOf="@id/share"
+ app:layout_constraintTop_toTopOf="@id/pin" />
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 007d7ed4..4d181cfe 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -299,4 +299,5 @@
<string name="simple_repair">Repair</string>
<string name="backup">We detected an irrecoverably state of the app. Please backup your unsynchronized changes and clear the storage of the Notes app.</string>
<string name="simple_details">Details</string>
+ <string name="simple_title">Title</string>
</resources>