Implement tag editing

This commit is contained in:
Phillip Thelen 2017-04-04 12:48:22 +02:00
parent 4f4dc9e917
commit 166a9fb496
11 changed files with 99 additions and 474 deletions

View file

@ -89,7 +89,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="24dp"
android:orientation="vertical"/>
android:orientation="vertical"
android:showDividers="middle"
android:divider="@color/transparent"
android:dividerPadding="8dp"/>
</ScrollView>
</LinearLayout>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="match_parent">
<EditText
android:id="@+id/edit_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:id="@+id/delete_button"
android:layout_width="45dp"
android:layout_height="wrap_content"
android:drawableRight="@drawable/ic_delete_black_24dp"
android:padding="0dp"
style="@style/Base.Widget.AppCompat.Button.Borderless"/>
</LinearLayout>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tagTextView"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:paddingLeft="@dimen/material_drawer_vertical_padding"
android:paddingRight="@dimen/material_drawer_vertical_padding"/>
<Button
android:id="@+id/btnEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="@string/edit_tag_btn_edit"/>
</LinearLayout>

View file

@ -1,38 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View android:id="@+id/material_drawer_divider"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="@dimen/material_drawer_padding" />
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/drawer_section_name"
android:layout_width="0dp"
android:layout_height="@dimen/material_drawer_item_primary"
android:layout_weight="1"
android:fontFamily="sans-serif-medium"
android:gravity="center_vertical|start"
android:lines="1"
android:paddingLeft="@dimen/material_drawer_vertical_padding"
android:paddingRight="@dimen/material_drawer_vertical_padding"
android:textSize="@dimen/material_drawer_item_section_text"
android:text="@string/filter_drawer_filter_tags"
android:maxLines="1"/>
<Button
android:id="@+id/btnEdit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="@string/edit_tag_btn_edit" />
</LinearLayout>
</LinearLayout>

View file

@ -1,19 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/editText"
android:layout_height="wrap_content"
android:layout_width="0dp"
android:layout_weight="1"
android:textColor="@android:color/black"
android:hint="@string/add_tag"
android:inputType="text" />
<Button
android:id="@+id/btnAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:text="+" />
</LinearLayout>

View file

