From 3a5c61d68064a559666b56f66e9f20447f29194f Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Fri, 4 Nov 2016 08:32:58 -0500 Subject: [PATCH] Drag and drop recycler view for task list --- .../gtasks/GtasksSubtaskListFragment.java | 35 +- .../OrderedMetadataListFragmentHelper.java | 130 ++--- .../GoogleTaskListSettingsActivity.java | 2 +- .../astrid/activity/TaskEditFragment.java | 2 +- .../astrid/activity/TaskListFragment.java | 103 ++-- .../todoroo/astrid/adapter/TaskAdapter.java | 126 +---- .../AstridOrderedListFragmentHelper.java | 142 ++--- .../astrid/subtasks/SubtasksListFragment.java | 36 +- .../subtasks/SubtasksTagListFragment.java | 32 +- .../com/todoroo/astrid/tags/TagService.java | 4 + .../todoroo/astrid/ui/DraggableListView.java | 530 ------------------ .../activities/FilterSettingsActivity.java | 2 +- .../tasks/activities/TagSettingsActivity.java | 2 +- .../org/tasks/data/TaskListDataProvider.java | 4 - .../java/org/tasks/tasklist/TagFormatter.java | 16 +- .../org/tasks/tasklist/TagListFragment.java | 7 - .../tasklist/TaskListRecyclerAdapter.java | 134 +++++ .../java/org/tasks/tasklist/ViewHolder.java | 62 +- .../org/tasks/tasklist/ViewHolderFactory.java | 12 +- .../java/org/tasks/themes/ThemeCache.java | 4 +- .../java/org/tasks/themes/WidgetTheme.java | 2 +- .../layout-v21/task_adapter_row_simple.xml | 19 + .../res/layout/beast_mode_pref_activity.xml | 4 +- src/main/res/layout/fragment_task_edit.xml | 5 +- .../res/layout/fragment_task_edit_empty.xml | 6 +- src/main/res/layout/fragment_task_list.xml | 13 +- .../res/layout/preference_draggable_row.xml | 1 + src/main/res/layout/task_adapter_row_body.xml | 123 ++++ .../res/layout/task_adapter_row_simple.xml | 128 +---- src/main/res/layout/task_list_body_empty.xml | 5 +- .../res/layout/task_list_body_standard.xml | 20 +- .../res/layout/task_list_body_subtasks.xml | 17 - src/main/res/layout/task_list_footer.xml | 5 - ...ngs_activity.xml => menu_tag_settings.xml} | 0 ...agment.xml => menu_task_edit_fragment.xml} | 0 src/main/res/values-night/colors.xml | 5 +- src/main/res/values-notnight/colors.xml | 5 +- src/main/res/values-w820dp/styles.xml | 2 +- src/main/res/values/attrs.xml | 2 + src/main/res/values/colors.xml | 5 +- src/main/res/values/dimens.xml | 3 +- src/main/res/values/styles.xml | 2 +- src/main/res/values/theme.xml | 13 +- src/main/res/values/theme_dark_grey.xml | 2 +- 44 files changed, 550 insertions(+), 1222 deletions(-) delete mode 100644 src/main/java/com/todoroo/astrid/ui/DraggableListView.java create mode 100644 src/main/java/org/tasks/tasklist/TaskListRecyclerAdapter.java create mode 100644 src/main/res/layout-v21/task_adapter_row_simple.xml create mode 100644 src/main/res/layout/task_adapter_row_body.xml delete mode 100644 src/main/res/layout/task_list_body_subtasks.xml delete mode 100644 src/main/res/layout/task_list_footer.xml rename src/main/res/menu/{tag_settings_activity.xml => menu_tag_settings.xml} (100%) rename src/main/res/menu/{task_edit_fragment.xml => menu_task_edit_fragment.xml} (100%) diff --git a/src/googleplay/java/com/todoroo/astrid/gtasks/GtasksSubtaskListFragment.java b/src/googleplay/java/com/todoroo/astrid/gtasks/GtasksSubtaskListFragment.java index 941435ea3..73b41521f 100644 --- a/src/googleplay/java/com/todoroo/astrid/gtasks/GtasksSubtaskListFragment.java +++ b/src/googleplay/java/com/todoroo/astrid/gtasks/GtasksSubtaskListFragment.java @@ -8,8 +8,6 @@ package com.todoroo.astrid.gtasks; import android.app.Activity; import android.content.Context; import android.os.Bundle; -import android.view.View; -import android.widget.ListView; import com.todoroo.andlib.data.Property; import com.todoroo.andlib.data.TodorooCursor; @@ -18,7 +16,6 @@ import com.todoroo.astrid.adapter.TaskAdapter; import com.todoroo.astrid.api.GtasksFilter; import com.todoroo.astrid.data.Task; -import org.tasks.R; import org.tasks.injection.ForApplication; import org.tasks.injection.FragmentComponent; import org.tasks.tasklist.GtasksListFragment; @@ -42,8 +39,6 @@ public class GtasksSubtaskListFragment extends GtasksListFragment { @Inject Theme theme; @Inject OrderedMetadataListFragmentHelper helper; - private int lastVisibleIndex = -1; - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -73,18 +68,6 @@ public class GtasksSubtaskListFragment extends GtasksListFragment { helper.setTaskListFragment(this); } - @Override - protected int getListBody() { - return R.layout.task_list_body_subtasks; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - helper.setUpUiComponents(); - } - @Override public void setTaskAdapter() { helper.setList(list); @@ -93,25 +76,9 @@ public class GtasksSubtaskListFragment extends GtasksListFragment { super.setTaskAdapter(); } - @Override - public void onPause() { - super.onPause(); - lastVisibleIndex = getListView().getFirstVisiblePosition(); - } - - @Override - public void onResume() { - super.onResume(); - ListView listView = getListView(); - if (lastVisibleIndex >= 0) { - listView.setSelection(lastVisibleIndex); - } - unregisterForContextMenu(listView); - } - @Override protected TaskAdapter createTaskAdapter(TodorooCursor cursor) { - return helper.createTaskAdapter(theme.wrap(context), cursor, taskListDataProvider.getSqlQueryTemplate()); + return helper.createTaskAdapter(theme.wrap(context), cursor); } @Override diff --git a/src/googleplay/java/com/todoroo/astrid/gtasks/OrderedMetadataListFragmentHelper.java b/src/googleplay/java/com/todoroo/astrid/gtasks/OrderedMetadataListFragmentHelper.java index 7b9f42c92..3d58a0932 100644 --- a/src/googleplay/java/com/todoroo/astrid/gtasks/OrderedMetadataListFragmentHelper.java +++ b/src/googleplay/java/com/todoroo/astrid/gtasks/OrderedMetadataListFragmentHelper.java @@ -5,14 +5,9 @@ */ package com.todoroo.astrid.gtasks; -import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.View; -import android.widget.ListView; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.utility.DateUtilities; @@ -23,20 +18,11 @@ import com.todoroo.astrid.dao.MetadataDao; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.Task; -import com.todoroo.astrid.ui.DraggableListView; -import com.todoroo.astrid.ui.DraggableListView.DropListener; -import com.todoroo.astrid.ui.DraggableListView.GrabberClickListener; -import com.todoroo.astrid.ui.DraggableListView.SwipeListener; - -import org.tasks.R; -import org.tasks.tasklist.ViewHolder; -import org.tasks.tasklist.ViewHolderFactory; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; @@ -44,9 +30,7 @@ import timber.log.Timber; class OrderedMetadataListFragmentHelper { - private final DisplayMetrics metrics = new DisplayMetrics(); private final GtasksTaskListUpdater updater; - private final ViewHolderFactory viewHolderFactory; private final TaskDao taskDao; private final MetadataDao metadataDao; @@ -56,46 +40,52 @@ class OrderedMetadataListFragmentHelper { private GtasksList list; @Inject - OrderedMetadataListFragmentHelper(TaskDao taskDao, MetadataDao metadataDao, - GtasksTaskListUpdater updater, ViewHolderFactory viewHolderFactory) { + OrderedMetadataListFragmentHelper(TaskDao taskDao, MetadataDao metadataDao, GtasksTaskListUpdater updater) { this.taskDao = taskDao; this.metadataDao = metadataDao; this.updater = updater; - this.viewHolderFactory = viewHolderFactory; } void setTaskListFragment(TaskListFragment fragment) { this.fragment = fragment; } - // --- ui component setup - - private Activity getActivity() { - return fragment.getActivity(); + void beforeSetUpTaskList(Filter filter) { + updater.initialize(filter); } - private ListView getListView() { - return fragment.getListView(); - } + TaskAdapter createTaskAdapter(Context context, TodorooCursor cursor) { + taskAdapter = new DraggableTaskAdapter(context, fragment, cursor); - void setUpUiComponents() { - TypedValue tv = new TypedValue(); - getActivity().getTheme().resolveAttribute(R.attr.colorAccent, tv, false); - DraggableListView draggableListView = (DraggableListView) fragment.getListView(); - draggableListView.setDragndropBackgroundColor(tv.data); - draggableListView.setDropListener(dropListener); - draggableListView.setClickListener(rowClickListener); - draggableListView.setSwipeListener(swipeListener); - getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics); - } + taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks); - void beforeSetUpTaskList(Filter filter) { - updater.initialize(filter); + return taskAdapter; } - private final DropListener dropListener = new DropListener() { + private final class DraggableTaskAdapter extends TaskAdapter { + + private DraggableTaskAdapter(Context context, TaskListFragment activity, Cursor c) { + super(context, activity, c); + } + + @Override + public int getIndent(Task task) { + return task.getValue(GtasksMetadata.INDENT); + } + + @Override + public boolean canIndent(int position, Task task) { + Task parent = taskAdapter.getTask(position - 1); + return parent != null && getIndent(task) <= parent.getValue(GtasksMetadata.INDENT); + } + @Override - public void drop(int from, int to) { + public boolean isManuallySorted() { + return true; + } + + @Override + public void moved(int from, int to) { long targetTaskId = taskAdapter.getItemId(from); if (targetTaskId <= 0) { return; // This can happen with gestures on empty parts of the list (e.g. extra space below tasks) @@ -103,7 +93,7 @@ class OrderedMetadataListFragmentHelper { long destinationTaskId = taskAdapter.getItemId(to); try { - if(to >= getListView().getCount()) { + if(to >= taskAdapter.getCount()) { updater.moveTo(list, targetTaskId, -1); } else { updater.moveTo(list, targetTaskId, destinationTaskId); @@ -114,20 +104,9 @@ class OrderedMetadataListFragmentHelper { fragment.loadTaskListContent(); } - }; - - private final SwipeListener swipeListener = new SwipeListener() { - @Override - public void swipeRight(int which) { - indent(which, 1); - } @Override - public void swipeLeft(int which) { - indent(which, -1); - } - - void indent(int which, int delta) { + public void indented(int which, int delta) { long targetTaskId = taskAdapter.getItemId(which); if (targetTaskId <= 0) { return; // This can happen with gestures on empty parts of the list (e.g. extra space below tasks) @@ -139,51 +118,6 @@ class OrderedMetadataListFragmentHelper { } fragment.loadTaskListContent(); } - }; - - private final GrabberClickListener rowClickListener = new GrabberClickListener() { - @Override - public void onLongClick(final View v) { - if(v == null) { - return; - } - - fragment.registerForContextMenu(getListView()); - getListView().showContextMenuForChild(v); - fragment.unregisterForContextMenu(getListView()); - } - - @Override - public void onClick(View v) { - if(v == null) { - return; - } - taskAdapter.onClick(v); - } - }; - - TaskAdapter createTaskAdapter(Context context, TodorooCursor cursor, - AtomicReference sqlQueryTemplate) { - - taskAdapter = new DraggableTaskAdapter(context, fragment, cursor, sqlQueryTemplate); - - taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks); - - return taskAdapter; - } - - private final class DraggableTaskAdapter extends TaskAdapter { - - private DraggableTaskAdapter(Context context, TaskListFragment activity, - Cursor c, AtomicReference query) { - super(context, taskDao, activity, c, query, viewHolderFactory); - } - - @Override - protected void adjustView(ViewHolder vh) { - int indent = vh.task.getValue(GtasksMetadata.INDENT); - vh.rowBody.setPadding(Math.round(indent * 20 * metrics.density), 0, 0, 0); - } } private final Map> chainedCompletions = diff --git a/src/googleplay/java/org/tasks/activities/GoogleTaskListSettingsActivity.java b/src/googleplay/java/org/tasks/activities/GoogleTaskListSettingsActivity.java index 4ac2dea0c..9b6821a7e 100644 --- a/src/googleplay/java/org/tasks/activities/GoogleTaskListSettingsActivity.java +++ b/src/googleplay/java/org/tasks/activities/GoogleTaskListSettingsActivity.java @@ -108,7 +108,7 @@ public class GoogleTaskListSettingsActivity extends ThemedInjectingAppCompatActi save(); } }); - toolbar.inflateMenu(R.menu.tag_settings_activity); + toolbar.inflateMenu(R.menu.menu_tag_settings); toolbar.setOnMenuItemClickListener(this); toolbar.showOverflowMenu(); diff --git a/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java b/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java index f7054b289..fe9238c71 100755 --- a/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java +++ b/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java @@ -133,7 +133,7 @@ public final class TaskEditFragment extends InjectingFragment implements Toolbar save(); } }); - toolbar.inflateMenu(R.menu.task_edit_fragment); + toolbar.inflateMenu(R.menu.menu_task_edit_fragment); toolbar.setOnMenuItemClickListener(this); MenuColorizer.colorToolbar(context, toolbar); diff --git a/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java b/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java index ac0ef7067..15459341d 100644 --- a/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java +++ b/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java @@ -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.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; import android.support.v7.widget.SearchView; import android.support.v7.widget.Toolbar; import android.view.ContextMenu; @@ -26,7 +28,6 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView.AdapterContextMenuInfo; -import android.widget.ListView; import com.todoroo.andlib.data.Callback; import com.todoroo.andlib.data.Property; @@ -60,8 +61,9 @@ import org.tasks.dialogs.SortDialog; import org.tasks.gtasks.SyncAdapterHelper; import org.tasks.injection.ForActivity; import org.tasks.injection.FragmentComponent; -import org.tasks.injection.InjectingListFragment; +import org.tasks.injection.InjectingFragment; import org.tasks.preferences.Preferences; +import org.tasks.tasklist.TaskListRecyclerAdapter; import org.tasks.tasklist.ViewHolder; import org.tasks.tasklist.ViewHolderFactory; import org.tasks.ui.CheckBoxes; @@ -83,9 +85,8 @@ import static com.todoroo.astrid.voice.VoiceInputAssistant.voiceInputAvailable; * @author Tim Su * */ -public class TaskListFragment extends InjectingListFragment implements - SwipeRefreshLayout.OnRefreshListener, - Toolbar.OnMenuItemClickListener { +public class TaskListFragment extends InjectingFragment implements + SwipeRefreshLayout.OnRefreshListener, Toolbar.OnMenuItemClickListener { public static TaskListFragment newTaskListFragment(Filter filter) { TaskListFragment fragment = new TaskListFragment(); @@ -124,11 +125,13 @@ public class TaskListFragment extends InjectingListFragment implements @Inject ViewHolderFactory viewHolderFactory; @BindView(R.id.swipe_layout) SwipeRefreshLayout swipeRefreshLayout; - @BindView(R.id.swipe_layout_empty) SwipeRefreshLayout emptyView; + @BindView(R.id.swipe_layout_empty) SwipeRefreshLayout emptyRefreshLayout; @BindView(R.id.toolbar) Toolbar toolbar; @BindView(R.id.task_list_coordinator) CoordinatorLayout coordinatorLayout; + @BindView(R.id.recycler_view) RecyclerView recyclerView; private TaskAdapter taskAdapter = null; + private TaskListRecyclerAdapter recyclerAdapter; private final RefreshReceiver refreshReceiver = new RefreshReceiver(); private TaskListFragmentCallbackHandler callbacks; @@ -152,7 +155,7 @@ public class TaskListFragment extends InjectingListFragment implements if (activity != null) { activity.runOnUiThread(() -> { swipeRefreshLayout.setRefreshing(ongoing); - emptyView.setRefreshing(ongoing); + emptyRefreshLayout.setRefreshing(ongoing); }); } } @@ -179,15 +182,6 @@ public class TaskListFragment extends InjectingListFragment implements component.inject(this); } - /** - * @return view to attach to the body of the task list. must contain two - * elements, a view with id android:id/empty and a list view with id - * android:id/list. It should NOT be attached to root - */ - protected int getListBody() { - return R.layout.task_list_body_standard; - } - /** Called when loading up the activity */ @Override public void onCreate(Bundle savedInstanceState) { @@ -215,12 +209,9 @@ public class TaskListFragment extends InjectingListFragment implements public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View parent = inflater.inflate(R.layout.fragment_task_list, container, false); - ((ViewGroup) parent.findViewById(R.id.task_list_body)).addView(inflater.inflate(getListBody(), null), 0); ButterKnife.bind(this, parent); setupRefresh(swipeRefreshLayout); - setupRefresh(emptyView); - ListView listView = (ListView) swipeRefreshLayout.findViewById(android.R.id.list); - listView.setEmptyView(emptyView); + setupRefresh(emptyRefreshLayout); toolbar.setTitle(filter.listingTitle); toolbar.setNavigationIcon(R.drawable.ic_menu_24dp); @@ -334,15 +325,6 @@ public class TaskListFragment extends InjectingListFragment implements return taskCreator.createWithValues(filter.valuesForNewTasks, title); } - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - ListView listView = getListView(); - View footer = getActivity().getLayoutInflater().inflate(R.layout.task_list_footer, listView, false); - listView.addFooterView(footer, null, false); - } - private void setupRefresh(SwipeRefreshLayout layout) { layout.setOnRefreshListener(this); layout.setColorSchemeColors(checkBoxes.getPriorityColorsArray()); @@ -352,44 +334,22 @@ public class TaskListFragment extends InjectingListFragment implements public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // We have a menu item to show in action bar. - final ListView listView = getListView(); - registerForContextMenu(listView); +// registerForContextMenu(recyclerView); filter.setFilterQueryOverride(null); - setListAdapter(taskAdapter); + recyclerAdapter.applyToRecyclerView(recyclerView); + recyclerView.setLayoutManager(new LinearLayoutManager(context)); loadTaskListContent(); if (getResources().getBoolean(R.bool.two_pane_layout)) { // In dual-pane mode, the list view highlights the selected item. - listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); - listView.setItemsCanFocus(false); +// listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); +// listView.setItemsCanFocus(false); } - - if (this instanceof SubtasksListFragment || this instanceof SubtasksTagListFragment || this instanceof GtasksSubtaskListFragment) { - return; - } - - listView.setOnItemClickListener((parent, view, position, id) -> { - if (taskAdapter != null) { - TodorooCursor cursor = (TodorooCursor) taskAdapter.getItem(position); - Task task = new Task(cursor); - if (task.isDeleted()) { - return; - } - - onTaskListItemClicked(id); - } - }); } - /* - * ====================================================================== - * ============================================================ lifecycle - * ====================================================================== - */ - @Override public void onResume() { super.onResume(); @@ -462,20 +422,24 @@ public class TaskListFragment extends InjectingListFragment implements Cursor taskCursor = taskAdapter.getCursor(); taskCursor.requery(); - taskAdapter.notifyDataSetChanged(); + recyclerAdapter.notifyDataSetChanged(); + if (recyclerAdapter.getItemCount() == 0) { + swipeRefreshLayout.setVisibility(View.GONE); + emptyRefreshLayout.setVisibility(View.VISIBLE); + } else { + swipeRefreshLayout.setVisibility(View.VISIBLE); + emptyRefreshLayout.setVisibility(View.GONE); + } } protected TaskAdapter createTaskAdapter(TodorooCursor cursor) { - - return new TaskAdapter(context, taskDao, this, cursor, - taskListDataProvider.getSqlQueryTemplate(), viewHolderFactory); + return new TaskAdapter(context, this, cursor); } public static final String TAGS_METADATA_JOIN = "for_tags"; //$NON-NLS-1$ public static final String FILE_METADATA_JOIN = "for_actions"; //$NON-NLS-1$ - /** * Fill in the Task List with current items */ @@ -491,6 +455,7 @@ public class TaskListFragment extends InjectingListFragment implements // set up list adapters taskAdapter = createTaskAdapter(currentCursor); + recyclerAdapter = new TaskListRecyclerAdapter(context, taskAdapter, viewHolderFactory); } public Property[] taskProperties() { @@ -501,8 +466,6 @@ public class TaskListFragment extends InjectingListFragment implements return filter; } - - public void reconstructCursor() { TodorooCursor cursor = taskListDataProvider.constructCursor(filter, taskProperties()); if (cursor == null || taskAdapter == null) { @@ -558,13 +521,13 @@ public class TaskListFragment extends InjectingListFragment implements timerPlugin.stopTimer(task); } - @Override - public void onListItemClick(ListView l, View v, int position, long id) { - super.onListItemClick(l, v, position, id); - if (getResources().getBoolean(R.bool.two_pane_layout)) { - setSelection(position); - } - } +// @Override +// public void onListItemClick(ListView l, View v, int position, long id) { +// super.onListItemClick(l, v, position, id); +// if (getResources().getBoolean(R.bool.two_pane_layout)) { +// setSelection(position); +// } +// } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { diff --git a/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java b/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java index 09b15b921..248f0e018 100644 --- a/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java +++ b/src/main/java/com/todoroo/astrid/adapter/TaskAdapter.java @@ -7,7 +7,6 @@ package com.todoroo.astrid.adapter; import android.content.Context; import android.database.Cursor; -import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CursorAdapter; @@ -18,22 +17,13 @@ import com.todoroo.andlib.data.Property.IntegerProperty; import com.todoroo.andlib.data.Property.LongProperty; import com.todoroo.andlib.data.Property.StringProperty; import com.todoroo.andlib.data.TodorooCursor; -import com.todoroo.andlib.sql.Criterion; -import com.todoroo.andlib.sql.Functions; -import com.todoroo.andlib.sql.Query; import com.todoroo.astrid.activity.TaskListFragment; -import com.todoroo.astrid.api.PermaSql; -import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskAttachment; import com.todoroo.astrid.tags.TaskToTagMetadata; -import org.tasks.R; import org.tasks.tasklist.ViewHolder; -import org.tasks.tasklist.ViewHolderFactory; - -import java.util.concurrent.atomic.AtomicReference; /** * Adapter for displaying a user's tasks as a list @@ -41,7 +31,7 @@ import java.util.concurrent.atomic.AtomicReference; * @author Tim Su * */ -public class TaskAdapter extends CursorAdapter implements Filterable { +public class TaskAdapter extends CursorAdapter implements Filterable, ViewHolder.ViewHolderCallbacks { public interface OnCompletedTaskListener { void onCompletedTask(Task item, boolean newState); @@ -75,94 +65,55 @@ public class TaskAdapter extends CursorAdapter implements Filterable { // --- instance variables - private final TaskDao taskDao; - private final TaskListFragment fragment; private OnCompletedTaskListener onCompletedTaskListener = null; - private final AtomicReference query; - - private final ViewHolderFactory viewHolderFactory; - - public TaskAdapter(Context context, TaskDao taskDao, TaskListFragment fragment, Cursor c, - AtomicReference query, ViewHolderFactory viewHolderFactory) { + public TaskAdapter(Context context, TaskListFragment fragment, Cursor c) { super(context, c, false); - this.taskDao = taskDao; - this.query = query; this.fragment = fragment; - this.viewHolderFactory = viewHolderFactory; } @Override - public Cursor runQueryOnBackgroundThread(CharSequence constraint) { - if (getFilterQueryProvider() != null) { - return getFilterQueryProvider().runQuery(constraint); - } - - return fetchFiltered(query.get(), constraint, fragment.taskProperties()); + public View newView(Context context, Cursor cursor, ViewGroup parent) { + throw new RuntimeException(); } - /** - * Fetch tasks for the given filter - * @param constraint text constraint, or null - */ - private TodorooCursor fetchFiltered(String queryTemplate, CharSequence constraint, - Property... properties) { - Criterion whereConstraint = null; - if(constraint != null) { - whereConstraint = Functions.upper(Task.TITLE).like("%" + - constraint.toString().toUpperCase() + "%"); - } - - if(queryTemplate == null) { - if(whereConstraint == null) { - return taskDao.query(Query.selectDistinct(properties)); - } else { - return taskDao.query(Query.selectDistinct(properties).where(whereConstraint)); - } - } - - String sql; - if(whereConstraint != null) { - if(!queryTemplate.toUpperCase().contains("WHERE")) { - sql = queryTemplate + " WHERE " + whereConstraint; - } else { - sql = queryTemplate.replace("WHERE ", "WHERE " + whereConstraint + " AND "); - } - } else { - sql = queryTemplate; - } + @Override + public void bindView(View view, Context context, Cursor c) { + throw new RuntimeException(); + } - sql = PermaSql.replacePlaceholders(sql); + public int getIndent(Task task) { + return 0; + } - return taskDao.query(Query.select(properties).withQueryTemplate(sql)); + public boolean canIndent(int position, Task task) { + return false; } - @Override - public View newView(Context context, Cursor cursor, ViewGroup parent) { - ViewGroup view = (ViewGroup) LayoutInflater.from(context) - .inflate(R.layout.task_adapter_row_simple, parent, false); + public boolean isManuallySorted() { + return false; + } - // create view holder - viewHolderFactory.newViewHolder(view, this::onTaskCompleted); + public void moved(int from, int to) { - return view; } - @Override - public void bindView(View view, Context context, Cursor c) { - TodorooCursor cursor = (TodorooCursor)c; - ViewHolder viewHolder = ((ViewHolder)view.getTag()); - viewHolder.bindView(cursor); + public void indented(int position, int delta) { - adjustView(viewHolder); } - protected void adjustView(ViewHolder viewHolder) { - + public Task getTask(int position) { + TodorooCursor c = (TodorooCursor) getCursor(); + if (c != null) { + if (c.moveToPosition(position)) { + return c.toModel(); + } + } + return null; } - public String getItemUuid(int position) { + protected String getItemUuid(int position) { TodorooCursor c = (TodorooCursor) getCursor(); if (c != null) { if (c.moveToPosition(position)) { @@ -175,28 +126,13 @@ public class TaskAdapter extends CursorAdapter implements Filterable { } } - public void onClick(View v) { - // expand view (unless deleted) - final ViewHolder viewHolder = (ViewHolder)v.getTag(); - if(viewHolder.task.isDeleted()) { - return; - } - - long taskId = viewHolder.task.getId(); - fragment.onTaskListItemClicked(taskId); - } - - /* ====================================================================== - * ======================================================= event handlers - * ====================================================================== */ - @Override - public void notifyDataSetChanged() { - super.notifyDataSetChanged(); - viewHolderFactory.updateTagMap(); + public void onClick(long id) { + fragment.onTaskListItemClicked(id); } - private void onTaskCompleted(Task task, boolean newState) { + @Override + public void onCompletedTask(Task task, boolean newState) { if (onCompletedTaskListener != null) { onCompletedTaskListener.onCompletedTask(task, newState); } diff --git a/src/main/java/com/todoroo/astrid/subtasks/AstridOrderedListFragmentHelper.java b/src/main/java/com/todoroo/astrid/subtasks/AstridOrderedListFragmentHelper.java index ed66ab09c..b2675c1cf 100644 --- a/src/main/java/com/todoroo/astrid/subtasks/AstridOrderedListFragmentHelper.java +++ b/src/main/java/com/todoroo/astrid/subtasks/AstridOrderedListFragmentHelper.java @@ -1,13 +1,8 @@ package com.todoroo.astrid.subtasks; -import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.text.TextUtils; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.View; -import android.widget.ListView; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.sql.Criterion; @@ -21,20 +16,11 @@ import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskListMetadata; -import com.todoroo.astrid.ui.DraggableListView; -import com.todoroo.astrid.ui.DraggableListView.DropListener; -import com.todoroo.astrid.ui.DraggableListView.GrabberClickListener; -import com.todoroo.astrid.ui.DraggableListView.SwipeListener; - -import org.tasks.R; -import org.tasks.tasklist.ViewHolder; -import org.tasks.tasklist.ViewHolderFactory; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import java.util.concurrent.atomic.AtomicReference; import javax.inject.Inject; @@ -42,58 +28,60 @@ import timber.log.Timber; class AstridOrderedListFragmentHelper { - private final DisplayMetrics metrics = new DisplayMetrics(); private final SubtasksFilterUpdater updater; private final TaskDao taskDao; - private final ViewHolderFactory viewHolderFactory; private DraggableTaskAdapter taskAdapter; private TaskListFragment fragment; private TaskListMetadata list; @Inject - AstridOrderedListFragmentHelper(SubtasksFilterUpdater updater, TaskDao taskDao, ViewHolderFactory viewHolderFactory) { + AstridOrderedListFragmentHelper(SubtasksFilterUpdater updater, TaskDao taskDao) { this.updater = updater; this.taskDao = taskDao; - this.viewHolderFactory = viewHolderFactory; } void setTaskListFragment(TaskListFragment fragment) { this.fragment = fragment; } - // --- ui component setup - - private Activity getActivity() { - return fragment.getActivity(); + void beforeSetUpTaskList(Filter filter) { + updater.initialize(list, filter); } - private ListView getListView() { - return fragment.getListView(); - } + TaskAdapter createTaskAdapter(Context context, TodorooCursor cursor) { + taskAdapter = new DraggableTaskAdapter(context, fragment, cursor); - private Filter getFilter() { - return fragment.getFilter(); - } + taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks); - void setUpUiComponents() { - TypedValue tv = new TypedValue(); - getActivity().getTheme().resolveAttribute(R.attr.colorAccent, tv, false); - DraggableListView draggableListView = (DraggableListView) fragment.getListView(); - draggableListView.setDragndropBackgroundColor(tv.data); - draggableListView.setDropListener(dropListener); - draggableListView.setClickListener(rowClickListener); - draggableListView.setSwipeListener(swipeListener); - getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics); + return taskAdapter; } - void beforeSetUpTaskList(Filter filter) { - updater.initialize(list, filter); - } + private final class DraggableTaskAdapter extends TaskAdapter { + + private DraggableTaskAdapter(Context context, TaskListFragment activity, Cursor c) { + super(context, activity, c); + } + + @Override + public int getIndent(Task task) { + return updater.getIndentForTask(task.getUuid()); + } + + @Override + public boolean canIndent(int position, Task task) { + String parentUuid = taskAdapter.getItemUuid(position - 1); + int parentIndent = updater.getIndentForTask(parentUuid); + return getIndent(task) <= parentIndent; + } - private final DropListener dropListener = new DropListener() { @Override - public void drop(int from, int to) { + public boolean isManuallySorted() { + return true; + } + + @Override + public void moved(int from, int to) { String targetTaskId = taskAdapter.getItemUuid(from); if (!RemoteModel.isValidUuid(targetTaskId)) { return; // This can happen with gestures on empty parts of the list (e.g. extra space below tasks) @@ -101,10 +89,10 @@ class AstridOrderedListFragmentHelper { String destinationTaskId = taskAdapter.getItemUuid(to); try { - if(to >= getListView().getCount()) { - updater.moveTo(list, getFilter(), targetTaskId, "-1"); //$NON-NLS-1$ + if(to >= taskAdapter.getCount()) { + updater.moveTo(list, fragment.getFilter(), targetTaskId, "-1"); //$NON-NLS-1$ } else { - updater.moveTo(list, getFilter(), targetTaskId, destinationTaskId); + updater.moveTo(list, fragment.getFilter(), targetTaskId, destinationTaskId); } } catch (Exception e) { Timber.e(e, e.getMessage()); @@ -113,26 +101,15 @@ class AstridOrderedListFragmentHelper { fragment.reconstructCursor(); fragment.loadTaskListContent(); } - }; - - private final SwipeListener swipeListener = new SwipeListener() { - @Override - public void swipeRight(int which) { - indent(which, 1); - } @Override - public void swipeLeft(int which) { - indent(which, -1); - } - - void indent(int which, int delta) { + public void indented(int which, int delta) { String targetTaskId = taskAdapter.getItemUuid(which); if (!RemoteModel.isValidUuid(targetTaskId)) { return; // This can happen with gestures on empty parts of the list (e.g. extra space below tasks) } try { - updater.indent(list, getFilter(), targetTaskId, delta); + updater.indent(list, fragment.getFilter(), targetTaskId, delta); } catch (Exception e) { Timber.e(e, e.getMessage()); } @@ -140,51 +117,6 @@ class AstridOrderedListFragmentHelper { fragment.reconstructCursor(); fragment.loadTaskListContent(); } - }; - - private final GrabberClickListener rowClickListener = new GrabberClickListener() { - @Override - public void onLongClick(final View v) { - if(v == null) { - return; - } - - fragment.registerForContextMenu(getListView()); - getListView().showContextMenuForChild(v); - fragment.unregisterForContextMenu(getListView()); - } - - @Override - public void onClick(View v) { - if(v == null) { - return; - } - taskAdapter.onClick(v); - } - }; - - TaskAdapter createTaskAdapter(Context context, TodorooCursor cursor, - AtomicReference sqlQueryTemplate) { - - taskAdapter = new DraggableTaskAdapter(context, fragment, cursor, sqlQueryTemplate); - - taskAdapter.setOnCompletedTaskListener(this::setCompletedForItemAndSubtasks); - - return taskAdapter; - } - - private final class DraggableTaskAdapter extends TaskAdapter { - - private DraggableTaskAdapter(Context context, TaskListFragment activity, Cursor c, - AtomicReference query) { - super(context, taskDao, activity, c, query, viewHolderFactory); - } - - @Override - protected void adjustView(ViewHolder vh) { - int indent = updater.getIndentForTask(vh.task.getUuid()); - vh.rowBody.setPadding(Math.round(indent * 20 * metrics.density), 0, 0, 0); - } } private final Map> chainedCompletions = @@ -250,13 +182,13 @@ class AstridOrderedListFragmentHelper { } void onCreateTask(String uuid) { - updater.onCreateTask(list, getFilter(), uuid); + updater.onCreateTask(list, fragment.getFilter(), uuid); fragment.reconstructCursor(); fragment.loadTaskListContent(); } void onDeleteTask(Task task) { - updater.onDeleteTask(list, getFilter(), task.getUuid()); + updater.onDeleteTask(list, fragment.getFilter(), task.getUuid()); taskAdapter.notifyDataSetInvalidated(); } } diff --git a/src/main/java/com/todoroo/astrid/subtasks/SubtasksListFragment.java b/src/main/java/com/todoroo/astrid/subtasks/SubtasksListFragment.java index 6aaeb98d2..ad7960c7b 100644 --- a/src/main/java/com/todoroo/astrid/subtasks/SubtasksListFragment.java +++ b/src/main/java/com/todoroo/astrid/subtasks/SubtasksListFragment.java @@ -7,10 +7,7 @@ package com.todoroo.astrid.subtasks; import android.app.Activity; import android.content.Context; -import android.os.Bundle; import android.text.TextUtils; -import android.view.View; -import android.widget.ListView; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.astrid.activity.TaskListFragment; @@ -22,7 +19,6 @@ import com.todoroo.astrid.dao.TaskListMetadataDao; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskListMetadata; -import org.tasks.R; import org.tasks.injection.ForApplication; import org.tasks.injection.FragmentComponent; import org.tasks.preferences.Preferences; @@ -44,8 +40,6 @@ public class SubtasksListFragment extends TaskListFragment { return fragment; } - private int lastVisibleIndex = -1; - @Inject Preferences preferences; @Inject @ForApplication Context context; @Inject TaskListMetadataDao taskListMetadataDao; @@ -60,18 +54,6 @@ public class SubtasksListFragment extends TaskListFragment { helper.setTaskListFragment(this); } - @Override - protected int getListBody() { - return R.layout.task_list_body_subtasks; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - helper.setUpUiComponents(); - } - @Override public void setTaskAdapter() { helper.setList(initializeTaskListMetadata()); @@ -108,22 +90,6 @@ public class SubtasksListFragment extends TaskListFragment { return taskListMetadata; } - @Override - public void onPause() { - super.onPause(); - lastVisibleIndex = getListView().getFirstVisiblePosition(); - } - - @Override - public void onResume() { - super.onResume(); - ListView listView = getListView(); - if (lastVisibleIndex >= 0) { - listView.setSelection(lastVisibleIndex); - } - unregisterForContextMenu(listView); - } - @Override public void onTaskCreated(String uuid) { helper.onCreateTask(uuid); @@ -137,7 +103,7 @@ public class SubtasksListFragment extends TaskListFragment { @Override protected TaskAdapter createTaskAdapter(TodorooCursor cursor) { - return helper.createTaskAdapter(theme.wrap(context), cursor, taskListDataProvider.getSqlQueryTemplate()); + return helper.createTaskAdapter(theme.wrap(context), cursor); } @Override diff --git a/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java b/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java index cd27eda22..4e716e40e 100644 --- a/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java +++ b/src/main/java/com/todoroo/astrid/subtasks/SubtasksTagListFragment.java @@ -20,7 +20,6 @@ import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskListMetadata; -import org.tasks.R; import org.tasks.injection.ForApplication; import org.tasks.injection.FragmentComponent; import org.tasks.tasklist.TagListFragment; @@ -42,8 +41,6 @@ public class SubtasksTagListFragment extends TagListFragment { @Inject Theme theme; @Inject AstridOrderedListFragmentHelper helper; - private int lastVisibleIndex = -1; - @Override public void onAttach(Activity activity) { super.onAttach(activity); @@ -51,18 +48,6 @@ public class SubtasksTagListFragment extends TagListFragment { helper.setTaskListFragment(this); } - @Override - protected int getListBody() { - return R.layout.task_list_body_subtasks; - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - helper.setUpUiComponents(); - } - @Override public void setTaskAdapter() { String tdId = tagData.getUuid(); @@ -78,21 +63,6 @@ public class SubtasksTagListFragment extends TagListFragment { super.setTaskAdapter(); } - @Override - public void onPause() { - super.onPause(); - lastVisibleIndex = getListView().getFirstVisiblePosition(); - } - - @Override - public void onResume() { - super.onResume(); - if (lastVisibleIndex >= 0) { - getListView().setSelection(lastVisibleIndex); - } - unregisterForContextMenu(getListView()); - } - @Override public void onTaskCreated(String uuid) { helper.onCreateTask(uuid); @@ -106,7 +76,7 @@ public class SubtasksTagListFragment extends TagListFragment { @Override protected TaskAdapter createTaskAdapter(TodorooCursor cursor) { - return helper.createTaskAdapter(theme.wrap(context), cursor, taskListDataProvider.getSqlQueryTemplate()); + return helper.createTaskAdapter(theme.wrap(context), cursor); } @Override diff --git a/src/main/java/com/todoroo/astrid/tags/TagService.java b/src/main/java/com/todoroo/astrid/tags/TagService.java index f69aa2ea5..fb19ffd4b 100644 --- a/src/main/java/com/todoroo/astrid/tags/TagService.java +++ b/src/main/java/com/todoroo/astrid/tags/TagService.java @@ -128,6 +128,10 @@ public final class TagService { return tagList; } + public TagData getTagByUuid(String uuid) { + return tagDataDao.getByUuid(uuid); + } + /** * If a tag already exists in the database that case insensitively matches the * given tag, return that. Otherwise, return the argument diff --git a/src/main/java/com/todoroo/astrid/ui/DraggableListView.java b/src/main/java/com/todoroo/astrid/ui/DraggableListView.java deleted file mode 100644 index 232939e9a..000000000 --- a/src/main/java/com/todoroo/astrid/ui/DraggableListView.java +++ /dev/null @@ -1,530 +0,0 @@ -/* - * Copyright (c) 2010 CommonsWare, LLC - * Portions Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.todoroo.astrid.ui; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.Bitmap; -import android.graphics.PixelFormat; -import android.graphics.Point; -import android.graphics.Rect; -import android.os.Vibrator; -import android.util.AttributeSet; -import android.view.Gravity; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.ImageView; -import android.widget.ListView; - -import com.todoroo.astrid.utility.Flags; - -import org.tasks.R; - -import timber.log.Timber; - -public class DraggableListView extends ListView { - - private static final int SWIPE_THRESHOLD = 40; - - private static final int MOVEMENT_THRESHOLD = 30; - - // --- drag status - private float mTouchStartX, mTouchCurrentX, mTouchStartY, mTouchCurrentY; - private boolean mDragging = false; - - private int mDragPos; // which item is being dragged - private int mFirstDragPos; // where was the dragged item originally - private Point mDragPoint; // at what offset inside the item did the user grab it - private Point mCoordOffset; // the difference between screen coordinates and coordinates in this view - - // --- drag drawing - private ImageView mDragView; - private WindowManager mWindowManager; - private WindowManager.LayoutParams mWindowParams; - private int mUpperBound; - private int mLowerBound; - private int mHeight; - private final Rect mTempRect = new Rect(); - private Bitmap mDragBitmap; - private final int mTouchSlop; - private int dragndropBackgroundColor = 0x00000000; - - // --- listeners - private DropListener mDropListener; - private SwipeListener mSwipeListener; - private GrabberClickListener mClickListener; - - // --- other instance variables - private int mItemHeightNormal = -1; - private Thread dragThread = null; - - // --- constructors - - public DraggableListView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public DraggableListView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); - - if (attrs != null) { - TypedArray a = getContext().obtainStyledAttributes(attrs, - R.styleable.TouchListView, 0, 0); - - mItemHeightNormal = a.getDimensionPixelSize( - R.styleable.TouchListView_normal_height, 0); - dragndropBackgroundColor = a.getColor( - R.styleable.TouchListView_dragndrop_background, 0x00000000); - - a.recycle(); - } - - setSelector(R.drawable.none); - } - - public void setItemHightNormal(int itemHeightNormal) { - this.mItemHeightNormal = itemHeightNormal; - } - - /* - * pointToPosition() doesn't consider invisible views, but we need to, so - * implement a slightly different version. - */ - private int myPointToPosition(int x, int y) { - Rect frame = mTempRect; - final int count = getChildCount(); - for (int i = count - 1; i >= 0; i--) { - final View child = getChildAt(i); - child.getHitRect(frame); - if (frame.contains(x, y)) { - return getFirstVisiblePosition() + i; - } - } - return INVALID_POSITION; - } - - private int getItemForPosition(int y) { - int adjustedy = y - mDragPoint.y - (mItemHeightNormal / 2); - int pos = myPointToPosition(0, adjustedy); - if (pos >= 0) { - if (pos <= mFirstDragPos) { - pos += 1; - } - } else if (adjustedy < 0) { - pos = 0; - } - return pos; - } - - private void adjustScrollBounds(int y) { - if (y >= mHeight / 3) { - mUpperBound = mHeight / 3; - } - if (y <= mHeight * 2 / 3) { - mLowerBound = mHeight * 2 / 3; - } - } - - /* - * Restore size and visibility for all list items - */ - private void unExpandViews() { - for (int i = 0;; i++) { - View v = getChildAt(i); - if (v == null) { - layoutChildren(); // force children to be recreated where needed - v = getChildAt(i); - if (v == null) { - break; - } - } - - ViewGroup.LayoutParams params = v.getLayoutParams(); - params.height = LayoutParams.WRAP_CONTENT; - v.setLayoutParams(params); - v.setVisibility(View.VISIBLE); - v.setPadding(0, 0, 0, 0); - } - } - - /* - * Adjust visibility and size to make it appear as though an item is being - * dragged around and other items are making room for it: If dropping the - * item would result in it still being in the same place, then make the - * dragged listitem's size normal, but make the item invisible. Otherwise, - * if the dragged list item is still on screen, make it as small as possible - * and expand the item below the insert point. If the dragged item is not on - * screen, only expand the item below the current insert point. - */ - private void doExpansion() { - int childnum = mDragPos - getFirstVisiblePosition(); - if (mDragPos > mFirstDragPos) { - childnum++; - } - - View first = getChildAt(mFirstDragPos - getFirstVisiblePosition()); - - for (int i = 0;; i++) { - View vv = getChildAt(i); - if (vv == null) { - break; - } - int height = LayoutParams.WRAP_CONTENT; - int marginTop = 0; - int visibility = View.VISIBLE; - if (vv.equals(first)) { - // processing the item that is being dragged - if (mDragPos == mFirstDragPos) { - // hovering over the original location - visibility = View.INVISIBLE; - } else { - // not hovering over it - height = 1; - } - } else if (i == childnum) { - if (mDragPos < getCount() - 1) { - marginTop = mItemHeightNormal; - height = 2 * mItemHeightNormal; - } - } - - ViewGroup.LayoutParams params = vv.getLayoutParams(); - params.height = height; - vv.setLayoutParams(params); - vv.setVisibility(visibility); - vv.setPadding(0, marginTop, 0, 0); - } - // Request re-layout since we changed the items layout - // and not doing this would cause bogus hitbox calculation - // in myPointToPosition - layoutChildren(); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - mTouchCurrentX = ev.getX(); - mTouchCurrentY = ev.getY(); - - int action = ev.getAction(); - switch (action) { - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - if(mDragging) { - stopDragging(); - } else { - if (dragThread != null && mClickListener != null) { - dragThread.interrupt(); - dragThread = null; - if (action == MotionEvent.ACTION_UP) { - mClickListener.onClick(viewAtPosition()); - } - } - - else if (mSwipeListener != null && - Math.abs(mTouchCurrentY - mTouchStartY) < MOVEMENT_THRESHOLD) { - int dragPos = pointToPosition((int)mTouchCurrentX, (int)mTouchCurrentY); - if (mTouchCurrentX > mTouchStartX + SWIPE_THRESHOLD) { - mSwipeListener.swipeRight(dragPos); - } else if (mTouchCurrentX < mTouchStartX - SWIPE_THRESHOLD) { - mSwipeListener.swipeLeft(dragPos); - } - } - } - - if(dragThread != null) { - dragThread.interrupt(); - dragThread = null; - } - - break; - - case MotionEvent.ACTION_DOWN: - dragThread = new Thread(new DragRunnable(ev)); - dragThread.start(); - stopDragging(); - - mTouchStartX = ev.getX(); - mTouchStartY = ev.getY(); - - case MotionEvent.ACTION_MOVE: - if(mDragging) { - dragView(ev); - } - - // detect scrolling - if(dragThread != null && (Math.abs(mTouchCurrentX - mTouchStartX) > MOVEMENT_THRESHOLD || - Math.abs(mTouchCurrentY - mTouchStartY) > MOVEMENT_THRESHOLD)) { - dragThread.interrupt(); - dragThread = null; - } - - break; - } - - if(mDragging) { - return true; - } - - return super.onTouchEvent(ev); - } - - private View viewAtPosition() { - int itemNum = pointToPosition((int) mTouchCurrentX, (int) mTouchCurrentY); - - if (itemNum == AdapterView.INVALID_POSITION) { - return null; - } - - return getChildAt(itemNum - getFirstVisiblePosition()); - } - - // --- drag logic - - private class DragRunnable implements Runnable { - - private final MotionEvent ev; - - public DragRunnable(MotionEvent ev) { - this.ev = ev; - } - - @Override - public void run() { - try { - Thread.sleep(300L); - - post(() -> initiateDrag(ev)); - - Thread.sleep(1000L); - - post(() -> { - stopDragging(); - dragThread = null; - Vibrator v = (Vibrator) getContext().getSystemService( - Context.VIBRATOR_SERVICE); - v.vibrate(50); - mClickListener.onLongClick(viewAtPosition()); - }); - - } catch (InterruptedException e) { - // bye! - Timber.v(e, e.getMessage()); - } - } - } - - private void initiateDrag(MotionEvent ev) { - int x = (int) mTouchCurrentX; - int y = (int) mTouchCurrentY; - int itemNum = pointToPosition(x, y); - - if (itemNum == AdapterView.INVALID_POSITION) { - return; - } - - View item = getChildAt(itemNum - getFirstVisiblePosition()); - - mDragPoint = new Point(x - item.getLeft(), y - item.getTop()); - mCoordOffset = new Point((int)ev.getRawX() - x, (int)ev.getRawY() - y); - - item.setDrawingCacheEnabled(true); - - // Create a copy of the drawing cache so that it does not get - // recycled by the framework when the list tries to clean up memory - Bitmap bitmap = Bitmap.createBitmap(item.getDrawingCache()); - item.setDrawingCacheEnabled(false); - - Rect listBounds = new Rect(); - - getGlobalVisibleRect(listBounds, null); - - startDragging(bitmap, listBounds.left, y); - mDragPos = itemNum; - mFirstDragPos = mDragPos; - mHeight = getHeight(); - - int touchSlop = mTouchSlop; - mUpperBound = Math.min(y - touchSlop, mHeight / 3); - mLowerBound = Math.max(y + touchSlop, mHeight * 2 / 3); - - Vibrator v = (Vibrator) getContext().getSystemService(Context.VIBRATOR_SERVICE); - v.vibrate(50); - } - - private void startDragging(Bitmap bm, int x, int y) { - mWindowParams = new WindowManager.LayoutParams(); - mWindowParams.gravity = Gravity.TOP | Gravity.START; - mWindowParams.x = x; - mWindowParams.y = y - mDragPoint.y + mCoordOffset.y; - - mWindowParams.height = WindowManager.LayoutParams.WRAP_CONTENT; - mWindowParams.width = WindowManager.LayoutParams.WRAP_CONTENT; - mWindowParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE - | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE - | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON - | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; - mWindowParams.format = PixelFormat.TRANSLUCENT; - mWindowParams.windowAnimations = 0; - - ImageView v = new ImageView(getContext()); - v.setBackgroundColor(dragndropBackgroundColor); - v.setImageBitmap(bm); - mDragBitmap = bm; - - mWindowManager = (WindowManager) getContext().getSystemService( - Context.WINDOW_SERVICE); - mWindowManager.addView(v, mWindowParams); - mDragView = v; - mDragging = true; - Flags.set(Flags.TLFP_NO_INTERCEPT_TOUCH); - } - - private void dragView(MotionEvent ev) { - int x = (int) ev.getX(); - int y = (int) ev.getY(); - - mWindowParams.y = y - mDragPoint.y + mCoordOffset.y; - - if (mDragPos == mFirstDragPos && x > mTouchStartX + SWIPE_THRESHOLD) { - mDragView.setPadding(30, 1, 0, 1); - } else if (mDragPos == mFirstDragPos && x < mTouchStartX - SWIPE_THRESHOLD) { - mDragView.setPadding(-30, 2, 0, 2); - } else { - mDragView.setPadding(0, 0, 0, 0); - } - - mWindowManager.updateViewLayout(mDragView, mWindowParams); - - int itemnum = getItemForPosition(y); - if (itemnum >= 0) { - if (ev.getAction() == MotionEvent.ACTION_DOWN - || itemnum != mDragPos) { - mDragPos = itemnum; - doExpansion(); - } - int speed = 0; - adjustScrollBounds(y); - if (y > mLowerBound) { - // scroll the list up a bit - speed = y > (mHeight + mLowerBound) / 2 ? 16 : 4; - } else if (y < mUpperBound) { - // scroll the list down a bit - speed = y < mUpperBound / 2 ? -16 : -4; - } - if (speed != 0) { - int ref = pointToPosition(0, mHeight / 2); - if (ref == AdapterView.INVALID_POSITION) { - // we hit a divider or an invisible view, check - // somewhere else - ref = pointToPosition(0, mHeight / 2 - + getDividerHeight() + 64); - } - View v = getChildAt(ref - getFirstVisiblePosition()); - if (v != null) { - int pos = v.getTop(); - setSelectionFromTop(ref, pos - speed); - } - } - } - } - - private void stopDragging() { - if (mDragBitmap != null) { - mDragBitmap.recycle(); - mDragBitmap = null; - } - - unExpandViews(); - - if (mDragView != null) { - WindowManager wm = (WindowManager) getContext().getSystemService( - Context.WINDOW_SERVICE); - wm.removeView(mDragView); - mDragView.setImageDrawable(null); - mDragView = null; - } - - if(mDragging) { - if (mSwipeListener != null && mDragPos == mFirstDragPos) { - if (mTouchCurrentX > mTouchStartX + SWIPE_THRESHOLD) { - mSwipeListener.swipeRight(mFirstDragPos); - } else if (mTouchCurrentX < mTouchStartX - SWIPE_THRESHOLD) { - mSwipeListener.swipeLeft(mFirstDragPos); - } - } else if(mDropListener != null && mDragPos != mFirstDragPos && - mDragPos >= 0 && mDragPos < getCount()) { - if(mFirstDragPos < mDragPos) { - mDragPos++; - } - mDropListener.drop(mFirstDragPos, mDragPos); - } - } - - mDragging = false; - Flags.checkAndClear(Flags.TLFP_NO_INTERCEPT_TOUCH); - } - - // --- getters and setters - - public void setDropListener(DropListener l) { - mDropListener = l; - } - - public void setSwipeListener(SwipeListener l) { - mSwipeListener = l; - } - - public void setClickListener(GrabberClickListener listener) { - this.mClickListener = listener; - } - - public void setDragndropBackgroundColor(int color) { - this.dragndropBackgroundColor = color; - } - - @Override - final public void addHeaderView(View v, Object data, boolean isSelectable) { - throw new RuntimeException( - "Headers are not supported with TouchListView"); - } - - @Override - final public void addHeaderView(View v) { - throw new RuntimeException( - "Headers are not supported with TouchListView"); - } - - public interface GrabberClickListener { - void onClick(View v); - void onLongClick(View v); - } - - public interface DropListener { - void drop(int from, int to); - } - public interface SwipeListener { - void swipeLeft(int which); - void swipeRight(int which); - } -} diff --git a/src/main/java/org/tasks/activities/FilterSettingsActivity.java b/src/main/java/org/tasks/activities/FilterSettingsActivity.java index 7e376ed03..8890a25f4 100644 --- a/src/main/java/org/tasks/activities/FilterSettingsActivity.java +++ b/src/main/java/org/tasks/activities/FilterSettingsActivity.java @@ -70,7 +70,7 @@ public class FilterSettingsActivity extends ThemedInjectingAppCompatActivity imp save(); } }); - toolbar.inflateMenu(R.menu.tag_settings_activity); + toolbar.inflateMenu(R.menu.menu_tag_settings); toolbar.setOnMenuItemClickListener(this); MenuColorizer.colorToolbar(this, toolbar); diff --git a/src/main/java/org/tasks/activities/TagSettingsActivity.java b/src/main/java/org/tasks/activities/TagSettingsActivity.java index 01d1ef9c6..1edbc7638 100644 --- a/src/main/java/org/tasks/activities/TagSettingsActivity.java +++ b/src/main/java/org/tasks/activities/TagSettingsActivity.java @@ -109,7 +109,7 @@ public class TagSettingsActivity extends ThemedInjectingAppCompatActivity implem save(); } }); - toolbar.inflateMenu(R.menu.tag_settings_activity); + toolbar.inflateMenu(R.menu.menu_tag_settings); toolbar.setOnMenuItemClickListener(this); toolbar.showOverflowMenu(); diff --git a/src/main/java/org/tasks/data/TaskListDataProvider.java b/src/main/java/org/tasks/data/TaskListDataProvider.java index d89348cbd..b58f1d38f 100644 --- a/src/main/java/org/tasks/data/TaskListDataProvider.java +++ b/src/main/java/org/tasks/data/TaskListDataProvider.java @@ -39,10 +39,6 @@ public class TaskListDataProvider { this.preferences = preferences; } - public AtomicReference getSqlQueryTemplate() { - return sqlQueryTemplate; - } - public TodorooCursor constructCursor(Filter filter, Property[] properties) { Criterion tagsJoinCriterion = Criterion.and( Field.field(TAGS_METADATA_JOIN + "." + Metadata.KEY.name).eq(TaskToTagMetadata.KEY), //$NON-NLS-1$ diff --git a/src/main/java/org/tasks/tasklist/TagFormatter.java b/src/main/java/org/tasks/tasklist/TagFormatter.java index 7872eaef3..471b0e0b5 100644 --- a/src/main/java/org/tasks/tasklist/TagFormatter.java +++ b/src/main/java/org/tasks/tasklist/TagFormatter.java @@ -46,16 +46,13 @@ public class TagFormatter { TypedValue typedValue = new TypedValue(); context.getResources().getValue(R.dimen.tag_characters, typedValue, true); tagCharacters = typedValue.getFloat(); - } - public void updateTagMap() { - tagMap.clear(); for (TagData tagData : tagService.getTagList()) { tagMap.put(tagData.getUuid(), tagData); } } - public CharSequence getTagString(List tagUuids) { + CharSequence getTagString(List tagUuids) { Iterable t = filter(transform(tagUuids, uuidToTag), Predicates.notNull()); List firstFourByName = orderByName.leastOf(t, 4); int numTags = firstFourByName.size(); @@ -99,7 +96,16 @@ public class TagFormatter { }; } - private final Function uuidToTag = tagMap::get; + private TagData getTag(String uuid) { + TagData tagData = tagMap.get(uuid); + if (tagData == null) { + tagData = tagService.getTagByUuid(uuid); + tagMap.put(uuid, tagData); + } + return tagData; + } + + private final Function uuidToTag = this::getTag; private final Ordering orderByName = new Ordering() { @Override diff --git a/src/main/java/org/tasks/tasklist/TagListFragment.java b/src/main/java/org/tasks/tasklist/TagListFragment.java index 3405ea5af..fbf05cd09 100644 --- a/src/main/java/org/tasks/tasklist/TagListFragment.java +++ b/src/main/java/org/tasks/tasklist/TagListFragment.java @@ -96,13 +96,6 @@ public class TagListFragment extends TaskListFragment { } } - @Override - public void onActivityCreated(final Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - getListView().setOnKeyListener(null); - } - @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); diff --git a/src/main/java/org/tasks/tasklist/TaskListRecyclerAdapter.java b/src/main/java/org/tasks/tasklist/TaskListRecyclerAdapter.java new file mode 100644 index 000000000..07f0b2a44 --- /dev/null +++ b/src/main/java/org/tasks/tasklist/TaskListRecyclerAdapter.java @@ -0,0 +1,134 @@ +package org.tasks.tasklist; + +import android.content.Context; +import android.database.Cursor; +import android.graphics.Canvas; +import android.support.v7.widget.RecyclerView; +import android.support.v7.widget.helper.ItemTouchHelper; +import android.view.LayoutInflater; +import android.view.ViewGroup; + +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.astrid.adapter.TaskAdapter; +import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.utility.Flags; + +import org.tasks.R; + +public class TaskListRecyclerAdapter extends RecyclerView.Adapter { + + private final Context context; + private final TaskAdapter adapter; + private final ViewHolderFactory viewHolderFactory; + private final ItemTouchHelper itemTouchHelper; + + public TaskListRecyclerAdapter(Context context, TaskAdapter adapter, ViewHolderFactory viewHolderFactory) { + this.context = context; + this.adapter = adapter; + this.viewHolderFactory = viewHolderFactory; + itemTouchHelper = new ItemTouchHelper(new ItemTouchHelperCallback()); + } + + public void applyToRecyclerView(RecyclerView recyclerView) { + recyclerView.setAdapter(this); + itemTouchHelper.attachToRecyclerView(recyclerView); + } + + @Override + public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + ViewGroup view = (ViewGroup) LayoutInflater.from(context) + .inflate(R.layout.task_adapter_row_simple, parent, false); + return viewHolderFactory.newViewHolder(view, adapter); + } + + @Override + public void onBindViewHolder(ViewHolder holder, int position) { + Cursor cursor = adapter.getCursor(); + cursor.moveToPosition(position); + holder.bindView((TodorooCursor) cursor); + holder.setIndent(adapter.getIndent(holder.task)); + } + + @Override + public int getItemCount() { + return adapter.getCount(); + } + + private class ItemTouchHelperCallback extends ItemTouchHelper.Callback { + + private int from = -1; + private int to = -1; + + @Override + public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + if (!adapter.isManuallySorted()) { + return makeMovementFlags(0, 0); + } + + ViewHolder vh = (ViewHolder) viewHolder; + int indentFlags = 0; + if (vh.isIndented()) { + indentFlags |= ItemTouchHelper.LEFT; + } + int position = vh.getAdapterPosition(); + if (position > 0 && adapter.canIndent(position, vh.task)) { + indentFlags |= ItemTouchHelper.RIGHT; + } + return makeMovementFlags(ItemTouchHelper.UP | ItemTouchHelper.DOWN, indentFlags); + } + + @Override + public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { + super.onSelectedChanged(viewHolder, actionState); + Flags.set(Flags.TLFP_NO_INTERCEPT_TOUCH); + } + + @Override + public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) { + int fromPosition = source.getAdapterPosition(); + int toPosition = target.getAdapterPosition(); + if (from == -1) { + from = fromPosition; + } + to = toPosition; + notifyItemMoved(fromPosition, toPosition); + return true; + } + + @Override + public float getSwipeThreshold(RecyclerView.ViewHolder viewHolder) { + return .2f; + } + + @Override + public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, float dX, float dY, int actionState, boolean isCurrentlyActive) { + if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) { + float shiftSize = ((ViewHolder) viewHolder).getShiftSize(); + dX = Math.max(-shiftSize, Math.min(shiftSize, dX)); + } + super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); + } + + @Override + public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) { + super.clearView(recyclerView, viewHolder); + + if (from >= 0 && from != to) { + if (from < to) { + to++; + } + adapter.moved(from, to); + } + from = -1; + to = -1; + Flags.checkAndClear(Flags.TLFP_NO_INTERCEPT_TOUCH); + } + + @Override + public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { + adapter.indented( + viewHolder.getAdapterPosition(), + direction == ItemTouchHelper.RIGHT ? 1 : -1); + } + } +} diff --git a/src/main/java/org/tasks/tasklist/ViewHolder.java b/src/main/java/org/tasks/tasklist/ViewHolder.java index 5a498845b..856461751 100644 --- a/src/main/java/org/tasks/tasklist/ViewHolder.java +++ b/src/main/java/org/tasks/tasklist/ViewHolder.java @@ -4,10 +4,12 @@ import android.app.PendingIntent; import android.content.Context; import android.graphics.Paint; import android.support.v7.app.AlertDialog; +import android.support.v7.widget.RecyclerView; import android.text.SpannableString; import android.text.TextUtils; import android.text.method.LinkMovementMethod; import android.text.util.Linkify; +import android.util.DisplayMetrics; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -37,25 +39,29 @@ import butterknife.ButterKnife; import timber.log.Timber; import static com.google.common.collect.Lists.newArrayList; +import static com.todoroo.andlib.utility.AndroidUtilities.atLeastLollipop; /** * View Holder saves a lot of findViewById lookups. * * @author Tim Su */ -public class ViewHolder { +public class ViewHolder extends RecyclerView.ViewHolder { - public interface OnCompletedTaskCallback { + public interface ViewHolderCallbacks { void onCompletedTask(Task task, boolean newState); + + void onClick(long id); } - @BindView(R.id.rowBody) public ViewGroup rowBody; + @BindView(R.id.row) public ViewGroup row; + @BindView(R.id.rowBody) ViewGroup rowBody; @BindView(R.id.title) TextView nameView; - @BindView(R.id.completeBox) public CheckableImageView completeBox; + @BindView(R.id.completeBox) CheckableImageView completeBox; @BindView(R.id.due_date) public TextView dueDate; @BindView(R.id.tag_block) TextView tagBlock; - @BindView(R.id.taskActionContainer) public View taskActionContainer; - @BindView(R.id.taskActionIcon) public ImageView taskActionIcon; + @BindView(R.id.taskActionContainer) View taskActionContainer; + @BindView(R.id.taskActionIcon) ImageView taskActionIcon; public Task task; @@ -70,14 +76,18 @@ public class ViewHolder { private final int textColorHint; private final TaskDao taskDao; private final DialogBuilder dialogBuilder; - private final OnCompletedTaskCallback callback; + private final ViewHolderCallbacks callback; + private final DisplayMetrics metrics; private final int textColorOverdue; private Pair lastTouchYRawY = new Pair<>(0f, 0f); + private int indent; public ViewHolder(Context context, ViewGroup view, boolean showFullTaskTitle, int fontSize, CheckBoxes checkBoxes, TagFormatter tagFormatter, int textColorOverdue, int textColorSecondary, int textColorHint, TaskDao taskDao, - DialogBuilder dialogBuilder, OnCompletedTaskCallback callback, int minRowHeight) { + DialogBuilder dialogBuilder, ViewHolderCallbacks callback, int minRowHeight, + DisplayMetrics metrics) { + super(view); this.context = context; this.fontSize = fontSize; this.checkBoxes = checkBoxes; @@ -88,6 +98,7 @@ public class ViewHolder { this.taskDao = taskDao; this.dialogBuilder = dialogBuilder; this.callback = callback; + this.metrics = metrics; ButterKnife.bind(this, view); task = new Task(); @@ -108,7 +119,30 @@ public class ViewHolder { addListeners(); } - public void bindView(TodorooCursor cursor) { + public void setIndent(int indent) { + this.indent = indent; + int indentSize = getIndentSize(indent); + if (atLeastLollipop()) { + ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) row.getLayoutParams(); + layoutParams.setMarginStart(indentSize); + } else { + rowBody.setPadding(indentSize, row.getPaddingTop(), 0, row.getPaddingBottom()); + } + } + + float getShiftSize() { + return 20 * metrics.density; + } + + private int getIndentSize(int indent) { + return Math.round(indent * getShiftSize()); + } + + boolean isIndented() { + return indent > 0; + } + + void bindView(TodorooCursor cursor) { tagsString = cursor.get(TaskAdapter.TAGS); hasFiles = cursor.get(TaskAdapter.FILE_ID_PROPERTY) > 0; hasNotes = cursor.get(TaskAdapter.HAS_NOTES_PROPERTY) > 0; @@ -120,7 +154,7 @@ public class ViewHolder { setTaskAppearance(); } - public void setMinimumHeight(int minRowHeight) { + private void setMinimumHeight(int minRowHeight) { if (fontSize < 16) { rowBody.setMinimumHeight(0); completeBox.setMinimumHeight(0); @@ -167,7 +201,7 @@ public class ViewHolder { return LinkActionExposer.getActionsForTask(context, task, hasFiles, hasNotes); } - public void setTaskAppearance() { + private void setTaskAppearance() { boolean completed = task.isCompleted(); TextView name = nameView; @@ -258,6 +292,12 @@ public class ViewHolder { completeBox.setOnTouchListener(otl); completeBox.setOnClickListener(completeBoxListener); + rowBody.setOnClickListener(view -> { + if (!task.isDeleted()) { + callback.onClick(task.getId()); + } + }); + if (taskActionContainer != null) { taskActionContainer.setOnClickListener(v -> { TaskAction action = (TaskAction) taskActionIcon.getTag(); diff --git a/src/main/java/org/tasks/tasklist/ViewHolderFactory.java b/src/main/java/org/tasks/tasklist/ViewHolderFactory.java index a3b77a8cf..fcfffffbd 100644 --- a/src/main/java/org/tasks/tasklist/ViewHolderFactory.java +++ b/src/main/java/org/tasks/tasklist/ViewHolderFactory.java @@ -30,6 +30,7 @@ public class ViewHolderFactory { private final TaskDao taskDao; private final DialogBuilder dialogBuilder; private final int minRowHeight; + private final DisplayMetrics metrics; @Inject public ViewHolderFactory(@ForActivity Context context, Preferences preferences, @@ -45,18 +46,13 @@ public class ViewHolderFactory { textColorOverdue = getColor(context, R.color.overdue); showFullTaskTitle = preferences.getBoolean(R.string.p_fullTaskTitle, false); fontSize = preferences.getIntegerFromString(R.string.p_fontSize, 18); - tagFormatter.updateTagMap(); - DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + metrics = context.getResources().getDisplayMetrics(); minRowHeight = (int) (metrics.density * 40); } - public ViewHolder newViewHolder(ViewGroup viewGroup, ViewHolder.OnCompletedTaskCallback onCompletedTaskCallback) { + ViewHolder newViewHolder(ViewGroup viewGroup, ViewHolder.ViewHolderCallbacks callbacks) { return new ViewHolder(context, viewGroup, showFullTaskTitle, fontSize, checkBoxes, tagFormatter, textColorOverdue, textColorSecondary, textColorHint, taskDao, - dialogBuilder, onCompletedTaskCallback, minRowHeight); - } - - public void updateTagMap() { - tagFormatter.updateTagMap(); + dialogBuilder, callbacks, minRowHeight, metrics); } } diff --git a/src/main/java/org/tasks/themes/ThemeCache.java b/src/main/java/org/tasks/themes/ThemeCache.java index 3c03754c4..814f3cac9 100644 --- a/src/main/java/org/tasks/themes/ThemeCache.java +++ b/src/main/java/org/tasks/themes/ThemeCache.java @@ -25,11 +25,11 @@ public class ThemeCache { public ThemeCache(Context context) { Resources resources = context.getResources(); - themes.add(new ThemeBase(context.getString(R.string.theme_light), 0, getColor(context, R.color.md_background_light), AppCompatDelegate.MODE_NIGHT_NO)); + themes.add(new ThemeBase(context.getString(R.string.theme_light), 0, getColor(context, R.color.grey_50), AppCompatDelegate.MODE_NIGHT_NO)); themes.add(new ThemeBase(context.getString(R.string.theme_black), 1, getColor(context, R.color.widget_background_black), AppCompatDelegate.MODE_NIGHT_YES)); themes.add(new ThemeBase(context.getString(R.string.theme_dark), 2, getColor(context, R.color.md_background_dark), AppCompatDelegate.MODE_NIGHT_YES)); themes.add(new ThemeBase(context.getString(R.string.theme_wallpaper), 3, getColor(context, R.color.black_38), AppCompatDelegate.MODE_NIGHT_YES)); - themes.add(new ThemeBase(context.getString(R.string.theme_day_night), 4, getColor(context, R.color.md_background_light), AppCompatDelegate.MODE_NIGHT_AUTO)); + themes.add(new ThemeBase(context.getString(R.string.theme_day_night), 4, getColor(context, R.color.grey_50), AppCompatDelegate.MODE_NIGHT_AUTO)); String[] colorNames = resources.getStringArray(R.array.colors); for (int i = 0 ; i < ThemeColor.COLORS.length ; i++) { diff --git a/src/main/java/org/tasks/themes/WidgetTheme.java b/src/main/java/org/tasks/themes/WidgetTheme.java index 2f76bb466..7dba03166 100644 --- a/src/main/java/org/tasks/themes/WidgetTheme.java +++ b/src/main/java/org/tasks/themes/WidgetTheme.java @@ -4,7 +4,7 @@ import org.tasks.R; public class WidgetTheme { public static final int[] BACKGROUNDS = new int[] { - R.color.md_background_light, + R.color.grey_50, R.color.widget_background_black, R.color.md_background_dark }; diff --git a/src/main/res/layout-v21/task_adapter_row_simple.xml b/src/main/res/layout-v21/task_adapter_row_simple.xml new file mode 100644 index 000000000..355486906 --- /dev/null +++ b/src/main/res/layout-v21/task_adapter_row_simple.xml @@ -0,0 +1,19 @@ + + + + + + diff --git a/src/main/res/layout/beast_mode_pref_activity.xml b/src/main/res/layout/beast_mode_pref_activity.xml index d9ef07c83..60d2d6784 100644 --- a/src/main/res/layout/beast_mode_pref_activity.xml +++ b/src/main/res/layout/beast_mode_pref_activity.xml @@ -2,13 +2,13 @@ + android:orientation="vertical"> diff --git a/src/main/res/layout/fragment_task_edit.xml b/src/main/res/layout/fragment_task_edit.xml index 45cd8ad28..4bbf2198e 100644 --- a/src/main/res/layout/fragment_task_edit.xml +++ b/src/main/res/layout/fragment_task_edit.xml @@ -15,7 +15,9 @@ android:layout_height="0dp" android:layout_weight="100" android:background="?attr/asContentBackground" - android:overScrollMode="never"> + android:elevation="0dp" + android:overScrollMode="never" + android:scrollbarStyle="outsideOverlay"> diff --git a/src/main/res/layout/fragment_task_edit_empty.xml b/src/main/res/layout/fragment_task_edit_empty.xml index 8e19bb0e5..77419d694 100644 --- a/src/main/res/layout/fragment_task_edit_empty.xml +++ b/src/main/res/layout/fragment_task_edit_empty.xml @@ -2,9 +2,13 @@ + + diff --git a/src/main/res/layout/fragment_task_list.xml b/src/main/res/layout/fragment_task_list.xml index 9827492e5..d04e75eb6 100644 --- a/src/main/res/layout/fragment_task_list.xml +++ b/src/main/res/layout/fragment_task_list.xml @@ -23,14 +23,16 @@ + android:orientation="horizontal" + android:background="?attr/asWindowBackground" + android:elevation="@dimen/elevation_task_list"> + android:layout_height="match_parent"> + + @@ -40,7 +42,6 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/layout/task_adapter_row_simple.xml b/src/main/res/layout/task_adapter_row_simple.xml index 15a232693..7d261e80e 100644 --- a/src/main/res/layout/task_adapter_row_simple.xml +++ b/src/main/res/layout/task_adapter_row_simple.xml @@ -1,133 +1,11 @@ - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/main/res/layout/task_list_body_empty.xml b/src/main/res/layout/task_list_body_empty.xml index d8802c1c2..23e4fc1a1 100644 --- a/src/main/res/layout/task_list_body_empty.xml +++ b/src/main/res/layout/task_list_body_empty.xml @@ -4,12 +4,13 @@ style="@style/task_list_container" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:elevation="@dimen/elevation_task_list" tools:ignore="UnusedAttribute"> + android:layout_height="wrap_content" + android:elevation="@dimen/elevation_task_list" + android:background="?attr/asWindowBackground"> - + - + diff --git a/src/main/res/layout/task_list_body_subtasks.xml b/src/main/res/layout/task_list_body_subtasks.xml deleted file mode 100644 index ebcec0ebb..000000000 --- a/src/main/res/layout/task_list_body_subtasks.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/src/main/res/layout/task_list_footer.xml b/src/main/res/layout/task_list_footer.xml deleted file mode 100644 index b159a0d93..000000000 --- a/src/main/res/layout/task_list_footer.xml +++ /dev/null @@ -1,5 +0,0 @@ - - diff --git a/src/main/res/menu/tag_settings_activity.xml b/src/main/res/menu/menu_tag_settings.xml similarity index 100% rename from src/main/res/menu/tag_settings_activity.xml rename to src/main/res/menu/menu_tag_settings.xml diff --git a/src/main/res/menu/task_edit_fragment.xml b/src/main/res/menu/menu_task_edit_fragment.xml similarity index 100% rename from src/main/res/menu/task_edit_fragment.xml rename to src/main/res/menu/menu_task_edit_fragment.xml diff --git a/src/main/res/values-night/colors.xml b/src/main/res/values-night/colors.xml index c37bb8e88..c4126c5f3 100644 --- a/src/main/res/values-night/colors.xml +++ b/src/main/res/values-night/colors.xml @@ -1,7 +1,8 @@ - @color/md_background_dark - @color/md_background_dark_dialog + @color/md_background_dark + @color/grey_800 + @color/grey_800 @color/icon_tint_dark @color/drawer_background_dark @color/drawer_background_dark_selected diff --git a/src/main/res/values-notnight/colors.xml b/src/main/res/values-notnight/colors.xml index f03e50dd3..a2de3ca2f 100644 --- a/src/main/res/values-notnight/colors.xml +++ b/src/main/res/values-notnight/colors.xml @@ -1,7 +1,8 @@ - @color/md_background_light - @color/md_background_light_dialog + @color/grey_50 + @android:color/white + @android:color/white @color/icon_tint_light @color/drawer_background_light @color/drawer_background_light_selected diff --git a/src/main/res/values-w820dp/styles.xml b/src/main/res/values-w820dp/styles.xml index 4ae1b98de..f2618edea 100644 --- a/src/main/res/values-w820dp/styles.xml +++ b/src/main/res/values-w820dp/styles.xml @@ -1,7 +1,7 @@ \ No newline at end of file diff --git a/src/main/res/values/theme_dark_grey.xml b/src/main/res/values/theme_dark_grey.xml index ef79f693e..7e333fb01 100644 --- a/src/main/res/values/theme_dark_grey.xml +++ b/src/main/res/values/theme_dark_grey.xml @@ -2,7 +2,7 @@ \ No newline at end of file