Merge branch 'producteev-custom-filters-2' of git://192.168.10.106/astrid

pull/14/head
Tim Su 14 years ago
commit de8bff5b81

@ -284,6 +284,12 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.tags.TagCustomFilterCriteriaExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_CUSTOM_FILTER_CRITERIA" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.tags.TagDetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
@ -418,6 +424,12 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.producteev.ProducteevCustomFilterCriteriaExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_CUSTOM_FILTER_CRITERIA" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<activity android:name="com.todoroo.astrid.producteev.ProducteevPreferences"
android:label="@string/producteev_PPr_header">
<meta-data android:name="category"

@ -1,18 +1,19 @@
package com.todoroo.astrid.core;
import java.util.ArrayList;
import java.util.List;
import java.util.*;
import java.util.Map.Entry;
import android.app.ListActivity;
import android.content.ContentValues;
import android.content.Intent;
import android.content.*;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.database.Cursor;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
@ -28,21 +29,12 @@ import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.CustomFilterCriterion;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.MultipleSelectCriterion;
import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.api.TextInputCriterion;
import com.todoroo.astrid.api.*;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TagService.Tag;
/**
* Activity that allows users to build custom filters
@ -52,7 +44,7 @@ import com.todoroo.astrid.tags.TagService.Tag;
*/
public class CustomFilterActivity extends ListActivity {
private static final String IDENTIFIER_TAG = "tag"; //$NON-NLS-1$
private static final String IDENTIFIER_TITLE = "title"; //$NON-NLS-1$
private static final String IDENTIFIER_IMPORTANCE = "importance"; //$NON-NLS-1$
private static final String IDENTIFIER_DUEDATE = "dueDate"; //$NON-NLS-1$
private static final String IDENTIFIER_UNIVERSE = "active"; //$NON-NLS-1$
@ -119,8 +111,9 @@ public class CustomFilterActivity extends ListActivity {
private TextView filterName;
private CustomFilterAdapter adapter;
private final ArrayList<CustomFilterCriterion> criteria =
new ArrayList<CustomFilterCriterion>();
private final Map<String,CustomFilterCriterion> criteria = Collections.synchronizedMap(new LinkedHashMap<String,CustomFilterCriterion>());
private FilterCriteriaReceiver filterCriteriaReceiver = new FilterCriteriaReceiver();
// --- activity
@ -150,112 +143,98 @@ public class CustomFilterActivity extends ListActivity {
}
/**
* Populate criteria list with built in and plugin criteria
* Populate criteria list with built in and plugin criteria. The request is sent to every application
* registered to listen for this broadcast. Each plugin can then add criteria to this activity.
*/
@SuppressWarnings("nls")
private void populateCriteria() {
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_CUSTOM_FILTER_CRITERIA);
sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
Resources r = getResources();
// built in criteria: due date
String[] entryValues = new String[] {
"0",
PermaSql.VALUE_EOD_YESTERDAY,
PermaSql.VALUE_EOD,
PermaSql.VALUE_EOD_TOMORROW,
PermaSql.VALUE_EOD_DAY_AFTER,
PermaSql.VALUE_EOD_NEXT_WEEK,
PermaSql.VALUE_EOD_NEXT_MONTH,
};
ContentValues values = new ContentValues();
values.put(Task.DUE_DATE.name, "?");
CustomFilterCriterion criterion = new MultipleSelectCriterion(
IDENTIFIER_DUEDATE,
getString(R.string.CFC_dueBefore_text),
Query.select(Task.ID).from(Task.TABLE).where(
Criterion.and(
TaskCriteria.activeAndVisible(),
Criterion.or(
Field.field("?").eq(0),
Task.DUE_DATE.gt(0)),
Task.DUE_DATE.lte("?"))).toString(),
values, r.getStringArray(R.array.CFC_dueBefore_entries),
entryValues, ((BitmapDrawable)r.getDrawable(R.drawable.tango_calendar)).getBitmap(),
getString(R.string.CFC_dueBefore_name));
criteria.add(criterion);
{
String[] entryValues = new String[] {
"0",
PermaSql.VALUE_EOD_YESTERDAY,
PermaSql.VALUE_EOD,
PermaSql.VALUE_EOD_TOMORROW,
PermaSql.VALUE_EOD_DAY_AFTER,
PermaSql.VALUE_EOD_NEXT_WEEK,
PermaSql.VALUE_EOD_NEXT_MONTH,
};
ContentValues values = new ContentValues();
values.put(Task.DUE_DATE.name, "?");
CustomFilterCriterion criterion = new MultipleSelectCriterion(
IDENTIFIER_DUEDATE,
getString(R.string.CFC_dueBefore_text),
Query.select(Task.ID).from(Task.TABLE).where(
Criterion.and(
TaskCriteria.activeAndVisible(),
Criterion.or(
Field.field("?").eq(0),
Task.DUE_DATE.gt(0)),
Task.DUE_DATE.lte("?"))).toString(),
values, r.getStringArray(R.array.CFC_dueBefore_entries),
entryValues, ((BitmapDrawable)r.getDrawable(R.drawable.tango_calendar)).getBitmap(),
getString(R.string.CFC_dueBefore_name));
criteria.put(IDENTIFIER_DUEDATE, criterion);
}
// built in criteria: importance
entryValues = new String[] {
Integer.toString(Task.IMPORTANCE_DO_OR_DIE),
Integer.toString(Task.IMPORTANCE_MUST_DO),
Integer.toString(Task.IMPORTANCE_SHOULD_DO),
Integer.toString(Task.IMPORTANCE_NONE),
};
String[] entries = new String[] {
"!!!!", "!!!", "!!", "!"
};
values = new ContentValues();
values.put(Task.IMPORTANCE.name, "?");
criterion = new MultipleSelectCriterion(
IDENTIFIER_IMPORTANCE,
getString(R.string.CFC_importance_text),
Query.select(Task.ID).from(Task.TABLE).where(
Criterion.and(TaskCriteria.activeAndVisible(),
Task.IMPORTANCE.lte("?"))).toString(),
values, entries,
entryValues, ((BitmapDrawable)r.getDrawable(R.drawable.tango_warning)).getBitmap(),
getString(R.string.CFC_importance_name));
criteria.add(criterion);
// built in criteria: tags
Tag[] tags = TagService.getInstance().getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE,
TaskCriteria.activeAndVisible());
String[] tagNames = new String[tags.length];
for(int i = 0; i < tags.length; i++)
tagNames[i] = tags[i].tag;
values = new ContentValues();
values.put(Metadata.KEY.name, TagService.KEY);
values.put(TagService.TAG.name, "?");
criterion = new MultipleSelectCriterion(
IDENTIFIER_TAG,
getString(R.string.CFC_tag_text),
Query.select(Metadata.TASK).from(Metadata.TABLE).join(Join.inner(
Task.TABLE, Metadata.TASK.eq(Task.ID))).where(Criterion.and(
TaskCriteria.activeAndVisible(),
MetadataCriteria.withKey(TagService.KEY),
TagService.TAG.eq("?"))).toString(),
values, tagNames, tagNames,
((BitmapDrawable)r.getDrawable(R.drawable.filter_tags1)).getBitmap(),
getString(R.string.CFC_tag_name));
criteria.add(criterion);
// built in criteria: tags containing X
criterion = new TextInputCriterion(
IDENTIFIER_TAG,
getString(R.string.CFC_tag_contains_text),
Query.select(Metadata.TASK).from(Metadata.TABLE).join(Join.inner(
Task.TABLE, Metadata.TASK.eq(Task.ID))).where(Criterion.and(
TaskCriteria.activeAndVisible(),
MetadataCriteria.withKey(TagService.KEY),
TagService.TAG.like("%?%"))).toString(),
null, getString(R.string.CFC_tag_contains_name), "",
((BitmapDrawable)r.getDrawable(R.drawable.filter_tags2)).getBitmap(),
getString(R.string.CFC_tag_contains_name));
criteria.add(criterion);
{
String[] entryValues = new String[] {
Integer.toString(Task.IMPORTANCE_DO_OR_DIE),
Integer.toString(Task.IMPORTANCE_MUST_DO),
Integer.toString(Task.IMPORTANCE_SHOULD_DO),
Integer.toString(Task.IMPORTANCE_NONE),
};
String[] entries = new String[] {
"!!!!", "!!!", "!!", "!"
};
ContentValues values = new ContentValues();
values.put(Task.IMPORTANCE.name, "?");
CustomFilterCriterion criterion = new MultipleSelectCriterion(
IDENTIFIER_IMPORTANCE,
getString(R.string.CFC_importance_text),
Query.select(Task.ID).from(Task.TABLE).where(
Criterion.and(TaskCriteria.activeAndVisible(),
Task.IMPORTANCE.lte("?"))).toString(),
values, entries,
entryValues, ((BitmapDrawable)r.getDrawable(R.drawable.tango_warning)).getBitmap(),
getString(R.string.CFC_importance_name));
criteria.put(IDENTIFIER_IMPORTANCE, criterion);
}
// built in criteria: title containing X
values = new ContentValues();
values.put(Task.TITLE.name, "?");
criterion = new TextInputCriterion(
IDENTIFIER_TAG,
getString(R.string.CFC_title_contains_text),
Query.select(Task.ID).from(Task.TABLE).where(
Criterion.and(TaskCriteria.activeAndVisible(),
Task.TITLE.like("%?%"))).toString(),
null, getString(R.string.CFC_title_contains_name), "",
((BitmapDrawable)r.getDrawable(R.drawable.tango_alpha)).getBitmap(),
getString(R.string.CFC_title_contains_name));
criteria.add(criterion);
{
ContentValues values = new ContentValues();
values.put(Task.TITLE.name, "?");
CustomFilterCriterion criterion = new TextInputCriterion(
IDENTIFIER_TITLE,
getString(R.string.CFC_title_contains_text),
Query.select(Task.ID).from(Task.TABLE).where(
Criterion.and(TaskCriteria.activeAndVisible(),
Task.TITLE.like("%?%"))).toString(),
null, getString(R.string.CFC_title_contains_name), "",
((BitmapDrawable)r.getDrawable(R.drawable.tango_alpha)).getBitmap(),
getString(R.string.CFC_title_contains_name));
criteria.put(IDENTIFIER_TITLE, criterion);
}
}
@Override
protected void onResume() {
super.onResume();
registerReceiver(filterCriteriaReceiver, new IntentFilter(AstridApiConstants.BROADCAST_SEND_CUSTOM_FILTER_CRITERIA));
populateCriteria();
}
@Override
protected void onPause() {
super.onPause();
unregisterReceiver(filterCriteriaReceiver);
}
private CriterionInstance getStartingUniverse() {
@ -310,13 +289,23 @@ public class CustomFilterActivity extends ListActivity {
@Override
public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) {
if(menu.hasVisibleItems())
if(menu.hasVisibleItems()) {
/* If it has items already, then the user did not click on the "Add Criteria" button, but instead
long held on a row in the list view, which caused CustomFilterAdapter.onCreateContextMenu
to be invoked before this onCreateContextMenu method was invoked.
*/
return;
}
for(int i = 0; i < criteria.size(); i++) {
CustomFilterCriterion item = criteria.get(i);
menu.add(CustomFilterActivity.MENU_GROUP_FILTER,
i, 0, item.name);
int i = 0;
for (CustomFilterCriterion item : criteria.values()) {
try {
menu.add(CustomFilterActivity.MENU_GROUP_FILTER,
i, 0, item.name);
} catch (NullPointerException e) {
throw new NullPointerException("One of the criteria is null. Criteria: " + criteria);
}
i++;
}
}
});
@ -459,12 +448,21 @@ public class CustomFilterActivity extends ListActivity {
adapter.notifyDataSetInvalidated();
}
private <V> V getNth(int index, Map<?,V> map) {
int i = 0;
for (V v : map.values()) {
if (i == index) return v;
i++;
}
throw new IllegalArgumentException("out of bounds");
}
@Override
public boolean onMenuItemSelected(int featureId, MenuItem item) {
// group filter option
if(item.getGroupId() == MENU_GROUP_FILTER) {
// give an initial value for the row before adding it
CustomFilterCriterion criterion = criteria.get(item.getItemId());
CustomFilterCriterion criterion = getNth(item.getItemId(), criteria);
final CriterionInstance instance = new CriterionInstance();
instance.criterion = criterion;
adapter.showOptionsFor(instance, new Runnable() {
@ -493,4 +491,29 @@ public class CustomFilterActivity extends ListActivity {
return super.onMenuItemSelected(featureId, item);
}
public class FilterCriteriaReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
try {
final Parcelable[] filters = intent.getExtras().
getParcelableArray(AstridApiConstants.EXTRAS_RESPONSE);
for (Parcelable filter : filters) {
CustomFilterCriterion filterCriterion = (CustomFilterCriterion) filter;
criteria.put(filterCriterion.identifier, filterCriterion);
}
} catch (Exception e) {
String addon;
try {
addon = intent.getStringExtra(AstridApiConstants.EXTRAS_ADDON);
} catch (Exception e1) {
Log.e("receive-custom-filter-criteria-error-retrieving-addon",
e.toString(), e);
return;
}
Log.e("receive-custom-filter-criteria-" + //$NON-NLS-1$
addon,
e.toString(), e);
}
}
}
}

@ -0,0 +1,117 @@
package com.todoroo.astrid.producteev;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import com.timsu.astrid.R;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.CustomFilterCriterion;
import com.todoroo.astrid.api.MultipleSelectCriterion;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.producteev.sync.ProducteevDashboard;
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
import com.todoroo.astrid.producteev.sync.ProducteevTask;
import com.todoroo.astrid.producteev.sync.ProducteevUser;
import java.util.Set;
import java.util.TreeSet;
public class ProducteevCustomFilterCriteriaExposer extends BroadcastReceiver {
private static final String IDENTIFIER_PRODUCTEEV_WORKSPACE = "producteev_workspace"; //$NON-NLS-1$
private static final String IDENTIFIER_PRODUCTEEV_ASSIGNEE = "producteev_assignee"; //$NON-NLS-1$
@Override
public void onReceive(Context context, Intent intent) {
// if we aren't logged in, don't expose features
if(!ProducteevUtilities.INSTANCE.isLoggedIn())
return;
Resources r = context.getResources();
StoreObject[] objects = ProducteevDataService.getInstance().getDashboards();
ProducteevDashboard[] dashboards = new ProducteevDashboard[objects.length];
for (int i = 0; i < objects.length; i++) {
dashboards[i] = new ProducteevDashboard(objects[i]);
}
CustomFilterCriterion[] ret = new CustomFilterCriterion[2];
int j = 0;
{
String[] workspaceNames = new String[objects.length];
String[] workspaceIds = new String[objects.length];
for (int i = 0; i < dashboards.length; i++) {
workspaceNames[i] = dashboards[i].getName();
workspaceIds[i] = String.valueOf(dashboards[i].getId());
}
ContentValues values = new ContentValues(2);
values.put(Metadata.KEY.name, ProducteevTask.METADATA_KEY);
values.put(ProducteevTask.DASHBOARD_ID.name, "?");
CustomFilterCriterion criterion = new MultipleSelectCriterion(
IDENTIFIER_PRODUCTEEV_WORKSPACE,
context.getString(R.string.CFC_producteev_in_workspace_text),
// Todo: abstract these metadata queries
Query.select(Metadata.TASK).from(Metadata.TABLE).join(Join.inner(
Task.TABLE, Metadata.TASK.eq(Task.ID))).where(Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
MetadataDao.MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
ProducteevTask.DASHBOARD_ID.eq("?"))).toString(),
values, // what is this?
workspaceNames,
workspaceIds,
((BitmapDrawable)r.getDrawable(R.drawable.silk_folder)).getBitmap(),
context.getString(R.string.CFC_producteev_in_workspace_name));
ret[j++] = criterion;
}
{
Set<ProducteevUser> users = new TreeSet<ProducteevUser>();
for (ProducteevDashboard dashboard : dashboards) {
users.addAll(dashboard.getUsers());
}
int numUsers = users.size();
String[] userNames = new String[numUsers];
String[] userIds = new String[numUsers];
int i = 0;
for (ProducteevUser user : users) {
userNames[i] = user.toString();
userIds[i] = String.valueOf(user.getId());
i++;
}
ContentValues values = new ContentValues(2);
values.put(Metadata.KEY.name, ProducteevTask.METADATA_KEY);
values.put(ProducteevTask.RESPONSIBLE_ID.name, "?");
CustomFilterCriterion criterion = new MultipleSelectCriterion(
IDENTIFIER_PRODUCTEEV_ASSIGNEE,
context.getString(R.string.CFC_producteev_assigned_to_text),
// Todo: abstract these metadata queries, and unify this code with the CustomFilterExposers.
Query.select(Metadata.TASK).from(Metadata.TABLE).join(Join.inner(
Task.TABLE, Metadata.TASK.eq(Task.ID))).where(Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
MetadataDao.MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
ProducteevTask.RESPONSIBLE_ID.eq("?"))).toString(),
values, // what is this?
userNames,
userIds,
((BitmapDrawable)r.getDrawable(R.drawable.silk_user_gray)).getBitmap(),
context.getString(R.string.CFC_producteev_assigned_to_name));
ret[j++] = criterion;
}
// transmit filter list
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_CUSTOM_FILTER_CRITERIA);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, ProducteevUtilities.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, ret);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
}

