Fot filters working, with icons even. sweet action.

pull/14/head
Tim Su 14 years ago
parent c43ff1aea6
commit fffc9f4a46

@ -1,192 +1,203 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.timsu.astrid"
android:versionName="2.14.4" android:versionCode="135">
package="com.timsu.astrid"
android:versionName="2.14.4" android:versionCode="135">
<!-- ============================ Metadata ============================ -->
<!-- ================================================== Used Permissions = -->
<uses-permission android:name="android.permission.VIBRATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- for notifications -->
<uses-permission android:name="android.permission.VIBRATE"/>
<!-- for synchronization -->
<uses-permission android:name="android.permission.INTERNET"/>
<!-- for google calendar integration -->
<uses-permission android:name="android.permission.WRITE_CALENDAR" />
<uses-permission android:name="android.permission.READ_CALENDAR" />
<!-- for creating shortcuts -->
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<!-- for backup -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- for analytics -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- ============================================== Exported Permissions = -->
<!-- for tasks provider -->
<permission android:name="com.timsu.astrid.permission.READ_TASKS"
android:permissionGroup="android.permission-group.MESSAGES"
android:protectionLevel="normal"
android:label="@string/read_tasks_permission"
android:description="@string/read_tasks_permission"/>
<uses-permission android:name="com.timsu.astrid.permission.READ_TASKS"/>
<!-- for reading data from plugins or astrid -->
<permission android:name="com.todoroo.astrid.READ"
android:description="@string/read_permission_desc"
android:protectionLevel="normal"
android:label="@string/read_permission_label" />
<uses-permission android:name="com.todoroo.astrid.READ" />
<!-- for writing data to plugins or astrid -->
<permission android:name="com.todoroo.astrid.WRITE"
android:description="@string/write_permission_desc"
android:protectionLevel="normal"
android:label="@string/write_permission_label" />
<uses-permission android:name="com.todoroo.astrid.WRITE" />
<!-- ========================================================== Metadata = -->
<uses-sdk android:minSdkVersion="3"
android:targetSdkVersion="4" />
<supports-screens />
<application android:icon="@drawable/icon" android:label="@string/app_name">
<!-- For Flurry analytics -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- ====================================================== Activities = -->
<!-- Activity that redirects to the appropriate home -->
<activity android:name="com.todoroo.astrid.activity.HomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Activity that displays task list -->
<activity android:name="com.todoroo.astrid.activity.TaskListActivity"
android:theme="@style/Theme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Activity that displays filter list -->
<activity android:name="com.todoroo.astrid.activity.FilterListActivity"
android:theme="@style/Theme">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/filter_list_searchable" />
</activity>
<!-- Activity that redirects to a task list, invoked by notifications -->
<activity android:name=".activities.TaskListNotify"
android:launchMode="singleTop" />
<!-- Activity that creates or edits tasks -->
<activity android:name=".activities.TaskEdit"
android:icon="@drawable/icon_add"
android:label="@string/taskEdit_label">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/task" />
</intent-filter>
</activity>
<!-- Activity that lets users log in to sync providers -->
<activity android:name=".activities.SyncLoginActivity"/>
<!-- Activity that lets users edit app preferences -->
<activity android:name=".activities.EditPreferences"/>
<!-- Activity that lets users edit synchronization preferences -->
<activity android:name=".activities.SyncPreferences"/>
<!-- Activity that Locale displays to edit tag notification settings -->
<activity android:name=".activities.LocaleEditAlerts"
android:label="@string/locale_edit_alerts_title"
android:icon="@drawable/icon_32"
android:exported="true" >
<intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" />
</intent-filter>
</activity>
<!-- ======================================================= Receivers = -->
<receiver android:name=".utilities.Notifications" />
<!-- For Tasks provider -->
<permission android:name="com.timsu.astrid.permission.READ_TASKS"
android:permissionGroup="android.permission-group.MESSAGES"
android:protectionLevel="normal"
android:label="@string/read_tasks_permission"
android:description="@string/read_tasks_permission"/>
<uses-permission android:name="com.timsu.astrid.permission.READ_TASKS"/>
<uses-sdk android:minSdkVersion="3"
android:targetSdkVersion="4" />
<supports-screens />
<application android:icon="@drawable/icon" android:label="@string/app_name" android:debuggable="false">
<receiver android:name=".utilities.LocaleReceiver">
<intent-filter>
<action android:name="com.timsu.astrid.action.LOCALE_ALERT" />
</intent-filter>
</receiver>
<!-- ========================= Activities ========================== -->
<!-- primary activity: agenda -->
<activity android:name="com.todoroo.astrid.activity.HomeActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver android:name=".utilities.StartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".appwidget.AstridAppWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget_provider_info" />
</receiver>
<!-- ======================================================== Services = -->
<service android:name=".appwidget.AstridAppWidgetProvider$UpdateService"></service>
<service android:name=".sync.SynchronizationService" />
<service android:name=".utilities.BackupService"/>
<!-- ======================================================= Providers = -->
<provider android:name=".provider.TasksProvider"
android:authorities="com.timsu.astrid.tasksprovider"
android:multiprocess="true"
android:grantUriPermissions="true"
android:readPermission="com.timsu.astrid.permission.READ_TASKS"/>
<!-- ========================================================= Plugins = -->
<activity android:name="com.todoroo.astrid.activity.TaskListActivity"
android:theme="@style/Theme">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="com.todoroo.astrid.activity.FilterListActivity"
android:theme="@style/Theme">
<intent-filter>
<action android:name="android.intent.action.SEARCH" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<meta-data android:name="android.app.searchable"
android:resource="@xml/filter_list_searchable" />
</activity>
<!-- ======================== Activities ========================= -->
<!-- Activity that displays the task list -->
<activity android:name=".activities.TaskList">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!-- Activity that redirects to a task list, invoked by notifications -->
<activity android:name=".activities.TaskListNotify"
android:launchMode="singleTop" />
<!-- Activity that creates or edits tasks -->
<activity android:name=".activities.TaskEdit"
android:icon="@drawable/icon_add"
android:label="@string/taskEdit_label">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="vnd.android.cursor.item/task" />
</intent-filter>
</activity>
<!-- Activity that views tags -->
<activity android:name=".activities.TagView">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<!-- Activity that lets users log in to sync providers -->
<activity android:name=".activities.SyncLoginActivity"/>
<!-- Activity that lets users edit app preferences -->
<activity android:name=".activities.EditPreferences"/>
<!-- Activity that lets users edit synchronization preferences -->
<activity android:name=".activities.SyncPreferences"/>
<!-- activity that Locale displays to edit tag notification settings -->
<activity
android:name=".activities.LocaleEditAlerts"
android:label="@string/locale_edit_alerts_title"
android:icon="@drawable/icon_32"
android:exported="true" >
<intent-filter>
<action android:name="com.twofortyfouram.locale.intent.action.EDIT_SETTING" />
</intent-filter>
</activity>
<!-- ======================== Receivers ========================= -->
<receiver android:name=".utilities.Notifications" />
<receiver android:name=".utilities.LocaleReceiver">
<intent-filter>
<action android:name="com.timsu.astrid.action.LOCALE_ALERT" />
</intent-filter>
</receiver>
<receiver android:name=".utilities.StartupReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".appwidget.AstridAppWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@xml/widget_provider_info" />
</receiver>
<!-- ======================== Services ========================== -->
<service android:name=".appwidget.AstridAppWidgetProvider$UpdateService"></service>
<service android:name=".sync.SynchronizationService" />
<service android:name=".utilities.BackupService"/>
<!-- ======================== Providers ========================== -->
<provider
android:name=".provider.TasksProvider"
android:authorities="com.timsu.astrid.tasksprovider"
android:multiprocess="true"
android:grantUriPermissions="true"
android:readPermission="com.timsu.astrid.permission.READ_TASKS"
/>
<!-- ====================== Internal Plug-ins ======================= -->
<!-- ====================== Filters ======================= -->
<receiver android:name="com.todoroo.astrid.filters.CorePlugin">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_PLUGINS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.filters.CoreFilterExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_FILTERS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.filters.FilterExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_FILTERS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.filters.ExtendedPlugin">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_PLUGINS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.filters.ExtendedFilterExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_FILTERS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- ====================== Tags ======================= -->
<receiver android:name="com.todoroo.astrid.tags.FilterExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_FILTERS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name=".tags.DetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.tags.TagsPlugin">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_PLUGINS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.tags.FilterExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_FILTERS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.tags.DetailExposer">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_DETAILS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
</application>
</application>
</manifest>

