Rewrite task lists

This commit is contained in:
Phillip Thelen 2016-05-10 16:07:12 +02:00
parent e6d7c6b2f2
commit b01890427b
25 changed files with 1681 additions and 976 deletions

View file

@ -132,7 +132,7 @@ dependencies {
android {
compileSdkVersion 23
buildToolsVersion "23.0.1"
buildToolsVersion "23.0.3"
lintOptions {
abortOnError false

View file

@ -1,23 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/tools">
<data>
<import type="com.magicmicky.habitrpgwrapper.lib.models.tasks.Task" />
<import type="android.view.View"/>
<variable
name="daily"
type="Task" />
<variable
name="displayChecklist"
type="Boolean" />
<variable
name="offset"
type="int" />
</data>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
@ -29,14 +12,12 @@
<RelativeLayout
android:id="@+id/checkBoxHolder"
android:layout_width="@dimen/button_width"
android:layout_height="match_parent"
app:backgroundColor="@{daily.isDisplayedActive(offset) ? daily.getLightTaskColor : @color/task_gray}">
android:layout_height="match_parent">
<CheckBox
android:id="@+id/checkBox"
android:layout_width="@dimen/checkbox_size"
android:layout_height="@dimen/checkbox_size"
android:layout_centerInParent="true"
android:checked="@{daily.completed}"
android:gravity="center"
android:button="@drawable/daily_checkbox"
android:layout_gravity="center_horizontal" />
@ -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" />
<com.github.data5tream.emojilib.EmojiTextView
android:id="@+id/notesTextView"
style="@style/CardText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
bind:parsemarkdown="@{daily.notes}"
android:visibility="@{daily.notes != null ? View.VISIBLE : View.GONE}"
android:maxLines="3" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="@{daily.streak > 0 ? View.VISIBLE : View.GONE}"
android:text="@{@string/daily_streak(daily.streak)}"/>
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout android:orientation="vertical"
android:id="@+id/checklistIndicatorWrapper"
android:layout_width="@dimen/checklist_wrapper_width"
android:layout_height="match_parent"
app:backgroundColor="@{daily.isChecklistDisplayActive(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_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true">
<TextView
android:id="@+id/checkListCompletedTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{String.valueOf(daily.getCompletedChecklistCount)}"
android:textColor="@color/white"
android:gravity="center"
android:layout_above="@+id/checklistDivider"/>
@ -104,9 +78,9 @@
android:background="@color/white"
android:layout_centerInParent="true"/>
<TextView
android:id="@+id/checkListAllTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{String.valueOf(daily.checklist.size)}"
android:textColor="@color/white"
android:gravity="center"
android:layout_below="@+id/checklistDivider"/>
@ -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 @@
</LinearLayout>
<View
android:id="@+id/checklistSeparator"
android:layout_width="match_parent"
android:layout_height="@dimen/hairline_height"
android:background="@color/cell_separator"
android:visibility="@{displayChecklist != null &amp;&amp; displayChecklist ? View.VISIBLE : View.GONE}" />
android:background="@color/cell_separator" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/checklistView"
android:orientation="vertical"
android:visibility="@{displayChecklist != null &amp;&amp; displayChecklist ? View.VISIBLE : View.GONE}" />
android:orientation="vertical" />
<View
android:id="@+id/checklistBottomSpace"
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="@color/checklist_separator"
android:visibility="@{displayChecklist != null &amp;&amp; displayChecklist ? View.VISIBLE : View.GONE}" />
android:background="@color/checklist_separator" />
</LinearLayout>
</layout>

View file

@ -1,18 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/tools">
<data>
<import type="com.magicmicky.habitrpgwrapper.lib.models.tasks.Task" />
<import type="android.view.View"/>
<variable
name="habit"
type="Task" />
</data>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white">
@ -24,12 +12,12 @@
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:visibility="@{habit.up ? View.VISIBLE : View.GONE}"
android:layout_weight="1">
android:layout_weight="1"
android:id="@+id/btnPlusWrapper">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
app:backgroundColor="@{habit.getLightTaskColor}"/>
android:id="@+id/btnPlusBackground"/>
<Button
android:id="@+id/btnPlus"
android:layout_width="match_parent"
@ -41,12 +29,12 @@
<FrameLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:visibility="@{habit.down ? View.VISIBLE : View.GONE}"
android:layout_weight="1">
android:layout_weight="1"
android:id="@+id/btnMinusWrapper">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
app:backgroundColor="@{habit.up ? habit.getMediumTaskColor : habit.getLightTaskColor}"/>
android:id="@+id/btnMinusBackground"/>
<Button
android:id="@+id/btnMinus"
android:layout_width="match_parent"
@ -73,27 +61,22 @@
android:id="@+id/checkedTextView"
style="@style/CardTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
bind:parsemarkdown="@{habit.text}" />
android:layout_height="wrap_content" />
<com.github.data5tream.emojilib.EmojiTextView
android:id="@+id/notesTextView"
style="@style/CardText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
bind:parsemarkdown="@{habit.notes}"
android:visibility="@{habit.notes != null ? View.VISIBLE : View.GONE}"
android:maxLines="3" />
</LinearLayout>
<View
android:id="@+id/rightBorderView"
android:layout_width="5dp"
android:layout_height="match_parent"
app:backgroundColor="@{habit.getLightTaskColor}"
android:gravity="center"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
</LinearLayout>
</layout>

View file

@ -1,70 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/apk/res-auto">
<data>
<import type="com.magicmicky.habitrpgwrapper.lib.models.tasks.Task" />
<import type="android.view.View"/>
<variable
name="reward"
type="Task" />
</data>
<LinearLayout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/gearElementsLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:clickable="false"
>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:weightSum="1">
android:orientation="horizontal"
android:clickable="false">
<ImageView
android:id="@+id/imageView3"
android:id="@+id/rewardImageView"
android:layout_width="60dp"
android:padding="5dp"
android:layout_height="60dp"
android:layout_gravity="center_vertical"
android:visibility='@{reward.specialTag == "item" ? View.VISIBLE : View.GONE}'
bind:imageName='@{"shop_"+reward.id}'
android:layout_centerVertical="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true" />
android:layout_gravity="center_vertical" />
<LinearLayout
android:id="@+id/textReward"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingBottom="@dimen/task_top_bottom_padding"
android:paddingTop="@dimen/task_top_bottom_padding"
android:paddingLeft='16dp'
android:paddingRight="@dimen/reward_spacing"
android:layout_toLeftOf="@+id/btnReward"
android:layout_toRightOf="@+id/imageView3"
android:layout_toEndOf="@+id/imageView3">
android:layout_gravity="center_vertical">
<com.github.data5tream.emojilib.EmojiTextView
android:id="@+id/checkedTextView"
style="@style/CardTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
bind:parsemarkdown="@{reward.text}"/>
android:layout_height="wrap_content"/>
<com.github.data5tream.emojilib.EmojiTextView
android:id="@+id/notesTextView"
style="@style/CardText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
bind:parsemarkdown="@{reward.notes}"
android:visibility="@{reward.notes != null ? View.VISIBLE : View.GONE}"/>
android:layout_height="wrap_content"/>
</LinearLayout>
@ -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" />
</RelativeLayout>
<View
android:id="@+id/bottomBorderView"
android:layout_width="match_parent"
android:layout_height="0.5dp"
android:background="@color/cell_separator"/>
</LinearLayout>
</layout>
android:paddingStart="6dp" />
</LinearLayout>

View file

@ -1,52 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:bind="http://schemas.android.com/tools">
<data>
<import type="com.magicmicky.habitrpgwrapper.lib.models.tasks.Task" />
<import type="android.view.View"/>
<variable
name="todo"
type="Task" />
<variable
name="duedate"
type="String" />
<variable
name="displayChecklist"
type="Boolean" />
</data>
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white">
<LinearLayout
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/white">
<LinearLayout
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<RelativeLayout
android:id="@+id/checkBoxHolder"
<RelativeLayout
android:id="@+id/checkBoxHolder"
android:layout_width="@dimen/button_width"
android:layout_height="match_parent"
app:backgroundColor="@{todo.completed ? @color/task_gray : todo.getLightTaskColor}">
android:layout_height="match_parent">
<CheckBox
android:id="@+id/checkBox"
android:layout_width="@dimen/checkbox_size"
android:layout_height="@dimen/checkbox_size"
android:layout_centerInParent="true"
android:checked="@{todo.completed}"
android:gravity="center"
android:button="@drawable/todo_checkbox"
android:layout_gravity="center_horizontal" />
</RelativeLayout>
<RelativeLayout
android:id="@+id/checkBox"
android:layout_width="@dimen/checkbox_size"
android:layout_height="@dimen/checkbox_size"
android:layout_centerInParent="true"
android:gravity="center"
android:button="@drawable/todo_checkbox"
android:layout_gravity="center_horizontal" />
</RelativeLayout>
<RelativeLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
@ -56,88 +37,77 @@
android:paddingEnd="16dp"
android:paddingBottom="@dimen/task_top_bottom_padding"
android:paddingTop="@dimen/task_top_bottom_padding">
<com.github.data5tream.emojilib.EmojiTextView
<com.github.data5tream.emojilib.EmojiTextView
android:id="@+id/checkedTextView"
style="@style/CardTitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
bind:parsemarkdown="@{todo.text}" />
android:layout_height="wrap_content" />
<com.github.data5tream.emojilib.EmojiTextView
<com.github.data5tream.emojilib.EmojiTextView
android:id="@+id/notesTextView"
style="@style/CardText"
android:layout_width="match_parent"
android:layout_height="match_parent"
bind:parsemarkdown="@{todo.notes}"
android:visibility="@{todo.notes != null ? View.VISIBLE : View.GONE}"
android:maxLines="3" />
<TextView
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
<RelativeLayout android:orientation="vertical"
android:id="@+id/checklistIndicatorWrapper"
android:layout_width="@dimen/checklist_wrapper_width"
android:layout_height="match_parent"
android:gravity="center"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true">
<TextView
android:id="@+id/checkListCompletedTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="@{todo.duedate != null ? View.VISIBLE : View.GONE}"
android:text="@{@string/todo_due(duedate)}"/>
</LinearLayout>
<RelativeLayout android:orientation="vertical"
android:id="@+id/checklistIndicatorWrapper"
android:layout_width="@dimen/checklist_wrapper_width"
android:layout_height="match_parent"
app:backgroundColor="@{todo.checklist.size != todo.getCompletedChecklistCount ? todo.getLightTaskColor : @color/task_gray}"
android:visibility="@{todo.checklist.size > 0 ? View.VISIBLE : View.GONE}"
android:gravity="center"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{String.valueOf(todo.getCompletedChecklistCount)}"
android:textColor="@color/white"
android:gravity="center"
android:layout_above="@+id/checklistDivider"/>
<View
<View
android:id="@+id/checklistDivider"
android:layout_width="@dimen/checklist_divider_width"
android:layout_height="@dimen/hairline_height"
android:background="@color/white"
android:layout_centerInParent="true"/>
<TextView
<TextView
android:id="@+id/checkListAllTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{String.valueOf(todo.checklist.size)}"
android:textColor="@color/white"
android:gravity="center"
android:layout_below="@+id/checklistDivider"/>
</RelativeLayout>
<View
</RelativeLayout>
<View
android:id="@+id/rightBorderView"
android:layout_width="5dp"
android:layout_height="match_parent"
app:backgroundColor="@{todo.completed ? @color/task_gray : todo.getLightTaskColor}"
android:visibility="@{todo.checklist.size == 0 ? View.VISIBLE : View.GONE}"
android:gravity="center"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
</RelativeLayout>
</RelativeLayout>
</LinearLayout>
<View
</LinearLayout>
<View
android:id="@id/checklistSeparator"
android:layout_width="match_parent"
android:layout_height="@dimen/hairline_height"
android:background="@color/cell_separator"
android:visibility="@{displayChecklist != null &amp;&amp; displayChecklist ? View.VISIBLE : View.GONE}" />
<LinearLayout
android:background="@color/cell_separator" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/checklistView"
android:orientation="vertical"
android:visibility="@{displayChecklist != null &amp;&amp; displayChecklist ? View.VISIBLE : View.GONE}" />
<View
android:orientation="vertical" />
<View
android:id="@+id/checklistBottomSpace"
android:layout_width="match_parent"
android:layout_height="10dp"
android:background="@color/checklist_separator"
android:visibility="@{displayChecklist != null &amp;&amp; displayChecklist ? View.VISIBLE : View.GONE}" />
android:background="@color/checklist_separator" />
</LinearLayout>
</layout>
</LinearLayout>

View file

@ -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;
}

View file

@ -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<VH extends BaseTaskViewHolder>
extends RecyclerView.Adapter<VH> {
int layoutResource;
String taskType;
Context context;
List<Task> content;
List<Task> 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<Task> tasks) {
this.content = new ObservableArrayList<>();
this.content.addAll(tasks);
filter();
}
}

View file

@ -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<DailyViewHolder> {
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);
}
}

