New style for filters page to show list pictures and restructure custom filters.

pull/14/head
Tim Su 15 years ago
parent 45e927e834
commit 94fd25098f

@ -583,4 +583,13 @@ public class AndroidUtilities {
return dest;
}
/**
* Capitalize the first character
* @param string
* @return
*/
public static String capitalize(String string) {
return string.substring(0, 1).toUpperCase() + string.substring(1);
}
}

@ -226,6 +226,32 @@
</intent-filter>
</activity>
<!-- tags -->
<receiver android:name="com.todoroo.astrid.tags.TagsPlugin">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_ADDONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.tags.TagFilterExposer">
<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.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" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- custom filters -->
<receiver android:name="com.todoroo.astrid.core.CustomFilterExposer">
<intent-filter android:priority="9000">
@ -359,32 +385,6 @@
</intent-filter>
</receiver>
<!-- tags -->
<receiver android:name="com.todoroo.astrid.tags.TagsPlugin">
<intent-filter>
<action android:name="com.todoroo.astrid.REQUEST_ADDONS" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<receiver android:name="com.todoroo.astrid.tags.TagFilterExposer">
<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.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" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
<!-- repeats -->
<receiver android:name="com.todoroo.astrid.repeats.RepeatsPlugin">
<intent-filter>

@ -5,9 +5,9 @@
<stringAttribute key="ch.zork.quicklaunch.icon" value="14.gif"/>
<intAttribute key="ch.zork.quicklaunch.index" value="0"/>
<stringAttribute key="ch.zork.quicklaunch.mode" value="run"/>
<intAttribute key="com.android.ide.eclipse.adt.action" value="0"/>
<intAttribute key="com.android.ide.eclipse.adt.action" value="1"/>
<stringAttribute key="com.android.ide.eclipse.adt.activity" value="com.todoroo.astrid.activity.FilterListActivity"/>
<stringAttribute key="com.android.ide.eclipse.adt.commandline" value="-scale 0.7 -partition-size 1024"/>
<stringAttribute key="com.android.ide.eclipse.adt.commandline" value="-partition-size 1024"/>
<intAttribute key="com.android.ide.eclipse.adt.delay" value="0"/>
<booleanAttribute key="com.android.ide.eclipse.adt.nobootanim" value="true"/>
<intAttribute key="com.android.ide.eclipse.adt.speed" value="0"/>

