diff --git a/Habitica/build.gradle b/Habitica/build.gradle
index 8b1e32a3a..49b46b2cd 100644
--- a/Habitica/build.gradle
+++ b/Habitica/build.gradle
@@ -132,7 +132,7 @@ dependencies {
android {
compileSdkVersion 23
- buildToolsVersion "23.0.1"
+ buildToolsVersion "23.0.3"
lintOptions {
abortOnError false
diff --git a/Habitica/res/layout/daily_item_card.xml b/Habitica/res/layout/daily_item_card.xml
index 2d85cc815..dd02ec7a9 100644
--- a/Habitica/res/layout/daily_item_card.xml
+++ b/Habitica/res/layout/daily_item_card.xml
@@ -1,23 +1,6 @@
-
-
-
-
-
-
-
-
-
-
-
+ android:layout_height="match_parent">
@@ -63,37 +44,30 @@
android:id="@+id/checkedTextView"
style="@style/CardTitle"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- bind:parsemarkdown="@{daily.text}" />
+ android:layout_height="wrap_content" />
+ android:layout_height="wrap_content"/>
@@ -104,9 +78,9 @@
android:background="@color/white"
android:layout_centerInParent="true"/>
@@ -115,8 +89,6 @@
android:id="@+id/rightBorderView"
android:layout_width="5dp"
android:layout_height="match_parent"
- app:backgroundColor="@{daily.isDisplayedActive(offset) ? daily.getLightTaskColor : @color/task_gray}"
- android:visibility="@{daily.checklist.size == 0 ? View.VISIBLE : View.GONE}"
android:gravity="center"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
@@ -125,21 +97,19 @@
+ android:background="@color/cell_separator" />
+ android:orientation="vertical" />
+ android:background="@color/checklist_separator" />
-
\ No newline at end of file
diff --git a/Habitica/res/layout/habit_item_card.xml b/Habitica/res/layout/habit_item_card.xml
index 1a8d1589b..c924509e2 100644
--- a/Habitica/res/layout/habit_item_card.xml
+++ b/Habitica/res/layout/habit_item_card.xml
@@ -1,18 +1,6 @@
-
-
-
-
-
-
-
-
-
-
-
@@ -24,12 +12,12 @@
+ android:layout_weight="1"
+ android:id="@+id/btnPlusWrapper">
+ android:id="@+id/btnPlusBackground"/>
-
\ No newline at end of file
diff --git a/Habitica/res/layout/reward_item_card.xml b/Habitica/res/layout/reward_item_card.xml
index 32c67d5f1..f000ec02e 100644
--- a/Habitica/res/layout/reward_item_card.xml
+++ b/Habitica/res/layout/reward_item_card.xml
@@ -1,70 +1,40 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:orientation="horizontal"
+ android:clickable="false">
+ android:layout_gravity="center_vertical" />
+ android:layout_gravity="center_vertical">
+ android:layout_height="wrap_content"/>
+ android:layout_height="wrap_content"/>
@@ -79,21 +49,7 @@
android:textSize="15sp"
android:drawableLeft="@drawable/ic_header_gold"
android:drawableStart="@drawable/ic_header_gold"
- android:text='@{String.format("%.2f", reward.value)}'
android:background="@drawable/rounded_purple_square"
android:paddingLeft="6dp"
- android:paddingStart="6dp"
- android:layout_centerVertical="true"
- android:layout_alignParentRight="true"
- android:layout_alignParentEnd="true" />
-
-
-
-
-
-
-
\ No newline at end of file
+ android:paddingStart="6dp" />
+
diff --git a/Habitica/res/layout/todo_item_card.xml b/Habitica/res/layout/todo_item_card.xml
index 2263a57b8..e314fcbac 100644
--- a/Habitica/res/layout/todo_item_card.xml
+++ b/Habitica/res/layout/todo_item_card.xml
@@ -1,52 +1,33 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+ android:layout_height="match_parent">
-
-
+
+
-
-
+ android:layout_height="wrap_content" />
-
-
+
+
+
-
-
-
-
-
-
-
+
-
+
-
-
+
-
+
-
+
+ android:background="@color/checklist_separator" />
-
-
\ No newline at end of file
+
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/events/HabitScoreEvent.java b/Habitica/src/main/java/com/habitrpg/android/habitica/events/HabitScoreEvent.java
index fb350828c..b66b128ea 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/events/HabitScoreEvent.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/events/HabitScoreEvent.java
@@ -8,5 +8,5 @@ import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
public class HabitScoreEvent {
public boolean Up = false;
- public Task Habit;
+ public Task habit;
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/BaseTasksRecyclerViewAdapter.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/BaseTasksRecyclerViewAdapter.java
new file mode 100644
index 000000000..11565233c
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/BaseTasksRecyclerViewAdapter.java
@@ -0,0 +1,196 @@
+package com.habitrpg.android.habitica.ui.adapter.tasks;
+
+import com.habitrpg.android.habitica.events.TaskCreatedEvent;
+import com.habitrpg.android.habitica.events.TaskRemovedEvent;
+import com.habitrpg.android.habitica.events.TaskUpdatedEvent;
+import com.habitrpg.android.habitica.events.commands.FilterTasksByTagsCommand;
+import com.habitrpg.android.habitica.events.commands.TaskCheckedCommand;
+import com.habitrpg.android.habitica.helpers.TagsHelper;
+import com.habitrpg.android.habitica.ui.viewHolders.tasks.BaseTaskViewHolder;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+import com.raizlabs.android.dbflow.runtime.transaction.BaseTransaction;
+import com.raizlabs.android.dbflow.runtime.transaction.TransactionListener;
+import com.raizlabs.android.dbflow.sql.builder.Condition;
+import com.raizlabs.android.dbflow.sql.language.OrderBy;
+import com.raizlabs.android.dbflow.sql.language.Select;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+
+import android.app.Activity;
+import android.content.Context;
+import android.databinding.ObservableArrayList;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx.Observable;
+import rx.android.schedulers.AndroidSchedulers;
+import rx.functions.Func0;
+import rx.schedulers.Schedulers;
+
+public abstract class BaseTasksRecyclerViewAdapter
+ extends RecyclerView.Adapter {
+
+ int layoutResource;
+ String taskType;
+ Context context;
+ List content;
+ List filteredContent;
+ private TagsHelper tagsHelper;
+
+ public BaseTasksRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource,
+ Context newContext) {
+ this.setHasStableIds(true);
+ this.taskType = taskType;
+ this.context = newContext;
+ this.tagsHelper = tagsHelper;
+ this.filteredContent = new ArrayList<>();
+
+ this.loadContent(true);
+
+ this.layoutResource = layoutResource;
+ }
+
+ @Override
+ public void onBindViewHolder(VH holder, int position) {
+ Task item = filteredContent.get(position);
+
+ holder.bindHolder(item, position);
+
+ /*if (this.displayedChecklist != null && ChecklistedViewHolder.class.isAssignableFrom(holder.getClass())) {
+ ChecklistedViewHolder checklistedHolder = (ChecklistedViewHolder) holder;
+ checklistedHolder.setDisplayChecklist(this.displayedChecklist == position);
+ }*/
+ }
+
+ @Override
+ public long getItemId(int position) {
+ Task task = filteredContent.get(position);
+ return task.getId().hashCode();
+ }
+
+ @Override
+ public int getItemCount() {
+ return filteredContent != null ? filteredContent.size() : 0;
+ }
+
+ public View getContentView(ViewGroup parent) {
+ return LayoutInflater.from(parent.getContext()).inflate(layoutResource, parent, false);
+ }
+
+ @Override
+ public void onAttachedToRecyclerView(RecyclerView recyclerView) {
+ super.onAttachedToRecyclerView(recyclerView);
+ EventBus.getDefault().register(this);
+ }
+
+ @Override
+ public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
+ super.onDetachedFromRecyclerView(recyclerView);
+ EventBus.getDefault().unregister(this);
+
+ }
+
+ @Subscribe
+ public void onEvent(FilterTasksByTagsCommand cmd) {
+ filter();
+ }
+
+ @Subscribe
+ public void onEvent(TaskCheckedCommand evnt){
+ if (!taskType.equals(evnt.Task.getType()))
+ return;
+
+ if(evnt.completed && evnt.Task.getType().equals("todo")){
+ // remove from the list
+ content.remove(evnt.Task);
+ }
+ this.updateTask(evnt.Task);
+ filter();
+ }
+
+ @Subscribe
+ public void onEvent(TaskUpdatedEvent evnt) {
+ if (!taskType.equals(evnt.task.getType()))
+ return;
+ this.updateTask(evnt.task);
+ filter();
+ }
+
+ @Subscribe
+ public void onEvent(TaskCreatedEvent evnt) {
+ if (!taskType.equals(evnt.task.getType()))
+ return;
+
+ content.add(0, evnt.task);
+ filter();
+ }
+
+ @Subscribe
+ public void onEvent(TaskRemovedEvent evnt) {
+ Task taskToDelete = null;
+
+ for(Task t : content) {
+ if(t.getId().equals(evnt.deletedTaskId)){
+ taskToDelete = t;
+ break;
+ }
+ }
+
+ if(taskToDelete != null) {
+ content.remove(taskToDelete);
+ filter();
+ }
+ }
+
+ private void updateTask(Task task) {
+ int i;
+ for(i = 0; i < this.content.size(); ++i) {
+ if (content.get(i).getId().equals(task.getId())) {
+ break;
+ }
+ }
+ if (i < content.size()) {
+ content.set(i, task);
+ }
+ }
+
+ private void filter() {
+ if (this.tagsHelper.howMany() == 0) {
+ filteredContent = content;
+ } else {
+ filteredContent = new ObservableArrayList<>();
+ filteredContent.addAll(this.tagsHelper.filter(filteredContent));
+ }
+
+ ((Activity) context).runOnUiThread(this::notifyDataSetChanged);
+ }
+
+ public void loadContent(boolean forced) {
+ if (this.content == null || forced) {
+ Observable.defer(() -> Observable.just(new Select().from(Task.class)
+ .where(Condition.column("type").eq(this.taskType))
+ .and(Condition.CombinedCondition
+ .begin(Condition.column("completed").eq(false))
+ .or(Condition.column("type").eq("daily"))
+ )
+ .orderBy(OrderBy.columns("position", "dateCreated").descending())
+ .queryList()))
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(this::setTasks, throwable -> {});
+ }
+ }
+
+ public void setTasks(List tasks) {
+ this.content = new ObservableArrayList<>();
+ this.content.addAll(tasks);
+ filter();
+ }
+
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.java
new file mode 100644
index 000000000..c8d379fd6
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/DailiesRecyclerViewHolder.java
@@ -0,0 +1,29 @@
+package com.habitrpg.android.habitica.ui.adapter.tasks;
+
+import com.habitrpg.android.habitica.helpers.TagsHelper;
+import com.habitrpg.android.habitica.ui.viewHolders.tasks.BaseTaskViewHolder;
+import com.habitrpg.android.habitica.ui.viewHolders.tasks.DailyViewHolder;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class DailiesRecyclerViewHolder extends BaseTasksRecyclerViewAdapter {
+
+ public int dailyResetOffset;
+
+ public DailiesRecyclerViewHolder(String taskType, TagsHelper tagsHelper, int layoutResource, Context newContext, int dailyResetOffset) {
+ super(taskType, tagsHelper, layoutResource, newContext);
+ }
+
+ @Override
+ public DailyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new DailyViewHolder(getContentView(parent), dailyResetOffset);
+ }
+
+ @Override
+ public void onBindViewHolder(DailyViewHolder holder, int position) {
+ holder.displayChecklist = false;
+ super.onBindViewHolder(holder, position);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitItemRecyclerViewAdapter.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitItemRecyclerViewAdapter.java
deleted file mode 100644
index 84b54cf17..000000000
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitItemRecyclerViewAdapter.java
+++ /dev/null
@@ -1,691 +0,0 @@
-package com.habitrpg.android.habitica.ui.adapter.tasks;
-
-import com.github.data5tream.emojilib.EmojiTextView;
-import com.habitrpg.android.habitica.R;
-import com.habitrpg.android.habitica.databinding.DailyItemCardBinding;
-import com.habitrpg.android.habitica.databinding.HabitItemCardBinding;
-import com.habitrpg.android.habitica.databinding.RewardItemCardBinding;
-import com.habitrpg.android.habitica.databinding.TodoItemCardBinding;
-import com.habitrpg.android.habitica.events.HabitScoreEvent;
-import com.habitrpg.android.habitica.events.TaskCreatedEvent;
-import com.habitrpg.android.habitica.events.TaskRemovedEvent;
-import com.habitrpg.android.habitica.events.TaskSaveEvent;
-import com.habitrpg.android.habitica.events.TaskTappedEvent;
-import com.habitrpg.android.habitica.events.TaskUpdatedEvent;
-import com.habitrpg.android.habitica.events.commands.BuyRewardCommand;
-import com.habitrpg.android.habitica.events.commands.FilterTasksByTagsCommand;
-import com.habitrpg.android.habitica.events.commands.TaskCheckedCommand;
-import com.habitrpg.android.habitica.helpers.TagsHelper;
-import com.habitrpg.android.habitica.ui.adapter.IReceiveNewEntries;
-import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils;
-import com.magicmicky.habitrpgwrapper.lib.models.tasks.ChecklistItem;
-import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
-import com.raizlabs.android.dbflow.runtime.transaction.BaseTransaction;
-import com.raizlabs.android.dbflow.runtime.transaction.TransactionListener;
-import com.raizlabs.android.dbflow.sql.builder.Condition;
-import com.raizlabs.android.dbflow.sql.language.OrderBy;
-import com.raizlabs.android.dbflow.sql.language.Select;
-
-import org.greenrobot.eventbus.EventBus;
-import org.greenrobot.eventbus.Subscribe;
-
-import android.app.Activity;
-import android.content.Context;
-import android.databinding.DataBindingUtil;
-import android.databinding.ObservableArrayList;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.v4.content.ContextCompat;
-import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.LinearLayoutManager;
-import android.support.v7.widget.RecyclerView;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.TouchDelegate;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.CheckBox;
-import android.widget.CompoundButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import java.text.DateFormat;
-import java.util.List;
-import java.util.Locale;
-
-import butterknife.BindView;
-import butterknife.ButterKnife;
-
-
-public class HabitItemRecyclerViewAdapter
- extends RecyclerView.Adapter
- implements IReceiveNewEntries {
-
- public interface IAdditionalEntries {
- void GetAdditionalEntries(IReceiveNewEntries callBack);
- }
-
- int layoutResource;
- private Class> viewHolderClass;
- Integer displayedChecklist = null;
- String taskType;
- private ObservableArrayList filteredObservableContent;
- private ObservableArrayList observableContent;
- Context context;
- public int dailyResetOffset;
-
- private static final int TYPE_CELL = 1;
- private TagsHelper tagsHelper;
- private IAdditionalEntries additionalEntries;
-
- public HabitItemRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Class> viewHolderClass, Context newContext, int dailyResetOffset) {
- this(taskType, tagsHelper, layoutResource, viewHolderClass, newContext, dailyResetOffset, null);
- }
-
- public HabitItemRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Class> viewHolderClass,
- Context newContext, int dailyResetOffset, final IAdditionalEntries additionalEntries) {
- this.setHasStableIds(true);
- this.taskType = taskType;
- this.context = newContext;
- this.tagsHelper = tagsHelper;
- this.additionalEntries = additionalEntries;
- filteredObservableContent = new ObservableArrayList<>();
-
- this.loadContent(true);
-
- this.layoutResource = layoutResource;
- this.viewHolderClass = viewHolderClass;
- this.dailyResetOffset = dailyResetOffset;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- super.onAttachedToRecyclerView(recyclerView);
- EventBus.getDefault().register(this);
- }
-
- @Override
- public void onDetachedFromRecyclerView(RecyclerView recyclerView) {
- super.onDetachedFromRecyclerView(recyclerView);
- EventBus.getDefault().unregister(this);
-
- }
-
- @Subscribe
- public void onEvent(FilterTasksByTagsCommand cmd) {
- filter();
- }
-
- @Subscribe
- public void onEvent(TaskCheckedCommand evnt){
- if (!taskType.equals(evnt.Task.getType()))
- return;
-
- if(evnt.completed && evnt.Task.getType().equals("todo")){
- // remove from the list
- observableContent.remove(evnt.Task);
- }
- this.updateTask(evnt.Task);
- filter();
- }
-
- @Subscribe
- public void onEvent(TaskUpdatedEvent evnt) {
- if (!taskType.equals(evnt.task.getType()))
- return;
- this.updateTask(evnt.task);
- filter();
- }
-
- @Subscribe
- public void onEvent(TaskCreatedEvent evnt) {
- if (!taskType.equals(evnt.task.getType()))
- return;
-
- observableContent.add(0, evnt.task);
- filter();
- }
-
- @Subscribe
- public void onEvent(TaskRemovedEvent evnt) {
- Task taskToDelete = null;
-
- for(Task t : observableContent) {
- if(t.getId().equals(evnt.deletedTaskId)){
- taskToDelete = t;
- break;
- }
- }
-
- if(taskToDelete != null) {
- observableContent.remove(taskToDelete);
- filter();
- }
- }
-
- private void updateTask(Task task) {
- int i;
- for(i = 0; i < this.observableContent.size(); ++i) {
- if (observableContent.get(i).getId().equals(task.getId())) {
- break;
- }
- }
- if (i < observableContent.size()) {
- observableContent.set(i, task);
- }
- }
-
- private void filter() {
- if (this.tagsHelper.howMany() == 0) {
- filteredObservableContent = observableContent;
- } else {
- filteredObservableContent = new ObservableArrayList<>();
- filteredObservableContent.addAll(this.tagsHelper.filter(observableContent));
- }
-
- ((Activity) context).runOnUiThread(this::notifyDataSetChanged);
- }
-
- @Override
- public int getItemViewType(int position) {
- switch (position) {
- default:
- return TYPE_CELL;
- }
- }
-
- @Override
- public long getItemId(int position) {
- Task task = filteredObservableContent.get(position);
- return task.getId().hashCode();
- }
-
- @Override
- public int getItemCount() {
- return filteredObservableContent.size();
- }
-
- @Override
- public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- switch (viewType) {
- case TYPE_CELL: {
- View view = LayoutInflater.from(parent.getContext())
- .inflate(layoutResource, parent, false);
-
- switch (viewHolderClass.getSimpleName()) {
- case "HabitViewHolder":
- return new HabitItemRecyclerViewAdapter.HabitViewHolder(view);
- case "DailyViewHolder":
- return new HabitItemRecyclerViewAdapter.DailyViewHolder(view);
- case "TodoViewHolder":
- return new HabitItemRecyclerViewAdapter.TodoViewHolder(view);
- case "RewardViewHolder":
- return new HabitItemRecyclerViewAdapter.RewardViewHolder(view);
- }
- }
- }
- return null;
- }
-
- @Override
- public void onBindViewHolder(ViewHolder holder, int position) {
- Task item = filteredObservableContent.get(position);
-
- holder.bindHolder(item, position);
-
- if (this.displayedChecklist != null && ChecklistedViewHolder.class.isAssignableFrom(holder.getClass())) {
- ChecklistedViewHolder checklistedHolder = (ChecklistedViewHolder) holder;
- checklistedHolder.setDisplayChecklist(this.displayedChecklist == position);
- }
- }
-
- // todo use debounce
-
- // region ViewHolders
-
- public abstract class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
-
- protected android.content.res.Resources resources;
-
- public HabitItem Item;
-
- @BindView(R.id.checkedTextView)
- TextView titleTextView;
-
- @BindView(R.id.notesTextView)
- TextView notesTextView;
-
- public ViewHolder(View itemView) {
- super(itemView);
-
- itemView.setOnClickListener(this);
- itemView.setClickable(true);
-
- ButterKnife.bind(this, itemView);
-
- //Re enable when we find a way to only react when a link is tapped.
- //this.notesTextView.setMovementMethod(LinkMovementMethod.getInstance());
- //this.titleTextView.setMovementMethod(LinkMovementMethod.getInstance());
-
- resources = itemView.getResources();
- }
-
- public void bindHolder(HabitItem habitItem, int position) {
- Item = habitItem;
- if (habitItem.notes == null || habitItem.notes.length() == 0) {
- notesTextView.setHeight(0);
- } else {
- notesTextView.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));
- }
- }
-
- @Override
- public void onClick(View v) {
- if (v != itemView)
- return;
-
- TaskTappedEvent event = new TaskTappedEvent();
- event.Task = Item;
-
- EventBus.getDefault().post(event);
- }
- }
-
- public class HabitViewHolder extends ViewHolder {
-
- @BindView(R.id.btnPlus)
- Button btnPlus;
-
- @BindView(R.id.btnMinus)
- Button btnMinus;
-
- HabitItemCardBinding binding;
-
- public HabitViewHolder(View itemView) {
- super(itemView);
-
-
- binding = DataBindingUtil.bind(itemView);
-
- btnPlus.setClickable(true);
- btnPlus.setOnClickListener(this);
-
- btnMinus.setClickable(true);
- btnMinus.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- HabitScoreEvent event = new HabitScoreEvent();
-
- if (v == btnPlus) {
- event.Up = true;
- event.Habit = Item;
-
- EventBus.getDefault().post(event);
- } else if (v == btnMinus) {
- event.Habit = Item;
-
- EventBus.getDefault().post(event);
- } else super.onClick(v);
- }
-
- @Override
- public void bindHolder(Task habitItem, int position) {
- super.bindHolder(habitItem, position);
- binding.setHabit(habitItem);
- }
- }
-
- public class ChecklistedViewHolder extends ViewHolder implements CompoundButton.OnCheckedChangeListener {
-
- @BindView(R.id.checkBoxHolder)
- RelativeLayout checkboxHolder;
-
- @BindView(R.id.checkBox)
- CheckBox checkbox;
-
- @BindView(R.id.checklistView)
- LinearLayout checklistView;
-
- @BindView(R.id.checklistIndicatorWrapper)
- RelativeLayout checklistIndicatorWrapper;
-
- public Boolean displayChecklist;
-
- public ChecklistedViewHolder(View itemView) {
- super(itemView);
- checklistIndicatorWrapper.setOnClickListener(this);
- checkbox.setOnCheckedChangeListener(this);
- expandCheckboxTouchArea(checkboxHolder, checkbox);
-
- }
-
- @Override
- public void onClick(View v) {
-
- if (v == checklistIndicatorWrapper) {
- if (this.displayChecklist != null) {
- this.setDisplayChecklist(!this.displayChecklist);
- } else {
- this.setDisplayChecklist(true);
- }
- RecyclerView recyclerView = (RecyclerView)this.checklistView.getParent().getParent();
- LinearLayoutManager layoutManager = (LinearLayoutManager)recyclerView.getLayoutManager();
- layoutManager.scrollToPositionWithOffset(this.getAdapterPosition(), 15);
- } else {
- super.onClick(v);
- }
-
- }
-
- @Override
- public void bindHolder(Task habitItem, int position) {
- boolean itemChanged = Item != null && !Item.getId().equals(habitItem.getId());
-
- super.bindHolder(habitItem, position);
- Boolean isClickable = false;
- if (habitItem.getChecklist() != null && habitItem.getChecklist().size() > 0) {
- isClickable = true;
- }
- checklistIndicatorWrapper.setClickable(isClickable);
-
- if(itemChanged) {
- this.setDisplayChecklist(false);
- }
- }
-
- public void setDisplayChecklist(Boolean displayChecklist) {
- this.displayChecklist = displayChecklist;
- //This needs to be a LinearLayout, as ListViews can not be inside other ListViews.
- if (this.checklistView != null) {
- if (this.displayChecklist && this.Item.checklist != null) {
- LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- for (ChecklistItem item : this.Item.checklist) {
- LinearLayout itemView = (LinearLayout) layoutInflater.inflate(R.layout.checklist_item_row, this.checklistView, false);
- CheckBox checkbox = (CheckBox) itemView.findViewById(R.id.checkBox);
- EmojiTextView textView = (EmojiTextView) itemView.findViewById(R.id.checkedTextView);
- // Populate the data into the template view using the data object
- textView.setText(item.getText());
- checkbox.setChecked(item.getCompleted());
- checkbox.setOnCheckedChangeListener(this);
- RelativeLayout checkboxHolder = (RelativeLayout) itemView.findViewById(R.id.checkBoxHolder);
- expandCheckboxTouchArea(checkboxHolder, checkbox);
- this.checklistView.addView(itemView);
- }
- } else {
- this.checklistView.removeAllViewsInLayout();
- }
- }
- }
-
- @Override
- public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
- if (buttonView == checkbox) {
- if (isChecked != Item.getCompleted()) {
- TaskCheckedCommand event = new TaskCheckedCommand();
- event.Task = Item;
- event.completed = !Item.getCompleted();
-
- // it needs to be changed after the event is send -> to the server
- // maybe a refactor is needed here
- EventBus.getDefault().post(event);
- Item.completed =event.completed;
- Item.save();
-
- }
- } else {
- View v = (View) buttonView.getParent();
- while (v.getParent() != this.checklistView) {
- v = (View) v.getParent();
- }
- Integer position = ((ViewGroup) v.getParent()).indexOfChild(v);
- if (Item.checklist.size() > position && isChecked != Item.checklist.get(position).getCompleted()) {
- TaskSaveEvent event = new TaskSaveEvent();
- Item.checklist.get(position).setCompleted(isChecked);
- event.task = Item;
- EventBus.getDefault().post(event);
- }
- }
- }
-
- public void expandCheckboxTouchArea(final View expandedView, final View checkboxView){
- expandedView.post(() -> {
- Rect rect = new Rect();
- expandedView.getHitRect(rect);
- expandedView.setTouchDelegate(new TouchDelegate(rect, checkboxView));
- });
- }
- }
-
- public class DailyViewHolder extends ChecklistedViewHolder {
-
- DailyItemCardBinding binding;
-
- public DailyViewHolder(View itemView) {
- super(itemView);
-
- binding = DataBindingUtil.bind(itemView);
- checkbox.setOnCheckedChangeListener(this);
- }
-
- @Override
- public void bindHolder(Task habitItem, int position) {
- super.bindHolder(habitItem, position);
- binding.setOffset(dailyResetOffset);
- binding.setDaily(habitItem);
- }
-
- @Override
- public void setDisplayChecklist(Boolean displayChecklist) {
- binding.setDisplayChecklist(displayChecklist);
- super.setDisplayChecklist(displayChecklist);
- }
-
- }
-
- public class TodoViewHolder extends ChecklistedViewHolder {
-
- TodoItemCardBinding binding;
-
- DateFormat dateFormat;
-
- public TodoViewHolder(View itemView) {
- super(itemView);
-
- binding = DataBindingUtil.bind(itemView);
-
- this.dateFormat = android.text.format.DateFormat.getDateFormat(context);
- }
-
- @Override
- public void bindHolder(Task habitItem, int position) {
- super.bindHolder(habitItem, position);
-
- binding.setTodo(habitItem);
- if (habitItem.duedate != null) {
- binding.setDuedate(this.dateFormat.format(habitItem.duedate));
- }
- }
-
- @Override
- public void setDisplayChecklist(Boolean displayChecklist) {
- binding.setDisplayChecklist(displayChecklist);
- super.setDisplayChecklist(displayChecklist);
- }
- }
-
- public class RewardViewHolder extends ViewHolder {
- RewardItemCardBinding binding;
-
- @BindView(R.id.btnReward)
- Button btnReward;
-
- public RewardViewHolder(View itemView) {
- super(itemView);
-
- binding = DataBindingUtil.bind(itemView);
-
- btnReward.setClickable(true);
- btnReward.setOnClickListener(this);
- }
-
- @Override
- public void onClick(View v) {
- if (v == btnReward) {
- BuyRewardCommand event = new BuyRewardCommand();
- event.Reward = Item;
- EventBus.getDefault().post(event);
- } else {
- if(Item.specialTag != null && Item.specialTag.equals("item")) {
- LinearLayout contentViewForDialog = createContentViewForGearDialog();
- AlertDialog dialog = createGearDialog(contentViewForDialog);
- dialog.show();
- } else {
- TaskTappedEvent event = new TaskTappedEvent();
- event.Task = Item;
-
- EventBus.getDefault().post(event);
- }
- }
- }
-
- private AlertDialog createGearDialog(LinearLayout contentViewForDialog) {
- return new AlertDialog.Builder(context)
- .setPositiveButton(R.string.reward_dialog_buy, (dialog, which) -> {
- BuyRewardCommand event = new BuyRewardCommand();
- event.Reward = Item;
- EventBus.getDefault().post(event);
- })
- .setTitle(binding.getReward().getText())
- .setView(contentViewForDialog)
- .setNegativeButton(R.string.reward_dialog_dismiss, (dialog, which) -> {
- dialog.dismiss();
- }).create();
- }
-
- @NonNull
- private LinearLayout createContentViewForGearDialog() {
- String price = String.format(Locale.getDefault(), "%.0f", binding.getReward().value);
- String content = binding.getReward().getNotes();
-
- // External ContentView
- LinearLayout contentViewLayout = new LinearLayout(context);
- contentViewLayout.setOrientation(LinearLayout.VERTICAL);
-
- // Gear Image
- ImageView gearImageView = new ImageView(context);
- LinearLayout.LayoutParams gearImageLayoutParams = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
-
- gearImageLayoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
- gearImageLayoutParams.setMargins(0,0,0,20);
- gearImageView.setMinimumWidth(200);
- gearImageView.setMinimumHeight(200);
- gearImageView.setLayoutParams(gearImageLayoutParams);
- DataBindingUtils.loadImage(gearImageView, "shop_" + binding.getReward().getId());
-
- // Gear Description
- TextView contentTextView = new TextView(context, null);
- if(!content.isEmpty()){
- contentTextView.setText(content);
- }
-
- // GoldPrice View
- LinearLayout goldPriceLayout = new LinearLayout(context);
- goldPriceLayout.setGravity(Gravity.CENTER_HORIZONTAL);
- LinearLayout.LayoutParams goldPriceLayoutParams = new LinearLayout.LayoutParams(
- LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- goldPriceLayoutParams.setMargins(0, 0, 0, 16);
- goldPriceLayoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
-
- goldPriceLayout.setOrientation(LinearLayout.HORIZONTAL);
- goldPriceLayout.setLayoutParams(goldPriceLayoutParams);
- goldPriceLayout.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
-
- // Price View
- TextView priceTextView = new TextView(context);
- priceTextView.setText(price);
- priceTextView.setPadding(10, 0, 0, 0);
-
- ImageView gold = new ImageView(context);
- gold.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_header_gold));
- gold.setMinimumHeight(50);
- gold.setMinimumWidth(50);
- gold.setPadding(0, 0, 5, 0);
-
- goldPriceLayout.addView(gold);
- goldPriceLayout.addView(priceTextView);
-
- if(gearImageView.getDrawable()!= null){
- contentViewLayout.addView(gearImageView);
- }
- contentViewLayout.setGravity(Gravity.CENTER_VERTICAL);
-
- contentViewLayout.addView(goldPriceLayout);
-
- if(!content.isEmpty()){
- contentViewLayout.addView(contentTextView);
- }
-
- return contentViewLayout;
- }
-
- @Override
- public void bindHolder(Task reward, int position) {
- super.bindHolder(reward, position);
-
- binding.setReward(reward);
- }
- }
-
- // endregion
-
- public void loadContent(boolean forced) {
-
- if (this.observableContent == null || forced) {
- this.observableContent = new ObservableArrayList<>();
- new Select().from(Task.class)
- .where(Condition.column("type").eq(this.taskType))
- .and(Condition.CombinedCondition
- .begin(Condition.column("completed").eq(false))
- .or(Condition.column("type").eq("daily"))
- )
- .orderBy(OrderBy.columns("position", "dateCreated").descending())
- .async()
- .queryList(taskTransactionListener);
-
- }
- }
-
- private TransactionListener> taskTransactionListener = new TransactionListener>() {
- @Override
- public void onResultReceived(List tasks) {
- observableContent.clear();
- observableContent.addAll(tasks);
- if (additionalEntries != null) {
- additionalEntries.GetAdditionalEntries(HabitItemRecyclerViewAdapter.this);
- }
- filter();
- }
-
- @Override
- public boolean onReady(BaseTransaction> transaction) {
- return true;
- }
-
- @Override
- public boolean hasResult(BaseTransaction> transaction, List result) {
- return true;
- }
- };
-
- @Override
- public void GotAdditionalItems(List items) {
- this.observableContent.addAll(items);
- notifyDataSetChanged();
- }
-}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.java
new file mode 100644
index 000000000..78f4d8f89
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/HabitsRecyclerViewAdapter.java
@@ -0,0 +1,20 @@
+package com.habitrpg.android.habitica.ui.adapter.tasks;
+
+import com.habitrpg.android.habitica.helpers.TagsHelper;
+import com.habitrpg.android.habitica.ui.viewHolders.tasks.HabitViewHolder;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class HabitsRecyclerViewAdapter extends BaseTasksRecyclerViewAdapter {
+ public HabitsRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Context newContext) {
+ super(taskType, tagsHelper, layoutResource, newContext);
+ }
+
+ @Override
+ public HabitViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new HabitViewHolder(getContentView(parent));
+ }
+}
\ No newline at end of file
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.java
new file mode 100644
index 000000000..bcdb080c4
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/RewardsRecyclerViewAdapter.java
@@ -0,0 +1,99 @@
+package com.habitrpg.android.habitica.ui.adapter.tasks;
+
+import com.habitrpg.android.habitica.APIHelper;
+import com.habitrpg.android.habitica.ContentCache;
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.helpers.TagsHelper;
+import com.habitrpg.android.habitica.ui.viewHolders.tasks.RewardViewHolder;
+import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.ItemData;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+import com.raizlabs.android.dbflow.sql.builder.Condition;
+import com.raizlabs.android.dbflow.sql.language.Select;
+
+import android.content.Context;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import rx.Observable;
+import rx.Subscriber;
+
+public class RewardsRecyclerViewAdapter extends BaseTasksRecyclerViewAdapter {
+
+ private final ContentCache contentCache;
+ private final HabitRPGUser user;
+ private APIHelper apiHelper;
+
+ public RewardsRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Context newContext, HabitRPGUser user, APIHelper apiHelper) {
+ super(taskType, tagsHelper, layoutResource, newContext);
+ this.user = user;
+ this.apiHelper = apiHelper;
+ this.contentCache = new ContentCache(apiHelper.apiService);
+ }
+
+ @Override
+ public RewardViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new RewardViewHolder(getContentView(parent));
+ }
+
+ public void loadEquipmentRewards() {
+ if (apiHelper != null) {
+ apiHelper.apiService.getInventoryBuyableGear()
+ .compose(apiHelper.configureApiCallObserver())
+ .flatMap(items -> {
+ // get itemdata list
+ ArrayList itemKeys = new ArrayList<>();
+ for (ItemData item : items) {
+ itemKeys.add(item.key);
+ }
+ itemKeys.add("potion");
+ if (user.getFlags().getArmoireEnabled()) {
+ itemKeys.add("armoire");
+ }
+ return Observable.create((Observable.OnSubscribe>) subscriber -> {
+ contentCache.GetItemDataList(itemKeys, obj -> {
+ ArrayList buyableItems = new ArrayList<>();
+ for (ItemData item : obj) {
+ Task reward = new Task();
+ reward.text = item.text;
+ reward.notes = item.notes;
+ reward.value = item.value;
+ reward.setType("reward");
+ reward.specialTag = "item";
+ reward.setId(item.key);
+
+ if (item.key.equals("armoire")) {
+ if (user.getFlags().getArmoireEmpty()) {
+ reward.notes = context.getResources().getString(R.string.armoireNotesEmpty);
+ } else {
+ long gearCount = new Select().count()
+ .from(ItemData.class)
+ .where(Condition.CombinedCondition.begin(Condition.column("klass").eq("armoire"))
+ .and(Condition.column("owned").isNull())
+ ).count();
+ reward.notes = context.getResources().getString(R.string.armoireNotesFull, gearCount);
+ }
+ }
+
+ buyableItems.add(reward);
+ }
+ subscriber.onNext(buyableItems);
+ subscriber.onCompleted();
+ });
+ });
+ })
+ .subscribe(items -> {
+ this.filteredContent.addAll(items);
+ notifyDataSetChanged();
+ }, throwable -> {});
+ }
+ }
+
+ @Override
+ public void setTasks(List tasks) {
+ super.setTasks(tasks);
+ this.loadEquipmentRewards();
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.java
new file mode 100644
index 000000000..e55f808dd
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/adapter/tasks/TodosRecyclerViewAdapter.java
@@ -0,0 +1,19 @@
+package com.habitrpg.android.habitica.ui.adapter.tasks;
+
+import com.habitrpg.android.habitica.helpers.TagsHelper;
+import com.habitrpg.android.habitica.ui.viewHolders.tasks.TodoViewHolder;
+
+import android.content.Context;
+import android.view.ViewGroup;
+
+public class TodosRecyclerViewAdapter extends BaseTasksRecyclerViewAdapter {
+
+ public TodosRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Context newContext) {
+ super(taskType, tagsHelper, layoutResource, newContext);
+ }
+
+ @Override
+ public TodoViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ return new TodoViewHolder(getContentView(parent));
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.java
index 81bb293ed..03459100b 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TaskRecyclerViewFragment.java
@@ -3,7 +3,7 @@ package com.habitrpg.android.habitica.ui.fragments.tasks;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.events.commands.AddNewTaskCommand;
import com.habitrpg.android.habitica.ui.DividerItemDecoration;
-import com.habitrpg.android.habitica.ui.adapter.tasks.HabitItemRecyclerViewAdapter;
+import com.habitrpg.android.habitica.ui.adapter.tasks.BaseTasksRecyclerViewAdapter;
import com.habitrpg.android.habitica.ui.fragments.BaseFragment;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
@@ -24,15 +24,15 @@ import android.view.ViewGroup;
* - Handles the ScrollPosition - if anyone has a better solution please share it
*/
public class TaskRecyclerViewFragment extends BaseFragment implements View.OnClickListener {
- public RecyclerView mRecyclerView;
- public RecyclerView.Adapter mAdapter;
+ public RecyclerView recyclerView;
+ public RecyclerView.Adapter recyclerAdapter;
private String classType;
private static final String CLASS_TYPE_KEY = "CLASS_TYPE_KEY";
// TODO needs a bit of cleanup
- public void SetInnerAdapter(HabitItemRecyclerViewAdapter adapter, String classType) {
+ public void SetInnerAdapter(BaseTasksRecyclerViewAdapter adapter, String classType) {
this.classType = classType;
- mAdapter = adapter;
+ recyclerAdapter = adapter;
}
private View view;
@@ -42,18 +42,18 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
if (view == null) {
view = inflater.inflate(R.layout.fragment_recyclerview, container, false);
- mRecyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
+ recyclerView = (RecyclerView) view.findViewById(R.id.recyclerView);
android.support.v4.app.FragmentActivity context = getActivity();
- layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
+ layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
if (layoutManager == null) {
layoutManager = new LinearLayoutManager(context);
- mRecyclerView.setLayoutManager(layoutManager);
+ recyclerView.setLayoutManager(layoutManager);
}
- mRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
+ recyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), DividerItemDecoration.VERTICAL_LIST));
}
if (savedInstanceState != null){
@@ -91,7 +91,7 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
- mRecyclerView.setAdapter(mAdapter);
+ recyclerView.setAdapter(recyclerAdapter);
}
@Override
@@ -100,7 +100,7 @@ public class TaskRecyclerViewFragment extends BaseFragment implements View.OnCli
outState.putString(CLASS_TYPE_KEY, this.classType);
}
- public static TaskRecyclerViewFragment newInstance(HabitItemRecyclerViewAdapter adapter, String classType) {
+ public static TaskRecyclerViewFragment newInstance(BaseTasksRecyclerViewAdapter adapter, String classType) {
TaskRecyclerViewFragment fragment = new TaskRecyclerViewFragment();
fragment.setRetainInstance(true);
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.java
index 9c72831e3..d5e92bfdb 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/tasks/TasksFragment.java
@@ -22,7 +22,11 @@ import com.habitrpg.android.habitica.ui.EditTextDrawer;
import com.habitrpg.android.habitica.ui.UiUtils;
import com.habitrpg.android.habitica.ui.activities.MainActivity;
import com.habitrpg.android.habitica.ui.activities.TaskFormActivity;
-import com.habitrpg.android.habitica.ui.adapter.tasks.HabitItemRecyclerViewAdapter;
+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.HabitsRecyclerViewAdapter;
+import com.habitrpg.android.habitica.ui.adapter.tasks.RewardsRecyclerViewAdapter;
+import com.habitrpg.android.habitica.ui.adapter.tasks.TodosRecyclerViewAdapter;
import com.habitrpg.android.habitica.ui.fragments.BaseMainFragment;
import com.habitrpg.android.habitica.ui.helpers.Debounce;
import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
@@ -85,7 +89,6 @@ public class TasksFragment extends BaseMainFragment implements OnCheckedChangeLi
private TagsHelper tagsHelper; // This will be used for this fragment. Currently being used to help filtering
private ArrayList tagNames; // Added this so other activities/fragments can get the String names, not IDs
private ArrayList tagIds; // Added this so other activities/fragments can get the IDs
- private ContentCache contentCache;
private boolean displayingTaskForm;
private HashMap tagFilterMap = new HashMap<>();
@@ -106,7 +109,6 @@ public class TasksFragment extends BaseMainFragment implements OnCheckedChangeLi
public void setActivity(MainActivity activity) {
super.setActivity(activity);
- contentCache = new ContentCache(apiHelper.apiService);
}
@Override
@@ -206,12 +208,12 @@ public class TasksFragment extends BaseMainFragment implements OnCheckedChangeLi
public Fragment getItem(int position) {
int layoutOfType;
TaskRecyclerViewFragment fragment;
- HabitItemRecyclerViewAdapter adapter;
+ BaseTasksRecyclerViewAdapter adapter;
switch (position) {
case 0:
layoutOfType = R.layout.habit_item_card;
- fragment = TaskRecyclerViewFragment.newInstance(new HabitItemRecyclerViewAdapter(Task.TYPE_HABIT, TasksFragment.this.tagsHelper, layoutOfType, HabitItemRecyclerViewAdapter.HabitViewHolder.class, activity, 0), Task.TYPE_HABIT);
+ fragment = TaskRecyclerViewFragment.newInstance(new HabitsRecyclerViewAdapter(Task.TYPE_HABIT, TasksFragment.this.tagsHelper, layoutOfType, activity), Task.TYPE_HABIT);
break;
case 1:
@@ -220,71 +222,19 @@ public class TasksFragment extends BaseMainFragment implements OnCheckedChangeLi
if (user != null) {
dailyResetOffset = user.getPreferences().getDayStart();
}
- adapter = new HabitItemRecyclerViewAdapter(Task.TYPE_DAILY, TasksFragment.this.tagsHelper, layoutOfType, HabitItemRecyclerViewAdapter.DailyViewHolder.class, activity, dailyResetOffset);
+ adapter = new DailiesRecyclerViewHolder(Task.TYPE_DAILY, TasksFragment.this.tagsHelper, layoutOfType, activity, dailyResetOffset);
fragment = TaskRecyclerViewFragment.newInstance(adapter, Task.TYPE_DAILY);
break;
case 3:
layoutOfType = R.layout.reward_item_card;
- adapter = new HabitItemRecyclerViewAdapter(Task.TYPE_REWARD, TasksFragment.this.tagsHelper,
- layoutOfType, HabitItemRecyclerViewAdapter.RewardViewHolder.class, activity, 0,
- callBack -> {
-
- // request buyable gear
- if (apiHelper != null) {
- apiHelper.apiService.getInventoryBuyableGear()
- .compose(apiHelper.configureApiCallObserver())
- .subscribe(itemDatas -> {
- // get itemdata list
- ArrayList itemKeys = new ArrayList<>();
- for (ItemData item : itemDatas) {
- itemKeys.add(item.key);
- }
- itemKeys.add("potion");
- if (user.getFlags().getArmoireEnabled())
- itemKeys.add("armoire");
-
- contentCache.GetItemDataList(itemKeys, obj -> {
- ArrayList buyableItems = new ArrayList<>();
- if (!isAdded()) {
- return;
- }
- for (ItemData item : obj) {
- Task reward = new Task();
- reward.text = item.text;
- reward.notes = item.notes;
- reward.value = item.value;
- reward.setType("reward");
- reward.specialTag = "item";
- reward.setId(item.key);
-
- if (item.key.equals("armoire")) {
- if (user.getFlags().getArmoireEmpty()) {
- reward.notes = getResources().getString(R.string.armoireNotesEmpty);
- } else {
- long gearCount = new Select().count()
- .from(ItemData.class)
- .where(Condition.CombinedCondition.begin(Condition.column("klass").eq("armoire"))
- .and(Condition.column("owned").isNull())
- ).count();
- reward.notes = getResources().getString(R.string.armoireNotesFull, gearCount);
- }
- }
-
- buyableItems.add(reward);
- }
-
- callBack.GotAdditionalItems(buyableItems);
- });
- }, throwable -> {});
- }
- });
+ adapter = new RewardsRecyclerViewAdapter(Task.TYPE_REWARD, TasksFragment.this.tagsHelper, layoutOfType, activity, user, apiHelper);
fragment = TaskRecyclerViewFragment.newInstance(adapter, Task.TYPE_REWARD);
break;
default:
layoutOfType = R.layout.todo_item_card;
- fragment = TaskRecyclerViewFragment.newInstance(new HabitItemRecyclerViewAdapter(Task.TYPE_TODO, TasksFragment.this.tagsHelper, layoutOfType, HabitItemRecyclerViewAdapter.TodoViewHolder.class, activity, 0), Task.TYPE_TODO);
+ fragment = TaskRecyclerViewFragment.newInstance(new TodosRecyclerViewAdapter(Task.TYPE_TODO, TasksFragment.this.tagsHelper, layoutOfType, activity), Task.TYPE_TODO);
}
ViewFragmentsDictionary.put(position, fragment);
@@ -330,9 +280,11 @@ public class TasksFragment extends BaseMainFragment implements OnCheckedChangeLi
for (TaskRecyclerViewFragment fragm : ViewFragmentsDictionary.values()) {
if (fragm != null) {
- final HabitItemRecyclerViewAdapter adapter = (HabitItemRecyclerViewAdapter) fragm.mAdapter;
- adapter.dailyResetOffset = this.user.getPreferences().getDayStart();
- AsyncTask.execute(() -> adapter.loadContent(true));
+ if (fragm.recyclerAdapter.getClass().equals(DailiesRecyclerViewHolder.class)) {
+ final DailiesRecyclerViewHolder adapter = (DailiesRecyclerViewHolder) fragm.recyclerAdapter;
+ adapter.dailyResetOffset = this.user.getPreferences().getDayStart();
+ AsyncTask.execute(() -> adapter.loadContent(true));
+ }
}
}
}
@@ -420,9 +372,9 @@ public class TasksFragment extends BaseMainFragment implements OnCheckedChangeLi
@Subscribe
public void onEvent(HabitScoreEvent event) {
- apiHelper.apiService.postTaskDirection(event.Habit.getId(), (event.Up ? TaskDirection.up : TaskDirection.down).toString())
+ apiHelper.apiService.postTaskDirection(event.habit.getId(), (event.Up ? TaskDirection.up : TaskDirection.down).toString())
.compose(apiHelper.configureApiCallObserver())
- .subscribe(new TaskScoringCallback(activity, event.Habit.getId()), throwable -> {});
+ .subscribe(new TaskScoringCallback(activity, event.habit.getId()), throwable -> {});
}
@Subscribe
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.java
new file mode 100644
index 000000000..e4a6823a5
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/BaseTaskViewHolder.java
@@ -0,0 +1,81 @@
+package com.habitrpg.android.habitica.ui.viewHolders.tasks;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.events.TaskTappedEvent;
+import com.habitrpg.android.habitica.ui.helpers.MarkdownParser;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+
+import org.greenrobot.eventbus.EventBus;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.widget.TextView;
+
+import butterknife.BindColor;
+import butterknife.BindView;
+import butterknife.ButterKnife;
+
+public class BaseTaskViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
+
+ protected Context context;
+
+ public Task task;
+
+ @BindView(R.id.checkedTextView)
+ TextView titleTextView;
+
+ @BindView(R.id.notesTextView)
+ TextView notesTextView;
+
+ @Nullable
+ @BindView(R.id.rightBorderView)
+ View rightBorderView;
+
+ @BindColor(R.color.task_gray)
+ int taskGray;
+
+ public BaseTaskViewHolder(View itemView) {
+ super(itemView);
+
+ itemView.setOnClickListener(this);
+ itemView.setClickable(true);
+
+ ButterKnife.bind(this, itemView);
+
+ //Re enable when we find a way to only react when a link is tapped.
+ //this.notesTextView.setMovementMethod(LinkMovementMethod.getInstance());
+ //this.titleTextView.setMovementMethod(LinkMovementMethod.getInstance());
+
+ context = itemView.getContext();
+ }
+
+ public void bindHolder(Task newTask, int position) {
+ this.task = newTask;
+ this.titleTextView.setText(MarkdownParser.parseMarkdown(this.task.getText()));
+ if (this.task.getNotes().length() > 0) {
+ this.notesTextView.setText(MarkdownParser.parseMarkdown(this.task.getNotes()));
+ this.notesTextView.setVisibility(View.VISIBLE);
+ } else {
+ this.notesTextView.setVisibility(View.GONE);
+ }
+
+ if (this.rightBorderView != null) {
+ this.rightBorderView.setBackgroundResource(this.task.getLightTaskColor());
+ }
+ }
+
+ @Override
+ public void onClick(View v) {
+ if (v != itemView) {
+ return;
+ }
+
+ TaskTappedEvent event = new TaskTappedEvent();
+ event.Task = task;
+
+ EventBus.getDefault().post(event);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.java
new file mode 100644
index 000000000..c6c915533
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/ChecklistedViewHolder.java
@@ -0,0 +1,168 @@
+package com.habitrpg.android.habitica.ui.viewHolders.tasks;
+
+import com.github.data5tream.emojilib.EmojiTextView;
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.events.TaskSaveEvent;
+import com.habitrpg.android.habitica.events.commands.TaskCheckedCommand;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.ChecklistItem;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+
+import org.greenrobot.eventbus.EventBus;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.TouchDelegate;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import butterknife.BindView;
+import butterknife.OnClick;
+
+public abstract class ChecklistedViewHolder extends BaseTaskViewHolder implements CompoundButton.OnCheckedChangeListener {
+
+ @BindView(R.id.checkBoxHolder)
+ RelativeLayout checkboxHolder;
+
+ @BindView(R.id.checkBox)
+ CheckBox checkbox;
+
+ @BindView(R.id.checklistView)
+ LinearLayout checklistView;
+ @BindView(R.id.checklistSeparator)
+ View checklistSeparator;
+ @BindView(R.id.checklistBottomSpace)
+ View checklistBottomSpace;
+
+ @BindView(R.id.checklistIndicatorWrapper)
+ RelativeLayout checklistIndicatorWrapper;
+
+ @BindView(R.id.checkListCompletedTextView)
+ TextView checklistCompletedTextView;
+ @BindView(R.id.checkListAllTextView)
+ TextView checklistAllTextView;
+
+ public Boolean displayChecklist;
+
+ public ChecklistedViewHolder(View itemView) {
+ super(itemView);
+ checklistIndicatorWrapper.setClickable(true);
+ checkbox.setOnCheckedChangeListener(this);
+ expandCheckboxTouchArea(checkboxHolder, checkbox);
+ this.displayChecklist = false;
+ }
+
+ @Override
+ public void bindHolder(Task newTask, int position) {
+ super.bindHolder(newTask, position);
+ if (this.shouldDisplayAsActive()) {
+ this.checkboxHolder.setBackgroundResource(this.task.getLightTaskColor());
+ } else {
+ this.checkboxHolder.setBackgroundColor(this.taskGray);
+ }
+ this.checklistCompletedTextView.setText(String.valueOf(task.getCompletedChecklistCount()));
+ this.checklistAllTextView.setText(String.valueOf(task.getChecklist().size()));
+
+ this.checklistView.removeAllViews();
+ this.setDisplayChecklist(this.displayChecklist);
+
+ this.checklistIndicatorWrapper.setVisibility(task.checklist.size() == 0 ? View.GONE : View.VISIBLE);
+ if (this.rightBorderView != null) {
+ this.rightBorderView.setVisibility(task.checklist.size() == 0 ? View.VISIBLE : View.GONE);
+ if (this.task.getCompleted()) {
+ this.rightBorderView.setBackgroundResource(this.task.getLightTaskColor());
+ } else {
+ this.rightBorderView.setBackgroundColor(this.taskGray);
+ }
+ }
+ }
+
+ abstract public Boolean shouldDisplayAsActive();
+
+ public void setDisplayChecklist(Boolean displayChecklist) {
+ this.displayChecklist = displayChecklist;
+ //This needs to be a LinearLayout, as ListViews can not be inside other ListViews.
+ if (this.checklistView != null) {
+ if (this.displayChecklist && this.task.checklist != null) {
+ LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ for (ChecklistItem item : this.task.checklist) {
+ LinearLayout itemView = (LinearLayout) layoutInflater.inflate(R.layout.checklist_item_row, this.checklistView, false);
+ CheckBox checkbox = (CheckBox) itemView.findViewById(R.id.checkBox);
+ EmojiTextView textView = (EmojiTextView) itemView.findViewById(R.id.checkedTextView);
+ // Populate the data into the template view using the data object
+ textView.setText(item.getText());
+ checkbox.setChecked(item.getCompleted());
+ checkbox.setOnCheckedChangeListener(this);
+ RelativeLayout checkboxHolder = (RelativeLayout) itemView.findViewById(R.id.checkBoxHolder);
+ expandCheckboxTouchArea(checkboxHolder, checkbox);
+ this.checklistView.addView(itemView);
+ }
+ this.checklistSeparator.setVisibility(View.VISIBLE);
+ this.checklistView.setVisibility(View.VISIBLE);
+ this.checklistBottomSpace.setVisibility(View.VISIBLE);
+ } else {
+ this.checklistView.removeAllViewsInLayout();
+ this.checklistSeparator.setVisibility(View.GONE);
+ this.checklistView.setVisibility(View.GONE);
+ this.checklistBottomSpace.setVisibility(View.GONE);
+ }
+ }
+ }
+
+ @OnClick(R.id.checklistIndicatorWrapper)
+ public void onChecklistIndicatorClicked() {
+ if (this.displayChecklist != null) {
+ this.setDisplayChecklist(!this.displayChecklist);
+ } else {
+ this.setDisplayChecklist(true);
+ }
+ RecyclerView recyclerView = (RecyclerView)this.checklistView.getParent().getParent();
+ LinearLayoutManager layoutManager = (LinearLayoutManager)recyclerView.getLayoutManager();
+ layoutManager.scrollToPositionWithOffset(this.getAdapterPosition(), 15);
+ }
+
+ public void expandCheckboxTouchArea(final View expandedView, final View checkboxView){
+ expandedView.post(() -> {
+ Rect rect = new Rect();
+ expandedView.getHitRect(rect);
+ expandedView.setTouchDelegate(new TouchDelegate(rect, checkboxView));
+ });
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (buttonView == checkbox) {
+ if (isChecked != task.getCompleted()) {
+ TaskCheckedCommand event = new TaskCheckedCommand();
+ event.Task = task;
+ event.completed = !task.getCompleted();
+
+ // it needs to be changed after the event is send -> to the server
+ // maybe a refactor is needed here
+ EventBus.getDefault().post(event);
+ task.completed =event.completed;
+ task.save();
+
+ }
+ } else {
+ View v = (View) buttonView.getParent();
+ while (v.getParent() != this.checklistView) {
+ v = (View) v.getParent();
+ }
+ Integer position = ((ViewGroup) v.getParent()).indexOfChild(v);
+ if (task.checklist.size() > position && isChecked != task.checklist.get(position).getCompleted()) {
+ TaskSaveEvent event = new TaskSaveEvent();
+ task.checklist.get(position).setCompleted(isChecked);
+ event.task = task;
+ EventBus.getDefault().post(event);
+ }
+ }
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.java
new file mode 100644
index 000000000..0c2240657
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/DailyViewHolder.java
@@ -0,0 +1,31 @@
+package com.habitrpg.android.habitica.ui.viewHolders.tasks;
+
+import com.habitrpg.android.habitica.R;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+
+import android.view.View;
+
+public class DailyViewHolder extends ChecklistedViewHolder {
+
+ public final int dailyResetOffset;
+
+ public DailyViewHolder(View itemView, int dailyResetOffset) {
+ super(itemView);
+ this.dailyResetOffset = dailyResetOffset;
+ }
+
+ @Override
+ public void bindHolder(Task newTask, int position) {
+ super.bindHolder(newTask, position);
+ if (this.task.isChecklistDisplayActive(dailyResetOffset)) {
+ this.checklistIndicatorWrapper.setBackgroundResource(this.task.getLightTaskColor());
+ } else {
+ this.checklistIndicatorWrapper.setBackgroundColor(this.taskGray);
+ }
+ }
+
+ @Override
+ public Boolean shouldDisplayAsActive() {
+ return this.task.isDisplayedActive(this.dailyResetOffset);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.java
new file mode 100644
index 000000000..6fd69bbe4
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/HabitViewHolder.java
@@ -0,0 +1,66 @@
+package com.habitrpg.android.habitica.ui.viewHolders.tasks;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.events.HabitScoreEvent;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+
+import org.greenrobot.eventbus.EventBus;
+
+import android.view.View;
+import android.widget.Button;
+import android.widget.FrameLayout;
+
+import butterknife.BindView;
+import butterknife.OnClick;
+
+public class HabitViewHolder extends BaseTaskViewHolder {
+
+ @BindView(R.id.btnPlusWrapper)
+ FrameLayout btnPlusWrapper;
+ @BindView(R.id.btnPlusBackground)
+ View btnPlusBackground;
+ @BindView(R.id.btnPlus)
+ Button btnPlus;
+
+ @BindView(R.id.btnMinusWrapper)
+ FrameLayout btnMinusWrapper;
+ @BindView(R.id.btnMinusBackground)
+ View btnMinusBackground;
+ @BindView(R.id.btnMinus)
+ Button btnMinus;
+
+ public HabitViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ @Override
+ public void bindHolder(Task newTask, int position) {
+ super.bindHolder(newTask, position);
+
+ this.btnPlusWrapper.setVisibility(this.task.getUp() ? View.VISIBLE : View.GONE);
+ this.btnPlusBackground.setBackgroundResource(this.task.getLightTaskColor());
+
+ this.btnMinusWrapper.setVisibility(this.task.getDown() ? View.VISIBLE : View.GONE);
+ if (task.getUp()) {
+ this.btnMinusBackground.setBackgroundResource(this.task.getMediumTaskColor());
+ } else {
+ this.btnMinusBackground.setBackgroundResource(this.task.getLightTaskColor());
+ }
+ }
+
+ @OnClick(R.id.btnPlus)
+ public void onPlusButtonClicked() {
+ HabitScoreEvent event = new HabitScoreEvent();
+ event.Up = true;
+ event.habit = task;
+ EventBus.getDefault().post(event);
+ }
+
+ @OnClick(R.id.btnMinus)
+ public void onMinusButtonClicked() {
+ HabitScoreEvent event = new HabitScoreEvent();
+ event.Up = false;
+ event.habit = task;
+ EventBus.getDefault().post(event);
+ }
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.java
new file mode 100644
index 000000000..836d87557
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/RewardViewHolder.java
@@ -0,0 +1,155 @@
+package com.habitrpg.android.habitica.ui.viewHolders.tasks;
+
+import com.habitrpg.android.habitica.R;
+import com.habitrpg.android.habitica.events.TaskTappedEvent;
+import com.habitrpg.android.habitica.events.commands.BuyRewardCommand;
+import com.habitrpg.android.habitica.ui.helpers.DataBindingUtils;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+
+import org.greenrobot.eventbus.EventBus;
+
+import android.support.annotation.NonNull;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.app.AlertDialog;
+import android.view.Gravity;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.text.DecimalFormat;
+
+import butterknife.BindView;
+import butterknife.OnClick;
+
+public class RewardViewHolder extends BaseTaskViewHolder {
+
+ private final DecimalFormat priceFormat;
+ @BindView(R.id.rewardImageView)
+ ImageView rewardImageView;
+
+ @BindView(R.id.btnReward)
+ Button rewardButton;
+
+ public RewardViewHolder(View itemView) {
+ super(itemView);
+ priceFormat = new DecimalFormat("0.##");
+
+ }
+
+ @Override
+ public void bindHolder(Task newTask, int position) {
+ super.bindHolder(newTask, position);
+
+ this.rewardButton.setText(this.priceFormat.format(this.task.value));
+
+ if (this.task.specialTag != null && this.task.specialTag.equals("item")) {
+ this.rewardImageView.setVisibility(View.VISIBLE);
+ DataBindingUtils.loadImage(this.rewardImageView, "shop_" + this.task.getId());
+ } else {
+ this.rewardImageView.setVisibility(View.GONE);
+ }
+ }
+
+ @OnClick(R.id.btnReward)
+ public void buyReward() {
+ BuyRewardCommand event = new BuyRewardCommand();
+ event.Reward = task;
+ EventBus.getDefault().post(event);
+ }
+
+ @Override
+ public void onClick(View v) {
+ if(task.specialTag != null && task.specialTag.equals("item")) {
+ LinearLayout contentViewForDialog = createContentViewForGearDialog();
+ AlertDialog dialog = createGearDialog(contentViewForDialog);
+ dialog.show();
+ } else {
+ TaskTappedEvent event = new TaskTappedEvent();
+ event.Task = task;
+
+ EventBus.getDefault().post(event);
+ }
+ }
+
+ private AlertDialog createGearDialog(LinearLayout contentViewForDialog) {
+ return new AlertDialog.Builder(context)
+ .setPositiveButton(R.string.reward_dialog_buy, (dialog, which) -> {
+ this.buyReward();
+ })
+ .setTitle(this.task.getText())
+ .setView(contentViewForDialog)
+ .setNegativeButton(R.string.reward_dialog_dismiss, (dialog, which) -> {
+ dialog.dismiss();
+ }).create();
+ }
+
+ @NonNull
+ private LinearLayout createContentViewForGearDialog() {
+ String price = this.priceFormat.format(this.task.value);
+ String content = this.task.getNotes();
+
+ // External ContentView
+ LinearLayout contentViewLayout = new LinearLayout(context);
+ contentViewLayout.setOrientation(LinearLayout.VERTICAL);
+
+ // Gear Image
+ ImageView gearImageView = new ImageView(context);
+ LinearLayout.LayoutParams gearImageLayoutParams = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+
+ gearImageLayoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
+ gearImageLayoutParams.setMargins(0,0,0,20);
+ gearImageView.setMinimumWidth(200);
+ gearImageView.setMinimumHeight(200);
+ gearImageView.setLayoutParams(gearImageLayoutParams);
+ DataBindingUtils.loadImage(gearImageView, "shop_" + this.task.getId());
+
+ // Gear Description
+ TextView contentTextView = new TextView(context, null);
+ if(!content.isEmpty()){
+ contentTextView.setText(content);
+ }
+
+ // GoldPrice View
+ LinearLayout goldPriceLayout = new LinearLayout(context);
+ goldPriceLayout.setGravity(Gravity.CENTER_HORIZONTAL);
+ LinearLayout.LayoutParams goldPriceLayoutParams = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
+ goldPriceLayoutParams.setMargins(0, 0, 0, 16);
+ goldPriceLayoutParams.gravity = Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL;
+
+ goldPriceLayout.setOrientation(LinearLayout.HORIZONTAL);
+ goldPriceLayout.setLayoutParams(goldPriceLayoutParams);
+ goldPriceLayout.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
+
+ // Price View
+ TextView priceTextView = new TextView(context);
+ priceTextView.setText(price);
+ priceTextView.setPadding(10, 0, 0, 0);
+
+ ImageView gold = new ImageView(context);
+ gold.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_header_gold));
+ gold.setMinimumHeight(50);
+ gold.setMinimumWidth(50);
+ gold.setPadding(0, 0, 5, 0);
+
+ goldPriceLayout.addView(gold);
+ goldPriceLayout.addView(priceTextView);
+
+ if(gearImageView.getDrawable()!= null){
+ contentViewLayout.addView(gearImageView);
+ }
+ contentViewLayout.setGravity(Gravity.CENTER_VERTICAL);
+
+ contentViewLayout.addView(goldPriceLayout);
+
+ if(!content.isEmpty()){
+ contentViewLayout.addView(contentTextView);
+ }
+
+ return contentViewLayout;
+ }
+
+}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.java
new file mode 100644
index 000000000..43d291062
--- /dev/null
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/viewHolders/tasks/TodoViewHolder.java
@@ -0,0 +1,28 @@
+package com.habitrpg.android.habitica.ui.viewHolders.tasks;
+
+import com.habitrpg.android.habitica.R;
+import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
+
+import android.view.View;
+
+public class TodoViewHolder extends ChecklistedViewHolder {
+
+ public TodoViewHolder(View itemView) {
+ super(itemView);
+ }
+
+ @Override
+ public void bindHolder(Task newTask, int position) {
+ super.bindHolder(newTask, position);
+ if (this.task.getCompleted()) {
+ this.checklistIndicatorWrapper.setBackgroundResource(this.task.getLightTaskColor());
+ } else {
+ this.checklistIndicatorWrapper.setBackgroundColor(this.taskGray);
+ }
+ }
+
+ @Override
+ public Boolean shouldDisplayAsActive() {
+ return this.task.getCompleted();
+ }
+}
diff --git a/reports/profile/css/base-style.css b/reports/profile/css/base-style.css
new file mode 100644
index 000000000..4afa73e3d
--- /dev/null
+++ b/reports/profile/css/base-style.css
@@ -0,0 +1,179 @@
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: sans-serif;
+ font-size: 12pt;
+}
+
+body, a, a:visited {
+ color: #303030;
+}
+
+#content {
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 30px;
+ padding-bottom: 30px;
+}
+
+#content h1 {
+ font-size: 160%;
+ margin-bottom: 10px;
+}
+
+#footer {
+ margin-top: 100px;
+ font-size: 80%;
+ white-space: nowrap;
+}
+
+#footer, #footer a {
+ color: #a0a0a0;
+}
+
+#line-wrapping-toggle {
+ vertical-align: middle;
+}
+
+#label-for-line-wrapping-toggle {
+ vertical-align: middle;
+}
+
+ul {
+ margin-left: 0;
+}
+
+h1, h2, h3 {
+ white-space: nowrap;
+}
+
+h2 {
+ font-size: 120%;
+}
+
+ul.tabLinks {
+ padding-left: 0;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ overflow: auto;
+ min-width: 800px;
+ width: auto !important;
+ width: 800px;
+}
+
+ul.tabLinks li {
+ float: left;
+ height: 100%;
+ list-style: none;
+ padding-left: 10px;
+ padding-right: 10px;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ margin-bottom: 0;
+ -moz-border-radius: 7px;
+ border-radius: 7px;
+ margin-right: 25px;
+ border: solid 1px #d4d4d4;
+ background-color: #f0f0f0;
+}
+
+ul.tabLinks li:hover {
+ background-color: #fafafa;
+}
+
+ul.tabLinks li.selected {
+ background-color: #c5f0f5;
+ border-color: #c5f0f5;
+}
+
+ul.tabLinks a {
+ font-size: 120%;
+ display: block;
+ outline: none;
+ text-decoration: none;
+ margin: 0;
+ padding: 0;
+}
+
+ul.tabLinks li h2 {
+ margin: 0;
+ padding: 0;
+}
+
+div.tab {
+}
+
+div.selected {
+ display: block;
+}
+
+div.deselected {
+ display: none;
+}
+
+div.tab table {
+ min-width: 350px;
+ width: auto !important;
+ width: 350px;
+ border-collapse: collapse;
+}
+
+div.tab th, div.tab table {
+ border-bottom: solid #d0d0d0 1px;
+}
+
+div.tab th {
+ text-align: left;
+ white-space: nowrap;
+ padding-left: 6em;
+}
+
+div.tab th:first-child {
+ padding-left: 0;
+}
+
+div.tab td {
+ white-space: nowrap;
+ padding-left: 6em;
+ padding-top: 5px;
+ padding-bottom: 5px;
+}
+
+div.tab td:first-child {
+ padding-left: 0;
+}
+
+div.tab td.numeric, div.tab th.numeric {
+ text-align: right;
+}
+
+span.code {
+ display: inline-block;
+ margin-top: 0em;
+ margin-bottom: 1em;
+}
+
+span.code pre {
+ font-size: 11pt;
+ padding-top: 10px;
+ padding-bottom: 10px;
+ padding-left: 10px;
+ padding-right: 10px;
+ margin: 0;
+ background-color: #f7f7f7;
+ border: solid 1px #d0d0d0;
+ min-width: 700px;
+ width: auto !important;
+ width: 700px;
+}
+
+span.wrapped pre {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ word-break: break-all;
+}
+
+label.hidden {
+ display: none;
+}
\ No newline at end of file
diff --git a/reports/profile/css/style.css b/reports/profile/css/style.css
new file mode 100644
index 000000000..c4a423933
--- /dev/null
+++ b/reports/profile/css/style.css
@@ -0,0 +1,4 @@
+
+div.tab td.indentPath {
+ padding-left: 3em;
+}
diff --git a/reports/profile/js/report.js b/reports/profile/js/report.js
new file mode 100644
index 000000000..83bab4a19
--- /dev/null
+++ b/reports/profile/js/report.js
@@ -0,0 +1,194 @@
+(function (window, document) {
+ "use strict";
+
+ var tabs = {};
+
+ function changeElementClass(element, classValue) {
+ if (element.getAttribute("className")) {
+ element.setAttribute("className", classValue);
+ } else {
+ element.setAttribute("class", classValue);
+ }
+ }
+
+ function getClassAttribute(element) {
+ if (element.getAttribute("className")) {
+ return element.getAttribute("className");
+ } else {
+ return element.getAttribute("class");
+ }
+ }
+
+ function addClass(element, classValue) {
+ changeElementClass(element, getClassAttribute(element) + " " + classValue);
+ }
+
+ function removeClass(element, classValue) {
+ changeElementClass(element, getClassAttribute(element).replace(classValue, ""));
+ }
+
+ function initTabs() {
+ var container = document.getElementById("tabs");
+
+ tabs.tabs = findTabs(container);
+ tabs.titles = findTitles(tabs.tabs);
+ tabs.headers = findHeaders(container);
+ tabs.select = select;
+ tabs.deselectAll = deselectAll;
+ tabs.select(0);
+
+ return true;
+ }
+
+ function getCheckBox() {
+ return document.getElementById("line-wrapping-toggle");
+ }
+
+ function getLabelForCheckBox() {
+ return document.getElementById("label-for-line-wrapping-toggle");
+ }
+
+ function findCodeBlocks() {
+ var spans = document.getElementById("tabs").getElementsByTagName("span");
+ var codeBlocks = [];
+ for (var i = 0; i < spans.length; ++i) {
+ if (spans[i].className.indexOf("code") >= 0) {
+ codeBlocks.push(spans[i]);
+ }
+ }
+ return codeBlocks;
+ }
+
+ function forAllCodeBlocks(operation) {
+ var codeBlocks = findCodeBlocks();
+
+ for (var i = 0; i < codeBlocks.length; ++i) {
+ operation(codeBlocks[i], "wrapped");
+ }
+ }
+
+ function toggleLineWrapping() {
+ var checkBox = getCheckBox();
+
+ if (checkBox.checked) {
+ forAllCodeBlocks(addClass);
+ } else {
+ forAllCodeBlocks(removeClass);
+ }
+ }
+
+ function initControls() {
+ if (findCodeBlocks().length > 0) {
+ var checkBox = getCheckBox();
+ var label = getLabelForCheckBox();
+
+ checkBox.onclick = toggleLineWrapping;
+ checkBox.checked = false;
+
+ removeClass(label, "hidden");
+ }
+ }
+
+ function switchTab() {
+ var id = this.id.substr(1);
+
+ for (var i = 0; i < tabs.tabs.length; i++) {
+ if (tabs.tabs[i].id === id) {
+ tabs.select(i);
+ break;
+ }
+ }
+
+ return false;
+ }
+
+ function select(i) {
+ this.deselectAll();
+
+ changeElementClass(this.tabs[i], "tab selected");
+ changeElementClass(this.headers[i], "selected");
+
+ while (this.headers[i].firstChild) {
+ this.headers[i].removeChild(this.headers[i].firstChild);
+ }
+
+ var h2 = document.createElement("H2");
+
+ h2.appendChild(document.createTextNode(this.titles[i]));
+ this.headers[i].appendChild(h2);
+ }
+
+ function deselectAll() {
+ for (var i = 0; i < this.tabs.length; i++) {
+ changeElementClass(this.tabs[i], "tab deselected");
+ changeElementClass(this.headers[i], "deselected");
+
+ while (this.headers[i].firstChild) {
+ this.headers[i].removeChild(this.headers[i].firstChild);
+ }
+
+ var a = document.createElement("A");
+
+ a.setAttribute("id", "ltab" + i);
+ a.setAttribute("href", "#tab" + i);
+ a.onclick = switchTab;
+ a.appendChild(document.createTextNode(this.titles[i]));
+
+ this.headers[i].appendChild(a);
+ }
+ }
+
+ function findTabs(container) {
+ return findChildElements(container, "DIV", "tab");
+ }
+
+ function findHeaders(container) {
+ var owner = findChildElements(container, "UL", "tabLinks");
+ return findChildElements(owner[0], "LI", null);
+ }
+
+ function findTitles(tabs) {
+ var titles = [];
+
+ for (var i = 0; i < tabs.length; i++) {
+ var tab = tabs[i];
+ var header = findChildElements(tab, "H2", null)[0];
+
+ header.parentNode.removeChild(header);
+
+ if (header.innerText) {
+ titles.push(header.innerText);
+ } else {
+ titles.push(header.textContent);
+ }
+ }
+
+ return titles;
+ }
+
+ function findChildElements(container, name, targetClass) {
+ var elements = [];
+ var children = container.childNodes;
+
+ for (var i = 0; i < children.length; i++) {
+ var child = children.item(i);
+
+ if (child.nodeType === 1 && child.nodeName === name) {
+ if (targetClass && child.className.indexOf(targetClass) < 0) {
+ continue;
+ }
+
+ elements.push(child);
+ }
+ }
+
+ return elements;
+ }
+
+ // Entry point.
+
+ window.onload = function() {
+ initTabs();
+ initControls();
+ };
+} (window, window.document));
\ No newline at end of file
diff --git a/reports/profile/profile-2016-05-09-17-48-55.html b/reports/profile/profile-2016-05-09-17-48-55.html
new file mode 100644
index 000000000..25b139160
--- /dev/null
+++ b/reports/profile/profile-2016-05-09-17-48-55.html
@@ -0,0 +1,148 @@
+
+
+
+
+
+Profile report
+
+
+
+
+
+
+
Profile report
+
+
+
+
+
Summary
+
+
+
+| Description |
+Duration |
+
+
+
+| Total Build Time |
+8.294s |
+
+
+| Startup |
+2.120s |
+
+
+| Settings and BuildSrc |
+0.225s |
+
+
+| Loading Projects |
+0.502s |
+
+
+| Configuring Projects |
+4.522s |
+
+
+| Task Execution |
+0s |
+
+
+
+
+
Configuration
+
+
+
+| Project |
+Duration |
+
+
+
+| All projects |
+4.522s |
+
+
+| :Habitica |
+2.818s |
+
+
+| : |
+1.704s |
+
+
+
+
+
Dependency Resolution
+
+
+
+| Dependencies |
+Duration |
+
+
+
+| All dependencies |
+0.915s |
+
+
+| :classpath |
+0.709s |
+
+
+| :Habitica:classpath |
+0.206s |
+
+
+
+
+
Task Execution
+
+
+
+| Task |
+Duration |
+Result |
+
+
+
+| : |
+0s |
+(total) |
+
+
+| :Habitica |
+0s |
+(total) |
+
+
+
+
+
+
+
+
diff --git a/reports/profile/profile-2016-05-09-17-50-45.html b/reports/profile/profile-2016-05-09-17-50-45.html
new file mode 100644
index 000000000..309ccddf6
--- /dev/null
+++ b/reports/profile/profile-2016-05-09-17-50-45.html
@@ -0,0 +1,148 @@
+
+
+
+
+
+Profile report
+
+
+
+
+
+
+
Profile report
+
+
+
+
+
Summary
+
+
+
+| Description |
+Duration |
+
+
+
+| Total Build Time |
+1.721s |
+
+
+| Startup |
+0.704s |
+
+
+| Settings and BuildSrc |
+0.003s |
+
+
+| Loading Projects |
+0.007s |
+
+
+| Configuring Projects |
+0.778s |
+
+
+| Task Execution |
+0s |
+
+
+
+
+
Configuration
+
+
+
+| Project |
+Duration |
+
+
+
+| All projects |
+0.778s |
+
+
+| :Habitica |
+0.586s |
+
+
+| : |
+0.192s |
+
+
+
+
+
Dependency Resolution
+
+
+
+| Dependencies |
+Duration |
+
+
+
+| All dependencies |
+0.318s |
+
+
+| :classpath |
+0.160s |
+
+
+| :Habitica:classpath |
+0.158s |
+
+
+
+
+
Task Execution
+
+
+
+| Task |
+Duration |
+Result |
+
+
+
+| : |
+0s |
+(total) |
+
+
+| :Habitica |
+0s |
+(total) |
+
+
+
+
+
+
+
+