View file

@ -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<THabitItem extends Task>
extends RecyclerView.Adapter<HabitItemRecyclerViewAdapter.ViewHolder>
implements IReceiveNewEntries {
public interface IAdditionalEntries {
void GetAdditionalEntries(IReceiveNewEntries callBack);
}
int layoutResource;
private Class<ViewHolder<Task>> viewHolderClass;
Integer displayedChecklist = null;
String taskType;
private ObservableArrayList<Task> filteredObservableContent;
private ObservableArrayList<Task> 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<ViewHolder<Task>> viewHolderClass, Context newContext, int dailyResetOffset) {
this(taskType, tagsHelper, layoutResource, viewHolderClass, newContext, dailyResetOffset, null);
}
public HabitItemRecyclerViewAdapter(String taskType, TagsHelper tagsHelper, int layoutResource, Class<ViewHolder<Task>> 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<THabitItem> 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<HabitItem extends Task> 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<Task> {
@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<Task> 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<Task> {
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<List<Task>> taskTransactionListener = new TransactionListener<List<Task>>() {
@Override
public void onResultReceived(List<Task> tasks) {
observableContent.clear();
observableContent.addAll(tasks);
if (additionalEntries != null) {
additionalEntries.GetAdditionalEntries(HabitItemRecyclerViewAdapter.this);
}
filter();
}
@Override
public boolean onReady(BaseTransaction<List<Task>> transaction) {
return true;
}
@Override
public boolean hasResult(BaseTransaction<List<Task>> transaction, List<Task> result) {
return true;
}
};
@Override
public void GotAdditionalItems(List<Task> items) {
this.observableContent.addAll(items);
notifyDataSetChanged();
}
}

View file

@ -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<HabitViewHolder> {
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));
}
}

View file

@ -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<RewardViewHolder> {
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<String> 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<List<Task>>) subscriber -> {
contentCache.GetItemDataList(itemKeys, obj -> {
ArrayList<Task> 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<Task> tasks) {
super.setTasks(tasks);
this.loadEquipmentRewards();
}
}

View file

@ -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<TodoViewHolder> {
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));
}
}

View file

@ -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);

View file

@ -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<String> tagNames; // Added this so other activities/fragments can get the String names, not IDs
private ArrayList<String> tagIds; // Added this so other activities/fragments can get the IDs
private ContentCache contentCache;
private boolean displayingTaskForm;
private HashMap<String, Boolean> 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<String> 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<Task> 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

View file

@ -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);
}
}

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;
}
}

View file

@ -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();
}
}

View file

@ -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;
}

View file

@ -0,0 +1,4 @@
div.tab td.indentPath {
padding-left: 3em;
}

View file

@ -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));

View file

@ -0,0 +1,148 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Profile report</title>
<link href="css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<script src="js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Profile report</h1>
<div id="header">
<p>Profiled build: build </p>
<p>Started on: 2016/05/09 - 17:48:55</p>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Summary</a>
</li>
<li>
<a href="#tab1">Configuration</a>
</li>
<li>
<a href="#tab2">Dependency Resolution</a>
</li>
<li>
<a href="#tab3">Task Execution</a>
</li>
</ul>
<div class="tab" id="tab0">
<h2>Summary</h2>
<table>
<thead>
<tr>
<th>Description</th>
<th class="numeric">Duration</th>
</tr>
</thead>
<tr>
<td>Total Build Time</td>
<td class="numeric">8.294s</td>
</tr>
<tr>
<td>Startup</td>
<td class="numeric">2.120s</td>
</tr>
<tr>
<td>Settings and BuildSrc</td>
<td class="numeric">0.225s</td>
</tr>
<tr>
<td>Loading Projects</td>
<td class="numeric">0.502s</td>
</tr>
<tr>
<td>Configuring Projects</td>
<td class="numeric">4.522s</td>
</tr>
<tr>
<td>Task Execution</td>
<td class="numeric">0s</td>
</tr>
</table>
</div>
<div class="tab" id="tab1">
<h2>Configuration</h2>
<table>
<thead>
<tr>
<th>Project</th>
<th class="numeric">Duration</th>
</tr>
</thead>
<tr>
<td>All projects</td>
<td class="numeric">4.522s</td>
</tr>
<tr>
<td>:Habitica</td>
<td class="numeric">2.818s</td>
</tr>
<tr>
<td>:</td>
<td class="numeric">1.704s</td>
</tr>
</table>
</div>
<div class="tab" id="tab2">
<h2>Dependency Resolution</h2>
<table>
<thead>
<tr>
<th>Dependencies</th>
<th class="numeric">Duration</th>
</tr>
</thead>
<tr>
<td>All dependencies</td>
<td class="numeric">0.915s</td>
</tr>
<tr>
<td>:classpath</td>
<td class="numeric">0.709s</td>
</tr>
<tr>
<td>:Habitica:classpath</td>
<td class="numeric">0.206s</td>
</tr>
</table>
</div>
<div class="tab" id="tab3">
<h2>Task Execution</h2>
<table>
<thead>
<tr>
<th>Task</th>
<th class="numeric">Duration</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td>:</td>
<td class="numeric">0s</td>
<td>(total)</td>
</tr>
<tr>
<td>:Habitica</td>
<td class="numeric">0s</td>
<td>(total)</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 2.13</a> at May 9, 2016 5:49:02 PM</p>
</div>
</div>
</body>
</html>