@ -3,9 +3,12 @@ package com.todoroo.astrid.actfm.sync;
import org.json.JSONException;
import org.json.JSONObject;
import android.text.TextUtils;
import com.timsu.astrid.R;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.sync.SyncProviderUtilities;
/**
@ -78,6 +81,19 @@ public class ActFmPreferenceService extends SyncProviderUtilities {
}
}
@SuppressWarnings("nls")
public static String updateToString(Update update) {
JSONObject updateUser = ActFmPreferenceService.userFromModel(update);
String description = update.getValue(Update.ACTION);
String message = update.getValue(Update.MESSAGE);
if(update.getValue(Update.ACTION_CODE).equals("task_comment") ||
update.getValue(Update.ACTION_CODE).equals("tag_comment"))
description = message;
else if(!TextUtils.isEmpty(message))
description += " " + message;
return String.format("%s: %s", updateUser.optString("name"), description);
}
@SuppressWarnings("nls")
private synchronized static JSONObject thisUser() {
if(user == null) {

@ -12,7 +12,6 @@ import android.graphics.drawable.BitmapDrawable;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.activity.FilterListActivity;
@ -41,22 +40,10 @@ public final class CoreFilterExposer extends BroadcastReceiver {
// core filters
Filter inbox = buildInboxFilter(r);
SearchFilter searchFilter = new SearchFilter(r.getString(R.string.BFE_Search));
searchFilter.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.tango_search)).getBitmap();
Filter recent = new Filter(r.getString(R.string.BFE_Recent),
r.getString(R.string.BFE_Recent),
new QueryTemplate().where(
TaskCriteria.ownedByMe()).orderBy(
Order.desc(Task.MODIFICATION_DATE)).limit(15),
null);
recent.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.tango_new)).getBitmap();
// transmit filter list
FilterListItem[] list = new FilterListItem[3];
FilterListItem[] list = new FilterListItem[1];
list[0] = inbox;
list[1] = recent;
list[2] = searchFilter;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, list);
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
@ -74,7 +61,7 @@ public final class CoreFilterExposer extends BroadcastReceiver {
Criterion.and(MetadataCriteria.withKey(TagService.KEY),
TagService.TAG.like("x_%", "x"))))))), //$NON-NLS-1$ //$NON-NLS-2$
null);
inbox.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.tango_home)).getBitmap();
inbox.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_inbox)).getBitmap();
return inbox;
}

@ -6,6 +6,7 @@ package com.todoroo.astrid.core;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
@ -16,17 +17,22 @@ import android.os.Bundle;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.activity.FilterListActivity;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterCategory;
import com.todoroo.astrid.api.FilterCategoryWithNewButton;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.api.IntentFilter;
import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.StoreObjectDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.data.Task;
/**
* Exposes Astrid's built in filters to the {@link FilterListActivity}
@ -45,21 +51,16 @@ public final class CustomFilterExposer extends BroadcastReceiver {
PendingIntent customFilterIntent = PendingIntent.getActivity(context, 0,
new Intent(context, CustomFilterActivity.class), 0);
IntentFilter customFilter = new IntentFilter(r.getString(R.string.BFE_Custom),
customFilterIntent);
customFilter.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.gnome_filter)).getBitmap();
Filter[] savedFilters = buildSavedFilters(context);
FilterListItem[] list;
if(savedFilters.length == 0) {
list = new FilterListItem[1];
} else {
list = new FilterListItem[2];
list[1] = new FilterCategory(r.getString(R.string.BFE_Saved), savedFilters);
}
list[0] = customFilter;
Filter[] savedFilters = buildSavedFilters(context, r);
FilterCategoryWithNewButton heading = new FilterCategoryWithNewButton(r.getString(R.string.BFE_Saved), savedFilters);
heading.label = r.getString(R.string.tag_FEx_add_new);
heading.intent = customFilterIntent;
FilterListItem[] list = new FilterListItem[1];
list[0] = heading;
// transmit filter list
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
@ -67,15 +68,36 @@ public final class CustomFilterExposer extends BroadcastReceiver {
context.sendBroadcast(broadcastIntent, AstridApiConstants.PERMISSION_READ);
}
private Filter[] buildSavedFilters(Context context) {
private Filter[] buildSavedFilters(Context context, Resources r) {
StoreObjectDao dao = PluginServices.getStoreObjectDao();
TodorooCursor<StoreObject> cursor = dao.query(Query.select(StoreObject.PROPERTIES).where(
StoreObject.TYPE.eq(SavedFilter.TYPE)).orderBy(Order.asc(SavedFilter.NAME)));
try {
Filter[] list = new Filter[cursor.getCount()];
Filter[] list = new Filter[cursor.getCount() + 2];
// stock filters
String todayTitle = AndroidUtilities.capitalize(r.getString(R.string.today));
ContentValues todayValues = new ContentValues();
todayValues.put(Task.DUE_DATE.name, PermaSql.VALUE_EOD);
list[0] = new Filter(todayTitle,
todayTitle,
new QueryTemplate().where(
Criterion.and(TaskCriteria.activeVisibleMine(),
Task.DUE_DATE.gt(0),
Task.DUE_DATE.lte(PermaSql.VALUE_EOD))),
todayValues);
list[0].listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_calendar)).getBitmap();
list[1] = new Filter(r.getString(R.string.BFE_Recent),
r.getString(R.string.BFE_Recent),
new QueryTemplate().where(
TaskCriteria.ownedByMe()).orderBy(
Order.desc(Task.MODIFICATION_DATE)).limit(15),
null);
list[1].listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_pencil)).getBitmap();
StoreObject savedFilter = new StoreObject();
for(int i = 0; i < list.length; i++) {
for(int i = 2; i < list.length; i++) {
cursor.moveToNext();
savedFilter.readFromCursor(cursor);
list[i] = SavedFilter.load(savedFilter);
@ -85,6 +107,7 @@ public final class CustomFilterExposer extends BroadcastReceiver {
deleteIntent.putExtra(TOKEN_FILTER_NAME, list[i].title);
list[i].contextMenuLabels = new String[] { context.getString(R.string.BFE_Saved_delete) };
list[i].contextMenuIntents = new Intent[] { deleteIntent };
list[i].listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_sliders)).getBitmap();
}
return list;

@ -3,6 +3,7 @@
*/
package com.todoroo.astrid.gtasks;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentValues;
@ -22,8 +23,7 @@ import com.todoroo.andlib.sql.Order;
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.FilterCategoryWithNewButton;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.api.FilterWithCustomIntent;
import com.todoroo.astrid.api.PermaSql;
@ -91,14 +91,14 @@ public class GtasksFilterExposer extends BroadcastReceiver {
for(int i = 0; i < lists.length; i++)
listFilters[i] = filterFromList(context, lists[i]);
FilterListHeader header = new FilterListHeader(context.getString(R.string.gtasks_FEx_header));
FilterCategory listsCategory = new FilterCategory(context.getString(R.string.gtasks_FEx_list),
FilterCategoryWithNewButton listsCategory = new FilterCategoryWithNewButton(context.getString(R.string.gtasks_FEx_header),
listFilters);
listsCategory.label = context.getString(R.string.tag_FEx_add_new);
listsCategory.intent = PendingIntent.getActivity(context, 0, new Intent(context, GtasksListAdder.class), 0);
// transmit filter list
FilterListItem[] list = new FilterListItem[2];
list[0] = header;
list[1] = listsCategory;
FilterListItem[] list = new FilterListItem[1];
list[0] = listsCategory;
Intent broadcastIntent = new Intent(AstridApiConstants.BROADCAST_SEND_FILTERS);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, GtasksPreferenceService.IDENTIFIER);
broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, list);

