mirror of https://github.com/tasks/tasks
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
376 lines
12 KiB
Java
376 lines
12 KiB
Java
/*
|
|
* ASTRID: Android's Simple Task Recording Dashboard
|
|
*
|
|
* Copyright (c) 2009 Tim Su
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
package com.timsu.astrid.activities;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
|
|
import android.app.Activity;
|
|
import android.app.AlertDialog;
|
|
import android.content.Context;
|
|
import android.content.DialogInterface;
|
|
import android.content.Intent;
|
|
import android.content.res.Resources;
|
|
import android.database.Cursor;
|
|
import android.os.Bundle;
|
|
import android.view.ContextMenu;
|
|
import android.view.LayoutInflater;
|
|
import android.view.Menu;
|
|
import android.view.MenuItem;
|
|
import android.view.View;
|
|
import android.view.ViewGroup;
|
|
import android.view.ContextMenu.ContextMenuInfo;
|
|
import android.view.View.OnCreateContextMenuListener;
|
|
import android.widget.AdapterView;
|
|
import android.widget.ArrayAdapter;
|
|
import android.widget.ListView;
|
|
import android.widget.TextView;
|
|
import android.widget.AdapterView.AdapterContextMenuInfo;
|
|
import android.widget.AdapterView.OnItemClickListener;
|
|
|
|
import com.timsu.astrid.R;
|
|
import com.timsu.astrid.data.tag.TagController;
|
|
import com.timsu.astrid.data.tag.TagIdentifier;
|
|
import com.timsu.astrid.data.tag.TagModelForView;
|
|
import com.timsu.astrid.data.task.TaskController;
|
|
import com.timsu.astrid.data.task.TaskIdentifier;
|
|
import com.timsu.astrid.data.task.TaskModelForList;
|
|
import com.timsu.astrid.utilities.Constants;
|
|
|
|
|
|
/** List all tags and allows a user to see all tasks for a given tag
|
|
*
|
|
* @author Tim Su (timsu@stanfordalumni.org)
|
|
*
|
|
*/
|
|
public class TagList extends Activity {
|
|
private static final int ACTIVITY_LIST = 0;
|
|
private static final int ACTIVITY_CREATE = 1;
|
|
|
|
private static final int MENU_SORT_ALPHA_ID = Menu.FIRST;
|
|
private static final int MENU_SORT_SIZE_ID = Menu.FIRST + 1;
|
|
private static final int CONTEXT_CREATE_ID = Menu.FIRST + 10;
|
|
private static final int CONTEXT_DELETE_ID = Menu.FIRST + 11;
|
|
private static final int CONTEXT_SHOWHIDE_ID = Menu.FIRST + 12;
|
|
|
|
private TagController controller;
|
|
private TaskController taskController;
|
|
private ListView listView;
|
|
|
|
private List<TagModelForView> tagArray;
|
|
private Map<Long, TaskModelForList> taskMap;
|
|
private Map<TagModelForView, Integer> tagToTaskCount;
|
|
private SortMode sortMode = SortMode.SIZE;
|
|
private boolean sortReverse = false;
|
|
|
|
/** Called when loading up the activity for the first time */
|
|
private void onLoad() {
|
|
controller = new TagController(this);
|
|
controller.open();
|
|
taskController = new TaskController(this);
|
|
taskController.open();
|
|
|
|
listView = (ListView)findViewById(R.id.taglist);
|
|
|
|
fillData();
|
|
}
|
|
|
|
// --- stuff for sorting
|
|
|
|
private enum SortMode {
|
|
ALPHA {
|
|
@Override
|
|
int compareTo(TagList self, TagModelForView arg0, TagModelForView arg1) {
|
|
return arg0.getName().compareTo(arg1.getName());
|
|
}
|
|
},
|
|
SIZE {
|
|
@Override
|
|
int compareTo(TagList self, TagModelForView arg0, TagModelForView arg1) {
|
|
return self.tagToTaskCount.get(arg1) - self.tagToTaskCount.get(arg0);
|
|
}
|
|
};
|
|
|
|
abstract int compareTo(TagList self, TagModelForView arg0, TagModelForView arg1);
|
|
};
|
|
|
|
private void sortTagArray() {
|
|
// get all tasks
|
|
Cursor taskCursor = taskController.getActiveTaskListCursor();
|
|
startManagingCursor(taskCursor);
|
|
List<TaskModelForList> taskArray =
|
|
taskController.createTaskListFromCursor(taskCursor);
|
|
taskMap = new HashMap<Long, TaskModelForList>();
|
|
for(TaskModelForList task : taskArray) {
|
|
if(task.isHidden())
|
|
continue;
|
|
taskMap.put(task.getTaskIdentifier().getId(), task);
|
|
}
|
|
|
|
// get accurate task count for each tag
|
|
tagToTaskCount = new HashMap<TagModelForView, Integer>();
|
|
for(TagModelForView tag : tagArray) {
|
|
int count = 0;
|
|
List<TaskIdentifier> tasks = controller.getTaggedTasks(TagList.this,
|
|
tag.getTagIdentifier());
|
|
|
|
for(TaskIdentifier taskId : tasks)
|
|
if(taskMap.containsKey(taskId.getId()))
|
|
count++;
|
|
tagToTaskCount.put(tag, count);
|
|
}
|
|
|
|
// do sort
|
|
Collections.sort(tagArray, new Comparator<TagModelForView>() {
|
|
@Override
|
|
public int compare(TagModelForView arg0, TagModelForView arg1) {
|
|
return sortMode.compareTo(TagList.this, arg0, arg1);
|
|
}
|
|
});
|
|
if(sortReverse)
|
|
Collections.reverse(tagArray);
|
|
}
|
|
|
|
// --- fill data
|
|
|
|
/** Fill in the Tag List with our tags */
|
|
private void fillData() {
|
|
Resources r = getResources();
|
|
|
|
tagArray = controller.getAllTags(this);
|
|
|
|
// perform sort
|
|
sortTagArray();
|
|
|
|
// set up the title
|
|
StringBuilder title = new StringBuilder().
|
|
append(r.getString(R.string.tagList_titlePrefix)).
|
|
append(" ").append(r.getQuantityString(R.plurals.Ntags,
|
|
tagArray.size(), tagArray.size()));
|
|
setTitle(title);
|
|
|
|
// set up our adapter
|
|
TagListAdapter tagAdapter = new TagListAdapter(this,
|
|
android.R.layout.simple_list_item_1, tagArray);
|
|
listView.setAdapter(tagAdapter);
|
|
|
|
// list view listener
|
|
listView.setOnItemClickListener(new OnItemClickListener() {
|
|
@Override
|
|
public void onItemClick(AdapterView<?> parent, View view,
|
|
int position, long id) {
|
|
TagModelForView tag = (TagModelForView)view.getTag();
|
|
|
|
Intent intent = new Intent(TagList.this, TaskList.class);
|
|
intent.putExtra(TaskList.TAG_TOKEN, tag.
|
|
getTagIdentifier().getId());
|
|
startActivityForResult(intent, ACTIVITY_LIST);
|
|
}
|
|
});
|
|
|
|
listView.setOnCreateContextMenuListener(new OnCreateContextMenuListener() {
|
|
@Override
|
|
public void onCreateContextMenu(ContextMenu menu, View v,
|
|
ContextMenuInfo menuInfo) {
|
|
AdapterContextMenuInfo adapterMenuInfo =
|
|
(AdapterContextMenuInfo)menuInfo;
|
|
int position = adapterMenuInfo.position;
|
|
|
|
menu.add(position, CONTEXT_CREATE_ID, Menu.NONE,
|
|
R.string.tagList_context_create);
|
|
menu.add(position, CONTEXT_DELETE_ID, Menu.NONE,
|
|
R.string.tagList_context_delete);
|
|
|
|
int showHideLabel = R.string.tagList_context_hideTag;
|
|
if(tagArray.get(position).shouldHideFromMainList())
|
|
showHideLabel = R.string.tagList_context_showTag;
|
|
menu.add(position, CONTEXT_SHOWHIDE_ID, Menu.NONE,
|
|
showHideLabel);
|
|
|
|
menu.setHeaderTitle(tagArray.get(position).getName());
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
protected void onActivityResult(int requestCode, int resultCode,
|
|
Intent intent) {
|
|
switch(resultCode) {
|
|
case Constants.RESULT_GO_HOME:
|
|
finish();
|
|
break;
|
|
|
|
default:
|
|
fillData();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onWindowFocusChanged(boolean hasFocus) {
|
|
super.onWindowFocusChanged(hasFocus);
|
|
|
|
if(hasFocus && TaskList.shouldCloseInstance) { // user wants to quit
|
|
finish();
|
|
}
|
|
}
|
|
|
|
// --- list adapter
|
|
|
|
private class TagListAdapter extends ArrayAdapter<TagModelForView> {
|
|
|
|
private List<TagModelForView> objects;
|
|
private int resource;
|
|
private LayoutInflater inflater;
|
|
|
|
public TagListAdapter(Context context, int resource,
|
|
List<TagModelForView> objects) {
|
|
super(context, resource, objects);
|
|
|
|
inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
|
this.objects = objects;
|
|
this.resource = resource;
|
|
}
|
|
|
|
@Override
|
|
public View getView(int position, View convertView, ViewGroup parent) {
|
|
View view;
|
|
|
|
view = inflater.inflate(resource, parent, false);
|
|
setupView(view, objects.get(position));
|
|
|
|
return view;
|
|
}
|
|
|
|
public void setupView(View view, final TagModelForView tag) {
|
|
Resources r = getResources();
|
|
view.setTag(tag);
|
|
|
|
final TextView name = ((TextView)view.findViewById(android.R.id.text1));
|
|
name.setText(new StringBuilder(tag.getName()).
|
|
append(" (").append(tagToTaskCount.get(tag)).append(")"));
|
|
|
|
if(tagToTaskCount.get(tag) == 0)
|
|
name.setTextColor(r.getColor(R.color.task_list_done));
|
|
}
|
|
}
|
|
|
|
// --- ui control handlers
|
|
|
|
private void createTask(TagModelForView tag) {
|
|
Intent intent = new Intent(this, TaskEdit.class);
|
|
intent.putExtra(TaskEdit.TAG_NAME_TOKEN, tag.getName());
|
|
startActivityForResult(intent, ACTIVITY_CREATE);
|
|
}
|
|
|
|
private void deleteTag(final TagIdentifier tagId) {
|
|
new AlertDialog.Builder(this)
|
|
.setTitle(R.string.delete_title)
|
|
.setMessage(R.string.delete_this_tag_title)
|
|
.setIcon(android.R.drawable.ic_dialog_alert)
|
|
.setPositiveButton(android.R.string.ok,
|
|
new DialogInterface.OnClickListener() {
|
|
@Override
|
|
public void onClick(DialogInterface dialog, int which) {
|
|
controller.deleteTag(tagId);
|
|
fillData();
|
|
}
|
|
})
|
|
.setNegativeButton(android.R.string.cancel, null)
|
|
.show();
|
|
}
|
|
|
|
@Override
|
|
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
|
switch(item.getItemId()) {
|
|
case MENU_SORT_ALPHA_ID:
|
|
if(sortMode == SortMode.ALPHA)
|
|
sortReverse = !sortReverse;
|
|
else {
|
|
sortMode = SortMode.ALPHA;
|
|
sortReverse = false;
|
|
}
|
|
fillData();
|
|
return true;
|
|
case MENU_SORT_SIZE_ID:
|
|
if(sortMode == SortMode.SIZE)
|
|
sortReverse = !sortReverse;
|
|
else {
|
|
sortMode = SortMode.SIZE;
|
|
sortReverse = false;
|
|
}
|
|
fillData();
|
|
return true;
|
|
case CONTEXT_CREATE_ID:
|
|
TagModelForView tag = tagArray.get(item.getGroupId());
|
|
createTask(tag);
|
|
return true;
|
|
case CONTEXT_DELETE_ID:
|
|
tag = tagArray.get(item.getGroupId());
|
|
deleteTag(tag.getTagIdentifier());
|
|
return true;
|
|
case CONTEXT_SHOWHIDE_ID:
|
|
tag = tagArray.get(item.getGroupId());
|
|
tag.toggleHideFromMainList();
|
|
controller.saveTag(tag);
|
|
fillData();
|
|
return true;
|
|
}
|
|
|
|
return super.onMenuItemSelected(featureId, item);
|
|
}
|
|
|
|
// --- creating stuff
|
|
|
|
@Override
|
|
public void onCreate(Bundle savedInstanceState) {
|
|
super.onCreate(savedInstanceState);
|
|
setContentView(R.layout.tag_list);
|
|
|
|
onLoad();
|
|
}
|
|
|
|
@Override
|
|
protected void onDestroy() {
|
|
super.onDestroy();
|
|
controller.close();
|
|
taskController.close();
|
|
}
|
|
|
|
@Override
|
|
public boolean onCreateOptionsMenu(Menu menu) {
|
|
super.onCreateOptionsMenu(menu);
|
|
|
|
MenuItem item;
|
|
|
|
item = menu.add(Menu.NONE, MENU_SORT_ALPHA_ID, Menu.NONE,
|
|
R.string.tagList_menu_sortAlpha);
|
|
item.setIcon(android.R.drawable.ic_menu_sort_alphabetically);
|
|
item.setAlphabeticShortcut('a');
|
|
|
|
item = menu.add(Menu.NONE, MENU_SORT_SIZE_ID, Menu.NONE,
|
|
R.string.tagList_menu_sortSize);
|
|
item.setIcon(android.R.drawable.ic_menu_sort_by_size);
|
|
item.setAlphabeticShortcut('s');
|
|
|
|
return true;
|
|
}
|
|
} |