RecyclerView animations

pull/618/head
Alex Baker 6 years ago
parent 8e3936b159
commit 9be5af7359

@ -73,8 +73,8 @@ public class GtasksSubtaskListFragment extends GtasksListFragment {
}
@Override
protected TaskAdapter createTaskAdapter(List<Task> tasks) {
return helper.createTaskAdapter(tasks);
protected TaskAdapter createTaskAdapter() {
return helper.createTaskAdapter();
}
@Override

@ -21,7 +21,6 @@ import org.tasks.data.GoogleTaskList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
@ -54,8 +53,8 @@ class OrderedMetadataListFragmentHelper {
updater.initialize(filter);
}
TaskAdapter createTaskAdapter(List<Task> cursor) {
taskAdapter = new DraggableTaskAdapter(cursor);
TaskAdapter createTaskAdapter() {
taskAdapter = new DraggableTaskAdapter();
taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks);
@ -64,10 +63,6 @@ class OrderedMetadataListFragmentHelper {
private final class DraggableTaskAdapter extends TaskAdapter {
private DraggableTaskAdapter(List<Task> tasks) {
super(tasks);
}
@Override
public int getIndent(Task task) {
return task.getGoogleTaskIndent();
@ -101,8 +96,6 @@ class OrderedMetadataListFragmentHelper {
} catch (Exception e) {
Timber.e(e, e.getMessage());
}
fragment.loadTaskListContent();
}
@Override
@ -116,7 +109,6 @@ class OrderedMetadataListFragmentHelper {
} catch (Exception e) {
Timber.e(e, e.getMessage());
}
fragment.loadTaskListContent();
}
}

@ -465,10 +465,6 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
@Override
public void sortChanged() {
localBroadcastManager.broadcastRefresh();
reloadCurrentFilter();
}
private void reloadCurrentFilter() {
onFilterItemClicked(getCurrentFilter());
}

@ -16,6 +16,8 @@ import android.support.design.widget.CoordinatorLayout;
import android.support.design.widget.Snackbar;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.util.DiffUtil;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.SearchView;
@ -190,6 +192,8 @@ public class TaskListFragment extends InjectingFragment implements
filter = BuiltInFilterExposer.getMyTasksFilter(getResources());
}
filter.setFilterQueryOverride(null);
setTaskAdapter();
}
@ -343,8 +347,7 @@ public class TaskListFragment extends InjectingFragment implements
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
filter.setFilterQueryOverride(null);
((DefaultItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);
recyclerAdapter.applyToRecyclerView(recyclerView);
recyclerView.setLayoutManager(new LinearLayoutManager(context));
}
@ -401,32 +404,72 @@ public class TaskListFragment extends InjectingFragment implements
* ======================================================================
*/
/**
* Load or re-load action items and update views
*/
private static class DiffUtilCallback extends DiffUtil.Callback {
private final List<Task> oldTasks;
private final List<Task> newTasks;
public DiffUtilCallback(List<Task> oldTasks, List<Task> newTasks) {
this.oldTasks = oldTasks;
this.newTasks = newTasks;
}
@Override
public int getOldListSize() {
return oldTasks.size();
}
@Override
public int getNewListSize() {
return newTasks.size();
}
@Override
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
return oldTasks.get(oldItemPosition).getId() == newTasks.get(newItemPosition).getId();
}
@Override
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
return oldTasks.get(oldItemPosition).equals(newTasks.get(newItemPosition));
}
}
public void loadTaskListContent() {
loadTaskListContent(true);
}
public void loadTaskListContent(boolean animate) {
if (taskAdapter == null) {
return;
}
// stash selected items
Bundle saveState = recyclerAdapter.getSaveState();
List<Task> tasks = taskListDataProvider.toList(filter, taskProperties());
taskAdapter.setTasks(tasks);
List<Task> oldTasks = taskAdapter.getTasks();
List<Task> newTasks = taskListDataProvider.toList(filter, taskProperties());
taskAdapter.setTasks(newTasks);
if (animate) {
DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new DiffUtilCallback(oldTasks, newTasks), true);
diffResult.dispatchUpdatesTo(recyclerAdapter);
} else {
recyclerAdapter.notifyDataSetChanged();
}
recyclerAdapter.restoreSaveState(saveState);
if (taskAdapter.getCount() == 0) {
if (newTasks.isEmpty()) {
swipeRefreshLayout.setVisibility(View.GONE);
emptyRefreshLayout.setVisibility(View.VISIBLE);
} else {
recyclerAdapter.notifyDataSetChanged();
recyclerAdapter.restoreSaveState(saveState);
swipeRefreshLayout.setVisibility(View.VISIBLE);
emptyRefreshLayout.setVisibility(View.GONE);
}
}
protected TaskAdapter createTaskAdapter(List<Task> tasks) {
return new TaskAdapter(tasks);
protected TaskAdapter createTaskAdapter() {
return new TaskAdapter();
}
public static final String TAGS_METADATA_JOIN = "for_tags"; //$NON-NLS-1$
@ -441,10 +484,8 @@ public class TaskListFragment extends InjectingFragment implements
return;
}
List<Task> tasks = taskListDataProvider.toList(filter, taskProperties());
// set up list adapters
taskAdapter = createTaskAdapter(tasks);
taskAdapter = createTaskAdapter();
recyclerAdapter = new TaskListRecyclerAdapter(getActivity(), taskAdapter, viewHolderFactory,
this, taskDeleter, taskDuplicator, tracker, dialogBuilder);
}

