/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.tags;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import android.app.Activity;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.TextView.OnEditorActionListener;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.ThemeService;
import com.todoroo.astrid.tags.TagService.Tag;
import com.todoroo.astrid.ui.PopupControlSet;
import com.todoroo.astrid.utility.Flags;
/**
* Control set to manage adding and removing tags
*
* @author Tim Su <tim@todoroo.com>
*
*/
public final class TagsControlSet extends PopupControlSet {
// --- instance variables
private static final String TRANSITORY_TAGS = "tags";//$NON-NLS-1$
private final TagService tagService = TagService.getInstance();
private ArrayList<String> allTagNames;
private LinearLayout newTags;
private ListView selectedTags;
private boolean populated = false;
private HashMap<String, Integer> tagIndices;
private final ImageView image;
//private final LinearLayout tagsContainer;
private final TextView tagsDisplay;
public TagsControlSet(Activity activity, int viewLayout, int displayViewLayout, int title) {
super(activity, viewLayout, displayViewLayout, title);
DependencyInjectionService.getInstance().inject(this);
tagsDisplay = (TextView) getDisplayView().findViewById(R.id.display_row_edit);
image = (ImageView) getDisplayView().findViewById(R.id.display_row_icon);
}
private Tag[] getTagArray() {
ArrayList<Tag> tagsList = TagService.getInstance().getTagList();
return tagsList.toArray(new Tag[tagsList.size()]);
}
private HashMap<String, Integer> buildTagIndices(ArrayList<String> tagNames) {
HashMap<String, Integer> indices = new HashMap<String, Integer>();
for (int i = 0; i < tagNames.size(); i++) {
indices.put(tagNames.get(i), i);
}
return indices;
}
private ArrayList<String> getTagNames(Tag[] tags) {
ArrayList<String> names = new ArrayList<String>();
for (int i = 0; i < tags.length; i++) {
names.add(tags[i].toString());
}
return names;
}
private String buildTagString() {
StringBuilder builder = new StringBuilder();
LinkedHashSet<String> tags = getTagSet();
for (String tag : tags) {
if (builder.length() != 0)
builder.append(", "); //$NON-NLS-1$
builder.append(tag);
}
return builder.toString();
}
private void setTagSelected(String tag) {
Integer index = tagIndices.get(tag);
if (index != null) {
selectedTags.setItemChecked(index, true);
} else {
allTagNames.add(tag);
tagIndices.put(tag, allTagNames.size() - 1);
((ArrayAdapter<String>)selectedTags.getAdapter()).notifyDataSetChanged();
}
}
private LinkedHashSet<String> getTagSet() {
LinkedHashSet<String> tags = new LinkedHashSet<String>();
if (initialized) {
for(int i = 0; i < selectedTags.getAdapter().getCount(); i++) {
if (selectedTags.isItemChecked(i))
tags.add(allTagNames.get(i));
}
for(int i = 0; i < newTags.getChildCount(); i++) {
TextView tagName = (TextView) newTags.getChildAt(i).findViewById(R.id.text1);
if(tagName.getText().length() == 0)
continue;
tags.add(tagName.getText().toString());
}
} else {
if (model.getTransitory(TRANSITORY_TAGS) != null) {
return (LinkedHashSet<String>) model.getTransitory(TRANSITORY_TAGS);
}
}
return tags;
}
/** Adds a tag to the tag field */
boolean addTag(String tagName, boolean reuse) {
LayoutInflater inflater = activity.getLayoutInflater();
// check if already exists
TextView lastText = null;
for(int i = 0; i < newTags.getChildCount(); i++) {
View view = newTags.getChildAt(i);
lastText = (TextView) view.findViewById(R.id.text1);
if(lastText.getText().equals(tagName))
return false;
}
final View tagItem;
if(reuse && lastText != null && lastText.getText().length() == 0) {
tagItem = (View) lastText.getParent();
} else {
tagItem = inflater.inflate(R.layout.tag_edit_row, null);
newTags.addView(tagItem);
}
if(tagName == null)
tagName = ""; //$NON-NLS-1$
final AutoCompleteTextView textView = (AutoCompleteTextView)tagItem.
findViewById(R.id.text1);
textView.setText(tagName);
textView.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
//
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
//
}
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
if(count > 0 && newTags.getChildAt(newTags.getChildCount()-1) ==
tagItem)
addTag("", false); //$NON-NLS-1$
}
});
textView.setOnEditorActionListener(new OnEditorActionListener() {
@Override
public boolean onEditorAction(TextView arg0, int actionId, KeyEvent arg2) {
if(actionId != EditorInfo.IME_NULL)
return false;
if(getLastTextView().getText().length() != 0) {
addTag("", false); //$NON-NLS-1$
}
return true;
}
});
ImageButton reminderRemoveButton;
reminderRemoveButton = (ImageButton)tagItem.findViewById(R.id.button1);
reminderRemoveButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
TextView lastView = getLastTextView();
if(lastView == textView && textView.getText().length() == 0)
return;
if(newTags.getChildCount() > 1)
newTags.removeView(tagItem);
else
textView.setText(""); //$NON-NLS-1$
}
});
return true;
}
/**
* Get tags container last text view. might be null
* @return
*/
private TextView getLastTextView() {
if(newTags.getChildCount() == 0)
return null;
View lastItem = newTags.getChildAt(newTags.getChildCount()-1);
TextView lastText = (TextView) lastItem.findViewById(R.id.text1);
return lastText;
}
@Override
public void readFromTask(Task task) {
super.readFromTask(task);
if(model.getId() != AbstractModel.NO_ID) {
TodorooCursor<Metadata> cursor = tagService.getTags(model.getId());
LinkedHashSet<String> tags = new LinkedHashSet<String>(cursor.getCount());
try {
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
String tag = cursor.get(TaskToTagMetadata.TAG_NAME);
tags.add(tag);
}
} finally {
cursor.close();
}
model.putTransitory(TRANSITORY_TAGS, tags);
refreshDisplayView();
}
}
@Override
protected void readFromTaskOnInitialize() {
newTags.removeAllViews();
for (int i = 0; i < selectedTags.getCount(); i++) { // clear all selected items
selectedTags.setItemChecked(i, false);
}
if(model.getId() != AbstractModel.NO_ID) {
selectTagsFromModel();
}
addTag("", false); //$NON-NLS-1$
refreshDisplayView();
populated = true;
}
private void selectTagsFromModel() {
LinkedHashSet<String> tags = (LinkedHashSet<String>) model.getTransitory(TRANSITORY_TAGS);
if (tags != null) {
for (String tag : tags) {
setTagSelected(tag);
}
}
}
@Override
protected void additionalDialogSetup() {
super.additionalDialogSetup();
dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
}
@Override
protected void afterInflate() {
Tag[] allTags = getTagArray();
allTagNames = getTagNames(allTags);
tagIndices = buildTagIndices(allTagNames);
selectedTags = (ListView) getView().findViewById(R.id.existingTags);
selectedTags.setAdapter(new ArrayAdapter<String>(activity,
R.layout.simple_list_item_multiple_choice_themed, allTagNames));
selectedTags.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
this.newTags = (LinearLayout) getView().findViewById(R.id.newTags);
}
@Override
protected String writeToModelAfterInitialized(Task task) {
// this is a case where we're asked to save but the UI was not yet populated
if(!populated)
return null;
LinkedHashSet<String> tags = getTagSet();
if(TagService.getInstance().synchronizeTags(task.getId(), task.getValue(Task.UUID), tags)) {
Flags.set(Flags.TAGS_CHANGED);
task.setValue(Task.MODIFICATION_DATE, DateUtilities.now());
}
return null;
}
@Override
protected void refreshDisplayView() {
String tagString = buildTagString();
if (!TextUtils.isEmpty(tagString)) {
tagsDisplay.setText(tagString);
tagsDisplay.setTextColor(themeColor);
image.setImageResource(ThemeService.getTaskEditDrawable(R.drawable.tea_icn_lists, R.drawable.tea_icn_lists_lightblue));
} else {
tagsDisplay.setText(R.string.tag_FEx_untagged);
tagsDisplay.setTextColor(unsetColor);
image.setImageResource(R.drawable.tea_icn_lists_gray);
}
}
public boolean hasLists() {
LinkedHashSet<String> tags = getTagSet();
return !tags.isEmpty();
}
}