@ -3,8 +3,7 @@
*/
package com.todoroo.astrid.producteev;
import java.util.TreeMap;
import java.util.Map.Entry;
import java.util.TreeSet;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
@ -14,7 +13,6 @@ import android.content.Intent;
import com.timsu.astrid.R;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.Pair;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterCategory;
@ -27,6 +25,7 @@ import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.producteev.sync.ProducteevDashboard;
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
import com.todoroo.astrid.producteev.sync.ProducteevTask;
import com.todoroo.astrid.producteev.sync.ProducteevUser;
/**
* Exposes filters based on Producteev Dashboards
@ -59,20 +58,19 @@ public class ProducteevFilterExposer extends BroadcastReceiver {
return filter;
}
private Filter filterFromUser(Context context, String user, Pair<Long, String> ids) {
String title = context.getString(R.string.producteev_FEx_responsible_title, user);
private Filter filterFromUser(Context context, ProducteevUser user) {
String title = context.getString(R.string.producteev_FEx_responsible_title, user.toString());
ContentValues values = new ContentValues();
values.put(Metadata.KEY.name, ProducteevTask.METADATA_KEY);
values.put(ProducteevTask.DASHBOARD_ID.name, ids.getLeft());
values.put(ProducteevTask.ID.name, 0);
values.put(ProducteevTask.CREATOR_ID.name, 0);
values.put(ProducteevTask.RESPONSIBLE_ID.name, ids.getRight());
Filter filter = new Filter(user, title, new QueryTemplate().join(
values.put(ProducteevTask.RESPONSIBLE_ID.name, user.getId());
Filter filter = new Filter(user.toString(), title, new QueryTemplate().join(
ProducteevDataService.METADATA_JOIN).where(Criterion.and(
MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
TaskCriteria.isActive(),
TaskCriteria.isVisible(),
ProducteevTask.RESPONSIBLE_ID.eq(ids.getRight()))),
ProducteevTask.RESPONSIBLE_ID.eq(user.getId()))),
values);
return filter;
@ -100,11 +98,11 @@ public class ProducteevFilterExposer extends BroadcastReceiver {
dashboardFilters);
// load responsible people
TreeMap<String, Pair<Long, String>> people = loadResponsiblePeople(dashboards);
TreeSet<ProducteevUser> people = loadResponsiblePeople(dashboards);
Filter[] peopleFilters = new Filter[people.size()];
int index = 0;
for(Entry<String, Pair<Long, String>> person : people.entrySet())
peopleFilters[index++] = filterFromUser(context, person.getKey(), person.getValue());
for (ProducteevUser person : people)
peopleFilters[index++] = filterFromUser(context, person);
FilterCategory producteevUsers = new FilterCategory(context.getString(R.string.producteev_FEx_responsible),
peopleFilters);
@ -124,22 +122,14 @@ public class ProducteevFilterExposer extends BroadcastReceiver {
* @return people in a map of name => pair(dashboard id, user id)
*/
@SuppressWarnings("nls")
private TreeMap<String, Pair<Long, String>> loadResponsiblePeople(
StoreObject[] dashboards) {
TreeMap<String, Pair<Long, String>> results = new TreeMap<String, Pair<Long, String>>();
private TreeSet<ProducteevUser> loadResponsiblePeople(StoreObject[] dashboards) {
TreeSet<ProducteevUser> users = new TreeSet<ProducteevUser>();
for(StoreObject dashboard : dashboards) {
String users = dashboard.getValue(ProducteevDashboard.USERS);
String[] entries = users.split(";");
for(String entry : entries) {
String[] data = entry.split(",");
if(data.length != 2)
continue;
results.put(data[1], new Pair<Long, String>(
dashboard.getValue(ProducteevDashboard.REMOTE_ID), data[0])); // name, id
}
ProducteevDashboard elDashboard = new ProducteevDashboard(dashboard);
users.addAll(elDashboard.getUsers());
}
return results;
return users;
}
}

