mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-04-15 04:06:31 +00:00
Merge pull request #581 from schrockblock/feature/schrockblock/reorder-tasks
allow habits, dailies, and todos rearranging
This commit is contained in:
commit
f5f5f0012e
12 changed files with 164 additions and 21 deletions
|
|
@ -154,6 +154,7 @@ android {
|
|||
}
|
||||
|
||||
dexOptions{
|
||||
javaMaxHeapSize "4g"
|
||||
preDexLibraries = false
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:orientation="vertical">
|
||||
android:orientation="vertical"
|
||||
android:foreground="?selectableItemBackground">
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/white"
|
||||
android:orientation="horizontal">
|
||||
android:orientation="horizontal"
|
||||
android:foreground="?selectableItemBackground">
|
||||
<LinearLayout
|
||||
android:layout_width="80dp"
|
||||
android:layout_height="match_parent"
|
||||
|
|
|
|||
|
|
@ -4,7 +4,8 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:background="@color/white">
|
||||
android:background="@color/white"
|
||||
android:foreground="?selectableItemBackground">
|
||||
<LinearLayout
|
||||
android:id="@+id/card_view"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
|||
|
|
@ -6,12 +6,14 @@ import com.habitrpg.android.habitica.ui.viewHolders.tasks.DailyViewHolder;
|
|||
import android.content.Context;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class DailiesRecyclerViewHolder extends BaseTasksRecyclerViewAdapter<DailyViewHolder> {
|
||||
public class DailiesRecyclerViewHolder extends SortableTasksRecyclerViewAdapter<DailyViewHolder> {
|
||||
|
||||
public int dailyResetOffset;
|
||||
|
||||
public DailiesRecyclerViewHolder(String taskType, TagsHelper tagsHelper, int layoutResource, Context newContext, String userID, int dailyResetOffset) {
|
||||
super(taskType, tagsHelper, layoutResource, newContext, userID);
|
||||
public DailiesRecyclerViewHolder(String taskType, TagsHelper tagsHelper, int layoutResource,
|
||||
Context newContext, String userID, int dailyResetOffset,
|
||||
SortTasksCallback sortTasksCallback) {
|
||||
super(taskType, tagsHelper, layoutResource, newContext, userID, sortTasksCallback);
|
||||
this.dailyResetOffset = dailyResetOffset;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ import com.habitrpg.android.habitica.ui.viewHolders.tasks.HabitViewHolder;
|
|||
import android.content.Context;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class HabitsRecyclerViewAdapter extends BaseTasksRecyclerViewAdapter<HabitViewHolder> {
|
||||
public HabitsRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Context newContext, String userID) {
|
||||
super(taskType, tagsHelper, layoutResource, newContext, userID);
|
||||
public class HabitsRecyclerViewAdapter extends SortableTasksRecyclerViewAdapter<HabitViewHolder> {
|
||||
|
||||
|
||||
public HabitsRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Context newContext, String userID, SortTasksCallback sortCallback) {
|
||||
super(taskType, tagsHelper, layoutResource, newContext, userID, sortCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package com.habitrpg.android.habitica.ui.adapter.tasks;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.habitrpg.android.habitica.helpers.TagsHelper;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ItemTouchHelperAdapter;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ItemTouchHelperDropCallback;
|
||||
import com.habitrpg.android.habitica.ui.viewHolders.tasks.BaseTaskViewHolder;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Created by ell on 7/21/16.
|
||||
*/
|
||||
public abstract class SortableTasksRecyclerViewAdapter<VH extends BaseTaskViewHolder>
|
||||
extends BaseTasksRecyclerViewAdapter<VH> implements ItemTouchHelperAdapter, ItemTouchHelperDropCallback {
|
||||
|
||||
public interface SortTasksCallback {
|
||||
void onMove(Task task, int from, int to);
|
||||
}
|
||||
|
||||
private SortTasksCallback sortCallback;
|
||||
|
||||
public SortableTasksRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource,
|
||||
Context newContext, String userID, SortTasksCallback sortCallback) {
|
||||
super(taskType, tagsHelper, layoutResource, newContext, userID);
|
||||
this.sortCallback = sortCallback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemMove(int fromPosition, int toPosition) {
|
||||
Collections.swap(filteredContent, fromPosition, toPosition);
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemDismiss(int position) {
|
||||
//NO OP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrop(int from, int to) {
|
||||
if (this.sortCallback != null && from != to){
|
||||
this.sortCallback.onMove(filteredContent.get(to), from, to);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -6,10 +6,11 @@ import com.habitrpg.android.habitica.ui.viewHolders.tasks.TodoViewHolder;
|
|||
import android.content.Context;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class TodosRecyclerViewAdapter extends BaseTasksRecyclerViewAdapter<TodoViewHolder> {
|
||||
public class TodosRecyclerViewAdapter extends SortableTasksRecyclerViewAdapter<TodoViewHolder> {
|
||||
|
||||
public TodosRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Context newContext, String userID) {
|
||||
super(taskType, tagsHelper, layoutResource, newContext, userID);
|
||||
public TodosRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource,
|
||||
Context newContext, String userID, SortTasksCallback sortCallback) {
|
||||
super(taskType, tagsHelper, layoutResource, newContext, userID, sortCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ package com.habitrpg.android.habitica.ui.fragments.tasks;
|
|||
|
||||
import com.habitrpg.android.habitica.APIHelper;
|
||||
import com.habitrpg.android.habitica.R;
|
||||
import com.habitrpg.android.habitica.callbacks.HabitRPGUserCallback;
|
||||
import com.habitrpg.android.habitica.components.AppComponent;
|
||||
import com.habitrpg.android.habitica.events.commands.AddNewTaskCommand;
|
||||
import com.habitrpg.android.habitica.helpers.TagsHelper;
|
||||
|
|
@ -9,22 +10,32 @@ import com.habitrpg.android.habitica.ui.adapter.tasks.BaseTasksRecyclerViewAdapt
|
|||
import com.habitrpg.android.habitica.ui.adapter.tasks.DailiesRecyclerViewHolder;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.HabitsRecyclerViewAdapter;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.RewardsRecyclerViewAdapter;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.SortableTasksRecyclerViewAdapter;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.TodosRecyclerViewAdapter;
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseFragment;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ItemTouchHelperAdapter;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ItemTouchHelperDropCallback;
|
||||
import com.habitrpg.android.habitica.ui.menu.DividerItemDecoration;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Named;
|
||||
|
||||
|
|
@ -49,12 +60,16 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
|
|||
private String classType;
|
||||
private HabitRPGUser user;
|
||||
private View view;
|
||||
private SortableTasksRecyclerViewAdapter.SortTasksCallback sortCallback;
|
||||
private ItemTouchHelper.Callback mItemTouchCallback;
|
||||
|
||||
public static TaskRecyclerViewFragment newInstance(HabitRPGUser user, String classType) {
|
||||
public static TaskRecyclerViewFragment newInstance(HabitRPGUser user, String classType,
|
||||
SortableTasksRecyclerViewAdapter.SortTasksCallback sortCallback) {
|
||||
TaskRecyclerViewFragment fragment = new TaskRecyclerViewFragment();
|
||||
fragment.setRetainInstance(true);
|
||||
fragment.user = user;
|
||||
fragment.classType = classType;
|
||||
fragment.sortCallback = sortCallback;
|
||||
return fragment;
|
||||
}
|
||||
|
||||
|
|
@ -65,7 +80,8 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
|
|||
switch (this.classType) {
|
||||
case Task.TYPE_HABIT:
|
||||
layoutOfType = R.layout.habit_item_card;
|
||||
this.recyclerAdapter = new HabitsRecyclerViewAdapter(Task.TYPE_HABIT, tagsHelper, layoutOfType, getContext(), userID);
|
||||
this.recyclerAdapter = new HabitsRecyclerViewAdapter(Task.TYPE_HABIT, tagsHelper, layoutOfType, getContext(), userID, sortCallback);
|
||||
allowReordering();
|
||||
break;
|
||||
case Task.TYPE_DAILY:
|
||||
layoutOfType = R.layout.daily_item_card;
|
||||
|
|
@ -73,11 +89,13 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
|
|||
if (user != null) {
|
||||
dailyResetOffset = user.getPreferences().getDayStart();
|
||||
}
|
||||
this.recyclerAdapter = new DailiesRecyclerViewHolder(Task.TYPE_DAILY, tagsHelper, layoutOfType, getContext(), userID, dailyResetOffset);
|
||||
this.recyclerAdapter = new DailiesRecyclerViewHolder(Task.TYPE_DAILY, tagsHelper, layoutOfType, getContext(), userID, dailyResetOffset, sortCallback);
|
||||
allowReordering();
|
||||
break;
|
||||
case Task.TYPE_TODO:
|
||||
layoutOfType = R.layout.todo_item_card;
|
||||
this.recyclerAdapter = new TodosRecyclerViewAdapter(Task.TYPE_TODO, tagsHelper, layoutOfType, getContext(), userID);
|
||||
this.recyclerAdapter = new TodosRecyclerViewAdapter(Task.TYPE_TODO, tagsHelper, layoutOfType, getContext(), userID, sortCallback);
|
||||
allowReordering();
|
||||
return;
|
||||
case Task.TYPE_REWARD:
|
||||
layoutOfType = R.layout.reward_item_card;
|
||||
|
|
@ -87,8 +105,51 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
|
|||
}
|
||||
}
|
||||
|
||||
private void allowReordering(){
|
||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(mItemTouchCallback);
|
||||
itemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
mItemTouchCallback = new ItemTouchHelper.Callback() {
|
||||
private Integer mFromPosition = null;
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
if (viewHolder != null){
|
||||
viewHolder.itemView.setBackgroundColor(Color.LTGRAY);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||
if (mFromPosition == null) mFromPosition = viewHolder.getAdapterPosition();
|
||||
((ItemTouchHelperAdapter)recyclerAdapter).onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
|
||||
|
||||
//defines the enabled move directions in each state (idle, swiping, dragging).
|
||||
@Override
|
||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
return makeFlag(ItemTouchHelper.ACTION_STATE_DRAG,
|
||||
ItemTouchHelper.DOWN | ItemTouchHelper.UP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
|
||||
viewHolder.itemView.setBackgroundColor(Color.WHITE);
|
||||
if (mFromPosition != null){
|
||||
((ItemTouchHelperDropCallback)recyclerAdapter).onDrop(mFromPosition, viewHolder.getAdapterPosition());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (view == null) {
|
||||
view = inflater.inflate(R.layout.fragment_recyclerview, container, false);
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.habitrpg.android.habitica.ui.activities.MainActivity;
|
|||
import com.habitrpg.android.habitica.ui.activities.TaskFormActivity;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.BaseTasksRecyclerViewAdapter;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.DailiesRecyclerViewHolder;
|
||||
import com.habitrpg.android.habitica.ui.adapter.tasks.SortableTasksRecyclerViewAdapter;
|
||||
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment;
|
||||
import com.habitrpg.android.habitica.ui.helpers.Debounce;
|
||||
import com.habitrpg.android.habitica.ui.helpers.UiUtils;
|
||||
|
|
@ -47,6 +48,7 @@ import android.support.v4.app.Fragment;
|
|||
import android.support.v4.app.FragmentPagerAdapter;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.view.ViewPager;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
|
|
@ -66,6 +68,9 @@ import java.util.Map;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import rx.Observer;
|
||||
import rx.functions.Action1;
|
||||
|
||||
public class TasksFragment extends BaseMainFragment implements OnCheckedChangeListener {
|
||||
|
||||
private static final int TASK_CREATED_RESULT = 1;
|
||||
|
|
@ -200,20 +205,29 @@ public class TasksFragment extends BaseMainFragment implements OnCheckedChangeLi
|
|||
@Override
|
||||
public Fragment getItem(int position) {
|
||||
TaskRecyclerViewFragment fragment;
|
||||
BaseTasksRecyclerViewAdapter adapter;
|
||||
SortableTasksRecyclerViewAdapter.SortTasksCallback sortCallback =
|
||||
(task, from, to) -> {
|
||||
if (apiHelper != null){
|
||||
apiHelper.apiService.postTaskNewPosition(task.getId(), String.valueOf(to))
|
||||
.compose(apiHelper.configureApiCallObserver())
|
||||
.subscribe(aVoid -> {
|
||||
new HabitRPGUserCallback(activity);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
switch (position) {
|
||||
case 0:
|
||||
fragment = TaskRecyclerViewFragment.newInstance(user, Task.TYPE_HABIT);
|
||||
fragment = TaskRecyclerViewFragment.newInstance(user, Task.TYPE_HABIT, sortCallback);
|
||||
break;
|
||||
case 1:
|
||||
fragment = TaskRecyclerViewFragment.newInstance(user, Task.TYPE_DAILY);
|
||||
fragment = TaskRecyclerViewFragment.newInstance(user, Task.TYPE_DAILY, sortCallback);
|
||||
break;
|
||||
case 3:
|
||||
fragment = TaskRecyclerViewFragment.newInstance(user, Task.TYPE_REWARD);
|
||||
fragment = TaskRecyclerViewFragment.newInstance(user, Task.TYPE_REWARD, null);
|
||||
break;
|
||||
default:
|
||||
fragment = TaskRecyclerViewFragment.newInstance(user, Task.TYPE_TODO);
|
||||
fragment = TaskRecyclerViewFragment.newInstance(user, Task.TYPE_TODO, sortCallback);
|
||||
}
|
||||
|
||||
ViewFragmentsDictionary.put(position, fragment);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
package com.habitrpg.android.habitica.ui.helpers;
|
||||
|
||||
/**
|
||||
* Created by ell on 3/30/16.
|
||||
*/
|
||||
public interface ItemTouchHelperDropCallback {
|
||||
void onDrop(int from, int to);
|
||||
}
|
||||
|
|
@ -97,6 +97,9 @@ public interface ApiService {
|
|||
@POST("tasks/{id}/score/{direction}")
|
||||
Observable<TaskDirectionData> postTaskDirection(@Path("id") String id, @Path("direction") String direction);
|
||||
|
||||
@POST("tasks/{id}/move/to/{position}")
|
||||
Observable<Void> postTaskNewPosition(@Path("id") String id, @Path("position") String position);
|
||||
|
||||
@POST("tasks/{taskId}/checklist/{itemId}/score")
|
||||
Observable<Task> scoreChecklistItem(@Path("taskId") String taskId, @Path("itemId") String itemId);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue