mirror of
https://github.com/nextcloud/notes-android.git
synced 2024-11-26 06:47:03 +03:00
recyclerview-selection
This commit is contained in:
parent
2d50087fb8
commit
bc1f4040da
15 changed files with 180 additions and 110 deletions
|
@ -1,7 +1,7 @@
|
|||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 29
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion '29.0.3'
|
||||
|
||||
compileOptions {
|
||||
|
@ -81,6 +81,7 @@ dependencies {
|
|||
implementation "androidx.fragment:fragment:1.2.5"
|
||||
implementation "androidx.preference:preference:1.1.1"
|
||||
implementation "androidx.recyclerview:recyclerview:1.1.0"
|
||||
implementation 'androidx.recyclerview:recyclerview-selection:1.0.0'
|
||||
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0'
|
||||
implementation 'androidx.work:work-runtime:2.4.0'
|
||||
implementation "com.google.android.material:material:1.2.1"
|
||||
|
|
|
@ -108,7 +108,7 @@ public abstract class BaseNoteFragment extends BrandedFragment implements Catego
|
|||
SingleAccountHelper.setCurrentAccount(requireActivity().getApplicationContext(), localAccount.getAccountName());
|
||||
}
|
||||
isNew = false;
|
||||
note = originalNote = db.getNoteDao().getFullNoteWithCategory(localAccount.getId(), id);
|
||||
note = originalNote = db.getNoteDao().getFullNoteWithCategory(id);
|
||||
} else {
|
||||
NoteWithCategory cloudNote = (NoteWithCategory) requireArguments().getSerializable(PARAM_NEWNOTE);
|
||||
String content = requireArguments().getString(PARAM_CONTENT);
|
||||
|
|
|
@ -213,7 +213,7 @@ public class NotePreviewFragment extends SearchableBaseNoteFragment implements O
|
|||
TextProcessorChain chain = defaultTextProcessorChain(note.getNote());
|
||||
Account account = db.getAccountDao().getLocalAccountByAccountName(SingleAccountHelper.getCurrentSingleSignOnAccount(requireContext()).name);
|
||||
db.getNoteServerSyncHelper().addCallbackPull(account, () -> {
|
||||
note = db.getNoteDao().getFullNoteWithCategory(note.getAccountId(), note.getId());
|
||||
note = db.getNoteDao().getFullNoteWithCategory(note.getId());
|
||||
changedText = note.getContent();
|
||||
binding.singleNoteContent.setText(parseCompat(markdownProcessor, chain.apply(note.getContent())));
|
||||
binding.swiperefreshlayout.setRefreshing(false);
|
||||
|
|
|
@ -27,6 +27,10 @@ import androidx.core.view.ViewCompat;
|
|||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.Observer;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.selection.SelectionPredicates;
|
||||
import androidx.recyclerview.selection.SelectionTracker;
|
||||
import androidx.recyclerview.selection.SelectionTracker.SelectionObserver;
|
||||
import androidx.recyclerview.selection.StorageStrategy;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
|
||||
|
@ -44,6 +48,7 @@ import com.nextcloud.android.sso.exceptions.TokenMismatchException;
|
|||
import com.nextcloud.android.sso.helper.SingleAccountHelper;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import it.niedermann.owncloud.notes.ImportAccountActivity;
|
||||
import it.niedermann.owncloud.notes.LockedActivity;
|
||||
|
@ -111,6 +116,8 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
|
|||
private NavigationAdapter adapterCategories;
|
||||
private MenuAdapter menuAdapter;
|
||||
|
||||
private SelectionTracker<Long> tracker;
|
||||
|
||||
protected DrawerLayoutBinding binding;
|
||||
protected ActivityNotesListViewBinding activityBinding;
|
||||
protected FloatingActionButton fabCreate;
|
||||
|
@ -206,10 +213,10 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
|
|||
});
|
||||
});
|
||||
mainViewModel.getNotesListLiveData().observe(this, notes -> {
|
||||
adapter.clearSelection(listView);
|
||||
if (mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
// adapter.clearSelection(listView);
|
||||
// if (mActionMode != null) {
|
||||
// mActionMode.finish();
|
||||
// }
|
||||
adapter.setItemList(notes);
|
||||
binding.activityNotesListView.progressCircular.setVisibility(GONE);
|
||||
binding.activityNotesListView.emptyContentView.getRoot().setVisibility(notes.size() > 0 ? GONE : VISIBLE);
|
||||
|
@ -386,6 +393,22 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
|
|||
};
|
||||
syncLiveData.observe(this, syncObserver);
|
||||
});
|
||||
|
||||
tracker = new SelectionTracker.Builder<>(
|
||||
"selection-1",
|
||||
listView,
|
||||
new ItemAdapter.ItemIdKeyProvider(listView),
|
||||
new ItemAdapter.ItemLookup(listView),
|
||||
StorageStrategy.createLongStorage()
|
||||
).withSelectionPredicate(SelectionPredicates.createSelectAnything()).build();
|
||||
adapter.setTracker(tracker);
|
||||
tracker.addObserver(new SelectionObserver<Long>() {
|
||||
@Override
|
||||
public void onSelectionChanged() {
|
||||
super.onSelectionChanged();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void setupNavigationList() {
|
||||
|
@ -578,21 +601,8 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
|
|||
|
||||
@Override
|
||||
public void onNoteClick(int position, View v) {
|
||||
boolean hasCheckedItems = adapter.getSelected().size() > 0;
|
||||
if (hasCheckedItems) {
|
||||
if (!adapter.select(position)) {
|
||||
v.setSelected(false);
|
||||
adapter.deselect(position);
|
||||
} else {
|
||||
v.setSelected(true);
|
||||
}
|
||||
int size = adapter.getSelected().size();
|
||||
if (size > 0) {
|
||||
mActionMode.setTitle(getResources().getQuantityString(R.plurals.ab_selected, size, size));
|
||||
} else {
|
||||
mActionMode.finish();
|
||||
}
|
||||
} else {
|
||||
boolean hasCheckedItems = tracker.getSelection().size() > 0;
|
||||
if (!hasCheckedItems) {
|
||||
NoteWithCategory note = (NoteWithCategory) adapter.getItem(position);
|
||||
Intent intent = new Intent(getApplicationContext(), EditNoteActivity.class);
|
||||
intent.putExtra(EditNoteActivity.PARAM_NOTE_ID, note.getId());
|
||||
|
@ -608,14 +618,13 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
|
|||
|
||||
@Override
|
||||
public boolean onNoteLongClick(int position, View v) {
|
||||
boolean selected = adapter.select(position);
|
||||
if (selected) {
|
||||
v.setSelected(true);
|
||||
mActionMode = startSupportActionMode(new MultiSelectedActionModeCallback(this, coordinatorLayout, mainViewModel, this, canMoveNoteToAnotherAccounts, adapter, listView, getSupportFragmentManager(), activityBinding.searchView));
|
||||
final int checkedItemCount = adapter.getSelected().size();
|
||||
mActionMode.setTitle(getResources().getQuantityString(R.plurals.ab_selected, checkedItemCount, checkedItemCount));
|
||||
}
|
||||
return selected;
|
||||
// int selected = tracker.getSelection().size();
|
||||
// if (selected > 0) {
|
||||
// v.setSelected(true);
|
||||
// mActionMode = startSupportActionMode(new MultiSelectedActionModeCallback(this, coordinatorLayout, mainViewModel, this, canMoveNoteToAnotherAccounts, tracker, listView, getSupportFragmentManager(), activityBinding.searchView));
|
||||
// mActionMode.setTitle(getResources().getQuantityString(R.plurals.ab_selected, selected, selected));
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -655,20 +664,17 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A
|
|||
|
||||
@Override
|
||||
public void onAccountPicked(@NonNull Account account) {
|
||||
for (Integer i : adapter.getSelected()) {
|
||||
final LiveData<NoteWithCategory> moveLiveData = mainViewModel.moveNoteToAnotherAccount(account, (NoteWithCategory) adapter.getItem(i));
|
||||
moveLiveData.observe(this, (v) -> moveLiveData.removeObservers(this));
|
||||
for(Long noteId : tracker.getSelection()) {
|
||||
new Thread(() -> {
|
||||
final LiveData<NoteWithCategory> moveLiveData = mainViewModel.moveNoteToAnotherAccount(account, noteId);
|
||||
moveLiveData.observe(this, (v) -> moveLiveData.removeObservers(this));
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCategoryChosen(String category) {
|
||||
final LiveData<Void> categoryLiveData = mainViewModel.setCategory(
|
||||
adapter.getSelected()
|
||||
.stream()
|
||||
.map(item -> ((NoteWithCategory) adapter.getItem(item)).getId())
|
||||
.collect(Collectors.toList())
|
||||
, category);
|
||||
final LiveData<Void> categoryLiveData = mainViewModel.setCategory(tracker.getSelection(), category);
|
||||
categoryLiveData.observe(this, (next) -> categoryLiveData.removeObservers(this));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -427,7 +427,7 @@ public class MainViewModel extends AndroidViewModel {
|
|||
return db.getAccountDao().getAccounts();
|
||||
}
|
||||
|
||||
public LiveData<Void> setCategory(Collection<Long> noteIds, @NonNull String category) {
|
||||
public LiveData<Void> setCategory(Iterable<Long> noteIds, @NonNull String category) {
|
||||
return switchMap(getCurrentAccount(), currentAccount -> {
|
||||
if (currentAccount == null) {
|
||||
return new MutableLiveData<>(null);
|
||||
|
@ -441,8 +441,8 @@ public class MainViewModel extends AndroidViewModel {
|
|||
});
|
||||
}
|
||||
|
||||
public LiveData<NoteWithCategory> moveNoteToAnotherAccount(Account account, NoteWithCategory note) {
|
||||
return db.moveNoteToAnotherAccount(account, note);
|
||||
public LiveData<NoteWithCategory> moveNoteToAnotherAccount(Account account, Long noteId) {
|
||||
return db.moveNoteToAnotherAccount(account, db.getNoteDao().getFullNoteWithCategory(noteId));
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
|
@ -506,7 +506,7 @@ public class MainViewModel extends AndroidViewModel {
|
|||
new Thread(() -> notes.postValue(
|
||||
ids
|
||||
.stream()
|
||||
.map(id -> db.getNoteDao().getFullNoteWithCategory(currentAccount.getId(), id))
|
||||
.map(id -> db.getNoteDao().getFullNoteWithCategory(id))
|
||||
.collect(Collectors.toList())
|
||||
)).start();
|
||||
return notes;
|
||||
|
@ -551,7 +551,7 @@ public class MainViewModel extends AndroidViewModel {
|
|||
new Thread(() -> {
|
||||
final StringBuilder noteContents = new StringBuilder();
|
||||
for (Long noteId : noteIds) {
|
||||
final NoteWithCategory fullNote = db.getNoteDao().getFullNoteWithCategory(currentAccount.getId(), noteId);
|
||||
final NoteWithCategory fullNote = db.getNoteDao().getFullNoteWithCategory(noteId);
|
||||
final String tempFullNote = fullNote.getContent();
|
||||
if (!TextUtils.isEmpty(tempFullNote)) {
|
||||
if (noteContents.length() > 0) {
|
||||
|
|
|
@ -16,6 +16,7 @@ import androidx.core.graphics.drawable.DrawableCompat;
|
|||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.lifecycle.LifecycleOwner;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.recyclerview.selection.SelectionTracker;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
@ -23,6 +24,7 @@ import com.google.android.material.snackbar.Snackbar;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import it.niedermann.owncloud.notes.R;
|
||||
import it.niedermann.owncloud.notes.accountpicker.AccountPickerDialogFragment;
|
||||
|
@ -46,19 +48,19 @@ public class MultiSelectedActionModeCallback implements Callback {
|
|||
@NonNull
|
||||
private final LifecycleOwner lifecycleOwner;
|
||||
private final boolean canMoveNoteToAnotherAccounts;
|
||||
private final ItemAdapter adapter;
|
||||
private final SelectionTracker<Long> tracker;
|
||||
private final RecyclerView recyclerView;
|
||||
private final FragmentManager fragmentManager;
|
||||
private final SearchView searchView;
|
||||
|
||||
public MultiSelectedActionModeCallback(
|
||||
@NonNull Context context, @NonNull View view, @NonNull MainViewModel mainViewModel, @NonNull LifecycleOwner lifecycleOwner, boolean canMoveNoteToAnotherAccounts, ItemAdapter adapter, RecyclerView recyclerView, FragmentManager fragmentManager, SearchView searchView) {
|
||||
@NonNull Context context, @NonNull View view, @NonNull MainViewModel mainViewModel, @NonNull LifecycleOwner lifecycleOwner, boolean canMoveNoteToAnotherAccounts, SelectionTracker<Long> tracker, RecyclerView recyclerView, FragmentManager fragmentManager, SearchView searchView) {
|
||||
this.context = context;
|
||||
this.view = view;
|
||||
this.mainViewModel = mainViewModel;
|
||||
this.lifecycleOwner = lifecycleOwner;
|
||||
this.canMoveNoteToAnotherAccounts = canMoveNoteToAnotherAccounts;
|
||||
this.adapter = adapter;
|
||||
this.tracker = tracker;
|
||||
this.recyclerView = recyclerView;
|
||||
this.fragmentManager = fragmentManager;
|
||||
this.searchView = searchView;
|
||||
|
@ -98,7 +100,10 @@ public class MultiSelectedActionModeCallback implements Callback {
|
|||
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
|
||||
int itemId = item.getItemId();
|
||||
if (itemId == R.id.menu_delete) {
|
||||
final List<Long> selection = adapter.getSelected().stream().map(itemPosition -> ((NoteWithCategory) adapter.getItem(itemPosition)).getId()).collect(Collectors.toList());
|
||||
final List<Long> selection = new ArrayList<>(tracker.getSelection().size());
|
||||
for(Long sel : tracker.getSelection()) {
|
||||
selection.add(sel);
|
||||
}
|
||||
final LiveData<List<NoteWithCategory>> fullNotes$ = mainViewModel.getFullNotesWithCategory(selection);
|
||||
fullNotes$.observe(lifecycleOwner, (fullNotes) -> {
|
||||
fullNotes$.removeObservers(lifecycleOwner);
|
||||
|
@ -133,15 +138,17 @@ public class MultiSelectedActionModeCallback implements Callback {
|
|||
});
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_share) {
|
||||
final String subject = (adapter.getSelected().size() == 1)
|
||||
? ((NoteWithCategory) adapter.getItem(adapter.getSelected().get(0))).getTitle()
|
||||
: context.getResources().getQuantityString(R.plurals.share_multiple, adapter.getSelected().size(), adapter.getSelected().size());
|
||||
final List<Long> selection = new ArrayList<>(tracker.getSelection().size());
|
||||
for(Long sel : tracker.getSelection()) {
|
||||
selection.add(sel);
|
||||
}
|
||||
// FIXME
|
||||
final String subject = context.getResources().getQuantityString(R.plurals.share_multiple, selection.size(), selection.size());
|
||||
// final String subject = (selection.size() == 1)
|
||||
// ? ((NoteWithCategory) adapter.getItem(adapter.getSelected().get(0))).getTitle()
|
||||
// : context.getResources().getQuantityString(R.plurals.share_multiple, adapter.getSelected().size(), adapter.getSelected().size());
|
||||
|
||||
final LiveData<String> contentCollector = mainViewModel.collectNoteContents(
|
||||
adapter.getSelected()
|
||||
.stream()
|
||||
.map(itemPosition -> ((NoteWithCategory) adapter.getItem(itemPosition)).getId())
|
||||
.collect(Collectors.toList()));
|
||||
final LiveData<String> contentCollector = mainViewModel.collectNoteContents(selection);
|
||||
contentCollector.observe(lifecycleOwner, (next) -> {
|
||||
contentCollector.removeObservers(lifecycleOwner);
|
||||
ShareUtil.openShareDialog(context, subject, next);
|
||||
|
@ -163,7 +170,7 @@ public class MultiSelectedActionModeCallback implements Callback {
|
|||
|
||||
@Override
|
||||
public void onDestroyActionMode(ActionMode mode) {
|
||||
adapter.clearSelection(recyclerView);
|
||||
adapter.notifyDataSetChanged();
|
||||
// adapter.clearSelection(recyclerView);
|
||||
// adapter.notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,15 +4,20 @@ import android.content.Context;
|
|||
import android.content.SharedPreferences;
|
||||
import android.graphics.Color;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Px;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
import androidx.recyclerview.selection.ItemKeyProvider;
|
||||
import androidx.recyclerview.selection.SelectionTracker;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
@ -35,6 +40,7 @@ import it.niedermann.owncloud.notes.persistence.entity.NoteWithCategory;
|
|||
import it.niedermann.owncloud.notes.shared.model.Item;
|
||||
import it.niedermann.owncloud.notes.shared.model.NoteClickListener;
|
||||
|
||||
import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
|
||||
import static it.niedermann.owncloud.notes.shared.util.NoteUtil.getFontSizeFromPreferences;
|
||||
|
||||
public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements Branded {
|
||||
|
@ -51,7 +57,8 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
|
|||
private List<Item> itemList = new ArrayList<>();
|
||||
private boolean showCategory = true;
|
||||
private CharSequence searchQuery;
|
||||
private final List<Integer> selected = new ArrayList<>();
|
||||
private SelectionTracker<Long> tracker = null;
|
||||
// private final List<Integer> selected = new ArrayList<>();
|
||||
@Px
|
||||
private final float fontSize;
|
||||
private final boolean monospace;
|
||||
|
@ -68,20 +75,17 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
|
|||
final SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
|
||||
this.fontSize = getFontSizeFromPreferences(context, sp);
|
||||
this.monospace = sp.getBoolean(context.getString(R.string.pref_key_font), false);
|
||||
// FIXME see getItemId()
|
||||
// setHasStableIds(true);
|
||||
setHasStableIds(true);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
FIXME this causes {@link it.niedermann.owncloud.notes.noteslist.items.list.NotesListViewItemTouchHelper} to not call clearView anymore → After marking a note as favorite, it stays yellow.
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return getItemViewType(position) == TYPE_SECTION
|
||||
? ((SectionItem) getItem(position)).getTitle().hashCode() * -1
|
||||
: ((NoteEntity) getItem(position)).getId();
|
||||
}
|
||||
*/
|
||||
// FIXME this causes {@link it.niedermann.owncloud.notes.noteslist.items.list.NotesListViewItemTouchHelper} to not call clearView anymore → After marking a note as favorite, it stays yellow.
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return getItemViewType(position) == TYPE_SECTION
|
||||
? ((SectionItem) getItem(position)).getTitle().hashCode() * -1
|
||||
: ((NoteWithCategory) getItem(position)).getId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the item list and notifies respective view to update.
|
||||
|
@ -134,6 +138,16 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
|
|||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, int position) {
|
||||
boolean isSelected = false;
|
||||
if(tracker != null) {
|
||||
Long itemId = getItemId(position);
|
||||
if(tracker.isSelected(itemId)) {
|
||||
tracker.select(itemId);
|
||||
isSelected = true;
|
||||
} else {
|
||||
tracker.deselect(itemId);
|
||||
}
|
||||
}
|
||||
switch (getItemViewType(position)) {
|
||||
case TYPE_SECTION: {
|
||||
((SectionViewHolder) holder).bind((SectionItem) itemList.get(position));
|
||||
|
@ -142,42 +156,73 @@ public class ItemAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> i
|
|||
case TYPE_NOTE_WITH_EXCERPT:
|
||||
case TYPE_NOTE_WITHOUT_EXCERPT:
|
||||
case TYPE_NOTE_ONLY_TITLE: {
|
||||
((NoteViewHolder) holder).bind((NoteWithCategory) itemList.get(position), showCategory, mainColor, textColor, searchQuery);
|
||||
((NoteViewHolder) holder).bind(new ItemDetailsLookup.ItemDetails<Long>() {
|
||||
@Override
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSelectionKey() {
|
||||
return getItemId(position);
|
||||
}
|
||||
}, isSelected, (NoteWithCategory) itemList.get(position), showCategory, mainColor, textColor, searchQuery);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean select(Integer position) {
|
||||
return !selected.contains(position) && selected.add(position);
|
||||
// --------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
public void setTracker(SelectionTracker<Long> tracker) {
|
||||
this.tracker = tracker;
|
||||
}
|
||||
|
||||
public void clearSelection(@NonNull RecyclerView recyclerView) {
|
||||
for (Integer i : getSelected()) {
|
||||
RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForAdapterPosition(i);
|
||||
if (viewHolder != null) {
|
||||
viewHolder.itemView.setSelected(false);
|
||||
} else {
|
||||
Log.w(TAG, "Could not found " + RecyclerView.ViewHolder.class.getSimpleName() + " to remove selection");
|
||||
}
|
||||
public static class ItemIdKeyProvider extends ItemKeyProvider<Long> {
|
||||
private final RecyclerView recyclerView;
|
||||
|
||||
public ItemIdKeyProvider(RecyclerView recyclerView) {
|
||||
super(SCOPE_MAPPED);
|
||||
this.recyclerView = recyclerView;
|
||||
}
|
||||
selected.clear();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public List<Integer> getSelected() {
|
||||
return selected;
|
||||
}
|
||||
|
||||
public void deselect(Integer position) {
|
||||
for (int i = 0; i < selected.size(); i++) {
|
||||
if (selected.get(i).equals(position)) {
|
||||
//position was selected and removed
|
||||
selected.remove(i);
|
||||
return;
|
||||
@Nullable
|
||||
@Override
|
||||
public Long getKey(int position) {
|
||||
final RecyclerView.Adapter<?> adapter = recyclerView.getAdapter();
|
||||
if (adapter == null) {
|
||||
throw new IllegalStateException("RecyclerView adapter is not set!");
|
||||
}
|
||||
return adapter.getItemId(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition(@NonNull Long key) {
|
||||
final RecyclerView.ViewHolder viewHolder = recyclerView.findViewHolderForItemId(key);
|
||||
return viewHolder == null ? NO_POSITION : viewHolder.getLayoutPosition();
|
||||
}
|
||||
}
|
||||
|
||||
public static class ItemLookup extends ItemDetailsLookup<Long> {
|
||||
|
||||
@NonNull
|
||||
private final RecyclerView rv;
|
||||
|
||||
public ItemLookup(@NonNull RecyclerView recyclerView) {
|
||||
this.rv = recyclerView;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ItemDetails<Long> getItemDetails(@NonNull MotionEvent e) {
|
||||
View view = rv.findChildViewUnder(e.getX(), e.getY());
|
||||
if(view != null) {
|
||||
return ((NoteViewHolder) rv.getChildViewHolder(view))
|
||||
.getItemDetails();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// position was not selected
|
||||
}
|
||||
|
||||
public Item getItem(int notePosition) {
|
||||
|
|
|
@ -19,6 +19,7 @@ import androidx.annotation.NonNull;
|
|||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.AppCompatImageView;
|
||||
import androidx.core.graphics.drawable.DrawableCompat;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.chip.Chip;
|
||||
|
@ -42,6 +43,7 @@ import static it.niedermann.owncloud.notes.shared.util.ColorUtil.isColorDark;
|
|||
public abstract class NoteViewHolder extends RecyclerView.ViewHolder {
|
||||
@NonNull
|
||||
private final NoteClickListener noteClickListener;
|
||||
private ItemDetailsLookup.ItemDetails<Long> itemDetails;
|
||||
|
||||
public NoteViewHolder(@NonNull View v, @NonNull NoteClickListener noteClickListener) {
|
||||
super(v);
|
||||
|
@ -50,7 +52,9 @@ public abstract class NoteViewHolder extends RecyclerView.ViewHolder {
|
|||
}
|
||||
|
||||
@CallSuper
|
||||
public void bind(@NonNull NoteWithCategory note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
public void bind(@NonNull ItemDetailsLookup.ItemDetails<Long> itemDetails, boolean isSelected, @NonNull NoteWithCategory note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
this.itemDetails = itemDetails;
|
||||
itemView.setSelected(isSelected);
|
||||
itemView.setOnClickListener((view) -> noteClickListener.onNoteClick(getAdapterPosition(), view));
|
||||
itemView.setOnLongClickListener((view) -> noteClickListener.onNoteLongClick(getAdapterPosition(), view));
|
||||
}
|
||||
|
@ -137,4 +141,8 @@ public abstract class NoteViewHolder extends RecyclerView.ViewHolder {
|
|||
|
||||
@Nullable
|
||||
public abstract View getNoteSwipeable();
|
||||
|
||||
public ItemDetailsLookup.ItemDetails<Long> getItemDetails() {
|
||||
return itemDetails;
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ import android.view.View;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Px;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
|
||||
import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemGridBinding;
|
||||
import it.niedermann.owncloud.notes.main.items.NoteViewHolder;
|
||||
|
@ -40,8 +41,8 @@ public class NoteViewGridHolder extends NoteViewHolder {
|
|||
throw new UnsupportedOperationException(NoteViewGridHolder.class.getSimpleName() + " does not support swiping");
|
||||
}
|
||||
|
||||
public void bind(@NonNull NoteWithCategory noteWithCategory, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
super.bind(noteWithCategory, showCategory, mainColor, textColor, searchQuery);
|
||||
public void bind(@NonNull ItemDetailsLookup.ItemDetails<Long> itemDetails, boolean isSelected, @NonNull NoteWithCategory noteWithCategory, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
super.bind(itemDetails, isSelected, noteWithCategory, showCategory, mainColor, textColor, searchQuery);
|
||||
Note note = noteWithCategory.getNote();
|
||||
@NonNull final Context context = itemView.getContext();
|
||||
bindCategory(context, binding.noteCategory, showCategory, noteWithCategory.getCategory(), mainColor);
|
||||
|
|
|
@ -8,10 +8,10 @@ import android.view.View;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.Px;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
|
||||
import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemGridOnlyTitleBinding;
|
||||
import it.niedermann.owncloud.notes.main.items.NoteViewHolder;
|
||||
import it.niedermann.owncloud.notes.persistence.entity.Note;
|
||||
import it.niedermann.owncloud.notes.persistence.entity.NoteWithCategory;
|
||||
import it.niedermann.owncloud.notes.shared.model.NoteClickListener;
|
||||
|
||||
|
@ -33,8 +33,8 @@ public class NoteViewGridHolderOnlyTitle extends NoteViewHolder {
|
|||
throw new UnsupportedOperationException(NoteViewGridHolderOnlyTitle.class.getSimpleName() + " does not support swiping");
|
||||
}
|
||||
|
||||
public void bind(@NonNull NoteWithCategory note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
super.bind(note, showCategory, mainColor, textColor, searchQuery);
|
||||
public void bind(@NonNull ItemDetailsLookup.ItemDetails<Long> itemDetails, boolean isSelected, @NonNull NoteWithCategory note, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
super.bind(itemDetails, isSelected, note, showCategory, mainColor, textColor, searchQuery);
|
||||
@NonNull final Context context = itemView.getContext();
|
||||
bindStatus(binding.noteStatus, note.getStatus(), mainColor);
|
||||
bindFavorite(binding.noteFavorite, note.getFavorite());
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.view.View;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
|
||||
import it.niedermann.owncloud.notes.R;
|
||||
import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemWithExcerptBinding;
|
||||
|
@ -29,8 +30,8 @@ public class NoteViewHolderWithExcerpt extends NoteViewHolder {
|
|||
binding.noteSwipeFrame.setBackgroundResource(left ? R.color.bg_warning : R.color.bg_attention);
|
||||
}
|
||||
|
||||
public void bind(@NonNull NoteWithCategory noteWithCategory, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
super.bind(noteWithCategory, showCategory, mainColor, textColor, searchQuery);
|
||||
public void bind(@NonNull ItemDetailsLookup.ItemDetails<Long> itemDetails, boolean isSelected, @NonNull NoteWithCategory noteWithCategory, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
super.bind(itemDetails, isSelected, noteWithCategory, showCategory, mainColor, textColor, searchQuery);
|
||||
Note note = noteWithCategory.getNote();
|
||||
@NonNull final Context context = itemView.getContext();
|
||||
binding.noteSwipeable.setAlpha(DBStatus.LOCAL_DELETED.equals(note.getStatus()) ? 0.5f : 1.0f);
|
||||
|
|
|
@ -5,6 +5,7 @@ import android.view.View;
|
|||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.selection.ItemDetailsLookup;
|
||||
|
||||
import it.niedermann.owncloud.notes.R;
|
||||
import it.niedermann.owncloud.notes.databinding.ItemNotesListNoteItemWithoutExcerptBinding;
|
||||
|
@ -29,8 +30,8 @@ public class NoteViewHolderWithoutExcerpt extends NoteViewHolder {
|
|||
binding.noteSwipeFrame.setBackgroundResource(left ? R.color.bg_warning : R.color.bg_attention);
|
||||
}
|
||||
|
||||
public void bind(@NonNull NoteWithCategory noteWithCategory, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
super.bind(noteWithCategory, showCategory, mainColor, textColor, searchQuery);
|
||||
public void bind(@NonNull ItemDetailsLookup.ItemDetails<Long> itemDetails, boolean isSelected, @NonNull NoteWithCategory noteWithCategory, boolean showCategory, int mainColor, int textColor, @Nullable CharSequence searchQuery) {
|
||||
super.bind(itemDetails, isSelected, noteWithCategory, showCategory, mainColor, textColor, searchQuery);
|
||||
Note note = noteWithCategory.getNote();
|
||||
@NonNull final Context context = itemView.getContext();
|
||||
binding.noteSwipeable.setAlpha(DBStatus.LOCAL_DELETED.equals(note.getStatus()) ? 0.5f : 1.0f);
|
||||
|
|
|
@ -202,7 +202,7 @@ public abstract class NotesDatabase extends RoomDatabase {
|
|||
entity.setFavorite(note.getFavorite());
|
||||
entity.setCategoryId(getOrCreateCategoryIdByTitle(accountId, note.getCategory()));
|
||||
entity.setETag(note.getETag());
|
||||
return getNoteDao().getFullNoteWithCategory(accountId, getNoteDao().addNote(entity));
|
||||
return getNoteDao().getFullNoteWithCategory(getNoteDao().addNote(entity));
|
||||
}
|
||||
|
||||
@AnyThread
|
||||
|
|
|
@ -73,8 +73,8 @@ public interface NoteDao {
|
|||
@Query("UPDATE NOTE SET scrollY = :scrollY WHERE id = :id")
|
||||
void updateScrollY(long id, int scrollY);
|
||||
|
||||
@Query("SELECT NOTE.*, CATEGORY.title as 'category' FROM NOTE INNER JOIN CATEGORY ON categoryId = CATEGORY.id WHERE NOTE.id = :id AND NOTE.accountId = :accountId AND status != :accountId")
|
||||
NoteWithCategory getFullNoteWithCategory(long accountId, long id);
|
||||
@Query("SELECT NOTE.*, CATEGORY.title as 'category' FROM NOTE INNER JOIN CATEGORY ON categoryId = CATEGORY.id WHERE NOTE.id = :id")
|
||||
NoteWithCategory getFullNoteWithCategory(long id);
|
||||
|
||||
@Query("SELECT NOTE.*, CATEGORY.title as 'category' FROM NOTE INNER JOIN CATEGORY ON categoryId = CATEGORY.id WHERE NOTE.id = :id AND NOTE.accountId = :accountId AND status != :accountId")
|
||||
LiveData<NoteWithCategory> getNoteWithCategoryLiveData(long accountId, long id);
|
||||
|
|
|
@ -61,7 +61,7 @@ public class SingleNoteWidgetFactory implements RemoteViewsService.RemoteViewsFa
|
|||
if (data != null) {
|
||||
final long noteId = data.getNoteId();
|
||||
Log.v(TAG, "Fetch note with id " + noteId);
|
||||
note = db.getNoteDao().getFullNoteWithCategory(data.getAccountId(), noteId);
|
||||
note = db.getNoteDao().getFullNoteWithCategory(noteId);
|
||||
|
||||
if (note == null) {
|
||||
Log.e(TAG, "Error: note not found");
|
||||
|
|
Loading…
Reference in a new issue