@ -2,6 +2,9 @@ package com.habitrpg.android.habitica.data;
import com.magicmicky.habitrpgwrapper.lib.models.Tag;
import java.util.Collection;
import java.util.List;
import rx.Observable;
public interface TagRepository extends BaseRepository {
@ -11,4 +14,9 @@ public interface TagRepository extends BaseRepository {
Observable<Tag> updateTag(Tag tag);
Observable<Void> deleteTag(String id);
Observable<Tag> createTags(Collection<Tag> tags);
Observable<Tag> updateTags(Collection<Tag> tags);
Observable<List<Void>> deleteTags(Collection<String> tagIds);
}

View file

@ -5,7 +5,11 @@ import com.habitrpg.android.habitica.data.local.TagLocalRepository;
import com.magicmicky.habitrpgwrapper.lib.api.ApiClient;
import com.magicmicky.habitrpgwrapper.lib.models.Tag;
import java.util.Collection;
import java.util.List;
import rx.Observable;
import rx.functions.Func0;
public class TagRepositoryImpl extends BaseRepositoryImpl<TagLocalRepository> implements TagRepository {
@ -28,4 +32,24 @@ public class TagRepositoryImpl extends BaseRepositoryImpl<TagLocalRepository> im
public Observable<Void> deleteTag(String id) {
return apiClient.deleteTag(id);
}
@Override
public Observable<Tag> createTags(Collection<Tag> tags) {
return Observable.defer(() -> Observable.from(tags))
.filter(tag -> !tag.getName().isEmpty())
.flatMap(this::createTag);
}
@Override
public Observable<Tag> updateTags(Collection<Tag> tags) {
return Observable.defer(() -> Observable.from(tags))
.flatMap(this::updateTag);
}
@Override
public Observable<List<Void>> deleteTags(Collection<String> tagIds) {
return Observable.defer(() -> Observable.from(tagIds))
.flatMap(this::deleteTag)
.toList();
}
}

View file

@ -1,114 +0,0 @@
package com.habitrpg.android.habitica.ui.menu;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.events.commands.EditTagCommand;
import com.habitrpg.android.habitica.ui.helpers.ViewHelper;
import com.magicmicky.habitrpgwrapper.lib.models.Tag;
import com.mikepenz.fastadapter.utils.ViewHolderFactory;
import com.mikepenz.materialdrawer.holder.ColorHolder;
import com.mikepenz.materialdrawer.holder.StringHolder;
import com.mikepenz.materialdrawer.model.BasePrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.BaseViewHolder;
import org.greenrobot.eventbus.EventBus;
import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
/**
* Created by jjbillings on 8/12/16.
*/
public class EditTagsDrawerItem extends BasePrimaryDrawerItem<EditTagsDrawerItem, EditTagsDrawerItem.ViewHolder> {
private StringHolder name;
public EditTagsDrawerItem withName(StringHolder name) {
this.name = name;
return this;
}
public EditTagsDrawerItem withName(String name) {
this.name = new StringHolder(name);
return this;
}
public EditTagsDrawerItem withName(@StringRes int nameRes) {
this.name = new StringHolder(nameRes);
return this;
}
public StringHolder getName() {
return name;
}
@Override
public int getType() {
return R.id.material_drawer_item_primary_toggle;
}
@Override
@LayoutRes
public int getLayoutRes() {
return R.layout.edit_tags_drawer_item;
}
@Override
public void bindView(final ViewHolder viewHolder) {
Context ctx = viewHolder.itemView.getContext();
//set the text for the name
StringHolder.applyTo(this.getName(), viewHolder.tagTextView);
viewHolder.tagTextView.setTextColor(ColorHolder.color(getTextColor(), ctx, com.mikepenz.materialdrawer.R.attr.material_drawer_primary_text, com.mikepenz.materialdrawer.R.color.material_drawer_primary_text));
//Setup the Delete Button
ViewHelper.SetBackgroundTint(viewHolder.btnEdit, ContextCompat.getColor(ctx, R.color.brand));
viewHolder.btnEdit.setEnabled(true);
viewHolder.tag = (Tag) this.getTag();
//call the onPostBindView method to trigger post bind view actions (like the listener to modify the item if required)
onPostBindView(this, viewHolder.itemView);
}
@Override
public ViewHolderFactory<ViewHolder> getFactory() {
return new ItemFactory();
}
public static class ItemFactory implements ViewHolderFactory<ViewHolder> {
public ViewHolder create(View v) {
return new ViewHolder(v);
}
}
public static class ViewHolder extends BaseViewHolder implements View.OnClickListener {
private TextView tagTextView;
private Button btnEdit;
private Tag tag;
private ViewHolder(View view) {
super(view);
tagTextView = (TextView) view.findViewById(R.id.tagTextView);
btnEdit = (Button) view.findViewById(R.id.btnEdit);
btnEdit.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if (this.tag != null) {
EventBus.getDefault().post(new EditTagCommand(this.tag));
//EventBus.getDefault().post(new DeleteTagCommand(this.tag));
}
}
}
}

View file

@ -1,198 +0,0 @@
package com.habitrpg.android.habitica.ui.menu;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.events.ToggledEditTagsEvent;
import com.habitrpg.android.habitica.ui.helpers.ViewHelper;
import com.mikepenz.fastadapter.utils.ViewHolderFactory;
import com.mikepenz.materialdrawer.holder.ColorHolder;
import com.mikepenz.materialdrawer.holder.StringHolder;
import com.mikepenz.materialdrawer.model.AbstractDrawerItem;
import com.mikepenz.materialdrawer.model.interfaces.Nameable;
import com.mikepenz.materialdrawer.model.interfaces.Typefaceable;
import com.mikepenz.materialize.util.UIUtils;
import org.greenrobot.eventbus.EventBus;
import android.content.Context;
import android.graphics.Typeface;
import android.support.annotation.LayoutRes;
import android.support.annotation.StringRes;
import android.support.v4.content.ContextCompat;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
/**
* Created by jjbillings on 8/12/16.
*/
public class EditTagsSectionDrawer extends AbstractDrawerItem<EditTagsSectionDrawer, EditTagsSectionDrawer.ViewHolder> implements Nameable<EditTagsSectionDrawer>, Typefaceable<EditTagsSectionDrawer> {
private StringHolder name;
private boolean divider = true;
private boolean editing = false;
private ColorHolder textColor;
private Typeface typeface = null;
public EditTagsSectionDrawer withName(StringHolder name) {
this.name = name;
return this;
}
public EditTagsSectionDrawer withName(String name) {
this.name = new StringHolder(name);
return this;
}
public EditTagsSectionDrawer withName(@StringRes int nameRes) {
this.name = new StringHolder(nameRes);
return this;
}
public EditTagsSectionDrawer withEditing(boolean edit) {
this.editing = edit;
return this;
}
public EditTagsSectionDrawer withDivider(boolean divider) {
this.divider = divider;
return this;
}
public EditTagsSectionDrawer withTextColor(int textColor) {
this.textColor = ColorHolder.fromColor(textColor);
return this;
}
public EditTagsSectionDrawer withTextColorRes(int textColorRes) {
this.textColor = ColorHolder.fromColorRes(textColorRes);
return this;
}
public EditTagsSectionDrawer withTypeface(Typeface typeface) {
this.typeface = typeface;
return this;
}
public boolean hasDivider() {
return divider;
}
public ColorHolder getTextColor() {
return textColor;
}
public StringHolder getName() {
return name;
}
@Override
public boolean isEnabled() {
return false;
}
@Override
public boolean isSelected() {
return false;
}
@Override
public int getType() {
return R.id.material_drawer_item_section;
}
@Override
@LayoutRes
public int getLayoutRes() {
return R.layout.edit_tags_section_drawer_item;
}
@Override
public Typeface getTypeface() {
return typeface;
}
@Override
public void bindView(ViewHolder viewHolder) {
Context ctx = viewHolder.itemView.getContext();
//set the identifier from the drawerItem here. It can be used to run tests
viewHolder.itemView.setId(hashCode());
//define this item to be not clickable nor enabled
viewHolder.view.setClickable(false);
viewHolder.view.setEnabled(false);
//define the text color
viewHolder.name.setTextColor(ColorHolder.color(getTextColor(), ctx, com.mikepenz.materialdrawer.R.attr.material_drawer_secondary_text, com.mikepenz.materialdrawer.R.color.material_drawer_secondary_text));
viewHolder.editing = this.editing;
if (this.editing) {
viewHolder.btnEdit.setText(ctx.getString(R.string.edit_tag_btn_done));
} else {
viewHolder.btnEdit.setText(ctx.getString(R.string.edit_tag_btn_edit));
}
ViewHelper.SetBackgroundTint(viewHolder.btnEdit, ContextCompat.getColor(ctx, R.color.brand));
//set the text for the name
StringHolder.applyTo(this.getName(), viewHolder.name);
//define the typeface for our textViews
if (getTypeface() != null) {
viewHolder.name.setTypeface(getTypeface());
}
//hide the divider if we do not need one
if (this.hasDivider()) {
viewHolder.divider.setVisibility(View.VISIBLE);
} else {
viewHolder.divider.setVisibility(View.GONE);
}
//set the color for the divider
viewHolder.divider.setBackgroundColor(UIUtils.getThemeColorFromAttrOrRes(ctx, com.mikepenz.materialdrawer.R.attr.material_drawer_divider, com.mikepenz.materialdrawer.R.color.material_drawer_divider));
//call the onPostBindView method to trigger post bind view actions (like the listener to modify the item if required)
onPostBindView(this, viewHolder.itemView);
}
@Override
public ViewHolderFactory<ViewHolder> getFactory() {
return new ItemFactory();
}
public static class ItemFactory implements ViewHolderFactory<ViewHolder> {
public ViewHolder create(View v) {
return new ViewHolder(v);
}
}
public static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
private View view;
private View divider;
private TextView name;
private Button btnEdit;
private boolean editing;
private ViewHolder(View view) {
super(view);
this.view = view;
this.divider = view.findViewById(R.id.material_drawer_divider);
this.name = (TextView) view.findViewById(R.id.drawer_section_name);
this.btnEdit = (Button) view.findViewById(R.id.btnEdit);
this.btnEdit.setOnClickListener(this);
}
@Override
public void onClick(View view) {
ToggledEditTagsEvent editTagsEvent = new ToggledEditTagsEvent(!this.editing);
EventBus.getDefault().post(editTagsEvent);
}
}
}