@ -15,8 +15,10 @@ import com.todoroo.astrid.data.Task;
import org.tasks.data.TaskAttachment;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static com.google.common.collect.Lists.newArrayList;
import static com.todoroo.astrid.data.Task.NO_ID;
import static com.todoroo.astrid.data.Task.NO_UUID;
@ -28,7 +30,7 @@ import static com.todoroo.astrid.data.Task.NO_UUID;
*/
public class TaskAdapter {
private List<Task> tasks;
private final List<Task> tasks = new ArrayList<>();
public List<Integer> getTaskPositions(List<Long> longs) {
List<Integer> result = new ArrayList<>();
@ -41,7 +43,8 @@ public class TaskAdapter {
}
public void setTasks(List<Task> tasks) {
this.tasks = tasks;
this.tasks.clear();
this.tasks.addAll(tasks);
}
public int getCount() {
@ -52,8 +55,8 @@ public class TaskAdapter {
void onCompletedTask(Task item, boolean newState);
}
public static final StringProperty TAGS = new StringProperty(null, "group_concat(nullif(" + TaskListFragment.TAGS_METADATA_JOIN + ".tag_uid, '')"+ ", ',')").as("tags");
public static final LongProperty FILE_ID_PROPERTY = TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId");
private static final StringProperty TAGS = new StringProperty(null, "group_concat(nullif(" + TaskListFragment.TAGS_METADATA_JOIN + ".tag_uid, '')"+ ", ',')").as("tags");
private static final LongProperty FILE_ID_PROPERTY = TaskAttachment.ID.cloneAs(TaskListFragment.FILE_METADATA_JOIN, "fileId");
public static final Property<?>[] PROPERTIES = ObjectArrays.concat(
Task.PROPERTIES,
@ -64,10 +67,6 @@ public class TaskAdapter {
private OnCompletedTaskListener onCompletedTaskListener = null;
public TaskAdapter(List<Task> tasks) {
this.tasks = tasks;
}
public int getIndent(Task task) {
return 0;
}
@ -89,7 +88,7 @@ public class TaskAdapter {
}
public List<Task> getTasks() {
return tasks;
return newArrayList(tasks);
}
public long getTaskId(int position) {

@ -1001,4 +1001,81 @@ public class Task implements Parcelable {
public boolean hasFiles() {
return hasFiles;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Task)) return false;
Task task = (Task) o;
if (googleTaskIndent != task.googleTaskIndent) return false;
if (hasFiles != task.hasFiles) return false;
if (id != null ? !id.equals(task.id) : task.id != null) return false;
if (title != null ? !title.equals(task.title) : task.title != null) return false;
if (importance != null ? !importance.equals(task.importance) : task.importance != null)
return false;
if (dueDate != null ? !dueDate.equals(task.dueDate) : task.dueDate != null) return false;
if (hideUntil != null ? !hideUntil.equals(task.hideUntil) : task.hideUntil != null)
return false;
if (created != null ? !created.equals(task.created) : task.created != null) return false;
if (modified != null ? !modified.equals(task.modified) : task.modified != null)
return false;
if (completed != null ? !completed.equals(task.completed) : task.completed != null)
return false;
if (deleted != null ? !deleted.equals(task.deleted) : task.deleted != null) return false;
if (notes != null ? !notes.equals(task.notes) : task.notes != null) return false;
if (estimatedSeconds != null ? !estimatedSeconds.equals(task.estimatedSeconds) : task.estimatedSeconds != null)
return false;
if (elapsedSeconds != null ? !elapsedSeconds.equals(task.elapsedSeconds) : task.elapsedSeconds != null)
return false;
if (timerStart != null ? !timerStart.equals(task.timerStart) : task.timerStart != null)
return false;
if (notificationFlags != null ? !notificationFlags.equals(task.notificationFlags) : task.notificationFlags != null)
return false;
if (notifications != null ? !notifications.equals(task.notifications) : task.notifications != null)
return false;
if (lastNotified != null ? !lastNotified.equals(task.lastNotified) : task.lastNotified != null)
return false;
if (snoozeTime != null ? !snoozeTime.equals(task.snoozeTime) : task.snoozeTime != null)
return false;
if (recurrence != null ? !recurrence.equals(task.recurrence) : task.recurrence != null)
return false;
if (repeatUntil != null ? !repeatUntil.equals(task.repeatUntil) : task.repeatUntil != null)
return false;
if (calendarUri != null ? !calendarUri.equals(task.calendarUri) : task.calendarUri != null)
return false;
if (remoteId != null ? !remoteId.equals(task.remoteId) : task.remoteId != null)
return false;
return tags != null ? tags.equals(task.tags) : task.tags == null;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (title != null ? title.hashCode() : 0);
result = 31 * result + (importance != null ? importance.hashCode() : 0);
result = 31 * result + (dueDate != null ? dueDate.hashCode() : 0);
result = 31 * result + (hideUntil != null ? hideUntil.hashCode() : 0);
result = 31 * result + (created != null ? created.hashCode() : 0);
result = 31 * result + (modified != null ? modified.hashCode() : 0);
result = 31 * result + (completed != null ? completed.hashCode() : 0);
result = 31 * result + (deleted != null ? deleted.hashCode() : 0);
result = 31 * result + (notes != null ? notes.hashCode() : 0);
result = 31 * result + (estimatedSeconds != null ? estimatedSeconds.hashCode() : 0);
result = 31 * result + (elapsedSeconds != null ? elapsedSeconds.hashCode() : 0);
result = 31 * result + (timerStart != null ? timerStart.hashCode() : 0);
result = 31 * result + (notificationFlags != null ? notificationFlags.hashCode() : 0);
result = 31 * result + (notifications != null ? notifications.hashCode() : 0);
result = 31 * result + (lastNotified != null ? lastNotified.hashCode() : 0);
result = 31 * result + (snoozeTime != null ? snoozeTime.hashCode() : 0);
result = 31 * result + (recurrence != null ? recurrence.hashCode() : 0);
result = 31 * result + (repeatUntil != null ? repeatUntil.hashCode() : 0);
result = 31 * result + (calendarUri != null ? calendarUri.hashCode() : 0);
result = 31 * result + (remoteId != null ? remoteId.hashCode() : 0);
result = 31 * result + googleTaskIndent;
result = 31 * result + (tags != null ? tags.hashCode() : 0);
result = 31 * result + (hasFiles ? 1 : 0);
return result;
}
}

@ -44,8 +44,8 @@ class AstridOrderedListFragmentHelper {
updater.initialize(list, filter);
}
TaskAdapter createTaskAdapter(List<Task> tasks) {
taskAdapter = new DraggableTaskAdapter(tasks);
TaskAdapter createTaskAdapter() {
taskAdapter = new DraggableTaskAdapter();
taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks);
@ -54,10 +54,6 @@ class AstridOrderedListFragmentHelper {
private final class DraggableTaskAdapter extends TaskAdapter {
private DraggableTaskAdapter(List<Task> tasks) {
super(tasks);
}
@Override
public int getIndent(Task task) {
return updater.getIndentForTask(task.getUuid());
@ -92,8 +88,6 @@ class AstridOrderedListFragmentHelper {
} catch (Exception e) {
Timber.e(e, e.getMessage());
}
fragment.loadTaskListContent();
}
@Override
@ -107,8 +101,6 @@ class AstridOrderedListFragmentHelper {
} catch (Exception e) {
Timber.e(e, e.getMessage());
}
fragment.loadTaskListContent();
}
}

@ -66,7 +66,7 @@ public class SubtasksFilterUpdater {
String query = filter.getSqlQuery();
query = query.replaceAll("ORDER BY .*", "");
query = query + String.format(" ORDER BY %s", getOrderString());
query = query + String.format("ORDER BY %s", getOrderString());
query = query.replace(
TaskDao.TaskCriteria.activeAndVisible().toString(),
TaskDao.TaskCriteria.notDeleted().toString());

@ -63,11 +63,11 @@ public class SubtasksHelper {
TagData tagData = tagDataDao.getTagByName(filter.listingTitle);
TaskListMetadata tlm = null;
if (tagData != null) {
tlm = taskListMetadataDao.fetchByTagId(tagData.getRemoteId());
tlm = taskListMetadataDao.fetchByTagOrFilter(tagData.getRemoteId());
} else if (BuiltInFilterExposer.isInbox(context, filter)) {
tlm = taskListMetadataDao.fetchByTagId(TaskListMetadata.FILTER_ID_ALL);
tlm = taskListMetadataDao.fetchByTagOrFilter(TaskListMetadata.FILTER_ID_ALL);
} else if (BuiltInFilterExposer.isTodayFilter(context, filter)) {
tlm = taskListMetadataDao.fetchByTagId(TaskListMetadata.FILTER_ID_TODAY);
tlm = taskListMetadataDao.fetchByTagOrFilter(TaskListMetadata.FILTER_ID_TODAY);
}
query = query.replaceAll("ORDER BY .*", "");
@ -133,15 +133,15 @@ public class SubtasksHelper {
return SubtasksFilterUpdater.serializeTree(tree);
}
interface TreeRemapHelper<T> {
T getKeyFromOldUuid(String uuid);
interface TreeRemapHelper {
Long getKeyFromOldUuid(String uuid);
}
private static <T> void remapTree(Node root, Map<T, String> idMap, TreeRemapHelper<T> helper) {
private static void remapTree(Node root, Map<Long, String> idMap, TreeRemapHelper helper) {
ArrayList<Node> children = root.children;
for (int i = 0; i < children.size(); i++) {
Node child = children.get(i);
T key = helper.getKeyFromOldUuid(child.uuid);
Long key = helper.getKeyFromOldUuid(child.uuid);
String uuid = idMap.get(key);
if (!Task.isValidUuid(uuid)) {
children.remove(i);

@ -74,7 +74,7 @@ public class SubtasksListFragment extends TaskListFragment {
if (TextUtils.isEmpty(filterId)) {
return null;
}
TaskListMetadata taskListMetadata = taskListMetadataDao.fetchByTagId(filterId);
TaskListMetadata taskListMetadata = taskListMetadataDao.fetchByTagOrFilter(filterId);
if (taskListMetadata == null) {
String defaultOrder = preferences.getStringValue(prefId);
if (TextUtils.isEmpty(defaultOrder)) {
@ -101,8 +101,8 @@ public class SubtasksListFragment extends TaskListFragment {
}
@Override
protected TaskAdapter createTaskAdapter(List<Task> tasks) {
return helper.createTaskAdapter(tasks);
protected TaskAdapter createTaskAdapter() {
return helper.createTaskAdapter();
}
@Override

@ -44,7 +44,7 @@ public class SubtasksTagListFragment extends TagListFragment {
@Override
public void setTaskAdapter() {
String tdId = tagData.getRemoteId();
TaskListMetadata taskListMetadata = taskListMetadataDao.fetchByTagId(tagData.getRemoteId());
TaskListMetadata taskListMetadata = taskListMetadataDao.fetchByTagOrFilter(tagData.getRemoteId());
if (taskListMetadata == null && !Task.isUuidEmpty(tdId)) {
taskListMetadata = new TaskListMetadata();
taskListMetadata.setTagUuid(tdId);
@ -68,8 +68,8 @@ public class SubtasksTagListFragment extends TagListFragment {
}
@Override
protected TaskAdapter createTaskAdapter(List<Task> tasks) {
return helper.createTaskAdapter(tasks);
protected TaskAdapter createTaskAdapter() {
return helper.createTaskAdapter();
}
@Override

@ -22,7 +22,6 @@ import static com.todoroo.astrid.activity.TaskListFragment.TAGS_METADATA_JOIN;
public class TaskListDataProvider {
private final AtomicReference<String> sqlQueryTemplate = new AtomicReference<>();
private final TaskDao taskDao;
private final Preferences preferences;
@ -53,19 +52,18 @@ public class TaskListDataProvider {
+ Join.left(TaskAttachment.TABLE.as(FILE_METADATA_JOIN), Task.UUID.eq(Field.field(FILE_METADATA_JOIN + ".task_id")))
+ filter.getSqlQuery();
sqlQueryTemplate.set(SortHelper.adjustQueryForFlagsAndSort(
preferences, joinedQuery, preferences.getSortMode()));
String query = SortHelper.adjustQueryForFlagsAndSort(
preferences, joinedQuery, preferences.getSortMode());
String groupedQuery;
if (sqlQueryTemplate.get().contains("GROUP BY")) {
groupedQuery = sqlQueryTemplate.get();
} else if (sqlQueryTemplate.get().contains("ORDER BY")) {
groupedQuery = sqlQueryTemplate.get().replace("ORDER BY", "GROUP BY " + Task.ID + " ORDER BY"); //$NON-NLS-1$
if (query.contains("GROUP BY")) {
groupedQuery = query;
} else if (query.contains("ORDER BY")) {
groupedQuery = query.replace("ORDER BY", "GROUP BY " + Task.ID + " ORDER BY"); //$NON-NLS-1$
} else {
groupedQuery = sqlQueryTemplate.get() + " GROUP BY " + Task.ID;
groupedQuery = query + " GROUP BY " + Task.ID;
}
sqlQueryTemplate.set(groupedQuery);
return taskDao.fetchFiltered(sqlQueryTemplate.get(), properties);
return taskDao.fetchFiltered(groupedQuery, properties);
}
}

@ -2,30 +2,23 @@ package org.tasks.data;
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Insert;
import android.arch.persistence.room.OnConflictStrategy;
import android.arch.persistence.room.Query;
import android.arch.persistence.room.Update;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.helper.UUIDHelper;
@Dao
public abstract class TaskListMetadataDao {
@Query("SELECT * from task_list_metadata where tag_uuid = :tagUuid OR filter = :tagUuid LIMIT 1")
public abstract TaskListMetadata fetchByTagId(String tagUuid);
public abstract TaskListMetadata fetchByTagOrFilter(String tagUuid);
@Update
public abstract void update(TaskListMetadata taskListMetadata);
public abstract int update(TaskListMetadata taskListMetadata);
@Insert(onConflict = OnConflictStrategy.REPLACE)
public abstract void insert(TaskListMetadata taskListMetadata);
@Insert
abstract long insert(TaskListMetadata taskListMetadata);
public void createNew(TaskListMetadata taskListMetadata) {
if (Task.isUuidEmpty(taskListMetadata.getRemoteId())) {
taskListMetadata.setRemoteId(UUIDHelper.newUUID());
}
insert(taskListMetadata);
taskListMetadata.setId(insert(taskListMetadata));
}
}

@ -10,10 +10,10 @@ import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.TagFilter;
import org.tasks.data.TagData;
import org.tasks.R;
import org.tasks.activities.TagSettingsActivity;
import org.tasks.data.TagData;
import org.tasks.injection.FragmentComponent;
public class TagListFragment extends TaskListFragment {

@ -301,6 +301,7 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder> im
to++;
}
adapter.moved(from, to);
taskList.loadTaskListContent(false);
}
}
}
@ -314,6 +315,7 @@ public class TaskListRecyclerAdapter extends RecyclerView.Adapter<ViewHolder> im
adapter.indented(
viewHolder.getAdapterPosition(),
direction == ItemTouchHelper.RIGHT ? 1 : -1);
taskList.loadTaskListContent(false);
}
}
}

Loading…
Cancel
Save