diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java index 24e912ff1..62509f576 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java @@ -2,9 +2,9 @@ package com.todoroo.astrid.tags; import java.util.LinkedHashSet; -import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.data.Property.CountProperty; import com.todoroo.andlib.data.Property.StringProperty; +import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.sql.Criterion; @@ -71,6 +71,11 @@ public final class TagService { public String tag; int count; + public Tag(String tag, int count) { + this.tag = tag; + this.count = count; + } + @Override public String toString() { return tag; @@ -114,9 +119,7 @@ public final class TagService { Tag[] array = new Tag[cursor.getCount()]; for (int i = 0; i < array.length; i++) { cursor.moveToNext(); - array[i] = new Tag(); - array[i].tag = cursor.get(TAG); - array[i].count = cursor.get(COUNT); + array[i] = new Tag(cursor.get(TAG), cursor.get(COUNT)); } return array; } finally { diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java index 4154e6e83..b24c0960a 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java @@ -1,16 +1,25 @@ package com.todoroo.astrid.tags; +import java.util.ArrayList; +import java.util.Arrays; import java.util.LinkedHashSet; import android.app.Activity; +import android.text.Editable; +import android.text.TextWatcher; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; -import android.view.View.OnClickListener; +import android.view.inputmethod.EditorInfo; +import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; import android.widget.ImageButton; import android.widget.LinearLayout; +import android.widget.Spinner; import android.widget.TextView; +import android.widget.TextView.OnEditorActionListener; import com.timsu.astrid.R; import com.todoroo.andlib.data.AbstractModel; @@ -32,6 +41,7 @@ public final class TagsControlSet implements TaskEditControlSet { // --- instance variables + private final Spinner tagSpinner; private final TagService tagService = TagService.getInstance(); private final Tag[] allTags; private String[] loadedTags; @@ -42,6 +52,36 @@ public final class TagsControlSet implements TaskEditControlSet { allTags = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE, Criterion.all); this.activity = activity; this.tagsContainer = (LinearLayout) activity.findViewById(tagsContainer); + this.tagSpinner = (Spinner) activity.findViewById(R.id.tags_dropdown); + + if(allTags.length == 0) { + tagSpinner.setVisibility(View.GONE); + } else { + ArrayList dropDownList = new ArrayList(Arrays.asList(allTags)); + dropDownList.add(0, new Tag(activity.getString(R.string.TEA_tag_dropdown), 0)); + ArrayAdapter tagAdapter = new ArrayAdapter(activity, + android.R.layout.simple_spinner_item, + dropDownList); + tagAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); + tagSpinner.setAdapter(tagAdapter); + tagSpinner.setSelection(0); + + tagSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { + @Override + public void onItemSelected(AdapterView arg0, View arg1, + int position, long arg3) { + if(position == 0 || position > allTags.length) + return; + addTag(allTags[position - 1].tag, true); + tagSpinner.setSelection(0); + } + + @Override + public void onNothingSelected(AdapterView arg0) { + // nothing! + } + }); + } } @Override @@ -55,16 +95,14 @@ public final class TagsControlSet implements TaskEditControlSet { for(int i = 0; i < loadedTags.length; i++) { cursor.moveToNext(); String tag = cursor.get(TagService.TAG); - addTag(tag); + addTag(tag, true); loadedTags[i] = tag; } } finally { cursor.close(); } } - - if(tagsContainer.getChildCount() == 0) - addTag(""); //$NON-NLS-1$ + addTag("", false); //$NON-NLS-1$ } @Override @@ -96,10 +134,25 @@ public final class TagsControlSet implements TaskEditControlSet { } /** Adds a tag to the tag field */ - boolean addTag(String tagName) { + boolean addTag(String tagName, boolean reuse) { LayoutInflater inflater = activity.getLayoutInflater(); - final View tagItem = inflater.inflate(R.layout.tag_edit_row, null); - tagsContainer.addView(tagItem); + + // check if already exists + TextView lastText = null; + for(int i = 0; i < tagsContainer.getChildCount(); i++) { + View view = tagsContainer.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); + tagsContainer.addView(tagItem); + } final AutoCompleteTextView textView = (AutoCompleteTextView)tagItem. findViewById(R.id.text1); @@ -109,36 +162,46 @@ public final class TagsControlSet implements TaskEditControlSet { android.R.layout.simple_dropdown_item_1line, allTags); textView.setAdapter(tagsAdapter); - textView.setOnClickListener(new OnClickListener() { + textView.addTextChangedListener(new TextWatcher() { @Override - public void onClick(View arg0) { - View lastItem = tagsContainer.getChildAt(tagsContainer.getChildCount()-1); - TextView lastText = (TextView) lastItem.findViewById(R.id.text1); - if(lastText.getText().length() != 0) { - addTag(""); //$NON-NLS-1$ - } + 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 && tagsContainer.getChildAt(tagsContainer.getChildCount()-1) == + tagItem) + addTag("", false); //$NON-NLS-1$ } }); - /*textView.setOnEditorActionListener(new OnEditorActionListener() { + textView.setOnEditorActionListener(new OnEditorActionListener() { @Override public boolean onEditorAction(TextView arg0, int actionId, KeyEvent arg2) { if(actionId != EditorInfo.IME_NULL) return false; - View lastItem = tagsContainer.getChildAt(tagsContainer.getChildCount()-1); - TextView lastText = (TextView) lastItem.findViewById(R.id.text1); - if(lastText.getText().length() != 0) { - addTag(""); //$NON-NLS-1$ + 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) { - if(tagsContainer.getChildCount() > 0) + TextView lastView = getLastTextView(); + if(lastView == textView && textView.getText().length() == 0) + return; + + if(tagsContainer.getChildCount() > 1) tagsContainer.removeView(tagItem); else textView.setText(""); //$NON-NLS-1$ @@ -147,4 +210,16 @@ public final class TagsControlSet implements TaskEditControlSet { return true; } + + /** + * Get tags container last text view. might be null + * @return + */ + private TextView getLastTextView() { + if(tagsContainer.getChildCount() == 0) + return null; + View lastItem = tagsContainer.getChildAt(tagsContainer.getChildCount()-1); + TextView lastText = (TextView) lastItem.findViewById(R.id.text1); + return lastText; + } } \ No newline at end of file diff --git a/astrid/res/layout/task_edit_activity.xml b/astrid/res/layout/task_edit_activity.xml index e6fdb48b2..5691e1d23 100644 --- a/astrid/res/layout/task_edit_activity.xml +++ b/astrid/res/layout/task_edit_activity.xml @@ -65,6 +65,10 @@ + diff --git a/astrid/res/values/strings-tags.xml b/astrid/res/values/strings-tags.xml index 86ed091ae..e33705159 100644 --- a/astrid/res/values/strings-tags.xml +++ b/astrid/res/values/strings-tags.xml @@ -11,6 +11,9 @@ Tag Name + + + Select a tag diff --git a/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java b/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java index 2bc380038..c4b6c4422 100644 --- a/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java +++ b/astrid/src/com/todoroo/astrid/activity/TaskEditActivity.java @@ -27,15 +27,15 @@ import java.util.List; import android.app.AlertDialog; import android.app.DatePickerDialog; -import android.app.TabActivity; import android.app.DatePickerDialog.OnDateSetListener; +import android.app.TabActivity; import android.content.BroadcastReceiver; import android.content.ContentValues; import android.content.Context; import android.content.DialogInterface; +import android.content.DialogInterface.OnCancelListener; import android.content.Intent; import android.content.IntentFilter; -import android.content.DialogInterface.OnCancelListener; import android.content.res.Resources; import android.os.Bundle; import android.text.format.DateUtils; @@ -45,6 +45,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.AdapterView; +import android.widget.AdapterView.OnItemSelectedListener; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CheckBox; @@ -59,7 +60,6 @@ import android.widget.TabHost; import android.widget.TimePicker; import android.widget.Toast; import android.widget.ToggleButton; -import android.widget.AdapterView.OnItemSelectedListener; import com.flurry.android.FlurryAgent; import com.timsu.astrid.R; @@ -155,6 +155,9 @@ public final class TaskEditActivity extends TabActivity { // --- other instance variables + /** true if editing started with a new task */ + boolean isNewTask = false; + /** task model */ private Task model = null; @@ -251,25 +254,10 @@ public final class TaskEditActivity extends TabActivity { }); } - // read data - populateFields(); - - // request add-on controls - Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_EDIT_CONTROLS); - broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, model.getId()); - sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); - // set up listeners setUpListeners(); } - /** - * @return true if task is newly created - */ - private boolean isNewTask() { - return model == null ? true : model.getValue(Task.TITLE).length() == 0; - } - /** Set up button listeners */ private void setUpListeners() { final View.OnClickListener mSaveListener = new View.OnClickListener() { @@ -324,9 +312,13 @@ public final class TaskEditActivity extends TabActivity { values = AndroidUtilities.contentValuesFromSerializedString(valuesAsString); model = TaskListActivity.createWithValues(values, null, taskService, metadataService); } - if(model.getValue(Task.TITLE).length() == 0) + + if(model.getValue(Task.TITLE).length() == 0) { FlurryAgent.onEvent("create-task"); - FlurryAgent.onEvent("edit-task"); + isNewTask = true; + } else { + FlurryAgent.onEvent("edit-task"); + } if(model == null) { exceptionService.reportError("task-edit-no-task", @@ -341,7 +333,7 @@ public final class TaskEditActivity extends TabActivity { Resources r = getResources(); loadItem(getIntent()); - if(isNewTask()) + if(isNewTask) setTitle(R.string.TEA_view_titleNew); else setTitle(r.getString(R.string.TEA_view_title, model.getValue(Task.TITLE))); @@ -352,14 +344,6 @@ public final class TaskEditActivity extends TabActivity { /** Save task model from values in UI components */ private void save() { - // abandon editing in this case - if(title.getText().length() == 0) { - if(isNewTask()) - taskService.delete(model); - discardButtonClick(); - return; - } - for(TaskEditControlSet controlSet : controls) controlSet.writeToModel(model); @@ -367,6 +351,18 @@ public final class TaskEditActivity extends TabActivity { showSaveToast(); } + @Override + public void finish() { + super.finish(); + + // abandon editing in this case + if(title.getText().length() == 0 && isNewTask) { + taskService.delete(model); + showCancelToast(); + setResult(RESULT_CANCELED); + } + } + /* ====================================================================== * ================================================ edit control handling * ====================================================================== */ @@ -416,7 +412,7 @@ public final class TaskEditActivity extends TabActivity { */ private void showSaveToast() { // if we have no title, or nothing's changed, don't show toast - if(isNewTask()) + if(isNewTask) return; int stringResource; @@ -445,7 +441,7 @@ public final class TaskEditActivity extends TabActivity { // abandon editing in this case if(title.getText().length() == 0) { - if(isNewTask()) + if(isNewTask) taskService.delete(model); } @@ -540,6 +536,7 @@ public final class TaskEditActivity extends TabActivity { super.onResume(); registerReceiver(controlReceiver, new IntentFilter(AstridApiConstants.BROADCAST_SEND_EDIT_CONTROLS)); + populateFields(); } @Override @@ -552,14 +549,6 @@ public final class TaskEditActivity extends TabActivity { protected void onStop() { super.onStop(); FlurryAgent.onEndSession(this); - - // don't save if user accidentally created a new task - if(title.getText().length() == 0) { - if(model.isSaved()) - taskService.delete(model); - showCancelToast(); - return; - } } /* ====================================================================== diff --git a/astrid/src/com/todoroo/astrid/dao/TaskDao.java b/astrid/src/com/todoroo/astrid/dao/TaskDao.java index debbf747a..613ec1658 100644 --- a/astrid/src/com/todoroo/astrid/dao/TaskDao.java +++ b/astrid/src/com/todoroo/astrid/dao/TaskDao.java @@ -223,7 +223,7 @@ public class TaskDao extends GenericDao { * @param skipHooks whether this save occurs as part of a sync */ private void afterSave(Task task, ContentValues values) { - if(values.containsKey(Task.COMPLETION_DATE.name) && task.isCompleted()) + if(values != null && values.containsKey(Task.COMPLETION_DATE.name) && task.isCompleted()) afterComplete(task, values); else ReminderService.getInstance().scheduleAlarm(task); diff --git a/astrid/src/com/todoroo/astrid/widget/TasksWidget.java b/astrid/src/com/todoroo/astrid/widget/TasksWidget.java index 576f1fb65..c89a41bd8 100644 --- a/astrid/src/com/todoroo/astrid/widget/TasksWidget.java +++ b/astrid/src/com/todoroo/astrid/widget/TasksWidget.java @@ -98,7 +98,9 @@ public class TasksWidget extends AppWidgetProvider { TasksWidget.class); AppWidgetManager manager = AppWidgetManager.getInstance(this); - int extrasId = intent.getIntExtra(EXTRA_WIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); + int extrasId = AppWidgetManager.INVALID_APPWIDGET_ID; + if(intent != null) + extrasId = intent.getIntExtra(EXTRA_WIDGET_ID, extrasId); if(extrasId == AppWidgetManager.INVALID_APPWIDGET_ID) { for(int id : manager.getAppWidgetIds(thisWidget)) { RemoteViews updateViews = buildUpdate(this, id);