From 55d3525869e48b83248fec4546981fd5742c17e0 Mon Sep 17 00:00:00 2001 From: geoffroy Date: Mon, 11 Jan 2016 17:22:02 -0500 Subject: [PATCH] New categories in Settings New type of task layout without description and with bigger title Old layout is now called Detailed Possibility to choose layout in Settings Task list delete confirmation checkbox "never ask again" implemented and present in Settings Divider between tasks Design changes (different colors on Swipe) Data validation on new task and new task list Correction of database open bug in Task List fragment --- DoNExt/app/build.gradle | 4 +- .../adapters/TaskRecyclerViewAdapter.java | 63 +++++-- .../donext/database/TaskDataAccess.java | 28 --- .../donext/database/TaskListDataAccess.java | 2 - .../donext/fragments/TaskDialogFragment.java | 38 +++- .../donext/fragments/TaskListsFragment.java | 62 ++++--- .../donext/fragments/TasksFragment.java | 170 ++++++++---------- .../donext/helpers/TaskTouchHelper.java | 15 +- .../donext/widgets/DividerItemDecoration.java | 54 ++++++ .../app/src/main/res/drawable/task_select.xml | 3 +- .../res/layout/fragment_task_confirmation.xml | 4 +- ...nt_task.xml => fragment_task_detailed.xml} | 5 +- ...ask_details.xml => fragment_task_form.xml} | 7 +- .../main/res/layout/fragment_task_simple.xml | 24 +++ .../src/main/res/layout/fragment_tasks.xml | 6 +- DoNExt/app/src/main/res/values/strings.xml | 16 +- DoNExt/app/src/main/res/xml/preferences.xml | 56 +++--- 17 files changed, 354 insertions(+), 203 deletions(-) create mode 100644 DoNExt/app/src/main/java/com/wismna/geoffroy/donext/widgets/DividerItemDecoration.java rename DoNExt/app/src/main/res/layout/{fragment_task.xml => fragment_task_detailed.xml} (89%) rename DoNExt/app/src/main/res/layout/{fragment_task_details.xml => fragment_task_form.xml} (91%) create mode 100644 DoNExt/app/src/main/res/layout/fragment_task_simple.xml diff --git a/DoNExt/app/build.gradle b/DoNExt/app/build.gradle index 689fb77..6f7b3d7 100644 --- a/DoNExt/app/build.gradle +++ b/DoNExt/app/build.gradle @@ -8,8 +8,8 @@ android { applicationId "com.wismna.geoffroy.donext" minSdkVersion 15 targetSdkVersion 23 - versionCode 3 - versionName "0.3" + versionCode 5 + versionName "0.5" } buildTypes { release { diff --git a/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/adapters/TaskRecyclerViewAdapter.java b/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/adapters/TaskRecyclerViewAdapter.java index 161100d..3e8fc19 100644 --- a/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/adapters/TaskRecyclerViewAdapter.java +++ b/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/adapters/TaskRecyclerViewAdapter.java @@ -17,29 +17,41 @@ import java.util.List; /** * {@link RecyclerView.Adapter} that can display a {@link Task}. */ -public class TaskRecyclerViewAdapter extends RecyclerView.Adapter { +public class TaskRecyclerViewAdapter extends RecyclerView.Adapter { private final List mValues; + private int viewType; - public TaskRecyclerViewAdapter(List items) { + public TaskRecyclerViewAdapter(List items, int viewType) { mValues = items; + this.viewType = viewType; } @Override - public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View view = LayoutInflater.from(parent.getContext()) - .inflate(R.layout.fragment_task, parent, false); - - return new ViewHolder(view); + public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View view; + switch (viewType) + { + case 1: + view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.fragment_task_simple, parent, false); + return new SimpleViewHolder(view); + case 2: + view = LayoutInflater.from(parent.getContext()) + .inflate(R.layout.fragment_task_detailed, parent, false); + return new DetailedViewHolder(view); + } + return null; } @Override - public void onBindViewHolder(final ViewHolder holder, int position) { + public void onBindViewHolder(final SimpleViewHolder holder, int position) { holder.mItem = mValues.get(position); holder.mIdView.setText(String.valueOf(holder.mItem.getId())); holder.mCycleView.setText(String.valueOf(holder.mItem.getCycle())); holder.mTitleView.setText(holder.mItem.getName()); - holder.mDescriptionView.setText(holder.mItem.getDescription()); + if (holder instanceof DetailedViewHolder) + ((DetailedViewHolder)holder).mDescriptionView.setText(holder.mItem.getDescription()); int priority = holder.mItem.getPriority(); // Reset task rendering @@ -67,6 +79,11 @@ public class TaskRecyclerViewAdapter extends RecyclerView.Adapter doInBackground(TaskListDataAccess... params) { TaskListDataAccess taskListDataAccess = params[0]; - taskListDataAccess.open(); - List taskLists = taskListDataAccess.getAllTaskLists(); - taskListDataAccess.close(); - return taskLists; + return taskListDataAccess.getAllTaskLists(); } @Override diff --git a/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/fragments/TasksFragment.java b/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/fragments/TasksFragment.java index abea386..a25aa96 100644 --- a/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/fragments/TasksFragment.java +++ b/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/fragments/TasksFragment.java @@ -31,6 +31,7 @@ import com.wismna.geoffroy.donext.dao.TaskList; import com.wismna.geoffroy.donext.database.TaskDataAccess; import com.wismna.geoffroy.donext.helpers.TaskTouchHelper; import com.wismna.geoffroy.donext.listeners.RecyclerItemClickListener; +import com.wismna.geoffroy.donext.widgets.DividerItemDecoration; import com.wismna.geoffroy.donext.widgets.NoScrollingLayoutManager; /** @@ -83,20 +84,20 @@ public class TasksFragment extends Fragment implements view = inflater.inflate(R.layout.fragment_tasks, container, false); final Context context = view.getContext(); + taskDataAccess = new TaskDataAccess(view.getContext()); + taskDataAccess.open(); + // Set the Recycler view recyclerView = (RecyclerView) view.findViewById(R.id.task_list_view); recyclerView.setLayoutManager(new NoScrollingLayoutManager(context)); - taskDataAccess = new TaskDataAccess(view.getContext()); - taskDataAccess.open(); - // Set RecyclerView Adapter - taskRecyclerViewAdapter = new TaskRecyclerViewAdapter(taskDataAccess.getAllTasks(taskListId)); + SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(getContext()); + taskRecyclerViewAdapter = new TaskRecyclerViewAdapter( + taskDataAccess.getAllTasks(taskListId), + Integer.valueOf(sharedPref.getString("pref_conf_task_layout", "1"))); recyclerView.setAdapter(taskRecyclerViewAdapter); - // Set total cycles - UpdateCycleCount(); - // Set ItemTouch helper in RecyclerView to handle swipe move on elements ItemTouchHelper.Callback callback = new TaskTouchHelper(this); ItemTouchHelper helper = new ItemTouchHelper(callback); @@ -125,18 +126,37 @@ public class TasksFragment extends Fragment implements }) ); - // Set total count - UpdateTaskCount(); - - // Handle updating remaining task count in a listener to be sure that the layout is available + // Handle updating total counts in a listener to be sure that the layout is available recyclerView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { @Override public boolean onPreDraw() { - UpdateRemainingTaskCount(); - recyclerView.getViewTreeObserver().removeOnPreDrawListener(this); + // Update total cycle count + int totalCycles = taskRecyclerViewAdapter.getCycleCount(); + if (totalCycles != 0) { + TextView totalCyclesView = (TextView) view.findViewById(R.id.total_task_cycles); + totalCyclesView.setText(String.valueOf(totalCycles + " cycles")); + } + + // Update total tasks + int totalTasks = taskRecyclerViewAdapter.getItemCount(); + TextView totalTasksView = (TextView) view.findViewById(R.id.total_task_count); + if (totalTasks == 0) totalTasksView.setText(getResources().getText(R.string.task_no_tasks)); + else totalTasksView.setText(String.valueOf(totalTasks + " task" + (totalTasks > 1 ? "s" : ""))); + + // Update remaining tasks + TextView remainingTasksView = (TextView) view.findViewById(R.id.remaining_task_count); + NoScrollingLayoutManager layoutManager = (NoScrollingLayoutManager) recyclerView.getLayoutManager(); + int remainingTaskCount = totalTasks - layoutManager.findLastVisibleItemPosition() - 1; + if (remainingTaskCount == 0) remainingTasksView.setText(""); + else remainingTasksView.setText(String.valueOf( + remainingTaskCount + " more task" + (remainingTaskCount > 1 ? "s" : ""))); + + //recyclerView.getViewTreeObserver().removeOnPreDrawListener(this); return true; } }); + + recyclerView.addItemDecoration(new DividerItemDecoration(getActivity())); return view; } @@ -152,31 +172,6 @@ public class TasksFragment extends Fragment implements taskDataAccess.open(); } - private void UpdateCycleCount() { - int totalCycles = taskDataAccess.getTotalCycles(taskListId); - if (totalCycles == 0) return; - TextView totalCyclesView = (TextView) view.findViewById(R.id.total_task_cycles); - totalCyclesView.setText(String.valueOf(totalCycles + " cycles")); - } - - private void UpdateTaskCount() { - int totalTasks = taskRecyclerViewAdapter.getItemCount(); - TextView totalTasksView = (TextView) view.findViewById(R.id.total_task_count); - if (totalTasks == 0) totalTasksView.setText(getResources().getText(R.string.task_no_tasks)); - else totalTasksView.setText(String.valueOf(totalTasks + " tasks")); - } - - private void UpdateRemainingTaskCount() { - TextView remainingTasksView = (TextView) view.findViewById(R.id.remaining_task_count); - NoScrollingLayoutManager layoutManager = (NoScrollingLayoutManager) recyclerView.getLayoutManager(); - int remainingTaskCount = taskRecyclerViewAdapter.getItemCount() - layoutManager.findLastVisibleItemPosition() - 1; - if (remainingTaskCount == 0) - remainingTasksView.setText(""); - else - remainingTasksView.setText(String.valueOf( - remainingTaskCount + " more task" + (remainingTaskCount > 1 ? "s" : ""))); - } - /** Performs an action on a task: done, next or delete */ public void PerformTaskAction(final int itemPosition, final int direction) { final long itemId = taskRecyclerViewAdapter.getItemId(itemPosition); @@ -203,58 +198,54 @@ public class TasksFragment extends Fragment implements // Setup the snack bar Snackbar.make(view, "Task " + action, Snackbar.LENGTH_LONG) - .setAction("Undo", new View.OnClickListener() { - @Override - public void onClick(View v) { - // Undo adapter changes - switch (direction) - { - // Nothing special to do for done - case ItemTouchHelper.LEFT: - break; - // Remove the last item - case ItemTouchHelper.RIGHT: - taskRecyclerViewAdapter.remove(taskRecyclerViewAdapter.getItemCount() - 1); - task.setCycle(task.getCycle() - 1); - break; - // Nothing special to do for delete - case -1: - break; - } - // Reset the first item - taskRecyclerViewAdapter.add(task, itemPosition); - recyclerView.scrollToPosition(0); + .setAction("Undo", new View.OnClickListener() { + @Override + public void onClick(View v) { + // Undo adapter changes + switch (direction) { + // Nothing special to do for done + case ItemTouchHelper.LEFT: + break; + // Remove the last item + case ItemTouchHelper.RIGHT: + taskRecyclerViewAdapter.remove(taskRecyclerViewAdapter.getItemCount() - 1); + task.setCycle(task.getCycle() - 1); + break; + // Nothing special to do for delete + case -1: + break; } - }).setCallback(new Snackbar.Callback() { - @Override - public void onDismissed(Snackbar snackbar, int event) { - super.onDismissed(snackbar, event); - - // When clicked on undo, do not write to DB - if (event == DISMISS_EVENT_ACTION) return; - - // Commit the changes to DB - switch (direction) - { - // Mark item as Done - case ItemTouchHelper.LEFT: - taskDataAccess.setDone(itemId); - break; - // Increase task cycle count - case ItemTouchHelper.RIGHT: - taskDataAccess.increaseCycle(task.getCycle(), itemId); - break; - case -1: - // Commit the changes to DB - taskDataAccess.deleteTask(itemId); + // Reset the first item + taskRecyclerViewAdapter.add(task, itemPosition); + recyclerView.scrollToPosition(0); } + }).setCallback(new Snackbar.Callback() { + @Override + public void onDismissed(Snackbar snackbar, int event) { + super.onDismissed(snackbar, event); - UpdateCycleCount(); + // When clicked on undo, do not write to DB + if (event == DISMISS_EVENT_ACTION) return; - UpdateTaskCount(); - UpdateRemainingTaskCount(); - } - }).show(); + // Commit the changes to DB + switch (direction) + { + // Mark item as Done + case ItemTouchHelper.LEFT: + taskDataAccess.setDone(itemId); + break; + // Increase task cycle count + case ItemTouchHelper.RIGHT: + taskDataAccess.increaseCycle(task.getCycle(), itemId); + break; + case -1: + // Commit the changes to DB + taskDataAccess.deleteTask(itemId); + } + + //UpdateCycleCount(); + } + }).show(); } @Override @@ -315,7 +306,6 @@ public class TasksFragment extends Fragment implements priorityRadio.getText().toString(), taskList.getId()); - Bundle args = dialog.getArguments(); // Should never happen because we will have to be on this tab to open the dialog if (taskRecyclerViewAdapter == null) return; @@ -324,9 +314,6 @@ public class TasksFragment extends Fragment implements if (task == null) { taskRecyclerViewAdapter.add(newTask, 0); recyclerView.scrollToPosition(0); - - // Update the task count - UpdateTaskCount(); } // Update the task else { @@ -336,13 +323,12 @@ public class TasksFragment extends Fragment implements { // Remove item from current tab taskRecyclerViewAdapter.remove(position); + //UpdateCycleCount(); // Add it to the corresponding tab provided it is already instanciated mAdapter.onTaskListChanged(newTask, listSpinner.getSelectedItemPosition()); } else taskRecyclerViewAdapter.update(newTask, position); } - - UpdateRemainingTaskCount(); } @Override diff --git a/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/helpers/TaskTouchHelper.java b/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/helpers/TaskTouchHelper.java index e72f875..0c3af39 100644 --- a/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/helpers/TaskTouchHelper.java +++ b/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/helpers/TaskTouchHelper.java @@ -1,7 +1,6 @@ package com.wismna.geoffroy.donext.helpers; import android.graphics.Canvas; -import android.graphics.Color; import android.graphics.Paint; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.helper.ItemTouchHelper; @@ -50,27 +49,27 @@ public class TaskTouchHelper extends ItemTouchHelper.SimpleCallback { View itemView = viewHolder.itemView; Paint p = new Paint(); + p.setARGB(255, 222, 222, 222); if (dX > 0) { - /* Set your color for positive displacement */ - p.setARGB(255, 204, 229, 255); + // Set your color for positive displacement + //p.setARGB(255, 204, 229, 255); // Draw Rect with varying right side, equal to displacement dX c.drawRect((float) itemView.getLeft(), (float) itemView.getTop(), dX, (float) itemView.getBottom(), p); } else { - /* Set your color for negative displacement */ - p.setARGB(255, 204, 255, 229); + // Set your color for negative displacement + //p.setARGB(255, 204, 255, 229); // Draw Rect with varying left side, equal to the item's right side plus negative displacement dX c.drawRect((float) itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(), (float) itemView.getBottom(), p); } - super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive); } } - @Override + /*@Override public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) { if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) { @@ -86,5 +85,5 @@ public class TaskTouchHelper extends ItemTouchHelper.SimpleCallback { viewHolder.itemView.setAlpha(1.0f); viewHolder.itemView.setBackgroundColor(0); - } + }*/ } diff --git a/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/widgets/DividerItemDecoration.java b/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/widgets/DividerItemDecoration.java new file mode 100644 index 0000000..d62cb71 --- /dev/null +++ b/DoNExt/app/src/main/java/com/wismna/geoffroy/donext/widgets/DividerItemDecoration.java @@ -0,0 +1,54 @@ +package com.wismna.geoffroy.donext.widgets; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.drawable.Drawable; +import android.support.v7.widget.RecyclerView; +import android.view.View; + +/** + * Created by geoffroy on 16-01-11. + * Displays dividers between RecyclerView items + */ +public class DividerItemDecoration extends RecyclerView.ItemDecoration { + + private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; + + private Drawable mDivider; + + /** + * Default divider will be used + */ + public DividerItemDecoration(Context context) { + final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS); + mDivider = styledAttributes.getDrawable(0); + styledAttributes.recycle(); + } + + /** + * Custom divider will be used + */ + /*public DividerItemDecoration(Context context, int resId) { + mDivider = ContextCompat.getDrawable(context, resId); + }*/ + + @Override + public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { + int left = parent.getPaddingLeft(); + int right = parent.getWidth() - parent.getPaddingRight(); + + int childCount = parent.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = parent.getChildAt(i); + + RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams(); + + int top = child.getBottom() + params.bottomMargin; + int bottom = top + mDivider.getIntrinsicHeight(); + + mDivider.setBounds(left, top, right, bottom); + mDivider.draw(c); + } + } +} diff --git a/DoNExt/app/src/main/res/drawable/task_select.xml b/DoNExt/app/src/main/res/drawable/task_select.xml index 484668f..69996f8 100644 --- a/DoNExt/app/src/main/res/drawable/task_select.xml +++ b/DoNExt/app/src/main/res/drawable/task_select.xml @@ -1,5 +1,6 @@ - + + \ No newline at end of file diff --git a/DoNExt/app/src/main/res/layout/fragment_task_confirmation.xml b/DoNExt/app/src/main/res/layout/fragment_task_confirmation.xml index 2523e5b..ce1fa6d 100644 --- a/DoNExt/app/src/main/res/layout/fragment_task_confirmation.xml +++ b/DoNExt/app/src/main/res/layout/fragment_task_confirmation.xml @@ -7,8 +7,8 @@ android:id="@+id/task_confirmation_never" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginLeft="16dp" - android:layout_marginStart="16dp" + android:layout_marginLeft="@dimen/text_margin" + android:layout_marginStart="@dimen/text_margin" android:layout_marginTop="10dp" android:text="@string/task_confirmation_never_button" /> \ No newline at end of file diff --git a/DoNExt/app/src/main/res/layout/fragment_task.xml b/DoNExt/app/src/main/res/layout/fragment_task_detailed.xml similarity index 89% rename from DoNExt/app/src/main/res/layout/fragment_task.xml rename to DoNExt/app/src/main/res/layout/fragment_task_detailed.xml index c2947fe..f439c65 100644 --- a/DoNExt/app/src/main/res/layout/fragment_task.xml +++ b/DoNExt/app/src/main/res/layout/fragment_task_detailed.xml @@ -2,7 +2,10 @@ + android:paddingTop="5dp" + android:orientation="horizontal" + android:focusable="true" + android:background="?android:attr/selectableItemBackground" > + android:layout_height="wrap_content" + android:hint="@string/new_task_name_hint" /> + + + + + diff --git a/DoNExt/app/src/main/res/layout/fragment_tasks.xml b/DoNExt/app/src/main/res/layout/fragment_tasks.xml index cefebff..ba1fe3a 100644 --- a/DoNExt/app/src/main/res/layout/fragment_tasks.xml +++ b/DoNExt/app/src/main/res/layout/fragment_tasks.xml @@ -21,13 +21,13 @@ android:name="com.wismna.geoffroy.donext.activities.TaskFragment" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginLeft="16dp" - android:layout_marginRight="16dp" + android:layout_marginLeft="@dimen/text_margin" + android:layout_marginRight="@dimen/text_margin" android:layout_below="@id/total_task_cycles" app:layoutManager="LinearLayoutManager" app:layout_heightPercent="90%" tools:context=".fragments.TasksFragment" - tools:listitem="@layout/fragment_task" /> + tools:listitem="@layout/fragment_task_detailed" /> New list name Create + List name cannot be blank Delete Delete task list? - List Name + New task name + Task name cannot be blank Description + Optional task description Priority Low Normal @@ -43,10 +46,21 @@ Never ask again + Tasks + Task lists Mark task as Confirm on next? Confirm on done? Confirm on delete? + Task layout: + + Simple + Detailed + + + 1 + 2 + Maximum number of lists: 1 diff --git a/DoNExt/app/src/main/res/xml/preferences.xml b/DoNExt/app/src/main/res/xml/preferences.xml index bd054d1..65c4be1 100644 --- a/DoNExt/app/src/main/res/xml/preferences.xml +++ b/DoNExt/app/src/main/res/xml/preferences.xml @@ -1,23 +1,39 @@ - - - - + + + + + + + + + + \ No newline at end of file