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

@ -1,18 +1,19 @@
package com.todoroo.astrid.core; package com.todoroo.astrid.core;
import java.util.ArrayList; import java.util.*;
import java.util.List;
import java.util.Map.Entry; import java.util.Map.Entry;
import android.app.ListActivity; import android.app.ListActivity;
import android.content.ContentValues; import android.content.*;
import android.content.Intent; import android.content.IntentFilter;
import android.content.res.Resources; import android.content.res.Resources;
import android.database.Cursor; import android.database.Cursor;
import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle; import android.os.Bundle;
import android.os.Parcelable;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
import android.util.Log;
import android.view.ContextMenu; import android.view.ContextMenu;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
@ -28,21 +29,12 @@ import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field; import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.activity.TaskListActivity; import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.api.CustomFilterCriterion; import com.todoroo.astrid.api.*;
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.dao.Database; import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria; import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task; 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 * Activity that allows users to build custom filters
@ -52,7 +44,7 @@ import com.todoroo.astrid.tags.TagService.Tag;
*/ */
public class CustomFilterActivity extends ListActivity { 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_IMPORTANCE = "importance"; //$NON-NLS-1$
private static final String IDENTIFIER_DUEDATE = "dueDate"; //$NON-NLS-1$ private static final String IDENTIFIER_DUEDATE = "dueDate"; //$NON-NLS-1$
private static final String IDENTIFIER_UNIVERSE = "active"; //$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 TextView filterName;
private CustomFilterAdapter adapter; private CustomFilterAdapter adapter;
private final ArrayList<CustomFilterCriterion> criteria = private final Map<String,CustomFilterCriterion> criteria = Collections.synchronizedMap(new LinkedHashMap<String,CustomFilterCriterion>());
new ArrayList<CustomFilterCriterion>();
private FilterCriteriaReceiver filterCriteriaReceiver = new FilterCriteriaReceiver();
// --- activity // --- 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") @SuppressWarnings("nls")
private void populateCriteria() { private void populateCriteria() {
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_REQUEST_CUSTOM_FILTER_CRITERIA);
sendOrderedBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
Resources r = getResources(); Resources r = getResources();
// built in criteria: due date // built in criteria: due date
String[] entryValues = new String[] { {
"0", String[] entryValues = new String[] {
PermaSql.VALUE_EOD_YESTERDAY, "0",
PermaSql.VALUE_EOD, PermaSql.VALUE_EOD_YESTERDAY,
PermaSql.VALUE_EOD_TOMORROW, PermaSql.VALUE_EOD,
PermaSql.VALUE_EOD_DAY_AFTER, PermaSql.VALUE_EOD_TOMORROW,
PermaSql.VALUE_EOD_NEXT_WEEK, PermaSql.VALUE_EOD_DAY_AFTER,
PermaSql.VALUE_EOD_NEXT_MONTH, PermaSql.VALUE_EOD_NEXT_WEEK,
}; PermaSql.VALUE_EOD_NEXT_MONTH,
ContentValues values = new ContentValues(); };
values.put(Task.DUE_DATE.name, "?"); ContentValues values = new ContentValues();
CustomFilterCriterion criterion = new MultipleSelectCriterion( values.put(Task.DUE_DATE.name, "?");
IDENTIFIER_DUEDATE, CustomFilterCriterion criterion = new MultipleSelectCriterion(
getString(R.string.CFC_dueBefore_text), IDENTIFIER_DUEDATE,
Query.select(Task.ID).from(Task.TABLE).where( getString(R.string.CFC_dueBefore_text),
Criterion.and( Query.select(Task.ID).from(Task.TABLE).where(
TaskCriteria.activeAndVisible(), Criterion.and(
Criterion.or( TaskCriteria.activeAndVisible(),
Field.field("?").eq(0), Criterion.or(
Task.DUE_DATE.gt(0)), Field.field("?").eq(0),
Task.DUE_DATE.lte("?"))).toString(), Task.DUE_DATE.gt(0)),
values, r.getStringArray(R.array.CFC_dueBefore_entries), Task.DUE_DATE.lte("?"))).toString(),
entryValues, ((BitmapDrawable)r.getDrawable(R.drawable.tango_calendar)).getBitmap(), values, r.getStringArray(R.array.CFC_dueBefore_entries),
getString(R.string.CFC_dueBefore_name)); entryValues, ((BitmapDrawable)r.getDrawable(R.drawable.tango_calendar)).getBitmap(),
criteria.add(criterion); getString(R.string.CFC_dueBefore_name));
criteria.put(IDENTIFIER_DUEDATE, criterion);
}
// built in criteria: importance // built in criteria: importance
entryValues = new String[] { {
Integer.toString(Task.IMPORTANCE_DO_OR_DIE), String[] entryValues = new String[] {
Integer.toString(Task.IMPORTANCE_MUST_DO), Integer.toString(Task.IMPORTANCE_DO_OR_DIE),
Integer.toString(Task.IMPORTANCE_SHOULD_DO), Integer.toString(Task.IMPORTANCE_MUST_DO),
Integer.toString(Task.IMPORTANCE_NONE), Integer.toString(Task.IMPORTANCE_SHOULD_DO),
}; Integer.toString(Task.IMPORTANCE_NONE),
String[] entries = new String[] { };
"!!!!", "!!!", "!!", "!" String[] entries = new String[] {
}; "!!!!", "!!!", "!!", "!"
values = new ContentValues(); };
values.put(Task.IMPORTANCE.name, "?"); ContentValues values = new ContentValues();
criterion = new MultipleSelectCriterion( values.put(Task.IMPORTANCE.name, "?");
IDENTIFIER_IMPORTANCE, CustomFilterCriterion criterion = new MultipleSelectCriterion(
getString(R.string.CFC_importance_text), IDENTIFIER_IMPORTANCE,
Query.select(Task.ID).from(Task.TABLE).where( getString(R.string.CFC_importance_text),
Criterion.and(TaskCriteria.activeAndVisible(), Query.select(Task.ID).from(Task.TABLE).where(
Task.IMPORTANCE.lte("?"))).toString(), Criterion.and(TaskCriteria.activeAndVisible(),
values, entries, Task.IMPORTANCE.lte("?"))).toString(),
entryValues, ((BitmapDrawable)r.getDrawable(R.drawable.tango_warning)).getBitmap(), values, entries,
getString(R.string.CFC_importance_name)); entryValues, ((BitmapDrawable)r.getDrawable(R.drawable.tango_warning)).getBitmap(),
criteria.add(criterion); getString(R.string.CFC_importance_name));
criteria.put(IDENTIFIER_IMPORTANCE, 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);
// built in criteria: title containing X // built in criteria: title containing X
values = new ContentValues(); {
values.put(Task.TITLE.name, "?"); ContentValues values = new ContentValues();
criterion = new TextInputCriterion( values.put(Task.TITLE.name, "?");
IDENTIFIER_TAG, CustomFilterCriterion criterion = new TextInputCriterion(
getString(R.string.CFC_title_contains_text), IDENTIFIER_TITLE,
Query.select(Task.ID).from(Task.TABLE).where( getString(R.string.CFC_title_contains_text),
Criterion.and(TaskCriteria.activeAndVisible(), Query.select(Task.ID).from(Task.TABLE).where(
Task.TITLE.like("%?%"))).toString(), Criterion.and(TaskCriteria.activeAndVisible(),
null, getString(R.string.CFC_title_contains_name), "", Task.TITLE.like("%?%"))).toString(),
((BitmapDrawable)r.getDrawable(R.drawable.tango_alpha)).getBitmap(), null, getString(R.string.CFC_title_contains_name), "",
getString(R.string.CFC_title_contains_name)); ((BitmapDrawable)r.getDrawable(R.drawable.tango_alpha)).getBitmap(),
criteria.add(criterion); 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() { private CriterionInstance getStartingUniverse() {
@ -310,13 +289,23 @@ public class CustomFilterActivity extends ListActivity {
@Override @Override
public void onCreateContextMenu(ContextMenu menu, View v, public void onCreateContextMenu(ContextMenu menu, View v,
ContextMenuInfo menuInfo) { 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; return;
}
for(int i = 0; i < criteria.size(); i++) { int i = 0;
CustomFilterCriterion item = criteria.get(i); for (CustomFilterCriterion item : criteria.values()) {
menu.add(CustomFilterActivity.MENU_GROUP_FILTER, try {
i, 0, item.name); 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(); 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 @Override
public boolean onMenuItemSelected(int featureId, MenuItem item) { public boolean onMenuItemSelected(int featureId, MenuItem item) {
// group filter option // group filter option
if(item.getGroupId() == MENU_GROUP_FILTER) { if(item.getGroupId() == MENU_GROUP_FILTER) {
// give an initial value for the row before adding it // 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(); final CriterionInstance instance = new CriterionInstance();
instance.criterion = criterion; instance.criterion = criterion;
adapter.showOptionsFor(instance, new Runnable() { adapter.showOptionsFor(instance, new Runnable() {
@ -493,4 +491,29 @@ public class CustomFilterActivity extends ListActivity {
return super.onMenuItemSelected(featureId, item); 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; package com.todoroo.astrid.producteev;
import java.util.TreeMap; import java.util.TreeSet;
import java.util.Map.Entry;
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.ContentValues; import android.content.ContentValues;
@ -14,7 +13,6 @@ import android.content.Intent;
import com.timsu.astrid.R; import com.timsu.astrid.R;
import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.QueryTemplate; import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.Pair;
import com.todoroo.astrid.api.AstridApiConstants; import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterCategory; 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.ProducteevDashboard;
import com.todoroo.astrid.producteev.sync.ProducteevDataService; import com.todoroo.astrid.producteev.sync.ProducteevDataService;
import com.todoroo.astrid.producteev.sync.ProducteevTask; import com.todoroo.astrid.producteev.sync.ProducteevTask;
import com.todoroo.astrid.producteev.sync.ProducteevUser;
/** /**
* Exposes filters based on Producteev Dashboards * Exposes filters based on Producteev Dashboards
@ -59,20 +58,19 @@ public class ProducteevFilterExposer extends BroadcastReceiver {
return filter; return filter;
} }
private Filter filterFromUser(Context context, String user, Pair<Long, String> ids) { private Filter filterFromUser(Context context, ProducteevUser user) {
String title = context.getString(R.string.producteev_FEx_responsible_title, user); String title = context.getString(R.string.producteev_FEx_responsible_title, user.toString());
ContentValues values = new ContentValues(); ContentValues values = new ContentValues();
values.put(Metadata.KEY.name, ProducteevTask.METADATA_KEY); 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.ID.name, 0);
values.put(ProducteevTask.CREATOR_ID.name, 0); values.put(ProducteevTask.CREATOR_ID.name, 0);
values.put(ProducteevTask.RESPONSIBLE_ID.name, ids.getRight()); values.put(ProducteevTask.RESPONSIBLE_ID.name, user.getId());
Filter filter = new Filter(user, title, new QueryTemplate().join( Filter filter = new Filter(user.toString(), title, new QueryTemplate().join(
ProducteevDataService.METADATA_JOIN).where(Criterion.and( ProducteevDataService.METADATA_JOIN).where(Criterion.and(
MetadataCriteria.withKey(ProducteevTask.METADATA_KEY), MetadataCriteria.withKey(ProducteevTask.METADATA_KEY),
TaskCriteria.isActive(), TaskCriteria.isActive(),
TaskCriteria.isVisible(), TaskCriteria.isVisible(),
ProducteevTask.RESPONSIBLE_ID.eq(ids.getRight()))), ProducteevTask.RESPONSIBLE_ID.eq(user.getId()))),
values); values);
return filter; return filter;
@ -100,11 +98,11 @@ public class ProducteevFilterExposer extends BroadcastReceiver {
dashboardFilters); dashboardFilters);
// load responsible people // load responsible people
TreeMap<String, Pair<Long, String>> people = loadResponsiblePeople(dashboards); TreeSet<ProducteevUser> people = loadResponsiblePeople(dashboards);
Filter[] peopleFilters = new Filter[people.size()]; Filter[] peopleFilters = new Filter[people.size()];
int index = 0; int index = 0;
for(Entry<String, Pair<Long, String>> person : people.entrySet()) for (ProducteevUser person : people)
peopleFilters[index++] = filterFromUser(context, person.getKey(), person.getValue()); peopleFilters[index++] = filterFromUser(context, person);
FilterCategory producteevUsers = new FilterCategory(context.getString(R.string.producteev_FEx_responsible), FilterCategory producteevUsers = new FilterCategory(context.getString(R.string.producteev_FEx_responsible),
peopleFilters); peopleFilters);
@ -124,22 +122,14 @@ public class ProducteevFilterExposer extends BroadcastReceiver {
* @return people in a map of name => pair(dashboard id, user id) * @return people in a map of name => pair(dashboard id, user id)
*/ */
@SuppressWarnings("nls") @SuppressWarnings("nls")
private TreeMap<String, Pair<Long, String>> loadResponsiblePeople( private TreeSet<ProducteevUser> loadResponsiblePeople(StoreObject[] dashboards) {
StoreObject[] dashboards) { TreeSet<ProducteevUser> users = new TreeSet<ProducteevUser>();
TreeMap<String, Pair<Long, String>> results = new TreeMap<String, Pair<Long, String>>();
for(StoreObject dashboard : dashboards) { for(StoreObject dashboard : dashboards) {
String users = dashboard.getValue(ProducteevDashboard.USERS); ProducteevDashboard elDashboard = new ProducteevDashboard(dashboard);
String[] entries = users.split(";"); users.addAll(elDashboard.getUsers());
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
}
} }
return results; return users;
} }
} }

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

@ -8,7 +8,7 @@ import org.json.JSONObject;
* @author Arne Jans <arne.jans@gmail.com> * @author Arne Jans <arne.jans@gmail.com>
*/ */
@SuppressWarnings("nls") @SuppressWarnings("nls")
public class ProducteevUser { public class ProducteevUser implements Comparable<ProducteevUser> {
private final long id; private final long id;
@ -82,4 +82,34 @@ public class ProducteevUser {
displayString += email; displayString += email;
return displayString; 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 // transmit filter list
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS); Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, list); broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, list);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, TagsPlugin.IDENTIFIER);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ); context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
} }

@ -123,5 +123,13 @@
<!-- Spinner-item for default dashboard on taskeditactivity --> <!-- Spinner-item for default dashboard on taskeditactivity -->
<string name="producteev_TEA_dashboard_default">&lt;Default&gt;</string> <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> </resources>
Loading…
Cancel
Save