View file

@ -1,79 +0,0 @@
package com.habitrpg.android.habitica.ui.menu;
import com.habitrpg.android.habitica.R;
import com.habitrpg.android.habitica.events.commands.CreateTagCommand;
import com.habitrpg.android.habitica.ui.helpers.ViewHelper;
import com.mikepenz.fastadapter.utils.ViewHolderFactory;
import com.mikepenz.materialdrawer.model.BasePrimaryDrawerItem;
import com.mikepenz.materialdrawer.model.BaseViewHolder;
import org.greenrobot.eventbus.EventBus;
import android.support.v4.content.ContextCompat;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import butterknife.BindView;
import butterknife.ButterKnife;
public class EditTextDrawer extends BasePrimaryDrawerItem<EditTextDrawer, EditTextDrawer.ViewHolder> {
@Override
public int getType() {
return R.id.material_drawer_item_primary;
}
@Override
public int getLayoutRes() {
return R.layout.edit_text_drawer_item;
}
@Override
public void bindView(ViewHolder holder) {
onPostBindView(this, holder.itemView);
}
@Override
public ViewHolderFactory getFactory() {
return new ItemFactory();
}
public static class ItemFactory implements ViewHolderFactory<EditTextDrawer.ViewHolder> {
public ViewHolder create(View v) {
return new ViewHolder(v);
}
}
public static class ViewHolder extends BaseViewHolder implements View.OnClickListener {
View view;
@BindView(R.id.editText)
EditText editText;
@BindView(R.id.btnAdd)
Button btnAdd;
private ViewHolder(View view) {
super(view);
this.view = view;
ButterKnife.bind(this, view);
ViewHelper.SetBackgroundTint(btnAdd, ContextCompat.getColor(view.getContext(), R.color.brand));
btnAdd.setOnClickListener(this);
}
@Override
public void onClick(View v) {
String text = editText.getText().toString();
if (text.equals(""))
return;
EventBus.getDefault().post(new CreateTagCommand(editText.getText().toString()));
editText.setText("");
}
}
}