View file

@ -0,0 +1,148 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<meta http-equiv="x-ua-compatible" content="IE=edge"/>
<title>Profile report</title>
<link href="css/base-style.css" rel="stylesheet" type="text/css"/>
<link href="css/style.css" rel="stylesheet" type="text/css"/>
<script src="js/report.js" type="text/javascript"></script>
</head>
<body>
<div id="content">
<h1>Profile report</h1>
<div id="header">
<p>Profiled build: build </p>
<p>Started on: 2016/05/09 - 17:50:45</p>
</div>
<div id="tabs">
<ul class="tabLinks">
<li>
<a href="#tab0">Summary</a>
</li>
<li>
<a href="#tab1">Configuration</a>
</li>
<li>
<a href="#tab2">Dependency Resolution</a>
</li>
<li>
<a href="#tab3">Task Execution</a>
</li>
</ul>
<div class="tab" id="tab0">
<h2>Summary</h2>
<table>
<thead>
<tr>
<th>Description</th>
<th class="numeric">Duration</th>
</tr>
</thead>
<tr>
<td>Total Build Time</td>
<td class="numeric">1.721s</td>
</tr>
<tr>
<td>Startup</td>
<td class="numeric">0.704s</td>
</tr>
<tr>
<td>Settings and BuildSrc</td>
<td class="numeric">0.003s</td>
</tr>
<tr>
<td>Loading Projects</td>
<td class="numeric">0.007s</td>
</tr>
<tr>
<td>Configuring Projects</td>
<td class="numeric">0.778s</td>
</tr>
<tr>
<td>Task Execution</td>
<td class="numeric">0s</td>
</tr>
</table>
</div>
<div class="tab" id="tab1">
<h2>Configuration</h2>
<table>
<thead>
<tr>
<th>Project</th>
<th class="numeric">Duration</th>
</tr>
</thead>
<tr>
<td>All projects</td>
<td class="numeric">0.778s</td>
</tr>
<tr>
<td>:Habitica</td>
<td class="numeric">0.586s</td>
</tr>
<tr>
<td>:</td>
<td class="numeric">0.192s</td>
</tr>
</table>
</div>
<div class="tab" id="tab2">
<h2>Dependency Resolution</h2>
<table>
<thead>
<tr>
<th>Dependencies</th>
<th class="numeric">Duration</th>
</tr>
</thead>
<tr>
<td>All dependencies</td>
<td class="numeric">0.318s</td>
</tr>
<tr>
<td>:classpath</td>
<td class="numeric">0.160s</td>
</tr>
<tr>
<td>:Habitica:classpath</td>
<td class="numeric">0.158s</td>
</tr>
</table>
</div>
<div class="tab" id="tab3">
<h2>Task Execution</h2>
<table>
<thead>
<tr>
<th>Task</th>
<th class="numeric">Duration</th>
<th>Result</th>
</tr>
</thead>
<tr>
<td>:</td>
<td class="numeric">0s</td>
<td>(total)</td>
</tr>
<tr>
<td>:Habitica</td>
<td class="numeric">0s</td>
<td>(total)</td>
</tr>
</table>
</div>
</div>
<div id="footer">
<p>
<div>
<label class="hidden" id="label-for-line-wrapping-toggle" for="line-wrapping-toggle">Wrap lines
<input id="line-wrapping-toggle" type="checkbox" autocomplete="off"/>
</label>
</div>Generated by
<a href="http://www.gradle.org">Gradle 2.13</a> at May 9, 2016 5:50:46 PM</p>
</div>
</div>
</body>
</html>