@ -206,31 +206,37 @@ public final class ProducteevDataService {
return cursor;
}
// --- dashboard methods
private StoreObject[] dashboards = null;
private void readDashboards() {
if (dashboards == null) {
dashboards = readStoreObjects(ProducteevDashboard.TYPE);
}
}
/**
* Reads dashboards
* Reads store objects.
*/
private void readDashboards() {
if(dashboards != null)
return;
public StoreObject[] readStoreObjects(String type) {
StoreObject[] ret;
TodorooCursor<StoreObject> cursor = storeObjectDao.query(Query.select(StoreObject.PROPERTIES).
where(StoreObjectCriteria.byType(ProducteevDashboard.TYPE)));
try {
dashboards = new StoreObject[cursor.getCount()];
for(int i = 0; i < dashboards.length; i++) {
ret = new StoreObject[cursor.getCount()];
for(int i = 0; i < ret.length; i++) {
cursor.moveToNext();
StoreObject dashboard = new StoreObject(cursor);
dashboards[i] = dashboard;
ret[i] = dashboard;
}
} finally {
cursor.close();
}
return ret;
}
// --- dashboard methods
private StoreObject[] dashboards = null;
/**
* @return a list of dashboards
*/

@ -8,7 +8,7 @@ import org.json.JSONObject;
* @author Arne Jans <arne.jans@gmail.com>
*/
@SuppressWarnings("nls")
public class ProducteevUser {
public class ProducteevUser implements Comparable<ProducteevUser> {
private final long id;
@ -82,4 +82,34 @@ public class ProducteevUser {
displayString += email;
return displayString;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ProducteevUser that = (ProducteevUser) o;
if (id != that.id) return false;
if (email != null ? !email.equals(that.email) : that.email != null) return false;
if (firstname != null ? !firstname.equals(that.firstname) : that.firstname != null) return false;
if (lastname != null ? !lastname.equals(that.lastname) : that.lastname != null) return false;
return true;
}
@Override
public int hashCode() {
int result = (int) (id ^ (id >>> 32));
result = 31 * result + (email != null ? email.hashCode() : 0);
result = 31 * result + (firstname != null ? firstname.hashCode() : 0);
result = 31 * result + (lastname != null ? lastname.hashCode() : 0);
return result;
}
@Override
public int compareTo(ProducteevUser o) {
int ret = toString().compareTo(o.toString());
return ret == 0 ? (new Long(id).compareTo(o.id)) : ret;
}
}

@ -0,0 +1,80 @@
package com.todoroo.astrid.tags;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.drawable.BitmapDrawable;
import com.timsu.astrid.R;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.CustomFilterCriterion;
import com.todoroo.astrid.api.MultipleSelectCriterion;
import com.todoroo.astrid.api.TextInputCriterion;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
public class TagCustomFilterCriteriaExposer extends BroadcastReceiver {
private static final String IDENTIFIER_TAG_IS = "tag_is"; //$NON-NLS-1$
private static final String IDENTIFIER_TAG_CONTAINS = "tag_contains"; //$NON-NLS-1$
@Override
public void onReceive(Context context, Intent intent) {
Resources r = context.getResources();
CustomFilterCriterion[] ret = new CustomFilterCriterion[2];
int j = 0;
// built in criteria: tags
{
TagService.Tag[] tags = TagService.getInstance().getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE,
TaskDao.TaskCriteria.activeAndVisible());
String[] tagNames = new String[tags.length];
for(int i = 0; i < tags.length; i++)
tagNames[i] = tags[i].tag;
ContentValues values = new ContentValues();
values.put(Metadata.KEY.name, TagService.KEY);
values.put(TagService.TAG.name, "?");
CustomFilterCriterion criterion = new MultipleSelectCriterion(
IDENTIFIER_TAG_IS,
context.getString(R.string.CFC_tag_text),
Query.select(Metadata.TASK).from(Metadata.TABLE).join(Join.inner(
Task.TABLE, Metadata.TASK.eq(Task.ID))).where(Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
MetadataDao.MetadataCriteria.withKey(TagService.KEY),
TagService.TAG.eq("?"))).toString(),
values, tagNames, tagNames,
((BitmapDrawable)r.getDrawable(R.drawable.filter_tags1)).getBitmap(),
context.getString(R.string.CFC_tag_name));
ret[j++] = criterion;
}
// built in criteria: tags containing X
{
CustomFilterCriterion criterion = new TextInputCriterion(
IDENTIFIER_TAG_CONTAINS,
context.getString(R.string.CFC_tag_contains_text),
Query.select(Metadata.TASK).from(Metadata.TABLE).join(Join.inner(
Task.TABLE, Metadata.TASK.eq(Task.ID))).where(Criterion.and(
TaskDao.TaskCriteria.activeAndVisible(),
MetadataDao.MetadataCriteria.withKey(TagService.KEY),
TagService.TAG.like("%?%"))).toString(),
null, context.getString(R.string.CFC_tag_contains_name), "",
((BitmapDrawable)r.getDrawable(R.drawable.filter_tags2)).getBitmap(),
context.getString(R.string.CFC_tag_contains_name));
ret[j++] = criterion;
}
// transmit filter list
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_CUSTOM_FILTER_CRITERIA);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, ret);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, TagsPlugin.IDENTIFIER);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
}

@ -133,6 +133,7 @@ public class TagFilterExposer extends BroadcastReceiver {
// transmit filter list
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, list);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, TagsPlugin.IDENTIFIER);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}

@ -123,5 +123,13 @@
<!-- Spinner-item for default dashboard on taskeditactivity -->
<string name="producteev_TEA_dashboard_default">&lt;Default&gt;</string>
<string name="CFC_producteev_in_workspace_text">In workspace: ?</string>
<string name="CFC_producteev_in_workspace_name">In workspace...</string>
<string name="CFC_producteev_assigned_to_text">Assigned to: ?</string>
<string name="CFC_producteev_assigned_to_name">Assigned to...</string>
</resources>
Loading…
Cancel
Save