View file

@ -5,6 +5,7 @@ import android.support.annotation.IdRes;
import android.support.v7.app.AlertDialog;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
@ -22,7 +23,10 @@ import com.habitrpg.android.habitica.data.TagRepository;
import com.magicmicky.habitrpgwrapper.lib.models.Tag;
import com.magicmicky.habitrpgwrapper.lib.models.tasks.Task;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.inject.Inject;
@ -60,12 +64,14 @@ public class TaskFilterDialog extends AlertDialog implements RadioGroup.OnChecke
private String filterType;
private List<Tag> tags;
private List<String> activeTags;
private Map<String, Tag> editedTags = new HashMap<>();
private Map<String, Tag> createdTags = new HashMap<>();
private List<String> deletedTags = new ArrayList<>();
private boolean isEditing;
public TaskFilterDialog(Context context, AppComponent component) {
super(context);
component.inject(this);
LayoutInflater inflater = LayoutInflater.from(context);
@ -88,6 +94,14 @@ public class TaskFilterDialog extends AlertDialog implements RadioGroup.OnChecke
});
}
@Override
public void show() {
super.show();
if (this.getWindow() != null) {
this.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
}
}
public void setTags(List<Tag> tags) {
this.tags = tags;
createTagViews();
@ -97,6 +111,7 @@ public class TaskFilterDialog extends AlertDialog implements RadioGroup.OnChecke
for (Tag tag : tags) {
CheckBox tagCheckbox = new CheckBox(getContext());
tagCheckbox.setText(tag.getName());
tagCheckbox.setTextSize(TypedValue.COMPLEX_UNIT_SP,14);
tagCheckbox.setOnCheckedChangeListener((buttonView, isChecked) -> {
if (isChecked) {
if (!activeTags.contains(tag.getId())) {
@ -124,6 +139,7 @@ public class TaskFilterDialog extends AlertDialog implements RadioGroup.OnChecke
Tag tag = new Tag();
tag.id = UUID.randomUUID().toString();
tags.add(tag);
createdTags.put(tag.getId(), tag);
startEditing();
}
@ -145,18 +161,23 @@ public class TaskFilterDialog extends AlertDialog implements RadioGroup.OnChecke
if (this.getWindow() != null) {
this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
}
repository.updateTags(editedTags.values()).subscribe(tag -> editedTags.remove(tag.getId()), throwable -> {});
repository.createTags(createdTags.values()).subscribe(tag -> createdTags.remove(tag.getId()), throwable -> {});
repository.deleteTags(deletedTags).subscribe(tags1 -> deletedTags.clear(), throwable -> {});
}
private void createTagEditViews() {
LayoutInflater inflater = LayoutInflater.from(getContext());
for (int index = 0; index < tags.size(); index++) {
Tag tag = tags.get(index);
createTagEditView(index, tag);
createTagEditView(inflater, index, tag);
}
createAddTagButton();
}
private void createTagEditView(int index, Tag tag) {
EditText tagEditText = new EditText(getContext());
private void createTagEditView(LayoutInflater inflater, int index, Tag tag) {
LinearLayout wrapper = (LinearLayout) inflater.inflate(R.layout.edit_tag_item, tagsList, false);
EditText tagEditText = (EditText) wrapper.findViewById(R.id.edit_text);
tagEditText.setText(tag.getName());
tagEditText.addTextChangedListener(new TextWatcher() {
@Override
@ -166,7 +187,14 @@ public class TaskFilterDialog extends AlertDialog implements RadioGroup.OnChecke
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
tags.get(index).setName(s.toString());
Tag tag = tags.get(index);
tag.setName(s.toString());
if (createdTags.containsKey(tag.getId())) {
createdTags.put(tag.getId(), tag);
} else {
editedTags.put(tag.getId(), tag);
}
tags.set(index, tag);
}
@Override
@ -174,7 +202,19 @@ public class TaskFilterDialog extends AlertDialog implements RadioGroup.OnChecke
}
});
tagsList.addView(tagEditText);
Button deleteButton = (Button) wrapper.findViewById(R.id.delete_button);
deleteButton.setOnClickListener(v -> {
deletedTags.add(tag.getId());
if (createdTags.containsKey(tag.getId())) {
createdTags.remove(tag.getId());
}
if (editedTags.containsKey(tag.getId())) {
editedTags.remove(tag.getId());
}
tags.remove(tag);
tagsList.removeView(wrapper);
});
tagsList.addView(wrapper);
}
public void setActiveTags(List<String> tagIds) {