/** * Copyright (c) 2012 Todoroo Inc * * See the file "LICENSE" for the full license governing this code. */ package com.todoroo.astrid.ui; import java.util.HashSet; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.content.Context; import android.content.res.Resources; import android.content.res.TypedArray; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.inputmethod.EditorInfo; import android.widget.ImageButton; import android.widget.LinearLayout; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; import com.timsu.astrid.R; import com.todoroo.andlib.service.ContextManager; import com.todoroo.andlib.utility.Preferences; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.helper.AsyncImageView; import com.todoroo.astrid.utility.ResourceDrawableCache; public class PeopleContainer extends LinearLayout { private boolean completeTags = false; protected OnAddNewPersonListener onAddNewPerson = null; protected Resources resources; // --- accessors and boilerplate public PeopleContainer(Context arg0, AttributeSet attrs) { super(arg0, attrs); resources = arg0.getResources(); TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ContactsAutoComplete); completeTags = a.getBoolean(R.styleable.ContactsAutoComplete_completeTags, false); } public PeopleContainer(Context context) { super(context); } public interface OnAddNewPersonListener { public void textChanged(String text); } public void setOnAddNewPerson(OnAddNewPersonListener onAddNewPerson) { this.onAddNewPerson = onAddNewPerson; } // --- methods public TextView addPerson() { return addPerson("", "", false); //$NON-NLS-1$ //$NON-NLS-2$ } /** Adds a tag to the tag field */ public TextView addPerson(String person, String image, boolean hideRemove) { LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); // check if already exists for(int i = 0; i < getChildCount(); i++) { View view = getChildAt(i); TextView matching = (TextView) view.findViewById(R.id.text1); if(matching.getText().equals(person)) return matching; } final View tagItem = inflater.inflate(R.layout.contact_edit_row, null); if(person.length() == 0) addView(tagItem, getChildCount()); else addView(tagItem); final ContactsAutoComplete textView = (ContactsAutoComplete)tagItem. findViewById(R.id.text1); textView.setText(person); textView.setHint(R.string.actfm_person_hint); if(completeTags) { textView.setCompleteSharedTags(true); textView.setHint(R.string.actfm_person_or_tag_hint); } final ImageButton removeButton = (ImageButton)tagItem.findViewById(R.id.button1); if (hideRemove) removeButton.setVisibility(View.GONE); else removeButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { TextView lastView = getLastTextView(); if(lastView == textView && textView.getText().length() == 0) return; if(getChildCount() > 1) removeView(tagItem); else { textView.setText(""); //$NON-NLS-1$ textView.setEnabled(true); } } }); final AsyncImageView imageView = (AsyncImageView)tagItem. findViewById(R.id.icon); imageView.setUrl(image); if (TextUtils.isEmpty(textView.getText())) { imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_add_contact)); removeButton.setVisibility(View.GONE); } else { imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image)); if (!hideRemove) removeButton.setVisibility(View.VISIBLE); } textView.addTextChangedListener(new TextWatcher() { @Override public void afterTextChanged(Editable s) { // } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { // } @SuppressWarnings("nls") @Override public void onTextChanged(CharSequence s, int start, int before, int count) { if(count > 0 && getLastTextView() == textView) { addPerson("", "", false); } if (TextUtils.isEmpty(textView.getText())) { imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_add_contact)); removeButton.setVisibility(View.GONE); } else { imageView.setDefaultImageDrawable(ResourceDrawableCache.getImageDrawableFromId(resources, R.drawable.icn_default_person_image)); removeButton.setVisibility(View.VISIBLE); } if(onAddNewPerson != null) onAddNewPerson.textChanged(s.toString()); } }); textView.setOnEditorActionListener(new OnEditorActionListener() { @SuppressWarnings("nls") @Override public boolean onEditorAction(TextView arg0, int actionId, KeyEvent arg2) { if(actionId != EditorInfo.IME_NULL) return false; if(getLastTextView().getText().length() != 0) { addPerson("", "", false); } return true; } }); return textView; } /** * Get tags container last text view. might be null * @return */ private TextView getLastTextView() { for(int i = getChildCount() - 1; i >= 0; i--) { View lastItem = getChildAt(i); TextView lastText = (TextView) lastItem.findViewById(R.id.text1); if(lastText.isEnabled()) return lastText; } return null; } public TextView getTextView(int index) { View item = getChildAt(index); return (TextView) item.findViewById(R.id.text1); } /** * * @return json array of people */ public JSONArray toJSONArray() { JSONArray people = new JSONArray(); for(int i = 0; i < getChildCount(); i++) { TextView textView = getTextView(i); JSONObject person = PeopleContainer.createUserJson(textView); if(person != null) { String email = person.optString("email"); //$NON-NLS-1$ if (email.indexOf('@') != -1) people.put(person); } } return people; } @SuppressWarnings("nls") public JSONObject parseSharedWithAndTags(Activity activity, boolean peopleAsJSON) throws JSONException, ParseSharedException { JSONObject sharedWith = new JSONObject(); HashSet<String> addedEmails = new HashSet<String>(); HashSet<Long> addedIds = new HashSet<Long>(); JSONArray peopleList = new JSONArray(); for(int i = 0; i < getChildCount(); i++) { TextView textView = getTextView(i); String text = textView.getText().toString(); if(text.length() == 0) continue; if(text.indexOf('@') == -1 && textView.isEnabled()) throw new ParseSharedException(textView, activity.getString(R.string.actfm_EPA_invalid_email, text)); if (peopleAsJSON) { JSONObject person = PeopleContainer.createUserJson(textView); if (person != null) { if (person.optBoolean("owner")) //$NON-NLS-1$ continue; String email = person.optString("email"); Long id = person.optLong("id", -1); if (!TextUtils.isEmpty(email) && !addedEmails.contains(email)) { addedEmails.add(email); if (id > 0) addedIds.add(id); peopleList.put(person); } else if (id > 0 && !addedIds.contains(id)) { addedIds.add(id); peopleList.put(person); } } } else if (!addedEmails.contains(text)) { addedEmails.add(text); peopleList.put(text); } } if(peopleList.length() > 0) sharedWith.put("p", peopleList); return sharedWith; } public static class ParseSharedException extends Exception { private static final long serialVersionUID = -4135848250086302970L; public TextView view; public String message; public ParseSharedException(TextView view, String message) { this.view = view; this.message = message; } } /** * Add people from JSON Array * @param people */ @SuppressWarnings("nls") public void fromJSONArray(JSONArray people) throws JSONException { for(int i = 0; i < people.length(); i++) { JSONObject person = people.getJSONObject(i); TextView textView = null; String imageURL = person.optString("picture", ""); boolean owner = person.optBoolean("owner"); boolean hideRemove = owner; String name = ""; if(person.has("id") && ActFmPreferenceService.userId().equals(person.getString("id"))) { name = Preferences.getStringValue(ActFmPreferenceService.PREF_NAME); hideRemove = true; } else if(!TextUtils.isEmpty(person.optString("name")) && !"null".equals(person.optString("name"))) { name = person.getString("name"); } else if(!TextUtils.isEmpty(person.optString("email")) && !"null".equals(person.optString("email"))) { name = person.getString("email"); } if (owner) name = name + " " + ContextManager.getString(R.string.actfm_list_owner); textView = addPerson(name, imageURL, hideRemove); if(textView != null) { textView.setTag(person); textView.setEnabled(false); } } } /** * Warning: user json may not have a valid email address. * @param textView * @return */ @SuppressWarnings("nls") public static JSONObject createUserJson(TextView textView) { if(textView.isEnabled() == false) return (JSONObject) textView.getTag(); String text = textView.getText().toString().trim(); if(text.length() == 0) return null; JSONObject user = new JSONObject(); int bracket = text.lastIndexOf('<'); try { if(bracket > -1) { user.put("name", text.substring(0, bracket - 1).trim()); user.put("email", text.substring(bracket + 1, text.length() - 1).trim()); } else { user.put("email", text); } } catch (JSONException e) { throw new RuntimeException(e); } return user; } }