Track selections by task id

pull/645/head
Alex Baker 8 years ago
parent 948e79c15a
commit 76c24fde67

@ -4,7 +4,7 @@ jdk: oraclejdk8
env: env:
global: global:
- TARGET_API=27 - TARGET_API=27
- BUILD_TOOLS=27.0.0 - BUILD_TOOLS=27.0.3
matrix: matrix:
- EMULATOR_API=21 ANDROID_ABI=armeabi-v7a - EMULATOR_API=21 ANDROID_ABI=armeabi-v7a
android: android:

@ -141,7 +141,6 @@ dependencies {
compile 'com.jakewharton:process-phoenix:2.0.0' compile 'com.jakewharton:process-phoenix:2.0.0'
compile 'com.google.android.apps.dashclock:dashclock-api:2.0.0' compile 'com.google.android.apps.dashclock:dashclock-api:2.0.0'
compile 'com.twofortyfouram:android-plugin-api-for-locale:1.0.2' compile 'com.twofortyfouram:android-plugin-api-for-locale:1.0.2'
compile 'com.bignerdranch.android:recyclerview-multiselect:0.2'
compile ('com.rubiconproject.oss:jchronic:0.2.6') { compile ('com.rubiconproject.oss:jchronic:0.2.6') {
transitive = false transitive = false
} }

@ -16,6 +16,13 @@ import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskAttachment; import org.tasks.data.TaskAttachment;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.primitives.Longs.asList;
/** /**
* Adapter for displaying a user's tasks as a list * Adapter for displaying a user's tasks as a list
* *
@ -25,6 +32,7 @@ import org.tasks.data.TaskAttachment;
public class TaskAdapter { public class TaskAdapter {
private PagedListAdapterHelper<Task> helper; private PagedListAdapterHelper<Task> helper;
private Set<Long> selected = new HashSet<>();
public int getCount() { public int getCount() {
return helper.getItemCount(); return helper.getItemCount();
@ -34,6 +42,14 @@ public class TaskAdapter {
this.helper = helper; this.helper = helper;
} }
public List<Long> getSelected() {
return newArrayList(selected);
}
public void clearSelections() {
selected.clear();
}
public interface OnCompletedTaskListener { public interface OnCompletedTaskListener {
void onCompletedTask(Task item, boolean newState); void onCompletedTask(Task item, boolean newState);
} }
@ -58,6 +74,24 @@ public class TaskAdapter {
return false; return false;
} }
public void setSelected(long... ids) {
selected.clear();
selected.addAll(asList(ids));
}
public boolean isSelected(Task task) {
return selected.contains(task.getId());
}
public void toggleSelection(Task task) {
long id = task.getId();
if (selected.contains(id)) {
selected.remove(id);
} else {
selected.add(id);
}
}
public boolean isManuallySorted() { public boolean isManuallySorted() {
return false; return false;
} }

@ -64,11 +64,12 @@ public class TaskDeleter {
taskDao.save(item); taskDao.save(item);
} }
public int markDeleted(List<Task> tasks) { public List<Task> markDeleted(List<Long> taskIds) {
List<Task> tasks = taskDao.fetch(taskIds);
for (Task task : tasks) { for (Task task : tasks) {
markDeleted(task); markDeleted(task);
} }
return tasks.size(); return tasks;
} }
public int clearCompleted(Filter filter) { public int clearCompleted(Filter filter) {
@ -81,6 +82,9 @@ public class TaskDeleter {
completed.add(task); completed.add(task);
} }
} }
return markDeleted(completed); for (Task task : completed) {
markDeleted(task);
}
return completed.size();
} }
} }

@ -38,9 +38,9 @@ public class TaskDuplicator {
this.googleTaskDao = googleTaskDao; this.googleTaskDao = googleTaskDao;
} }
public List<Task> duplicate(List<Task> tasks) { public List<Task> duplicate(List<Long> taskIds) {
List<Task> result = new ArrayList<>(); List<Task> result = new ArrayList<>();
for (Task task : tasks) { for (Task task : taskDao.fetch(taskIds)) {
result.add(clone(task)); result.add(clone(task));
} }
localBroadcastManager.broadcastRefresh(); localBroadcastManager.broadcastRefresh();

@ -49,6 +49,10 @@ public class TimerPlugin {
updateTimer(task, true); updateTimer(task, true);
} }
public void stopTimer(Long task) {
stopTimer(taskDao.fetch(task));
}
public void stopTimer(Task task) { public void stopTimer(Task task) {
updateTimer(task, false); updateTimer(task, false);
} }

@ -18,8 +18,6 @@ import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.bignerdranch.android.multiselector.ModalMultiSelectorCallback;
import com.bignerdranch.android.multiselector.MultiSelector;
import com.google.common.primitives.Longs; import com.google.common.primitives.Longs;
import com.todoroo.astrid.activity.TaskListActivity; import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.activity.TaskListFragment; import com.todoroo.astrid.activity.TaskListFragment;
@ -35,12 +33,8 @@ import org.tasks.analytics.Tracking;
import org.tasks.dialogs.DialogBuilder; import org.tasks.dialogs.DialogBuilder;
import org.tasks.ui.MenuColorizer; import org.tasks.ui.MenuColorizer;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Lists.transform;
public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder> public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
implements ViewHolder.ViewHolderCallbacks, ListUpdateCallback { implements ViewHolder.ViewHolderCallbacks, ListUpdateCallback {
@ -58,8 +52,6 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
} }
}; };
private final MultiSelector multiSelector = new MultiSelector();
private final Activity activity; private final Activity activity;
private final TaskAdapter adapter; private final TaskAdapter adapter;
private final ViewHolderFactory viewHolderFactory; private final ViewHolderFactory viewHolderFactory;
@ -99,42 +91,26 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
public Bundle getSaveState() { public Bundle getSaveState() {
Bundle information = new Bundle(); Bundle information = new Bundle();
List<Task> selectedTasks = transform(multiSelector.getSelectedPositions(), adapterHelper::getItem); List<Long> selectedTaskIds = adapter.getSelected();
List<Long> selectedTaskIds = transform(selectedTasks, Task::getId);
information.putLongArray(EXTRA_SELECTED_TASK_IDS, Longs.toArray(selectedTaskIds)); information.putLongArray(EXTRA_SELECTED_TASK_IDS, Longs.toArray(selectedTaskIds));
return information; return information;
} }
public void restoreSaveState(Bundle savedState) { public void restoreSaveState(Bundle savedState) {
long[] longArray = savedState.getLongArray(EXTRA_SELECTED_TASK_IDS); long[] longArray = savedState.getLongArray(EXTRA_SELECTED_TASK_IDS);
if (longArray.length > 0) { if (longArray != null && longArray.length > 0) {
mode = ((TaskListActivity) activity).startSupportActionMode(actionModeCallback); mode = ((TaskListActivity) activity).startSupportActionMode(actionModeCallback);
multiSelector.setSelectable(true); adapter.setSelected(longArray);
for (int position : getTaskPositions(Longs.asList(longArray))) {
multiSelector.setSelected(position, 0L, true);
}
updateModeTitle(); updateModeTitle();
} }
} }
private List<Integer> getTaskPositions(List<Long> longs) {
List<Integer> result = new ArrayList<>();
for (int i = 0 ; i < adapterHelper.getItemCount() ; i++) {
Task item = adapterHelper.getItem(i);
if (longs.contains(item.getId())) {
result.add(i);
}
}
return result;
}
@Override @Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
ViewGroup view = (ViewGroup) LayoutInflater.from(activity) ViewGroup view = (ViewGroup) LayoutInflater.from(activity)
.inflate(R.layout.task_adapter_row_simple, parent, false); .inflate(R.layout.task_adapter_row_simple, parent, false);
return viewHolderFactory.newViewHolder(view, this, multiSelector); return viewHolderFactory.newViewHolder(view, this);
} }
@Override @Override
@ -144,6 +120,7 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
holder.bindView(task); holder.bindView(task);
holder.setMoving(false); holder.setMoving(false);
holder.setIndent(adapter.getIndent(task)); holder.setIndent(adapter.getIndent(task));
holder.setSelected(adapter.isSelected(task));
} }
} }
@ -173,9 +150,9 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
} }
private void toggle(ViewHolder viewHolder) { private void toggle(ViewHolder viewHolder) {
multiSelector.setSelectable(true); adapter.toggleSelection(viewHolder.task);
multiSelector.tapSelection(viewHolder); notifyItemChanged(viewHolder.getAdapterPosition());
if (multiSelector.getSelectedPositions().isEmpty()) { if (adapter.getSelected().isEmpty()) {
dragging = false; dragging = false;
if (mode != null) { if (mode != null) {
mode.finish(); mode.finish();
@ -196,22 +173,18 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
} }
} }
private List<Task> getSelectedTasks() {
return newArrayList(transform(multiSelector.getSelectedPositions(), adapterHelper::getItem));
}
private void deleteSelectedItems() { private void deleteSelectedItems() {
tracker.reportEvent(Tracking.Events.MULTISELECT_DELETE); tracker.reportEvent(Tracking.Events.MULTISELECT_DELETE);
List<Task> tasks = getSelectedTasks(); List<Long> tasks = adapter.getSelected();
mode.finish(); mode.finish();
int result = taskDeleter.markDeleted(tasks); List<Task> result = taskDeleter.markDeleted(tasks);
taskList.onTaskDelete(tasks); taskList.onTaskDelete(result);
taskList.makeSnackbar(activity.getString(R.string.delete_multiple_tasks_confirmation, Integer.toString(result))).show(); taskList.makeSnackbar(activity.getString(R.string.delete_multiple_tasks_confirmation, Integer.toString(result.size()))).show();
} }
private void copySelectedItems() { private void copySelectedItems() {
tracker.reportEvent(Tracking.Events.MULTISELECT_CLONE); tracker.reportEvent(Tracking.Events.MULTISELECT_CLONE);
List<Task> tasks = getSelectedTasks(); List<Long> tasks = adapter.getSelected();
mode.finish(); mode.finish();
List<Task> duplicates = taskDuplicator.duplicate(tasks); List<Task> duplicates = taskDuplicator.duplicate(tasks);
taskList.onTaskCreated(duplicates); taskList.onTaskCreated(duplicates);
@ -220,11 +193,11 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
private void updateModeTitle() { private void updateModeTitle() {
if (mode != null) { if (mode != null) {
mode.setTitle(Integer.toString(multiSelector.getSelectedPositions().size())); mode.setTitle(Integer.toString(adapter.getSelected().size()));
} }
} }
private ModalMultiSelectorCallback actionModeCallback = new ModalMultiSelectorCallback(multiSelector) { private ActionMode.Callback actionModeCallback = new ActionMode.Callback() {
@Override @Override
public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
MenuInflater inflater = actionMode.getMenuInflater(); MenuInflater inflater = actionMode.getMenuInflater();
@ -233,6 +206,11 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
return true; return true;
} }
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override @Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) { public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) { switch (item.getItemId()) {
@ -255,9 +233,9 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder>
@Override @Override
public void onDestroyActionMode(ActionMode actionMode) { public void onDestroyActionMode(ActionMode actionMode) {
super.onDestroyActionMode(actionMode); adapter.clearSelections();
multiSelector.clearSelections();
TaskListRecyclerAdapter.this.mode = null; TaskListRecyclerAdapter.this.mode = null;
notifyDataSetChanged();
} }
}; };

@ -5,6 +5,7 @@ import android.app.PendingIntent;
import android.content.Context; import android.content.Context;
import android.graphics.Paint; import android.graphics.Paint;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.widget.RecyclerView;
import android.text.SpannableString; import android.text.SpannableString;
import android.text.TextUtils; import android.text.TextUtils;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
@ -15,8 +16,6 @@ import android.view.ViewGroup;
import android.widget.ImageView; import android.widget.ImageView;
import android.widget.TextView; import android.widget.TextView;
import com.bignerdranch.android.multiselector.MultiSelector;
import com.bignerdranch.android.multiselector.MultiSelectorBindingHolder;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.api.TaskAction; import com.todoroo.astrid.api.TaskAction;
@ -43,21 +42,9 @@ import static com.google.common.collect.Lists.newArrayList;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastKitKat; import static com.todoroo.andlib.utility.AndroidUtilities.atLeastKitKat;
import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop; import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop;
class ViewHolder extends MultiSelectorBindingHolder { class ViewHolder extends RecyclerView.ViewHolder {
@Override public void setSelected(boolean selected) {
public void setSelectable(boolean selectable) {
this.selectable = selectable;
updateBackground();
}
@Override
public boolean isSelectable() {
return selectable;
}
@Override
public void setActivated(boolean selected) {
this.selected = selected; this.selected = selected;
updateBackground(); updateBackground();
} }
@ -70,16 +57,13 @@ class ViewHolder extends MultiSelectorBindingHolder {
private void updateBackground() { private void updateBackground() {
if (selected || moving) { if (selected || moving) {
rowBody.setBackgroundColor(selectedColor); rowBody.setBackgroundColor(selectedColor);
} else if (selectable) {
rowBody.setBackgroundColor(0);
} else { } else {
rowBody.setBackgroundResource(background); rowBody.setBackgroundResource(background);
rowBody.getBackground().jumpToCurrentState(); rowBody.getBackground().jumpToCurrentState();
} }
} }
@Override public boolean isSelected() {
public boolean isActivated() {
return selected; return selected;
} }
@ -114,7 +98,6 @@ class ViewHolder extends MultiSelectorBindingHolder {
private final int selectedColor; private final int selectedColor;
private final int textColorOverdue; private final int textColorOverdue;
private int indent; private int indent;
private boolean selectable = false;
private boolean selected; private boolean selected;
private boolean moving; private boolean moving;
@ -122,9 +105,8 @@ class ViewHolder extends MultiSelectorBindingHolder {
CheckBoxes checkBoxes, TagFormatter tagFormatter, CheckBoxes checkBoxes, TagFormatter tagFormatter,
int textColorOverdue, int textColorSecondary, int textColorHint, TaskDao taskDao, int textColorOverdue, int textColorSecondary, int textColorHint, TaskDao taskDao,
DialogBuilder dialogBuilder, ViewHolderCallbacks callback, DialogBuilder dialogBuilder, ViewHolderCallbacks callback,
DisplayMetrics metrics, int background, int selectedColor, MultiSelector multiSelector, DisplayMetrics metrics, int background, int selectedColor, int rowPadding) {
int rowPadding) { super(view);
super(view, multiSelector);
this.context = context; this.context = context;
this.checkBoxes = checkBoxes; this.checkBoxes = checkBoxes;
this.tagFormatter = tagFormatter; this.tagFormatter = tagFormatter;

@ -4,7 +4,6 @@ import android.content.Context;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.view.ViewGroup; import android.view.ViewGroup;
import com.bignerdranch.android.multiselector.MultiSelector;
import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao;
import org.tasks.R; import org.tasks.R;
@ -57,9 +56,9 @@ public class ViewHolderFactory {
rowPadding = convertDpToPixels(metrics, preferences.getInt(R.string.p_rowPadding, 16)); rowPadding = convertDpToPixels(metrics, preferences.getInt(R.string.p_rowPadding, 16));
} }
ViewHolder newViewHolder(ViewGroup viewGroup, ViewHolder.ViewHolderCallbacks callbacks, MultiSelector multiSelector) { ViewHolder newViewHolder(ViewGroup viewGroup, ViewHolder.ViewHolderCallbacks callbacks) {
return new ViewHolder(context, viewGroup, showFullTaskTitle, fontSize, checkBoxes, return new ViewHolder(context, viewGroup, showFullTaskTitle, fontSize, checkBoxes,
tagFormatter, textColorOverdue, textColorSecondary, textColorHint, taskDao, tagFormatter, textColorOverdue, textColorSecondary, textColorHint, taskDao,
dialogBuilder, callbacks, metrics, background, selectedColor, multiSelector, rowPadding); dialogBuilder, callbacks, metrics, background, selectedColor, rowPadding);
} }
} }

Loading…
Cancel
Save