@ -51,7 +51,7 @@ public class TagCustomFilterCriteriaExposer extends BroadcastReceiver {
MetadataDao.MetadataCriteria.withKey(TagService.KEY),
TagService.TAG.eq("?"))).toString(),
values, tagNames, tagNames,
((BitmapDrawable)r.getDrawable(R.drawable.filter_tags1)).getBitmap(),
((BitmapDrawable)r.getDrawable(R.drawable.gl_list)).getBitmap(),
context.getString(R.string.CFC_tag_name));
ret[j++] = criterion;
}
@ -67,7 +67,7 @@ public class TagCustomFilterCriteriaExposer extends BroadcastReceiver {
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(),
((BitmapDrawable)r.getDrawable(R.drawable.gl_list)).getBitmap(),
context.getString(R.string.CFC_tag_contains_name));
ret[j++] = criterion;
}

@ -4,9 +4,14 @@
package com.todoroo.astrid.tags;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map.Entry;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentValues;
@ -32,16 +37,19 @@ import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.actfm.TagViewActivity;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
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.FilterCategoryWithNewButton;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.api.FilterWithCustomIntent;
import com.todoroo.astrid.api.FilterWithUpdate;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Update;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.tags.TagService.Tag;
@ -70,7 +78,7 @@ public class TagFilterExposer extends BroadcastReceiver {
contentValues.put(Metadata.KEY.name, TagService.KEY);
contentValues.put(TagService.TAG.name, tag.tag);
FilterWithCustomIntent filter = new FilterWithCustomIntent(listTitle,
FilterWithUpdate filter = new FilterWithUpdate(listTitle,
title, tagTemplate,
contentValues);
if(tag.count == 0)
@ -85,6 +93,10 @@ public class TagFilterExposer extends BroadcastReceiver {
newTagIntent(context, DeleteTagActivity.class, tag)
};
filter.customTaskList = new ComponentName(ContextManager.getContext(), TagViewActivity.class);
if(tag.image != null)
filter.imageUrl = tag.image;
if(tag.updateText != null)
filter.updateText = tag.updateText;
Bundle extras = new Bundle();
extras.putString(TagViewActivity.EXTRA_TAG_NAME, tag.tag);
extras.putLong(TagViewActivity.EXTRA_TAG_REMOTE_ID, tag.remoteId);
@ -113,21 +125,9 @@ public class TagFilterExposer extends BroadcastReceiver {
ContextManager.setContext(context);
tagService = TagService.getInstance();
Resources r = context.getResources();
ArrayList<FilterListItem> list = new ArrayList<FilterListItem>();
// --- header
FilterListHeader tagsHeader = new FilterListHeader(context.getString(R.string.tag_FEx_header));
list.add(tagsHeader);
// --- untagged
Filter untagged = new Filter(r.getString(R.string.tag_FEx_untagged),
r.getString(R.string.tag_FEx_untagged),
tagService.untaggedTemplate(),
null);
untagged.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.filter_untagged)).getBitmap();
list.add(untagged);
addTags(list);
// transmit filter list
@ -139,60 +139,71 @@ public class TagFilterExposer extends BroadcastReceiver {
}
private void addTags(ArrayList<FilterListItem> list) {
HashSet<String> tagNames = new HashSet<String>();
// active tags
Tag[] myTags = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE,
Criterion.and(TaskCriteria.ownedByMe(), TaskCriteria.activeAndVisible()));
for(Tag tag : myTags)
tagNames.add(tag.tag);
if(myTags.length > 0)
list.add(filterFromTags(myTags, R.string.tag_FEx_category_mine));
// find all tag data not in active tag list
TodorooCursor<TagData> cursor = tagDataService.query(Query.select(
TagData.NAME, TagData.TASK_COUNT, TagData.REMOTE_ID).where(TagData.DELETION_DATE.eq(0)));
ArrayList<Tag> notListed = new ArrayList<Tag>();
HashMap<String, Tag> tags = new HashMap<String, Tag>();
Tag[] tagsByAlpha = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_ALPHA,
TaskCriteria.activeAndVisible());
for(Tag tag : tagsByAlpha)
if(!TextUtils.isEmpty(tag.tag))
tags.put(tag.tag, tag);
TodorooCursor<TagData> cursor = tagDataService.query(Query.select(TagData.PROPERTIES));
try {
ArrayList<Tag> sharedTags = new ArrayList<Tag>();
TagData tagData = new TagData();
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
String tagName = cursor.get(TagData.NAME);
if(tagNames.contains(tagName))
tagData.readFromCursor(cursor);
String tagName = tagData.getValue(TagData.NAME).trim();
Tag tag = new Tag(tagData);
if(tagData.getValue(TagData.DELETION_DATE) > 0 && !tags.containsKey(tagName)) continue;
if(TextUtils.isEmpty(tag.tag))
continue;
Tag tag = new Tag(tagName, cursor.get(TagData.TASK_COUNT),
cursor.get(TagData.REMOTE_ID));
if(tag.count > 0)
sharedTags.add(tag);
else
notListed.add(tag);
tagNames.add(tagName);
tags.put(tagName, tag);
Update update = tagDataService.getLatestUpdate(tagData);
if(update != null)
tag.updateText = ActFmPreferenceService.updateToString(update);
}
if(sharedTags.size() > 0)
list.add(filterFromTags(sharedTags.toArray(new Tag[sharedTags.size()]), R.string.tag_FEx_category_shared));
} finally {
cursor.close();
}
// find inactive tags, intersect tag list
Tag[] inactiveTags = tagService.getGroupedTags(TagService.GROUPED_TAGS_BY_ALPHA,
Criterion.and(TaskCriteria.notDeleted(), Criterion.not(TaskCriteria.activeAndVisible())));
for(Tag tag : inactiveTags) {
if(!tagNames.contains(tag.tag) && !TextUtils.isEmpty(tag.tag)) {
notListed.add(tag);
tag.count = 0;
ArrayList<Tag> tagList = new ArrayList<Tag>(tags.values());
Collections.sort(tagList,
new Comparator<Tag>() {
@Override
public int compare(Tag object1, Tag object2) {
return object1.tag.compareTo(object2.tag);
}
});
for(Iterator<Entry<String, Tag>> i = tags.entrySet().iterator(); i.hasNext(); ) {
Entry<String, Tag> entry = i.next();
if(TextUtils.isEmpty(entry.getValue().tag))
i.remove();
}
if(notListed.size() > 0)
list.add(filterFromTags(notListed.toArray(new Tag[notListed.size()]),
R.string.tag_FEx_category_inactive));
list.add(filterFromTags(tagList.toArray(new Tag[tagList.size()]),
R.string.tag_FEx_header));
}
private FilterCategory filterFromTags(Tag[] tags, int name) {
Filter[] filters = new Filter[tags.length];
Filter[] filters = new Filter[tags.length + 1];
Resources r = ContextManager.getContext().getResources();
Filter untagged = new Filter(r.getString(R.string.tag_FEx_untagged),
r.getString(R.string.tag_FEx_untagged),
tagService.untaggedTemplate(),
null);
untagged.listingIcon = ((BitmapDrawable)r.getDrawable(R.drawable.gl_lists)).getBitmap();
filters[0] = untagged;
Context context = ContextManager.getContext();
for(int i = 0; i < tags.length; i++)
filters[i] = filterFromTag(context, tags[i], TaskCriteria.activeAndVisible());
return new FilterCategory(context.getString(name), filters);
filters[i + 1] = filterFromTag(context, tags[i], TaskCriteria.activeAndVisible());
FilterCategoryWithNewButton filter = new FilterCategoryWithNewButton(context.getString(name), filters);
filter.label = r.getString(R.string.tag_FEx_add_new);
filter.intent = PendingIntent.getActivity(context, 0,
TagsPlugin.newTagDialog(context), 0);
return filter;
}
// --- tag manipulation activities

@ -11,6 +11,7 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
@ -73,7 +74,7 @@ public final class TagService {
* Property for retrieving count of aggregated rows
*/
private static final CountProperty COUNT = new CountProperty();
public static final Order GROUPED_TAGS_BY_ALPHA = Order.asc(TAG);
public static final Order GROUPED_TAGS_BY_ALPHA = Order.asc(Functions.upper(TAG));
public static final Order GROUPED_TAGS_BY_SIZE = Order.desc(COUNT);
/**
@ -84,8 +85,10 @@ public final class TagService {
*/
public static final class Tag {
public String tag;
int count;
long remoteId;
public int count;
public long remoteId;
public String image;
public String updateText;
public Tag(String tag, int count, long remoteId) {
this.tag = tag;
@ -93,6 +96,13 @@ public final class TagService {
this.remoteId = remoteId;
}
public Tag(TagData tagData) {
tag = tagData.getValue(TagData.NAME);
count = tagData.getValue(TagData.TASK_COUNT);
remoteId = tagData.getValue(TagData.REMOTE_ID);
image = tagData.getValue(TagData.PICTURE);
}
@Override
public String toString() {
return tag;

@ -1,6 +1,5 @@
package com.todoroo.astrid.tags;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -29,11 +28,11 @@ public class TagsPlugin extends BroadcastReceiver {
* Create new tag data
* @param activity
*/
public void showNewTagDialog(final Activity activity) {
Intent intent = new Intent(activity, TagViewActivity.class);
public static Intent newTagDialog(Context context) {
Intent intent = new Intent(context, TagViewActivity.class);
intent.putExtra(TagViewActivity.EXTRA_NEW_TAG, true);
intent.putExtra(TagViewActivity.EXTRA_START_TAB, "settings"); //$NON-NLS-1$
activity.startActivity(intent);
return intent;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 819 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

@ -0,0 +1,12 @@
<!-- See the file "LICENSE" for the full license governing this code. -->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid
android:color="#ff282828" />
<corners
android:bottomRightRadius="4dp"
android:bottomLeftRadius="4dp"
android:topLeftRadius="4dp"
android:topRightRadius="4dp" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 726 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 717 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

@ -1,51 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- See the file "LICENSE" for the full license governing this code. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_height="58dip"
android:background="@android:drawable/list_selector_background"
android:paddingTop="4dip"
android:paddingBottom="4dip"
android:paddingLeft="4dip"
android:paddingTop="5dip"
android:paddingBottom="5dip"
android:paddingLeft="7dip"
android:paddingRight="6dip"
android:orientation="horizontal">
<!-- expander icon -->
<ImageView android:id="@+id/expander"
android:layout_width="32dip"
android:layout_height="fill_parent"
android:layout_weight="1"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:layout_width="22dip"
android:layout_height="wrap_content"
android:layout_marginLeft="11dip"
android:scaleType="fitCenter"
android:visibility="gone"/>
<!-- filter icon -->
<ImageView android:id="@+id/icon"
android:layout_width="32dip"
android:layout_height="fill_parent"
android:layout_weight="1"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:layout_width="25dip"
android:layout_height="48dip"
android:layout_toRightOf="@id/expander"
android:layout_marginTop="4dp"
android:layout_marginLeft="12dip"
android:scaleType="fitCenter"
android:visibility="gone"/>
<!-- filter url image icon -->
<greendroid.widget.AsyncImageView android:id="@+id/url_image"
android:layout_width="30dip"
android:layout_height="48dip"
android:layout_toRightOf="@id/expander"
android:layout_marginTop="4dp"
android:layout_marginLeft="10dip"
android:scaleType="fitCenter"
android:visibility="gone"/>
<!-- filter name -->
<TextView android:id="@+id/name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="100"
android:paddingLeft="5dip"
android:gravity="center_vertical"/>
android:layout_marginLeft="55dp"
android:layout_marginTop="2dp"
android:paddingRight="30dp"
android:gravity="center_vertical" />
<!-- size -->
<TextView android:id="@+id/size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:background="@drawable/filter_count"
android:layout_marginRight="5dip"
android:layout_marginTop="15dip"
android:paddingLeft="7dip"
android:paddingRight="7dip"
android:textColor="#ffffff"
android:gravity="center" />
<!-- selected -->
<ImageView android:id="@+id/selected"
android:layout_width="24dip"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_toLeftOf="@id/size"
android:paddingLeft="5dip"
android:paddingRight="5dip"
android:src="@drawable/filter_selected_icon"
android:scaleType="fitCenter"
android:visibility="gone"/>
<!-- activity text -->
<TextView android:id="@+id/activity"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="55dp"
android:layout_marginTop="29dp"
android:paddingRight="30dp"
android:gravity="center_vertical"
android:visibility="gone"/>
</LinearLayout>
</RelativeLayout>

@ -19,7 +19,7 @@
<string name="BFE_Custom">Custom Filter...</string>
<!-- Saved Filters Header -->
<string name="BFE_Saved">Saved Filters</string>
<string name="BFE_Saved">Filters</string>
<!-- Saved Filters Context Menu: delete -->
<string name="BFE_Saved_delete">Delete Filter</string>

@ -94,18 +94,18 @@
<!-- ============================================== FilterListAdapter == -->
<style name="TextAppearance.FLA_Filter">
<item name="android:textSize">20sp</item>
<item name="android:textSize">18sp</item>
<item name="android:textStyle">bold</item>
</style>
<style name="TextAppearance.FLA_Header" parent="TextAppearance.FLA_Filter">
<item name="android:textSize">18sp</item>
<item name="android:textColor">#ffdddddd</item>
<item name="android:textColor">#ffcccccc</item>
<item name="android:textStyle"></item>
</style>
<style name="TextAppearance.FLA_Category" parent="TextAppearance.FLA_Filter">
<item name="android:textSize">18sp</item>
<item name="android:textColor">#ff7ada24</item>
<item name="android:textStyle">bold|italic</item>
<item name="android:textColor">#ffdddddd</item>
<item name="android:textStyle"></item>
</style>
<!-- ========================================================= Widget == -->

@ -329,7 +329,7 @@ public class FilterListActivity extends ExpandableListActivity {
Bitmap emblem = filter.listingIcon;
if(emblem == null)
emblem = ((BitmapDrawable) getResources().getDrawable(
R.drawable.filter_tags1)).getBitmap();
R.drawable.gl_list)).getBitmap();
// create icon by superimposing astrid w/ icon
DisplayMetrics metrics = new DisplayMetrics();

@ -3,12 +3,15 @@
*/
package com.todoroo.astrid.adapter;
import greendroid.widget.AsyncImageView;
import java.util.ArrayList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import android.app.Activity;
import android.app.PendingIntent.CanceledException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@ -16,15 +19,18 @@ import android.content.IntentFilter;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.BaseExpandableListAdapter;
import android.widget.Button;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import com.timsu.astrid.R;
@ -34,11 +40,11 @@ import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterCategory;
import com.todoroo.astrid.api.FilterCategoryWithNewButton;
import com.todoroo.astrid.api.FilterListHeader;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.gtasks.GtasksListAdder;
import com.todoroo.astrid.api.FilterWithUpdate;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagsPlugin;
public class FilterAdapter extends BaseExpandableListAdapter {
@ -162,8 +168,11 @@ public class FilterAdapter extends BaseExpandableListAdapter {
viewHolder.view = convertView;
viewHolder.expander = (ImageView)convertView.findViewById(R.id.expander);
viewHolder.icon = (ImageView)convertView.findViewById(R.id.icon);
viewHolder.urlImage = (AsyncImageView)convertView.findViewById(R.id.url_image);
viewHolder.name = (TextView)convertView.findViewById(R.id.name);
viewHolder.activity = (TextView)convertView.findViewById(R.id.activity);
viewHolder.selected = (ImageView)convertView.findViewById(R.id.selected);
viewHolder.size = (TextView)convertView.findViewById(R.id.size);
viewHolder.decoration = null;
convertView.setTag(viewHolder);
}
@ -174,7 +183,10 @@ public class FilterAdapter extends BaseExpandableListAdapter {
public FilterListItem item;
public ImageView expander;
public ImageView icon;
public AsyncImageView urlImage;
public TextView name;
public TextView activity;
public TextView size;
public ImageView selected;
public View view;
public View decoration;
@ -209,7 +221,7 @@ public class FilterAdapter extends BaseExpandableListAdapter {
convertView = newView(convertView, parent);
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
viewHolder.item = (FilterListItem) getChild(groupPosition, childPosition);
populateView(viewHolder, true, false);
populateView(viewHolder, false);
return convertView;
}
@ -237,7 +249,7 @@ public class FilterAdapter extends BaseExpandableListAdapter {
convertView = newView(convertView, parent);
ViewHolder viewHolder = (ViewHolder) convertView.getTag();
viewHolder.item = (FilterListItem) getGroup(groupPosition);
populateView(viewHolder, false, isExpanded);
populateView(viewHolder, isExpanded);
return convertView;
}
@ -390,40 +402,70 @@ public class FilterAdapter extends BaseExpandableListAdapter {
* ================================================================ views
* ====================================================================== */
public void populateView(ViewHolder viewHolder, boolean isChild, boolean isExpanded) {
public void populateView(ViewHolder viewHolder, boolean isExpanded) {
FilterListItem filter = viewHolder.item;
if(filter == null)
return;
viewHolder.view.setBackgroundResource(0);
viewHolder.expander.setVisibility(View.GONE);
if(viewHolder.decoration != null) {
((ViewGroup)viewHolder.view).removeView(viewHolder.decoration);
viewHolder.decoration = null;
}
if(viewHolder.item instanceof FilterListHeader) {
if(viewHolder.item instanceof FilterListHeader || viewHolder.item instanceof FilterCategory) {
viewHolder.name.setTextAppearance(activity, headerStyle);
viewHolder.view.setBackgroundResource(R.drawable.edit_titlebar);
viewHolder.view.setPadding((int) ((isChild ? 33 : 7) * metrics.density), 5, 0, 5);
} else if(viewHolder.item instanceof FilterCategory) {
viewHolder.expander.setVisibility(View.VISIBLE);
if(isExpanded)
viewHolder.expander.setImageResource(R.drawable.expander_ic_maximized);
else
viewHolder.expander.setImageResource(R.drawable.expander_ic_minimized);
viewHolder.name.setTextAppearance(activity, categoryStyle);
viewHolder.view.setPadding((int)(7 * metrics.density), 8, 0, 8);
viewHolder.view.setPadding((int) (7 * metrics.density), 5, 0, 5);
viewHolder.view.getLayoutParams().height = (int) (40 * metrics.density);
} else {
viewHolder.name.setTextAppearance(activity, filterStyle);
viewHolder.view.setPadding((int) ((isChild ? 27 : 7) * metrics.density), 8, 0, 8);
viewHolder.view.setPadding((int) (7 * metrics.density), 8, 0, 8);
viewHolder.view.getLayoutParams().height = (int) (58 * metrics.density);
}
if(viewHolder.item instanceof FilterCategory) {
viewHolder.expander.setVisibility(View.VISIBLE);
viewHolder.expander.setImageResource(isExpanded ?
R.drawable.expander_ic_maximized : R.drawable.expander_ic_minimized);
} else
viewHolder.expander.setVisibility(View.GONE);
// update with filter attributes (listing icon, url, update text, size)
viewHolder.urlImage.setVisibility(View.GONE);
viewHolder.activity.setVisibility(View.GONE);
viewHolder.icon.setVisibility(View.GONE);
if(filter.listingIcon != null) {
viewHolder.icon.setVisibility(View.VISIBLE);
viewHolder.icon.setImageBitmap(filter.listingIcon);
}
// title / size
if(filter.listingTitle.matches(".* \\(\\d+\\)$")) { //$NON-NLS-1$
viewHolder.size.setVisibility(View.VISIBLE);
viewHolder.size.setText(filter.listingTitle.substring(filter.listingTitle.lastIndexOf('(') + 1,
filter.listingTitle.length() - 1));
viewHolder.name.setText(filter.listingTitle.substring(0, filter.listingTitle.lastIndexOf(' ')));
} else {
viewHolder.name.setText(filter.listingTitle);
viewHolder.size.setVisibility(View.GONE);
}
viewHolder.icon.setVisibility(filter.listingIcon != null ? View.VISIBLE : View.GONE);
viewHolder.icon.setImageBitmap(filter.listingIcon);
viewHolder.name.getLayoutParams().height = (int) (58 * metrics.density);
if(filter instanceof FilterWithUpdate) {
viewHolder.urlImage.setVisibility(View.VISIBLE);
viewHolder.urlImage.setDefaultImageResource(R.drawable.gl_list);
viewHolder.urlImage.setUrl(((FilterWithUpdate)filter).imageUrl);
if(!TextUtils.isEmpty(((FilterWithUpdate)filter).updateText)) {
viewHolder.activity.setText(((FilterWithUpdate)filter).updateText);
viewHolder.name.getLayoutParams().height = (int) (25 * metrics.density);
viewHolder.activity.setVisibility(View.VISIBLE);
}
}
viewHolder.name.setText(filter.listingTitle);
if(filter.color != 0)
viewHolder.name.setTextColor(filter.color);
@ -434,43 +476,33 @@ public class FilterAdapter extends BaseExpandableListAdapter {
} else
viewHolder.selected.setVisibility(View.GONE);
updateForActFm(viewHolder);
updateForGtasks(viewHolder);
}
private void setupCustomHeader(ViewHolder viewHolder, String forTitle, View.OnClickListener buttonListener) {
if(viewHolder.item instanceof FilterListHeader &&
viewHolder.item.listingTitle.equals(forTitle)) {
Button add = new Button(activity);
add.setText(R.string.tag_FEx_add_new);
add.setBackgroundResource(android.R.drawable.btn_default_small);
add.setCompoundDrawablesWithIntrinsicBounds(R.drawable.tango_add,0,0,0);
viewHolder.decoration = add;
add.setHeight((int)(35 * metrics.density));
((ViewGroup)viewHolder.view).addView(add);
add.setOnClickListener(buttonListener);
}
}
private void updateForActFm(ViewHolder viewHolder) {
setupCustomHeader(viewHolder,
activity.getString(R.string.tag_FEx_header),
new View.OnClickListener() {
@Override
public void onClick(View v) {
new TagsPlugin().showNewTagDialog(activity);
}
});
if(filter instanceof FilterCategoryWithNewButton)
setupCustomHeader(viewHolder, (FilterCategoryWithNewButton) filter);
}
private void updateForGtasks(ViewHolder viewHolder) {
setupCustomHeader(viewHolder,
activity.getString(R.string.gtasks_FEx_header),
new View.OnClickListener() {
private void setupCustomHeader(ViewHolder viewHolder, final FilterCategoryWithNewButton filter) {
Button add = new Button(activity);
add.setBackgroundResource(R.drawable.filter_btn_background);
add.setCompoundDrawablesWithIntrinsicBounds(R.drawable.filter_new,0,0,0);
add.setTextColor(Color.WHITE);
add.setShadowLayer(1, 1, 1, Color.BLACK);
add.setText(filter.label);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
(int)(32 * metrics.density));
lp.rightMargin = (int) (4 * metrics.density);
lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
add.setLayoutParams(lp);
((ViewGroup)viewHolder.view).addView(add);
viewHolder.decoration = add;
add.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
new GtasksListAdder().showNewListDialog(activity);
try {
filter.intent.send();
} catch (CanceledException e) {
// do nothing
}
}
});
}

@ -0,0 +1,107 @@
/**
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.api;
import android.app.PendingIntent;
import android.os.Parcel;
import android.os.Parcelable;
/**
* A <code>FilterCategoryWithNewButton</code> has a button for new filter creation
*
* @author Tim Su <tim@todoroo.com>
*
*/
public class FilterCategoryWithNewButton extends FilterCategory {
/**
* Intent to launch
*/
public PendingIntent intent;
/**
* Label for new button
*/
public String label;
/**
* Constructor for creating a new FilterCategory
* @param listingTitle
* Title of this item as displayed on the lists page, e.g. Inbox
* @param children
* filters belonging to this category
*/
public FilterCategoryWithNewButton(String listingTitle, Filter[] children) {
this.listingTitle = listingTitle;
this.children = children;
}
/**
* Constructor for creating a new FilterCategory
*
* @param plugin
* {@link Addon} identifier that encompasses object
*/
protected FilterCategoryWithNewButton() {
//
}
// --- parcelable
/**
* {@inheritDoc}
*/
@Override
public int describeContents() {
return 0;
}
/**
* {@inheritDoc}
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeParcelable(intent, 0);
dest.writeString(label);
}
/**
* Parcelable creator
*/
@SuppressWarnings("hiding")
public static final Parcelable.Creator<FilterCategoryWithNewButton> CREATOR = new Parcelable.Creator<FilterCategoryWithNewButton>() {
/**
* {@inheritDoc}
*/
public FilterCategoryWithNewButton createFromParcel(Parcel source) {
FilterCategoryWithNewButton item = new FilterCategoryWithNewButton();
item.readFromParcel(source);
Parcelable[] parcelableChildren = source.readParcelableArray(
FilterCategoryWithNewButton.class.getClassLoader());
item.children = new Filter[parcelableChildren.length];
for(int i = 0; i < item.children.length; i++) {
if(parcelableChildren[i] instanceof FilterListItem)
item.children[i] = (Filter) parcelableChildren[i];
else
item.children[i] = null;
}
item.intent = source.readParcelable(PendingIntent.class.getClassLoader());
item.label = source.readString();
return item;
}
/**
* {@inheritDoc}
*/
public FilterCategoryWithNewButton[] newArray(int size) {
return new FilterCategoryWithNewButton[size];
}
};
}

@ -0,0 +1,87 @@
package com.todoroo.astrid.api;
import android.content.ContentValues;
import android.os.Parcel;
import android.os.Parcelable;
import com.todoroo.andlib.sql.QueryTemplate;
public class FilterWithUpdate extends FilterWithCustomIntent {
/**
* Update image URL
*/
public String imageUrl = null;
/**
* Update message text
*/
public String updateText = null;
protected FilterWithUpdate() {
super();
}
public FilterWithUpdate(String listingTitle, String title,
QueryTemplate sqlQuery, ContentValues valuesForNewTasks) {
super(listingTitle, title, sqlQuery, valuesForNewTasks);
}
public FilterWithUpdate(String listingTitle, String title,
String sqlQuery, ContentValues valuesForNewTasks) {
super(listingTitle, title, sqlQuery, valuesForNewTasks);
}
// --- parcelable
/**
* {@inheritDoc}
*/
@Override
public int describeContents() {
return 0;
}
/**
* {@inheritDoc}
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(imageUrl);
dest.writeString(updateText);
}
@Override
public void readFromParcel(Parcel source) {
super.readFromParcel(source);
imageUrl = source.readString();
updateText = source.readString();
}
/**
* Parcelable Creator Object
*/
@SuppressWarnings("hiding")
public static final Parcelable.Creator<FilterWithUpdate> CREATOR = new Parcelable.Creator<FilterWithUpdate>() {
/**
* {@inheritDoc}
*/
public FilterWithUpdate createFromParcel(Parcel source) {
FilterWithUpdate item = new FilterWithUpdate();
item.readFromParcel(source);
return item;
}
/**
* {@inheritDoc}
*/
public FilterWithUpdate[] newArray(int size) {
return new FilterWithUpdate[size];
}
};
}

@ -140,4 +140,27 @@ public class TagDataService {
orderBy(Order.desc(Update.CREATION_DATE)));
}
/**
* Return update
* @param tagData
* @return
*/
public Update getLatestUpdate(TagData tagData) {
if(tagData.getValue(Task.REMOTE_ID) < 1)
return null;
@SuppressWarnings("nls")
TodorooCursor<Update> updates = updateDao.query(Query.select(Update.PROPERTIES).where(
Update.TAGS.like("%," + tagData.getValue(Task.REMOTE_ID) + ",%")).
orderBy(Order.desc(Update.CREATION_DATE)).limit(1));
try {
if(updates.getCount() == 0)
return null;
updates.moveToFirst();
return new Update(updates);
} finally {
updates.close();
}
}
}

Loading…
Cancel
Save