@ -20,6 +20,7 @@ import com.todoroo.andlib.data.Property;
public final class Query {
private SqlTable table;
private String queryTemplate = null;
private final ArrayList<Criterion> criterions = new ArrayList<Criterion>();
private final ArrayList<Field> fields = new ArrayList<Field>();
private final ArrayList<Join> joins = new ArrayList<Join>();
@ -80,10 +81,19 @@ public final class Query {
StringBuilder sql = new StringBuilder();
visitSelectClause(sql);
visitFromClause(sql);
visitJoinClause(sql);
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
if(queryTemplate == null) {
visitJoinClause(sql);
visitWhereClause(sql);
visitGroupByClause(sql);
visitOrderByClause(sql);
} else {
if(joins.size() > 0 || groupBies.size() > 0 || orders.size() > 0 ||
havings.size() > 0)
throw new IllegalStateException("Can't have extras AND query template"); //$NON-NLS-1$
sql.append(queryTemplate);
}
return sql.toString();
}
@ -169,4 +179,14 @@ public final class Query {
public Property<?>[] getFields() {
return fields.toArray(new Property<?>[fields.size()]);
}
/**
* Add the SQL query template (comes after the "from")
* @param sqlQuery
* @return
*/
public Query withQueryTemplate(String template) {
queryTemplate = template;
return this;
}
}

@ -38,8 +38,8 @@ public class Alarm extends AbstractModel {
public static final LongProperty TASK = new LongProperty(
TABLE, "task");
/** Alarm Time (seconds since epoch) */
public static final IntegerProperty TIME = new IntegerProperty(
/** Alarm Time */
public static final LongProperty TIME = new LongProperty(
TABLE, "time");
/** Alarm Type (see constants) */

@ -7,6 +7,7 @@ import android.content.BroadcastReceiver;
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;
@ -29,25 +30,18 @@ import com.todoroo.astrid.model.Task;
*/
public final class CoreFilterExposer extends BroadcastReceiver {
@SuppressWarnings("nls")
@Override
public void onReceive(Context context, Intent intent) {
Resources r = context.getResources();
// build filters
Filter inbox = new Filter(CorePlugin.pluginIdentifier, r.getString(R.string.BFE_Inbox),
r.getString(R.string.BFE_Inbox),
new QueryTemplate().where(Criterion.and(TaskCriteria.isActive(),
TaskCriteria.isVisible(DateUtilities.now()))).orderBy(
Order.asc(Functions.caseStatement(Task.DUE_DATE.eq(0),
String.format("(%d + 1000 * %s)", DateUtilities.now(), Task.IMPORTANCE),
String.format("(%s + 1000 * %s)", Task.DUE_DATE, Task.IMPORTANCE)))),
null);
Filter inbox = buildInboxFilter(r);
Filter all = new Filter(CorePlugin.pluginIdentifier, r.getString(R.string.BFE_All),
r.getString(R.string.BFE_All),
new QueryTemplate().orderBy(Order.desc(Task.MODIFICATION_DATE)),
null);
all.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_all)).getBitmap();
// transmit filter list
FilterListItem[] list = new FilterListItem[2];
@ -58,4 +52,22 @@ public final class CoreFilterExposer extends BroadcastReceiver {
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
/**
* Build inbox filter
* @return
*/
@SuppressWarnings("nls")
public static Filter buildInboxFilter(Resources r) {
Filter inbox = new Filter(CorePlugin.pluginIdentifier, r.getString(R.string.BFE_Inbox),
r.getString(R.string.BFE_Inbox),
new QueryTemplate().where(Criterion.and(TaskCriteria.isActive(),
TaskCriteria.isVisible(DateUtilities.now()))).orderBy(
Order.asc(Functions.caseStatement(Task.DUE_DATE.eq(0),
String.format("(%d + 1000 * %s)", DateUtilities.now(), Task.IMPORTANCE),
String.format("(%s + 1000 * %s)", Task.DUE_DATE, Task.IMPORTANCE)))),
null);
inbox.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_inbox)).getBitmap();
return inbox;
}
}

@ -7,7 +7,6 @@ import android.content.Intent;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Plugin;
@SuppressWarnings("nls")
public class CorePlugin extends BroadcastReceiver {
static final String pluginIdentifier = "core";

@ -7,7 +7,6 @@ import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Order;
@ -16,6 +15,7 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.FilterListActivity;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterListHeader;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.model.Task;
@ -28,31 +28,43 @@ import com.todoroo.astrid.model.Task;
*/
public final class ExtendedFilterExposer extends BroadcastReceiver {
@SuppressWarnings("nls")
@Override
public void onReceive(Context context, Intent intent) {
Resources r = context.getResources();
// build filters
FilterListHeader header = new FilterListHeader(ExtendedPlugin.pluginIdentifier,
"Extended");
Filter alphabetical = new Filter(ExtendedPlugin.pluginIdentifier,
"Inbox (sorted by name)",
"Inbox (sorted by name)",
new QueryTemplate().where(Criterion.and(TaskCriteria.isActive(),
TaskCriteria.isVisible(DateUtilities.now()))).
orderBy(Order.asc(Task.TITLE)),
null);
ContentValues hiddenValues = new ContentValues();
hiddenValues.put(Task.HIDE_UNTIL, DateUtilities.now() + DateUtilities.ONE_DAY);
Filter hidden = new Filter(ExtendedPlugin.pluginIdentifier, "Hidden Tasks",
hiddenValues.put(Task.HIDE_UNTIL.name, DateUtilities.now() + DateUtilities.ONE_DAY);
Filter hidden = new Filter(ExtendedPlugin.pluginIdentifier,
"Hidden Tasks",
"Hidden Tasks",
new QueryTemplate().where(Criterion.and(TaskCriteria.isActive(),
Criterion.not(TaskCriteria.isVisible(DateUtilities.now())))).
orderBy(Order.asc(Task.HIDE_UNTIL)),
hiddenValues);
Filter alphabetical = new Filter(ExtendedPlugin.pluginIdentifier,
"Inbox (sorted by name)",
"Inbox (sorted by name)",
new QueryTemplate().orderBy(Order.asc(Task.TITLE)),
Filter deleted = new Filter(ExtendedPlugin.pluginIdentifier,
"Deleted Tasks",
"Deleted Tasks",
new QueryTemplate().where(TaskCriteria.isDeleted()).
orderBy(Order.desc(Task.DELETION_DATE)),
null);
// transmit filter list
FilterListItem[] list = new FilterListItem[2];
list[0] = inbox;
list[1] = all;
FilterListItem[] list = new FilterListItem[4];
list[0] = header;
list[1] = alphabetical;
list[2] = hidden;
list[3] = deleted;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ITEMS, list);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);

@ -7,7 +7,6 @@ import android.content.Intent;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Plugin;
@SuppressWarnings("nls")
public class ExtendedPlugin extends BroadcastReceiver {
static final String pluginIdentifier = "extended";

@ -0,0 +1,50 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.tags;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.timsu.astrid.R;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.TaskDetail;
/**
* Exposes {@link TaskDetail} for tags, i.e. "Tags: frogs, animals"
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class DetailExposer extends BroadcastReceiver {
private static TagService tagService = null;
@Override
public void onReceive(Context context, Intent intent) {
// get tags associated with this task
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, -1);
if(taskId == -1)
return;
if(tagService == null)
tagService = new TagService(context);
String tagList = tagService.getTagsAsString(taskId);
if(tagList.length() == 0)
return;
TaskDetail taskDetail = new TaskDetail(TagsPlugin.IDENTIFIER,
context.getString(R.string.tag_TLA_detail, tagList));
// transmit
TaskDetail[] details = new TaskDetail[1];
details[0] = taskDetail;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_DETAILS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ITEMS, details);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, taskId);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
}

@ -4,16 +4,18 @@
package com.todoroo.astrid.tags;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import com.todoroo.astrid.R;
import com.timsu.astrid.R;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterCategory;
import com.todoroo.astrid.api.FilterListHeader;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.tags.DataService.Tag;
import com.todoroo.astrid.tags.TagService.Tag;
/**
* Exposes filters based on tags
@ -23,15 +25,21 @@ import com.todoroo.astrid.tags.DataService.Tag;
*/
public class FilterExposer extends BroadcastReceiver {
private TagService tagService;
@SuppressWarnings("nls")
private Filter filterFromTag(Context context, Tag tag, DataService tagService) {
private Filter filterFromTag(Context context, Tag tag) {
String listTitle = context.getString(R.string.tag_FEx_tag_w_size).
replace("$T", tag.tag).replace("$C", Integer.toString(tag.count));
String title = context.getString(R.string.tag_FEx_name, tag.tag);
Filter filter = new Filter(listTitle, title,
tagService.getQuery(tag.tag),
tagService.getNewTaskSql(tag.tag));
QueryTemplate tagTemplate = tag.queryTemplate();
ContentValues contentValues = new ContentValues();
contentValues.put(TagService.KEY, tag.tag);
Filter filter = new Filter(TagsPlugin.IDENTIFIER,
listTitle, title,
tagTemplate,
contentValues);
// filters[0].contextMenuLabels = new String[] {
// "Rename Tag",
@ -47,26 +55,28 @@ public class FilterExposer extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
DataService tagService = new DataService(context);
Tag[] tagsByAlpha = tagService.getGroupedTags(DataService.GROUPED_TAGS_BY_ALPHA);
tagService = new TagService(context);
Tag[] tagsByAlpha = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_ALPHA);
// If user does not have any tags, don't show this section at all
if(tagsByAlpha.length == 0)
return;
Tag[] tagsBySize = tagService.getGroupedTags(DataService.GROUPED_TAGS_BY_SIZE);
Tag[] tagsBySize = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE);
Filter[] filtersByAlpha = new Filter[tagsByAlpha.length];
for(int i = 0; i < tagsByAlpha.length; i++)
filtersByAlpha[i] = filterFromTag(context, tagsByAlpha[i], tagService);
filtersByAlpha[i] = filterFromTag(context, tagsByAlpha[i]);
Filter[] filtersBySize = new Filter[tagsBySize.length];
for(int i = 0; i < tagsBySize.length; i++)
filtersBySize[i] = filterFromTag(context, tagsBySize[i], tagService);
filtersBySize[i] = filterFromTag(context, tagsBySize[i]);
FilterListHeader tagsHeader = new FilterListHeader(context.getString(R.string.tag_FEx_header));
FilterCategory tagsCategoryBySize = new FilterCategory(
FilterListHeader tagsHeader = new FilterListHeader(TagsPlugin.IDENTIFIER,
context.getString(R.string.tag_FEx_header));
FilterCategory tagsCategoryBySize = new FilterCategory(TagsPlugin.IDENTIFIER,
context.getString(R.string.tag_FEx_by_size), filtersBySize);
FilterCategory tagsCategoryByAlpha = new FilterCategory(context.getString(R.string.tag_FEx_alpha), filtersByAlpha);
FilterCategory tagsCategoryByAlpha = new FilterCategory(TagsPlugin.IDENTIFIER,
context.getString(R.string.tag_FEx_alpha), filtersByAlpha);
// transmit filter list
FilterListItem[] list = new FilterListItem[3];

@ -4,7 +4,6 @@ import java.util.ArrayList;
import android.content.Context;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.data.Property.CountProperty;
import com.todoroo.andlib.service.Autowired;
@ -13,6 +12,7 @@ import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.model.Metadata;
@ -57,7 +57,7 @@ public class TagService {
* @author Tim Su <tim@todoroo.com>
*
*/
public class Tag {
public final class Tag {
public String tag;
int count;
@ -65,6 +65,18 @@ public class TagService {
public String toString() {
return tag;
}
/**
* Return SQL selector query for getting tasks with a given tag
*
* @param tag
* @return
*/
public QueryTemplate queryTemplate() {
return new QueryTemplate().join(Join.inner(Metadata.TABLE,
Task.ID.eq(Metadata.TASK))).where(Criterion.and(
MetadataCriteria.withKey(KEY), Metadata.VALUE.eq(tag)));
}
}
/**
@ -123,18 +135,6 @@ public class TagService {
return tagBuilder.toString();
}
/**
* Return SQL selector query for getting tasks with a given tag
*
* @param tag
* @return
*/
public Query tasksWithTag(String tag, Property<?>... properties) {
return Query.select(properties).join(Join.inner(Metadata.TABLE,
Task.ID.eq(Metadata.TASK))).where(Criterion.and(
MetadataCriteria.withKey(KEY), Metadata.VALUE.eq(tag)));
}
/**
* Save the given array of tags into the database
* @param taskId

@ -0,0 +1,24 @@
package com.todoroo.astrid.tags;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Plugin;
public class TagsPlugin extends BroadcastReceiver {
static final String IDENTIFIER = "tags";
@Override
public void onReceive(Context context, Intent intent) {
Plugin plugin = new Plugin(IDENTIFIER, "Tags", "Todoroo",
"Provides tagging support for tasks.");
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_PLUGINS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_PLUGIN, plugin);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 853 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 806 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 586 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 701 B

@ -55,7 +55,7 @@
<!-- ======================== FilterListAdapter ======================== -->
<style name="TextAppearance.FLA_Filter" parent="TextAppearance.TAd_ItemTitle">
<item name="android:textSize">22sp</item>
<item name="android:textSize">20sp</item>
<item name="android:paddingTop">5px</item>
<item name="android:paddingBottom">5px</item>
<item name="android:paddingLeft">10px</item>

@ -277,9 +277,7 @@ public class FilterListActivity extends ExpandableListActivity {
menuItem = menu.add(0, CONTEXT_MENU_SHORTCUT, 0, R.string.FLA_context_shortcut);
Intent shortcutIntent = new Intent(this, TaskListActivity.class);
shortcutIntent.setAction(Intent.ACTION_VIEW);
shortcutIntent.putExtra(TaskListActivity.TOKEN_SHORTCUT_TITLE, filter.title);
shortcutIntent.putExtra(TaskListActivity.TOKEN_SHORTCUT_SQL, filter.sqlQuery);
shortcutIntent.putExtra(TaskListActivity.TOKEN_SHORTCUT_NEW_TASK_SQL, filter.valuesForNewTasks);
shortcutIntent.putExtra(TaskListActivity.TOKEN_FILTER, filter);
menuItem.setIntent(shortcutIntent);
}

@ -82,9 +82,6 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
// --- constants
public static final String TOKEN_FILTER = "filter"; //$NON-NLS-1$
public static final String TOKEN_SHORTCUT_SQL = "query"; //$NON-NLS-1$
public static final String TOKEN_SHORTCUT_TITLE = "title"; //$NON-NLS-1$
public static final String TOKEN_SHORTCUT_NEW_TASK_SQL = "newsql"; //$NON-NLS-1$
// --- instance variables
@ -130,11 +127,6 @@ public class TaskListActivity extends ListActivity implements OnScrollListener {
Bundle extras = getIntent().getExtras();
if(extras.containsKey(TOKEN_FILTER)) {
filter = extras.getParcelable(TOKEN_FILTER);
} else if(extras.containsKey(TOKEN_SHORTCUT_SQL)) {
filter = new Filter();
filter.sqlQuery = extras.getString(TOKEN_SHORTCUT_SQL);
filter.title = extras.getString(TOKEN_SHORTCUT_TITLE);
filter.valuesForNewTasks = extras.getString(TOKEN_SHORTCUT_NEW_TASK_SQL);
} else {
filter = CoreFilterExposer.buildInboxFilter(getResources());
}

@ -14,6 +14,7 @@ import android.widget.AbsListView;
import android.widget.BaseExpandableListAdapter;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.timsu.astrid.R;
@ -132,42 +133,72 @@ public class FilterAdapter extends BaseExpandableListAdapter {
TextView textView = new TextView(activity);
textView.setGravity(Gravity.CENTER_VERTICAL);
textView.setLayoutParams(llp);
textView.setPadding(40, 0, 0, 0);
textView.setText(filter.listingTitle);
textView.setTextAppearance(activity, R.style.TextAppearance_FLA_Category);
layout.addView(textView);
View view = augmentView(textView, filter);
view.setPadding(40, 2, 0, 2);
view.setLayoutParams(llp);
layout.addView(view);
return layout;
}
public TextView getFilterView(Filter filter, boolean isChild) {
/**
* Decorate textview and add an image if the filter requests it
* @param textView
* @param filter
* @return final view ready to be added
*/
private View augmentView(TextView textView, FilterListItem filter) {
if(filter.listingIcon != null) {
LinearLayout layout = new LinearLayout(activity);
layout.setGravity(textView.getGravity());
layout.setOrientation(LinearLayout.HORIZONTAL);
ImageView icon = new ImageView(activity);
icon.setImageBitmap(filter.listingIcon);
icon.setPadding(0, 0, 20, 0);
layout.addView(icon);
layout.addView(textView);
return layout;
}
return textView;
}
public View getFilterView(Filter filter, boolean isChild) {
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, 64);
TextView textView = new TextView(activity);
textView.setBackgroundDrawable(null);
textView.setLayoutParams(lp);
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
textView.setPadding(isChild ? 40 : 10, 0, 0, 0);
textView.setText(filter.listingTitle);
textView.setTextAppearance(activity, R.style.TextAppearance_FLA_Filter);
return textView;
View view = augmentView(textView, filter);
view.setBackgroundDrawable(null);
view.setLayoutParams(lp);
view.setPadding(isChild ? 40 : 10, 0, 0, 0);
return view;
}
public TextView getHeaderView(FilterListHeader header, boolean isChild) {
public View getHeaderView(FilterListHeader header, boolean isChild) {
AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
ViewGroup.LayoutParams.FILL_PARENT, 40);
TextView textView = new TextView(activity);
textView.setLayoutParams(lp);
textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
textView.setPadding(isChild ? 40 : 10, 0, 0, 0);
textView.setTextAppearance(activity, R.style.TextAppearance_FLA_Header);
textView.setBackgroundResource(R.drawable.edit_titlebar);
textView.setText(header.listingTitle);
return textView;
View view = augmentView(textView, header);
view.setBackgroundResource(R.drawable.edit_titlebar);
view.setLayoutParams(lp);
view.setPadding(isChild ? 40 : 10, 0, 0, 0);
return view;
}
}

@ -201,7 +201,7 @@ public class TaskAdapter extends CursorAdapter {
// name
final TextView nameView = viewHolder.nameView; {
String nameValue = task.getValue(Task.TITLE);
int hiddenUntil = task.getValue(Task.HIDE_UNTIL);
long hiddenUntil = task.getValue(Task.HIDE_UNTIL);
if(hiddenUntil > DateUtilities.now())
nameValue = r.getString(R.string.TAd_hiddenFormat, nameValue);
nameView.setText(nameValue);
@ -219,8 +219,8 @@ public class TaskAdapter extends CursorAdapter {
// due date / completion date
final TextView dueDateView = viewHolder.dueDate; {
if(!task.isCompleted() && task.hasDueDate()) {
int dueDate = task.getValue(Task.DUE_DATE);
int secondsLeft = dueDate - DateUtilities.now();
long dueDate = task.getValue(Task.DUE_DATE);
long secondsLeft = dueDate - DateUtilities.now();
if(secondsLeft > 0) {
dueDateView.setTextAppearance(activity, R.style.TextAppearance_TAd_ItemDueDate);
} else {
@ -326,7 +326,7 @@ public class TaskAdapter extends CursorAdapter {
return textView;
}
private View.OnClickListener completeBoxListener = new View.OnClickListener() {
private final View.OnClickListener completeBoxListener = new View.OnClickListener() {
public void onClick(View v) {
View container = (View) v.getParent();
Task task = ((ViewHolder)container.getTag()).task;

@ -52,6 +52,11 @@ public class TaskDao extends GenericDao<Task> {
return Task.ID.eq(id);
}
/** Return tasks that were deleted */
public static Criterion isDeleted() {
return Task.DELETION_DATE.neq(0);
}
/** Return tasks that have not yet been completed */
public static Criterion isActive() {
return Criterion.and(Task.COMPLETION_DATE.eq(0),

@ -52,7 +52,7 @@ public final class Task extends AbstractModel {
/** Unixtime Task is due, 0 if not set */
public static final LongProperty DUE_DATE = new LongProperty(
TABLE, "dyeDate");
TABLE, "dueDate");
/** Unixtime Task should be hidden until */
public static final LongProperty HIDE_UNTIL = new LongProperty(

@ -13,6 +13,7 @@ import android.util.Log;
import com.timsu.astrid.data.AbstractController;
import com.timsu.astrid.data.alerts.Alert;
import com.timsu.astrid.data.task.AbstractTaskModel;
import com.timsu.astrid.utilities.TasksXmlExporter;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.GenericDao;
import com.todoroo.andlib.data.Property;
@ -90,6 +91,15 @@ public class Astrid2To3UpgradeHelper {
public void upgrade2To3() {
Context context = ContextManager.getContext();
// initiate a backup
try {
TasksXmlExporter exporter = new TasksXmlExporter(true);
exporter.setContext(ContextManager.getContext());
exporter.exportTasks(TasksXmlExporter.getExportDirectory());
} catch (Exception e) {
// unable to create a backup before upgrading :(
}
database.openForWriting();
// --- upgrade tasks table
@ -165,22 +175,7 @@ public class Astrid2To3UpgradeHelper {
@Override
public Void visitInteger(Property<Integer> property, UpgradeVisitorContainer data) {
int value;
// convert long date -> integer
if(property == Task.COMPLETION_DATE ||
property == Task.CREATION_DATE ||
property == Task.DELETION_DATE ||
property == Task.DUE_DATE ||
property == Task.HIDE_UNTIL ||
property == Task.LAST_NOTIFIED ||
property == Task.MODIFICATION_DATE ||
property == Task.PREFERRED_DUE_DATE ||
property == Alarm.TIME)
value = (int) (data.cursor.getLong(data.columnIndex) / 1000L);
else
value = data.cursor.getInt(data.columnIndex);
int value = data.cursor.getInt(data.columnIndex);
data.model.setValue(property, value);
Log.d("upgrade", "wrote " + value + " to -> " + property + " of model id " + data.cursor.getLong(1));
return null;

@ -47,7 +47,7 @@ public class TaskService {
if(completed)
item.setValue(Task.COMPLETION_DATE, DateUtilities.now());
else
item.setValue(Task.COMPLETION_DATE, 0);
item.setValue(Task.COMPLETION_DATE, 0L);
taskDao.save(item, false);
}
@ -94,7 +94,10 @@ public class TaskService {
public TodorooCursor<Task> fetchFiltered(Property<?>[] properties,
Filter filter) {
return taskDao.query(Query.select(properties));
if(filter == null || filter.sqlQuery == null)
return taskDao.query(Query.select(properties));
else
return taskDao.query(Query.select(properties).withQueryTemplate(filter.sqlQuery));
}
}

Loading…
Cancel
Save