mirror of
https://github.com/sudoxnym/habitica-android.git
synced 2026-05-20 04:39:04 +00:00
Merge pull request #53 from HabitRPG/ability-change-checklist
Fixes #40 - Add ability to change checklist
This commit is contained in:
commit
d0d7cf8e8d
19 changed files with 659 additions and 34 deletions
|
|
@ -68,9 +68,9 @@
|
|||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="72dp"
|
||||
android:layout_height="140dp"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:id="@+id/task_startdate_layout">
|
||||
|
||||
|
|
@ -82,12 +82,12 @@
|
|||
android:id="@+id/textView"
|
||||
android:layout_gravity="center_vertical" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
<DatePicker
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/task_startdate_textview"
|
||||
android:textAlignment="gravity"
|
||||
android:layout_gravity="center_vertical|right" />
|
||||
android:id="@+id/task_startdate_picker"
|
||||
android:datePickerMode="spinner"
|
||||
android:calendarViewShown="false" />
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -120,7 +120,8 @@
|
|||
android:id="@+id/textView7"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginTop="11dp" />
|
||||
android:layout_marginTop="11dp"
|
||||
android:layout_toLeftOf="@+id/task_positive_checkbox"/>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="wrap_content"
|
||||
|
|
@ -144,7 +145,8 @@
|
|||
android:id="@+id/textView8"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginTop="11dp" />
|
||||
android:layout_marginTop="11dp"
|
||||
android:layout_toLeftOf="@+id/task_negative_checkbox"/>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="wrap_content"
|
||||
|
|
@ -170,7 +172,33 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:text="@string/checklist"
|
||||
android:id="@+id/textView9" />
|
||||
android:id="@+id/textView9"
|
||||
android:layout_marginBottom="8dp"/>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@+id/checklist_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<EditText
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/new_checklist"
|
||||
android:hint="@string/new_checklist_item"
|
||||
android:layout_weight="1" />
|
||||
|
||||
<Button
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/add_checklist_item"
|
||||
android:id="@+id/add_checklist_button" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
|
@ -203,6 +231,5 @@
|
|||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
||||
27
Habitica/res/layout/checklist_item.xml
Normal file
27
Habitica/res/layout/checklist_item.xml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/item"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?selectableItemBackground"
|
||||
android:orientation="horizontal"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingBottom="4dp">
|
||||
|
||||
<Button
|
||||
style="?android:attr/buttonStyleSmall"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/delete_item_button"
|
||||
android:text="x" />
|
||||
|
||||
<EditText
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@+id/item_edittext"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginLeft="4dp" />
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -183,4 +183,6 @@
|
|||
|
||||
<string name="mana_price_button" formatted="false">%d MP</string>
|
||||
<string name="used_skill" formatted="false">You used %1$s for %2$d mana.</string>
|
||||
<string name="new_checklist_item">new checklist item</string>
|
||||
<string name="add_checklist_item">Add</string>
|
||||
</resources>
|
||||
|
|
@ -18,6 +18,7 @@ import com.google.gson.stream.JsonWriter;
|
|||
import com.habitrpg.android.habitica.callbacks.HabitRPGUserCallback;
|
||||
import com.habitrpg.android.habitica.callbacks.TaskDeletionCallback;
|
||||
import com.habitrpg.android.habitica.callbacks.TaskScoringCallback;
|
||||
import com.habitrpg.android.habitica.database.CheckListItemExcludeStrategy;
|
||||
import com.magicmicky.habitrpgwrapper.lib.api.ApiService;
|
||||
import com.magicmicky.habitrpgwrapper.lib.api.InAppPurchasesApiService;
|
||||
import com.magicmicky.habitrpgwrapper.lib.api.Server;
|
||||
|
|
@ -30,10 +31,12 @@ import com.magicmicky.habitrpgwrapper.lib.models.UserAuth;
|
|||
import com.magicmicky.habitrpgwrapper.lib.models.UserAuthResponse;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.UserAuthSocial;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.UserAuthSocialTokens;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.ChecklistItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TaskTag;
|
||||
import com.magicmicky.habitrpgwrapper.lib.utils.SkillDeserializer;
|
||||
import com.raizlabs.android.dbflow.structure.ModelAdapter;
|
||||
import com.raizlabs.android.dbflow.structure.container.ForeignKeyContainer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
|
|
@ -77,6 +80,7 @@ public class APIHelper implements ErrorHandler, Profiler {
|
|||
|
||||
//Exclusion stratety needed for DBFlow https://github.com/Raizlabs/DBFlow/issues/121
|
||||
Gson gson = new GsonBuilder()
|
||||
.setExclusionStrategies(new CheckListItemExcludeStrategy())
|
||||
.setExclusionStrategies(new ExclusionStrategy() {
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import org.solovyev.android.checkout.Checkout;
|
|||
import org.solovyev.android.checkout.ProductTypes;
|
||||
import org.solovyev.android.checkout.Products;
|
||||
import org.solovyev.android.checkout.PurchaseVerifier;
|
||||
import org.solovyev.android.checkout.RequestListener;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Arrays;
|
||||
|
|
|
|||
|
|
@ -158,13 +158,6 @@ public class MainActivity extends InstabugAppCompatActivity implements HabitRPGU
|
|||
drawer.setSelection(MainDrawerBuilder.SIDEBAR_PURCHASE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
mAPIHelper.retrieveUser(new HabitRPGUserCallback(this));
|
||||
setUserData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
package com.habitrpg.android.habitica;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.EditText;
|
||||
import android.widget.LinearLayout;
|
||||
|
|
@ -16,7 +23,11 @@ import android.widget.Spinner;
|
|||
import android.widget.TextView;
|
||||
|
||||
import com.habitrpg.android.habitica.events.TaskSaveEvent;
|
||||
import com.habitrpg.android.habitica.ui.WrapContentRecyclerViewLayoutManager;
|
||||
import com.habitrpg.android.habitica.ui.adapter.CheckListAdapter;
|
||||
import com.habitrpg.android.habitica.ui.helpers.SimpleItemTouchHelperCallback;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.Tag;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.ChecklistItem;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Days;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.TaskTag;
|
||||
|
|
@ -44,6 +55,8 @@ public class TaskFormActivity extends AppCompatActivity implements AdapterView.O
|
|||
private NumberPicker frequencyPicker;
|
||||
private LinearLayout frequencyContainer;
|
||||
private List<String> tags;
|
||||
private CheckListAdapter checklistAdapter;
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
|
@ -94,12 +107,12 @@ public class TaskFormActivity extends AppCompatActivity implements AdapterView.O
|
|||
this.dailyFrequencySpinner.setAdapter(frequencyAdapter);
|
||||
this.dailyFrequencySpinner.setOnItemSelectedListener(this);
|
||||
|
||||
|
||||
this.frequencyContainer = (LinearLayout) weekdayWrapper.findViewById(R.id.task_frequency_container);
|
||||
} else {
|
||||
mainWrapper.removeView(weekdayWrapper);
|
||||
}
|
||||
|
||||
|
||||
if (taskId != null) {
|
||||
Task task = new Select().from(Task.class).byIds(taskId).querySingle();
|
||||
this.task = task;
|
||||
|
|
@ -108,6 +121,41 @@ public class TaskFormActivity extends AppCompatActivity implements AdapterView.O
|
|||
} else {
|
||||
setTitle((Task) null);
|
||||
}
|
||||
|
||||
if(taskType.equals("todo") || taskType.equals("daily")){
|
||||
createCheckListRecyclerView();
|
||||
}
|
||||
}
|
||||
|
||||
private void createCheckListRecyclerView() {
|
||||
checklistAdapter = new CheckListAdapter(task.getChecklist());
|
||||
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.checklist_recycler_view);
|
||||
|
||||
LinearLayoutManager llm = new LinearLayoutManager(this);
|
||||
llm.setOrientation(LinearLayoutManager.VERTICAL);
|
||||
|
||||
recyclerView.setLayoutManager(llm);
|
||||
recyclerView.setAdapter(checklistAdapter);
|
||||
int i = checklistAdapter.getItemCount();
|
||||
|
||||
recyclerView.setLayoutManager(new WrapContentRecyclerViewLayoutManager(this));
|
||||
|
||||
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(checklistAdapter);
|
||||
ItemTouchHelper mItemTouchHelper = new ItemTouchHelper(callback);
|
||||
mItemTouchHelper.attachToRecyclerView(recyclerView);
|
||||
|
||||
final EditText newCheckListEditText = (EditText)findViewById(R.id.new_checklist);
|
||||
|
||||
Button button = (Button)findViewById(R.id.add_checklist_button);
|
||||
button.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
String checklist = newCheckListEditText.getText().toString();
|
||||
ChecklistItem item = new ChecklistItem(checklist);
|
||||
checklistAdapter.addItem(item);
|
||||
newCheckListEditText.setText("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void setTitle(Task task) {
|
||||
|
|
@ -197,6 +245,7 @@ public class TaskFormActivity extends AppCompatActivity implements AdapterView.O
|
|||
//noinspection SimplifiableIfStatement
|
||||
if (id == R.id.action_discard_changes) {
|
||||
finish();
|
||||
dismissKeyboard();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -249,6 +298,8 @@ public class TaskFormActivity extends AppCompatActivity implements AdapterView.O
|
|||
private boolean saveTask(Task task) {
|
||||
task.text = taskText.getText().toString();
|
||||
|
||||
task.setChecklist(checklistAdapter.getCheckListItems());
|
||||
|
||||
if (task.text.isEmpty())
|
||||
return false;
|
||||
|
||||
|
|
@ -319,15 +370,27 @@ public class TaskFormActivity extends AppCompatActivity implements AdapterView.O
|
|||
|
||||
@Override
|
||||
public boolean onSupportNavigateUp() {
|
||||
this.prepareSave();
|
||||
finish();
|
||||
return super.onSupportNavigateUp();
|
||||
this.finishActivitySuccessfuly();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
this.finishActivitySuccessfuly();
|
||||
}
|
||||
|
||||
private void finishActivitySuccessfuly() {
|
||||
this.prepareSave();
|
||||
finish();
|
||||
dismissKeyboard();
|
||||
}
|
||||
|
||||
private void dismissKeyboard() {
|
||||
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||
View currentFocus = getCurrentFocus();
|
||||
if (currentFocus != null) {
|
||||
imm.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
private TransactionListener<List<Tag>> tagsSearchingListener = new TransactionListener<List<Tag>>() {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package com.habitrpg.android.habitica.callbacks;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.HabitRPGUser;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
package com.habitrpg.android.habitica.database;
|
||||
|
||||
import com.google.gson.ExclusionStrategy;
|
||||
import com.google.gson.FieldAttributes;
|
||||
|
||||
/**
|
||||
* Created by franzejr on 29/11/15.
|
||||
*/
|
||||
public class CheckListItemExcludeStrategy implements ExclusionStrategy {
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipField(FieldAttributes f) {
|
||||
return f.getAnnotation(ExcludeCheckListItem.class) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldSkipClass(Class<?> clazz) {
|
||||
return clazz.getAnnotation(ExcludeCheckListItem.class) != null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.habitrpg.android.habitica.database;
|
||||
|
||||
/**
|
||||
* Created by franzejr on 29/11/15.
|
||||
*/
|
||||
public @interface ExcludeCheckListItem {
|
||||
|
||||
}
|
||||
|
|
@ -1,8 +1,17 @@
|
|||
package com.habitrpg.android.habitica.events;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.habitrpg.android.habitica.TaskFormActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Negue on 10.07.2015.
|
||||
*/
|
||||
public class TaskLongPressedEvent {
|
||||
public com.magicmicky.habitrpgwrapper.lib.models.tasks.Task Task;
|
||||
public com.magicmicky.habitrpgwrapper.lib.models.tasks.Task task;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,201 @@
|
|||
package com.habitrpg.android.habitica.ui;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
|
||||
import com.habitrpg.android.habitica.BuildConfig;
|
||||
import com.raizlabs.android.dbflow.sql.index.Index;
|
||||
|
||||
/**
|
||||
* http://stackoverflow.com/a/29945693/1315039
|
||||
*/
|
||||
public class WrapContentRecyclerViewLayoutManager extends android.support.v7.widget.LinearLayoutManager {
|
||||
|
||||
private static final int CHILD_WIDTH = 0;
|
||||
private static final int CHILD_HEIGHT = 1;
|
||||
private static final int DEFAULT_CHILD_SIZE = 100;
|
||||
|
||||
private final int[] childDimensions = new int[2];
|
||||
|
||||
private int childSize = DEFAULT_CHILD_SIZE;
|
||||
private boolean hasChildSize;
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public WrapContentRecyclerViewLayoutManager(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
public WrapContentRecyclerViewLayoutManager(Context context, int orientation, boolean reverseLayout) {
|
||||
super(context, orientation, reverseLayout);
|
||||
}
|
||||
|
||||
public static int makeUnspecifiedSpec() {
|
||||
return View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
|
||||
final int widthMode = View.MeasureSpec.getMode(widthSpec);
|
||||
final int heightMode = View.MeasureSpec.getMode(heightSpec);
|
||||
|
||||
final int widthSize = View.MeasureSpec.getSize(widthSpec);
|
||||
final int heightSize = View.MeasureSpec.getSize(heightSpec);
|
||||
|
||||
final boolean exactWidth = widthMode == View.MeasureSpec.EXACTLY;
|
||||
final boolean exactHeight = heightMode == View.MeasureSpec.EXACTLY;
|
||||
|
||||
final int unspecified = makeUnspecifiedSpec();
|
||||
|
||||
if (exactWidth && exactHeight) {
|
||||
// in case of exact calculations for both dimensions let's use default "onMeasure" implementation
|
||||
super.onMeasure(recycler, state, widthSpec, heightSpec);
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean vertical = getOrientation() == VERTICAL;
|
||||
|
||||
initChildDimensions(widthSize, heightSize, vertical);
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
// it's possible to get scrap views in recycler which are bound to old (invalid) adapter entities. This
|
||||
// happens because their invalidation happens after "onMeasure" method. As a workaround let's clear the
|
||||
// recycler now (it should not cause any performance issues while scrolling as "onMeasure" is never
|
||||
// called whiles scrolling)
|
||||
recycler.clear();
|
||||
|
||||
final int stateItemCount = state.getItemCount();
|
||||
final int adapterItemCount = getItemCount();
|
||||
// adapter always contains actual data while state might contain old data (f.e. data before the animation is
|
||||
// done). As we want to measure the view with actual data we must use data from the adapter and not from the
|
||||
// state
|
||||
for (int i = 0; i < adapterItemCount; i++) {
|
||||
if (vertical) {
|
||||
if (!hasChildSize) {
|
||||
if (i < stateItemCount) {
|
||||
// we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
|
||||
// we will use previously calculated dimensions
|
||||
measureChild(recycler, i, widthSpec, unspecified, childDimensions);
|
||||
} else {
|
||||
logMeasureWarning(i);
|
||||
}
|
||||
}
|
||||
height += childDimensions[CHILD_HEIGHT];
|
||||
if (i == 0) {
|
||||
width = childDimensions[CHILD_WIDTH];
|
||||
}
|
||||
} else {
|
||||
if (!hasChildSize) {
|
||||
if (i < stateItemCount) {
|
||||
// we should not exceed state count, otherwise we'll get IndexOutOfBoundsException. For such items
|
||||
// we will use previously calculated dimensions
|
||||
measureChild(recycler, i, unspecified, heightSpec, childDimensions);
|
||||
} else {
|
||||
logMeasureWarning(i);
|
||||
}
|
||||
}
|
||||
width += childDimensions[CHILD_WIDTH];
|
||||
if (i == 0) {
|
||||
height = childDimensions[CHILD_HEIGHT];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we really should wrap the contents of the view, let's do it
|
||||
|
||||
if (exactWidth) {
|
||||
width = widthSize;
|
||||
} else {
|
||||
width += getPaddingLeft() + getPaddingRight();
|
||||
}
|
||||
|
||||
if (exactHeight) {
|
||||
height = heightSize;
|
||||
} else {
|
||||
height += getPaddingTop() + getPaddingBottom();
|
||||
}
|
||||
|
||||
setMeasuredDimension(width, height);
|
||||
}
|
||||
|
||||
private void logMeasureWarning(int child) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
Log.w("LinearLayoutManager", "Can't measure child #" + child + ", previously used dimensions will be reused." +
|
||||
"To remove this message either use #setChildSize() method or don't run RecyclerView animations");
|
||||
}
|
||||
}
|
||||
|
||||
private void initChildDimensions(int width, int height, boolean vertical) {
|
||||
if (childDimensions[CHILD_WIDTH] != 0 || childDimensions[CHILD_HEIGHT] != 0) {
|
||||
// already initialized, skipping
|
||||
return;
|
||||
}
|
||||
if (vertical) {
|
||||
childDimensions[CHILD_WIDTH] = width;
|
||||
childDimensions[CHILD_HEIGHT] = childSize;
|
||||
} else {
|
||||
childDimensions[CHILD_WIDTH] = childSize;
|
||||
childDimensions[CHILD_HEIGHT] = height;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrientation(int orientation) {
|
||||
// might be called before the constructor of this class is called
|
||||
//noinspection ConstantConditions
|
||||
if (childDimensions != null) {
|
||||
if (getOrientation() != orientation) {
|
||||
childDimensions[CHILD_WIDTH] = 0;
|
||||
childDimensions[CHILD_HEIGHT] = 0;
|
||||
}
|
||||
}
|
||||
super.setOrientation(orientation);
|
||||
}
|
||||
|
||||
public void clearChildSize() {
|
||||
hasChildSize = false;
|
||||
setChildSize(DEFAULT_CHILD_SIZE);
|
||||
}
|
||||
|
||||
public void setChildSize(int childSize) {
|
||||
hasChildSize = true;
|
||||
if (this.childSize != childSize) {
|
||||
this.childSize = childSize;
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
private void measureChild(RecyclerView.Recycler recycler, int position, int widthSpec, int heightSpec, int[] dimensions) {
|
||||
final View child;
|
||||
try {
|
||||
child = recycler.getViewForPosition(position);
|
||||
} catch (IndexOutOfBoundsException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
final RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) child.getLayoutParams();
|
||||
|
||||
final int hPadding = getPaddingLeft() + getPaddingRight();
|
||||
final int vPadding = getPaddingTop() + getPaddingBottom();
|
||||
|
||||
final int hMargin = p.leftMargin + p.rightMargin;
|
||||
final int vMargin = p.topMargin + p.bottomMargin;
|
||||
|
||||
final int hDecoration = getRightDecorationWidth(child) + getLeftDecorationWidth(child);
|
||||
final int vDecoration = getTopDecorationHeight(child) + getBottomDecorationHeight(child);
|
||||
|
||||
final int childWidthSpec = getChildMeasureSpec(widthSpec, hPadding + hMargin + hDecoration, p.width, canScrollHorizontally());
|
||||
final int childHeightSpec = getChildMeasureSpec(heightSpec, vPadding + vMargin + vDecoration, p.height, canScrollVertically());
|
||||
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
|
||||
dimensions[CHILD_WIDTH] = getDecoratedMeasuredWidth(child) + p.leftMargin + p.rightMargin;
|
||||
dimensions[CHILD_HEIGHT] = getDecoratedMeasuredHeight(child) + p.bottomMargin + p.topMargin;
|
||||
|
||||
recycler.recycleView(child);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
package com.habitrpg.android.habitica.ui.adapter;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.habitrpg.android.habitica.R;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ItemTouchHelperAdapter;
|
||||
import com.habitrpg.android.habitica.ui.helpers.ItemTouchHelperViewHolder;
|
||||
import com.magicmicky.habitrpgwrapper.lib.models.tasks.ChecklistItem;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
|
||||
/**
|
||||
* Created by franzejr on 15/11/15.
|
||||
*/
|
||||
public class CheckListAdapter extends RecyclerView.Adapter<CheckListAdapter.ItemViewHolder>
|
||||
implements ItemTouchHelperAdapter{
|
||||
|
||||
private final List<ChecklistItem> mItems = new ArrayList<>();
|
||||
|
||||
public CheckListAdapter(List<ChecklistItem> checklistItems) {
|
||||
mItems.addAll(checklistItems);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.checklist_item, parent, false);
|
||||
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
|
||||
return itemViewHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(final ItemViewHolder holder, int position) {
|
||||
holder.checkListTextView.setText(mItems.get(position).getText());
|
||||
}
|
||||
|
||||
public void addItem(ChecklistItem item){
|
||||
mItems.add(item);
|
||||
notifyItemInserted(mItems.size() - 1);
|
||||
}
|
||||
|
||||
public List<ChecklistItem> getCheckListItems(){
|
||||
return mItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mItems.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onItemDismiss(int position) {
|
||||
mItems.remove(position);
|
||||
notifyItemRemoved(position);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onItemMove(int fromPosition, int toPosition) {
|
||||
Collections.swap(mItems, fromPosition, toPosition);
|
||||
notifyItemMoved(fromPosition, toPosition);
|
||||
}
|
||||
|
||||
public class ItemViewHolder extends RecyclerView.ViewHolder implements
|
||||
ItemTouchHelperViewHolder, Button.OnClickListener {
|
||||
|
||||
@InjectView(R.id.item_edittext)
|
||||
EditText checkListTextView;
|
||||
|
||||
@InjectView(R.id.delete_item_button)
|
||||
Button deleteButton;
|
||||
|
||||
public ItemViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
ButterKnife.inject(this, itemView);
|
||||
deleteButton.setOnClickListener(this);
|
||||
|
||||
checkListTextView.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
mItems.get(getAdapterPosition()).setText(checkListTextView.getText().toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected() {
|
||||
itemView.setBackgroundColor(Color.LTGRAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClear() {
|
||||
itemView.setBackgroundColor(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (v == deleteButton) {
|
||||
CheckListAdapter.this.onItemDismiss(getAdapterPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -138,7 +138,9 @@ public class HabitItemRecyclerViewAdapter<THabitItem extends Task>
|
|||
break;
|
||||
}
|
||||
}
|
||||
observableContent.set(i, task);
|
||||
if (i < observableContent.size()) {
|
||||
observableContent.set(i, task);
|
||||
}
|
||||
}
|
||||
|
||||
private void filter() {
|
||||
|
|
@ -274,13 +276,11 @@ public class HabitItemRecyclerViewAdapter<THabitItem extends Task>
|
|||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
TaskLongPressedEvent event = new TaskLongPressedEvent();
|
||||
event.Task = Item;
|
||||
event.task = Item;
|
||||
|
||||
EventBus.getDefault().post(event);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class HabitViewHolder extends ViewHolder<Task> {
|
||||
|
|
@ -371,6 +371,7 @@ public class HabitItemRecyclerViewAdapter<THabitItem extends Task>
|
|||
isClickable = true;
|
||||
}
|
||||
checklistIndicatorWrapper.setClickable(isClickable);
|
||||
displayChecklist = false;
|
||||
}
|
||||
|
||||
public void setDisplayChecklist(Boolean displayChecklist) {
|
||||
|
|
@ -382,11 +383,11 @@ public class HabitItemRecyclerViewAdapter<THabitItem extends Task>
|
|||
for (ChecklistItem item : this.Item.checklist) {
|
||||
LinearLayout itemView = (LinearLayout) layoutInflater.inflate(R.layout.checklist_item_row, null);
|
||||
CheckBox checkbox = (CheckBox) itemView.findViewById(R.id.checkBox);
|
||||
checkbox.setOnCheckedChangeListener(this);
|
||||
TextView textView = (TextView) 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);
|
||||
this.checklistView.addView(itemView);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -411,7 +412,11 @@ public class HabitItemRecyclerViewAdapter<THabitItem extends Task>
|
|||
|
||||
}
|
||||
} else {
|
||||
Integer position = (Integer) ((ViewGroup) checkbox.getParent().getParent()).indexOfChild((View) checkbox.getParent());
|
||||
View v = (View) buttonView.getParent();
|
||||
while (v.getParent() != this.checklistView) {
|
||||
v = (View) v.getParent();
|
||||
}
|
||||
Integer position = (Integer) ((ViewGroup) v.getParent()).indexOfChild(v);
|
||||
if (isChecked != Item.checklist.get(position).getCompleted()) {
|
||||
TaskSaveEvent event = new TaskSaveEvent();
|
||||
Item.checklist.get(position).setCompleted(isChecked);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
package com.habitrpg.android.habitica.ui.helpers;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
|
||||
/**
|
||||
* Interface to notify a {@link RecyclerView.Adapter} of moving and dismissal event from a {@link
|
||||
* android.support.v7.widget.helper.ItemTouchHelper.Callback}.
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
public interface ItemTouchHelperAdapter {
|
||||
|
||||
/**
|
||||
* Called when an item has been dragged far enough to trigger a move. This is called every time
|
||||
* an item is shifted, and not at the end of a "drop" event.
|
||||
*
|
||||
* @param fromPosition The start position of the moved item.
|
||||
* @param toPosition Then end position of the moved item.
|
||||
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
|
||||
* @see RecyclerView.ViewHolder#getAdapterPosition()
|
||||
*/
|
||||
void onItemMove(int fromPosition, int toPosition);
|
||||
|
||||
|
||||
/**
|
||||
* Called when an item has been dismissed by a swipe.
|
||||
*
|
||||
* @param position The position of the item dismissed.
|
||||
* @see RecyclerView#getAdapterPositionFor(RecyclerView.ViewHolder)
|
||||
* @see RecyclerView.ViewHolder#getAdapterPosition()
|
||||
*/
|
||||
void onItemDismiss(int position);
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.habitrpg.android.habitica.ui.helpers;
|
||||
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
|
||||
/**
|
||||
* Interface to notify an item ViewHolder of relevant callbacks from {@link
|
||||
* android.support.v7.widget.helper.ItemTouchHelper.Callback}.
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
public interface ItemTouchHelperViewHolder {
|
||||
|
||||
/**
|
||||
* Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
|
||||
* Implementations should update the item view to indicate it's active state.
|
||||
*/
|
||||
void onItemSelected();
|
||||
|
||||
|
||||
/**
|
||||
* Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
|
||||
* state should be cleared.
|
||||
*/
|
||||
void onItemClear();
|
||||
}
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
package com.habitrpg.android.habitica.ui.helpers;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
|
||||
/**
|
||||
* An implementation of {@link ItemTouchHelper.Callback} that enables basic drag & drop and
|
||||
* swipe-to-dismiss. Drag events are automatically started by an item long-press.<br/>
|
||||
* </br/>
|
||||
* Expects the <code>RecyclerView.Adapter</code> to react to {@link
|
||||
* ItemTouchHelperAdapter} callbacks and the <code>RecyclerView.ViewHolder</code> to implement
|
||||
* {@link ItemTouchHelperViewHolder}.
|
||||
*
|
||||
* @author Paul Burke (ipaulpro)
|
||||
*/
|
||||
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
|
||||
|
||||
private final ItemTouchHelperAdapter mAdapter;
|
||||
|
||||
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemViewSwipeEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
final int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
||||
final int swipeFlags = ItemTouchHelper.START | ItemTouchHelper.END;
|
||||
return makeMovementFlags(dragFlags, swipeFlags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder source, RecyclerView.ViewHolder target) {
|
||||
mAdapter.onItemMove(source.getAdapterPosition(), target.getAdapterPosition());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int i) {
|
||||
mAdapter.onItemDismiss(viewHolder.getAdapterPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
|
||||
if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
|
||||
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
|
||||
itemViewHolder.onItemSelected();
|
||||
}
|
||||
|
||||
super.onSelectedChanged(viewHolder, actionState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
||||
super.clearView(recyclerView, viewHolder);
|
||||
|
||||
ItemTouchHelperViewHolder itemViewHolder = (ItemTouchHelperViewHolder) viewHolder;
|
||||
itemViewHolder.onItemClear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.magicmicky.habitrpgwrapper.lib.models.tasks;
|
||||
|
||||
import com.habitrpg.android.habitica.HabitDatabase;
|
||||
import com.habitrpg.android.habitica.database.ExcludeCheckListItem;
|
||||
import com.raizlabs.android.dbflow.annotation.Column;
|
||||
import com.raizlabs.android.dbflow.annotation.ForeignKey;
|
||||
import com.raizlabs.android.dbflow.annotation.ForeignKeyReference;
|
||||
|
|
@ -31,13 +32,14 @@ public class ChecklistItem extends BaseModel {
|
|||
columnType = String.class,
|
||||
foreignColumnName = "id")},
|
||||
saveForeignKeyModel = false)
|
||||
@ExcludeCheckListItem
|
||||
ForeignKeyContainer<Task> task;
|
||||
|
||||
public ChecklistItem() {
|
||||
this(null,null);
|
||||
}
|
||||
public ChecklistItem(String id, String text) {
|
||||
this(id,text,false);
|
||||
this(id, text, false);
|
||||
}
|
||||
public ChecklistItem(String id,String text, boolean completed) {
|
||||
this.setText(text);
|
||||
|
|
@ -72,7 +74,11 @@ public class ChecklistItem extends BaseModel {
|
|||
}
|
||||
|
||||
public Task getTask() {
|
||||
return task.toModel();
|
||||
if (task != null) {
|
||||
return task.toModel();
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void setTask(Task task) {
|
||||
|
|
@ -80,4 +86,12 @@ public class ChecklistItem extends BaseModel {
|
|||
this.task.setModel(task);
|
||||
this.task.put("id", task.id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void save() {
|
||||
if (this.getId() == null || this.getId().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
super.save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -374,7 +374,9 @@ public class Task extends BaseModel {
|
|||
}
|
||||
if (this.checklist != null) {
|
||||
for (ChecklistItem item : this.checklist) {
|
||||
item.setTask(this);
|
||||
if(item.getTask() == null){
|
||||
item.setTask(this);
|
||||
}
|
||||
item.async().save();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue