diff --git a/api/src/com/todoroo/andlib/data/Property.java b/api/src/com/todoroo/andlib/data/Property.java index b1526e629..40bfb08f7 100644 --- a/api/src/com/todoroo/andlib/data/Property.java +++ b/api/src/com/todoroo/andlib/data/Property.java @@ -5,7 +5,14 @@ */ package com.todoroo.andlib.data; +import static com.todoroo.andlib.sql.SqlConstants.COMMA; +import static com.todoroo.andlib.sql.SqlConstants.LEFT_PARENTHESIS; +import static com.todoroo.andlib.sql.SqlConstants.RIGHT_PARENTHESIS; +import static com.todoroo.andlib.sql.SqlConstants.SPACE; + +import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.Field; +import com.todoroo.andlib.sql.Operator; /** * Property represents a typed column in a database. @@ -150,6 +157,21 @@ public abstract class Property extends Field implements Cloneable { PropertyVisitor visitor, PARAMETER data) { return visitor.visitString(this, data); } + + public Criterion in(final String[] value) { + final Field field = this; + return new Criterion(Operator.in) { + + @Override + protected void populate(StringBuilder sb) { + sb.append(field).append(SPACE).append(Operator.in).append(SPACE).append(LEFT_PARENTHESIS).append(SPACE); + for (String s : value) { + sb.append("\"").append(s.toString()).append("\"").append(COMMA); + } + sb.deleteCharAt(sb.length() - 1).append(RIGHT_PARENTHESIS); + } + }; + } } /** diff --git a/api/src/com/todoroo/andlib/sql/Criterion.java b/api/src/com/todoroo/andlib/sql/Criterion.java index 5acdc6535..9059bc8f1 100644 --- a/api/src/com/todoroo/andlib/sql/Criterion.java +++ b/api/src/com/todoroo/andlib/sql/Criterion.java @@ -11,7 +11,7 @@ import static com.todoroo.andlib.sql.SqlConstants.SPACE; public abstract class Criterion { protected final Operator operator; - Criterion(Operator operator) { + public Criterion(Operator operator) { this.operator = operator; } diff --git a/api/src/com/todoroo/andlib/sql/SqlConstants.java b/api/src/com/todoroo/andlib/sql/SqlConstants.java index fa9d647fc..4739acfeb 100644 --- a/api/src/com/todoroo/andlib/sql/SqlConstants.java +++ b/api/src/com/todoroo/andlib/sql/SqlConstants.java @@ -2,24 +2,24 @@ package com.todoroo.andlib.sql; @SuppressWarnings("nls") public final class SqlConstants { - static final String SELECT = "SELECT"; - static final String DISTINCT = "DISTINCT"; - static final String SPACE = " "; - static final String AS = "AS"; - static final String COMMA = ","; - static final String FROM = "FROM"; - static final String ON = "ON"; - static final String JOIN = "JOIN"; - static final String ALL = "*"; - static final String LEFT_PARENTHESIS = "("; - static final String RIGHT_PARENTHESIS = ")"; - static final String AND = "AND"; - static final String BETWEEN = "BETWEEN"; - static final String LIKE = "LIKE"; - static final String OR = "OR"; - static final String ORDER_BY = "ORDER BY"; - static final String GROUP_BY = "GROUP BY"; - static final String WHERE = "WHERE"; + public static final String SELECT = "SELECT"; + public static final String DISTINCT = "DISTINCT"; + public static final String SPACE = " "; + public static final String AS = "AS"; + public static final String COMMA = ","; + public static final String FROM = "FROM"; + public static final String ON = "ON"; + public static final String JOIN = "JOIN"; + public static final String ALL = "*"; + public static final String LEFT_PARENTHESIS = "("; + public static final String RIGHT_PARENTHESIS = ")"; + public static final String AND = "AND"; + public static final String BETWEEN = "BETWEEN"; + public static final String LIKE = "LIKE"; + public static final String OR = "OR"; + public static final String ORDER_BY = "ORDER BY"; + public static final String GROUP_BY = "GROUP BY"; + public static final String WHERE = "WHERE"; public static final String EXISTS = "EXISTS"; public static final String NOT = "NOT"; public static final String LIMIT = "LIMIT"; diff --git a/api/src/com/todoroo/astrid/data/User.java b/api/src/com/todoroo/astrid/data/User.java index 0d6d6e2cc..f8cf69c82 100644 --- a/api/src/com/todoroo/astrid/data/User.java +++ b/api/src/com/todoroo/astrid/data/User.java @@ -8,6 +8,7 @@ package com.todoroo.astrid.data; import android.content.ContentValues; import android.net.Uri; +import android.text.TextUtils; import com.todoroo.andlib.data.AbstractModel; import com.todoroo.andlib.data.Property; @@ -91,6 +92,13 @@ public final class User extends RemoteModel { super.readPropertiesFromCursor(cursor); } + public String getDisplayName() { + String name = getValue(NAME); + if (!TextUtils.isEmpty(name)) + return name; + return getValue(EMAIL); + } + @Override public long getId() { return getIdHelper(ID); diff --git a/astrid/AndroidManifest.xml b/astrid/AndroidManifest.xml index fa56190d6..91e447e20 100644 --- a/astrid/AndroidManifest.xml +++ b/astrid/AndroidManifest.xml @@ -320,6 +320,16 @@ + + + + + + + + + diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java b/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java index dd5c7eeb4..908e08f96 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java @@ -241,7 +241,7 @@ public class EditPeopleControlSet extends PopupControlSet { @Override public void run() { ArrayList collaborators = new ArrayList(); - TodorooCursor tags = TagService.getInstance().getTags(task.getId()); + TodorooCursor tags = TagService.getInstance().getTags(task.getId(), true); try { Metadata metadata = new Metadata(); for(tags.moveToFirst(); !tags.isAfterLast(); tags.moveToNext()) { diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java index f71c8256d..2f894de98 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java @@ -394,7 +394,7 @@ public final class ActFmSyncService { } if(Flags.checkAndClear(Flags.TAGS_CHANGED) || newlyCreated) { - TodorooCursor cursor = TagService.getInstance().getTags(task.getId()); + TodorooCursor cursor = TagService.getInstance().getTags(task.getId(), false); try { if(cursor.getCount() == 0) { params.add("tags"); @@ -740,6 +740,10 @@ public final class ActFmSyncService { }, done, "tasks:" + tagData.getId(), "tag_id", tagData.getValue(TagData.REMOTE_ID)); } + public void fetchTasksForUser(final User user, final boolean manual, Runnable done) { + invokeFetchList("task", manual, null, new TaskListItemProcessor(false), + done, "user_" + user.getId(), "user_id", user.getValue(User.REMOTE_ID)); + } /** diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java index 9a4921d9a..1a40cf818 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java @@ -25,6 +25,7 @@ import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.data.RemoteModel; import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.User; import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.TagDataService; import com.todoroo.astrid.service.TaskService; @@ -273,6 +274,11 @@ public class ActFmSyncV2Provider extends SyncV2Provider { public void synchronizeList(Object list, final boolean manual, final SyncResultCallback callback) { + if (list instanceof User) { + synchronizeUser((User) list, manual, callback); + return; + } + if(!(list instanceof TagData)) return; @@ -299,6 +305,27 @@ public class ActFmSyncV2Provider extends SyncV2Provider { }).start(); } + private void synchronizeUser(final User user, final boolean manual, final SyncResultCallback callback) { + if (user.getValue(User.REMOTE_ID) == 0) + return; + + new Thread(new Runnable() { + @Override + public void run() { + callback.started(); + callback.incrementMax(100); + + actFmSyncService.waitUntilEmpty(); + actFmSyncService.fetchTasksForUser(user, manual, new Runnable() { + public void run() { + callback.finished(); + } + }); + callback.incrementProgress(50); + } + }).start(); + } + private void fetchTagData(final TagData tagData, final boolean noRemoteId, final boolean manual, final SyncResultCallback callback, final AtomicInteger finisher) { diff --git a/astrid/plugin-src/com/todoroo/astrid/core/PluginServices.java b/astrid/plugin-src/com/todoroo/astrid/core/PluginServices.java index b366713a8..ff50eabd6 100644 --- a/astrid/plugin-src/com/todoroo/astrid/core/PluginServices.java +++ b/astrid/plugin-src/com/todoroo/astrid/core/PluginServices.java @@ -8,6 +8,7 @@ import com.todoroo.andlib.sql.Query; import com.todoroo.astrid.dao.Database; import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; import com.todoroo.astrid.dao.StoreObjectDao; +import com.todoroo.astrid.dao.UserDao; import com.todoroo.astrid.data.Metadata; import com.todoroo.astrid.service.AddOnService; import com.todoroo.astrid.service.AstridDependencyInjector; @@ -44,6 +45,9 @@ public final class PluginServices { @Autowired StoreObjectDao storeObjectDao; + @Autowired + UserDao userDao; + private static PluginServices instance; static { @@ -86,6 +90,10 @@ public final class PluginServices { return getInstance().storeObjectDao; } + public static UserDao getUserDao() { + return getInstance().userDao; + } + // -- helpers /** diff --git a/astrid/plugin-src/com/todoroo/astrid/people/PeopleFilterAdapter.java b/astrid/plugin-src/com/todoroo/astrid/people/PeopleFilterAdapter.java new file mode 100644 index 000000000..55147ed6b --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/people/PeopleFilterAdapter.java @@ -0,0 +1,38 @@ +package com.todoroo.astrid.people; + +import android.app.Activity; +import android.content.Intent; +import android.content.IntentFilter; +import android.widget.ListView; + +import com.todoroo.astrid.adapter.FilterAdapter; +import com.todoroo.astrid.utility.Constants; + +public class PeopleFilterAdapter extends FilterAdapter { + + public static final String BROADCAST_REQUEST_PEOPLE_FILTERS = Constants.PACKAGE + ".REQUEST_PEOPLE_FILTERS"; //$NON-NLS-1$ + public static final String BROADCAST_SEND_PEOPLE_FILTERS = Constants.PACKAGE + ".SEND_PEOPLE_FILTERS"; //$NON-NLS-1$ + + public PeopleFilterAdapter(Activity activity, ListView listView, + int rowLayout, boolean skipIntentFilters) { + super(activity, listView, rowLayout, skipIntentFilters); + } + + @Override + public void getLists() { + Intent broadcastIntent = new Intent(BROADCAST_REQUEST_PEOPLE_FILTERS); + activity.sendBroadcast(broadcastIntent); + } + + @Override + public void registerRecevier() { + IntentFilter peopleFilter = new IntentFilter(BROADCAST_SEND_PEOPLE_FILTERS); + activity.registerReceiver(filterReceiver, peopleFilter); + getLists(); + } + + @Override + public void unregisterRecevier() { + activity.unregisterReceiver(filterReceiver); + } +} diff --git a/astrid/plugin-src/com/todoroo/astrid/people/PeopleFilterExposer.java b/astrid/plugin-src/com/todoroo/astrid/people/PeopleFilterExposer.java new file mode 100644 index 000000000..9a0775fae --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/people/PeopleFilterExposer.java @@ -0,0 +1,142 @@ +package com.todoroo.astrid.people; + +import org.json.JSONException; +import org.json.JSONObject; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.os.Bundle; + +import com.timsu.astrid.R; +import com.todoroo.andlib.data.TodorooCursor; +import com.todoroo.andlib.service.ContextManager; +import com.todoroo.andlib.sql.Criterion; +import com.todoroo.andlib.sql.Field; +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.andlib.utility.AndroidUtilities; +import com.todoroo.astrid.actfm.sync.ActFmSyncService; +import com.todoroo.astrid.api.AstridApiConstants; +import com.todoroo.astrid.api.Filter; +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.data.Metadata; +import com.todoroo.astrid.data.TagData; +import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.data.User; +import com.todoroo.astrid.tags.TagService; + +public class PeopleFilterExposer extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + FilterListItem[] listAsArray = prepareFilters(context); + + Intent broadcastIntent = new Intent(PeopleFilterAdapter.BROADCAST_SEND_PEOPLE_FILTERS); + broadcastIntent.putExtra(AstridApiConstants.EXTRAS_RESPONSE, listAsArray); + broadcastIntent.putExtra(AstridApiConstants.EXTRAS_ADDON, "people"); //$NON-NLS-1$ + context.sendBroadcast(broadcastIntent); + } + + private FilterListItem[] prepareFilters(Context context) { + TodorooCursor users = PluginServices.getUserDao().query(Query.select(User.PROPERTIES) + .orderBy(Order.asc(User.NAME), Order.asc(User.EMAIL))); + try { + FilterListItem[] items = new FilterListItem[users.getCount() + 1]; + items[0] = mySharedTasks(context); + User user = new User(); + int i = 1; + for (users.moveToFirst(); !users.isAfterLast(); users.moveToNext()) { + user.readFromCursor(users); + Filter currFilter = filterFromUserData(user); + items[i] = currFilter; + i++; + } + return items; + } finally { + users.close(); + } + } + + @SuppressWarnings("nls") + public static FilterWithCustomIntent filterFromUserData(User user) { + String email = user.getValue(User.EMAIL); + + String title = user.getDisplayName(); + QueryTemplate userTemplate = new QueryTemplate().where( + Criterion.or(Task.USER.like("%" + email + "%"), + Task.USER_ID.eq(user.getValue(User.REMOTE_ID)))); + + FilterWithUpdate filter = new FilterWithUpdate(title, title, userTemplate, null); + + filter.customTaskList = new ComponentName(ContextManager.getContext(), PersonViewFragment.class); + + ContentValues values = new ContentValues(); + values.put(Task.USER_ID.name, user.getValue(User.REMOTE_ID)); + try { + JSONObject userJson = new JSONObject(); + ActFmSyncService.JsonHelper.jsonFromUser(userJson, user); + values.put(Task.USER.name, userJson.toString()); + } catch (JSONException e) { + // Ignored + } + filter.valuesForNewTasks = values; + + String imageUrl = user.getValue(User.PICTURE); + filter.imageUrl = imageUrl; + + Bundle extras = new Bundle(); + extras.putLong(PersonViewFragment.EXTRA_USER_ID_LOCAL, user.getId()); + filter.customExtras = extras; + + return filter; + } + + @SuppressWarnings("nls") + public static FilterWithCustomIntent mySharedTasks(Context context) { + AndroidUtilities.copyDatabases(context, "/sdcard/databases"); + TodorooCursor tagsWithMembers = PluginServices.getTagDataService() + .query(Query.select(TagData.NAME, TagData.MEMBERS).where(TagData.MEMBER_COUNT.gt(0))); + String[] names; + try { + if (tagsWithMembers.getCount() == 0) { + names = new String[1]; + names[0] = "\"\""; + } else { + names = new String[tagsWithMembers.getCount()]; + TagData curr = new TagData(); + int i = 0; + for (tagsWithMembers.moveToFirst(); !tagsWithMembers.isAfterLast(); tagsWithMembers.moveToNext()) { + curr.readFromCursor(tagsWithMembers); + names[i] = "\"" + curr.getValue(TagData.NAME) + "\""; + System.err.println("Tag data " + curr.getValue(TagData.NAME) + " has members " + curr.getValue(TagData.MEMBERS)); + i++; + } + } + } finally { + tagsWithMembers.close(); + } + + String title = context.getString(R.string.actfm_my_shared_tasks_title); + QueryTemplate template = new QueryTemplate().join(Join.inner(Metadata.TABLE.as("mtags"), + Criterion.and(Task.ID.eq(Field.field("mtags." + Metadata.TASK.name)), + Field.field("mtags." + Metadata.KEY.name).eq(TagService.KEY), + Field.field("mtags." + TagService.TAG.name).in(names)))); + + FilterWithUpdate filter = new FilterWithUpdate(title, title, template, null); + + filter.customTaskList = new ComponentName(ContextManager.getContext(), PersonViewFragment.class); + + Bundle extras = new Bundle(); + extras.putBoolean(PersonViewFragment.EXTRA_HIDE_QUICK_ADD, true); + filter.customExtras = extras; + + return filter; + } +} diff --git a/astrid/plugin-src/com/todoroo/astrid/people/PeopleListFragment.java b/astrid/plugin-src/com/todoroo/astrid/people/PeopleListFragment.java new file mode 100644 index 000000000..7d4dc5ea5 --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/people/PeopleListFragment.java @@ -0,0 +1,24 @@ +package com.todoroo.astrid.people; + +import android.app.Activity; + +import com.timsu.astrid.R; +import com.todoroo.andlib.utility.AndroidUtilities; +import com.todoroo.astrid.activity.FilterListFragment; +import com.todoroo.astrid.adapter.FilterAdapter; + +public class PeopleListFragment extends FilterListFragment { + + @Override + protected FilterAdapter instantiateAdapter() { + return new PeopleFilterAdapter(getActivity(), null, R.layout.filter_adapter_row, false); + } + + @Override + protected int getLayout(Activity activity) { + if (AndroidUtilities.isTabletSized(activity)) + return R.layout.people_list_fragment_3pane; + else + return R.layout.people_list_fragment; + } +} diff --git a/astrid/plugin-src/com/todoroo/astrid/people/PeopleViewActivity.java b/astrid/plugin-src/com/todoroo/astrid/people/PeopleViewActivity.java new file mode 100644 index 000000000..3204a539e --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/people/PeopleViewActivity.java @@ -0,0 +1,79 @@ +package com.todoroo.astrid.people; + +import android.content.Intent; +import android.os.Bundle; + +import com.timsu.astrid.R; +import com.todoroo.andlib.utility.AndroidUtilities; +import com.todoroo.astrid.activity.FilterListFragment; +import com.todoroo.astrid.activity.TaskListActivity; +import com.todoroo.astrid.activity.TaskListFragment; +import com.todoroo.astrid.api.Filter; +import com.todoroo.astrid.api.FilterListItem; +import com.todoroo.astrid.api.FilterWithUpdate; +import com.todoroo.astrid.helper.AsyncImageView; +import com.todoroo.astrid.ui.MainMenuPopover; + +public class PeopleViewActivity extends TaskListActivity { + + private AsyncImageView imageView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + imageView = (AsyncImageView) findViewById(R.id.person_image); + imageView.setDefaultImageResource(R.drawable.icn_default_person_image); + } + + @Override + protected int getContentView() { + return R.layout.people_view_wrapper_activity; + } + + @Override + protected Filter getDefaultFilter() { + return PeopleFilterExposer.mySharedTasks(this); + } + + @Override + protected Class getFilterListClass() { + return PeopleListFragment.class; + } + + @Override + protected int getHeaderView() { + return R.layout.header_people_view; + } + + @Override + public boolean onFilterItemClicked(FilterListItem item) { + boolean result = super.onFilterItemClicked(item); + if (result && item instanceof FilterWithUpdate) + imageView.setUrl(((FilterWithUpdate) item).imageUrl); + else + imageView.setUrl(null); + return result; + } + + private static final int[] FORBIDDEN_MENU_ITEMS = { + TaskListFragment.MENU_NEW_FILTER_ID, + TaskListFragment.MENU_ADDONS_ID, + MainMenuPopover.MAIN_MENU_ITEM_FRIENDS + }; + + @Override + public boolean shouldAddMenuItem(int itemId) { + return AndroidUtilities.indexOf(FORBIDDEN_MENU_ITEMS, itemId) < 0; + } + + @Override + public void mainMenuItemSelected(int item, Intent customIntent) { + if (item == MainMenuPopover.MAIN_MENU_ITEM_LISTS) { + finish(); + return; + } + + super.mainMenuItemSelected(item, customIntent); + } +} diff --git a/astrid/plugin-src/com/todoroo/astrid/people/PersonViewFragment.java b/astrid/plugin-src/com/todoroo/astrid/people/PersonViewFragment.java new file mode 100644 index 000000000..d1e1792ef --- /dev/null +++ b/astrid/plugin-src/com/todoroo/astrid/people/PersonViewFragment.java @@ -0,0 +1,129 @@ +package com.todoroo.astrid.people; + +import android.content.Intent; +import android.support.v4.view.Menu; +import android.text.TextUtils; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import com.timsu.astrid.R; +import com.todoroo.andlib.service.Autowired; +import com.todoroo.andlib.service.ContextManager; +import com.todoroo.andlib.utility.DateUtilities; +import com.todoroo.andlib.utility.Preferences; +import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; +import com.todoroo.astrid.activity.TaskListFragment; +import com.todoroo.astrid.api.AstridApiConstants; +import com.todoroo.astrid.dao.UserDao; +import com.todoroo.astrid.data.User; +import com.todoroo.astrid.helper.ProgressBarSyncResultCallback; +import com.todoroo.astrid.service.SyncV2Service; +import com.todoroo.astrid.service.ThemeService; + +public class PersonViewFragment extends TaskListFragment { + + public static final String EXTRA_USER_ID_LOCAL = "user_local_id"; //$NON-NLS-1$ + + public static final String EXTRA_HIDE_QUICK_ADD = "hide_quickAdd"; //$NON-NLS-1$ + + private static final String LAST_FETCH_KEY = "actfm_last_user_"; //$NON-NLS-1$ + + protected static final int MENU_REFRESH_ID = MENU_SUPPORT_ID + 1; + + @Autowired UserDao userDao; + + @Autowired SyncV2Service syncService; + + @Autowired ActFmPreferenceService actFmPreferenceService; + + protected View taskListView; + + private User user; + + @Override + protected View getListBody(ViewGroup root) { + ViewGroup parent = (ViewGroup) getActivity().getLayoutInflater().inflate(R.layout.task_list_body_person, root, false); + + taskListView = super.getListBody(parent); + parent.addView(taskListView); + + return parent; + } + + @Override + protected void initializeData() { + super.initializeData(); + if (extras.containsKey(EXTRA_USER_ID_LOCAL)) { + user = userDao.fetch(extras.getLong(EXTRA_USER_ID_LOCAL), User.PROPERTIES); + } + ((TextView)taskListView.findViewById(android.R.id.empty)).setText(getEmptyDisplayString()); + } + + @Override + protected void setupQuickAddBar() { + super.setupQuickAddBar(); + quickAddBar.setUsePeopleControl(false); + if (user != null) + quickAddBar.getQuickAddBox().setHint(getString(R.string.TLA_quick_add_hint_assign, user.getDisplayName())); + + if (extras.containsKey(EXTRA_HIDE_QUICK_ADD)) + quickAddBar.setVisibility(View.GONE); + + } + + @Override + protected void addSyncRefreshMenuItem(Menu menu, int themeFlags) { + if(actFmPreferenceService.isLoggedIn()) { + addMenuItem(menu, R.string.actfm_TVA_menu_refresh, + ThemeService.getDrawable(R.drawable.icn_menu_refresh, themeFlags), MENU_REFRESH_ID, true); + } else { + super.addSyncRefreshMenuItem(menu, themeFlags); + } + } + + @Override + public boolean handleOptionsMenuItemSelected(int id, Intent intent) { + switch (id) { + case MENU_REFRESH_ID: + refreshData(true); + return true; + } + return super.handleOptionsMenuItemSelected(id, intent); + } + + @Override + protected void initiateAutomaticSyncImpl() { + if (!isCurrentTaskListFragment()) + return; + if (user != null) { + long lastAutoSync = Preferences.getLong(LAST_FETCH_KEY + user.getId(), 0); + if (DateUtilities.now() - lastAutoSync > DateUtilities.ONE_HOUR) + refreshData(false); + } + } + + private void refreshData(final boolean manual) { + if (user != null) { + ((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.DLG_loading); + + syncService.synchronizeList(user, manual, new ProgressBarSyncResultCallback(getActivity(), this, + R.id.progressBar, new Runnable() { + @Override + public void run() { + if (manual) + ContextManager.getContext().sendBroadcast(new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH)); + else + refresh(); + ((TextView)taskListView.findViewById(android.R.id.empty)).setText(getEmptyDisplayString()); + } + })); + } + } + + private String getEmptyDisplayString() { + String userName = user != null ? user.getDisplayName() : null; + return TextUtils.isEmpty(userName) ? getString(R.string.actfm_my_shared_tasks_empty) : getString(R.string.TLA_no_items_person, userName); + } + +} diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagCaseMigrator.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagCaseMigrator.java index 48fa80430..c29998099 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagCaseMigrator.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagCaseMigrator.java @@ -38,7 +38,7 @@ public class TagCaseMigrator { public void performTagCaseMigration(@SuppressWarnings("unused") Context context) { if (!Preferences.getBoolean(PREF_CASE_MIGRATION_PERFORMED, false)) { TagService.Tag[] allTagData = TagService.getInstance().getGroupedTags( - TagService.GROUPED_TAGS_BY_ALPHA, Criterion.all); + TagService.GROUPED_TAGS_BY_ALPHA, Criterion.all, false); boolean shouldShowDialog = false; for (int i = 0; i < allTagData.length - 1; i++) { diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagCustomFilterCriteriaExposer.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagCustomFilterCriteriaExposer.java index be9d7d32d..ebb821d15 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagCustomFilterCriteriaExposer.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagCustomFilterCriteriaExposer.java @@ -35,7 +35,7 @@ public class TagCustomFilterCriteriaExposer extends BroadcastReceiver { // built in criteria: tags { TagService.Tag[] tags = TagService.getInstance().getGroupedTags(TagService.GROUPED_TAGS_BY_SIZE, - TaskDao.TaskCriteria.activeAndVisible()); + TaskDao.TaskCriteria.activeAndVisible(), false); String[] tagNames = new String[tags.length]; for(int i = 0; i < tags.length; i++) tagNames[i] = tags[i].tag; diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagDetailExposer.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagDetailExposer.java index 3d890d606..70ef269e0 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagDetailExposer.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagDetailExposer.java @@ -37,7 +37,7 @@ public class TagDetailExposer extends BroadcastReceiver { } public String getTaskDetails(long id) { - String tagList = TagService.getInstance().getTagsAsString(id); + String tagList = TagService.getInstance().getTagsAsString(id, false); if(tagList.length() == 0) return null; diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java index e65dc142e..12eb7339a 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagService.java @@ -193,10 +193,15 @@ public final class TagService { * @param activeStatus criterion for specifying completed or uncompleted * @return empty array if no tags, otherwise array */ - public Tag[] getGroupedTags(Order order, Criterion activeStatus) { + public Tag[] getGroupedTags(Order order, Criterion activeStatus, boolean includeEmergent) { + Criterion criterion; + if (includeEmergent) + criterion = Criterion.and(activeStatus, MetadataCriteria.withKey(KEY)); + else + criterion = Criterion.and(activeStatus, MetadataCriteria.withKey(KEY), Criterion.not(TAG.in(getEmergentTags()))); Query query = Query.select(TAG, REMOTE_ID, COUNT). join(Join.inner(Task.TABLE, Metadata.TASK.eq(Task.ID))). - where(Criterion.and(activeStatus, MetadataCriteria.withKey(KEY))). + where(criterion). orderBy(order).groupBy(TAG); TodorooCursor cursor = metadataDao.query(query); try { @@ -211,15 +216,38 @@ public final class TagService { } } + private String[] getEmergentTags() { + TodorooCursor emergent = tagDataService.query(Query.select(TagData.NAME) + .where(Functions.bitwiseAnd(TagData.FLAGS, TagData.FLAG_EMERGENT).gt(0))); + try { + String[] tags = new String[emergent.getCount()]; + TagData data = new TagData(); + for (int i = 0; i < emergent.getCount(); i++) { + emergent.moveToPosition(i); + data.readFromCursor(emergent); + tags[i] = data.getValue(TagData.NAME); + } + return tags; + } finally { + emergent.close(); + } + } + /** * Return tags on the given task * * @param taskId * @return cursor. PLEASE CLOSE THE CURSOR! */ - public TodorooCursor getTags(long taskId) { - Query query = Query.select(TAG, REMOTE_ID).where(Criterion.and(MetadataCriteria.withKey(KEY), - MetadataCriteria.byTask(taskId))).orderBy(Order.asc(Functions.upper(TAG))); + public TodorooCursor getTags(long taskId, boolean includeEmergent) { + Criterion criterion; + if (includeEmergent) + criterion = Criterion.and(MetadataCriteria.withKey(KEY), + MetadataCriteria.byTask(taskId)); + else + criterion = Criterion.and(MetadataCriteria.withKey(KEY), + MetadataCriteria.byTask(taskId), Criterion.not(TAG.in(getEmergentTags()))); + Query query = Query.select(TAG, REMOTE_ID).where(criterion).orderBy(Order.asc(Functions.upper(TAG))); return metadataDao.query(query); } @@ -229,8 +257,8 @@ public final class TagService { * @param taskId * @return empty string if no tags, otherwise string */ - public String getTagsAsString(long taskId) { - return getTagsAsString(taskId, ", "); + public String getTagsAsString(long taskId, boolean includeEmergent) { + return getTagsAsString(taskId, ", ", includeEmergent); } /** @@ -239,9 +267,9 @@ public final class TagService { * @param taskId * @return empty string if no tags, otherwise string */ - public String getTagsAsString(long taskId, String separator) { + protected String getTagsAsString(long taskId, String separator, boolean includeEmergent) { StringBuilder tagBuilder = new StringBuilder(); - TodorooCursor tags = getTags(taskId); + TodorooCursor tags = getTags(taskId, includeEmergent); try { int length = tags.getCount(); Metadata metadata = new Metadata(); @@ -285,7 +313,7 @@ public final class TagService { HashMap tags = new HashMap(); Tag[] tagsByAlpha = getGroupedTags(TagService.GROUPED_TAGS_BY_ALPHA, - TaskCriteria.activeAndVisible()); + TaskCriteria.activeAndVisible(), false); for(Tag tag : tagsByAlpha) if(!TextUtils.isEmpty(tag.tag)) tags.put(tag.tag, tag); @@ -297,7 +325,7 @@ public final class TagService { tagData.readFromCursor(cursor); String tagName = tagData.getValue(TagData.NAME).trim(); Tag tag = new Tag(tagData); - if(tagData.getValue(TagData.DELETION_DATE) > 0) { + if(tagData.getValue(TagData.DELETION_DATE) > 0 || tagData.getFlag(TagData.FLAGS, TagData.FLAG_EMERGENT)) { tags.remove(tagName); continue; } diff --git a/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java b/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java index d538975c6..c1334d12a 100644 --- a/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/tags/TagsControlSet.java @@ -223,7 +223,7 @@ public final class TagsControlSet extends PopupControlSet { public void readFromTask(Task task) { super.readFromTask(task); if(model.getId() != AbstractModel.NO_ID) { - TodorooCursor cursor = tagService.getTags(model.getId()); + TodorooCursor cursor = tagService.getTags(model.getId(), false); LinkedHashSet tags = new LinkedHashSet(cursor.getCount()); try { for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) { diff --git a/astrid/res/drawable-hdpi/people_menu_button_blue_off.png b/astrid/res/drawable-hdpi/people_menu_button_blue_off.png new file mode 100644 index 000000000..919a1e72e Binary files /dev/null and b/astrid/res/drawable-hdpi/people_menu_button_blue_off.png differ diff --git a/astrid/res/drawable-hdpi/people_menu_button_blue_on.png b/astrid/res/drawable-hdpi/people_menu_button_blue_on.png new file mode 100644 index 000000000..95be72f90 Binary files /dev/null and b/astrid/res/drawable-hdpi/people_menu_button_blue_on.png differ diff --git a/astrid/res/drawable-hdpi/people_menu_button_dark_blue_off.png b/astrid/res/drawable-hdpi/people_menu_button_dark_blue_off.png new file mode 100644 index 000000000..a82daf39b Binary files /dev/null and b/astrid/res/drawable-hdpi/people_menu_button_dark_blue_off.png differ diff --git a/astrid/res/drawable-hdpi/people_menu_button_dark_blue_on.png b/astrid/res/drawable-hdpi/people_menu_button_dark_blue_on.png new file mode 100644 index 000000000..9b7cda0c9 Binary files /dev/null and b/astrid/res/drawable-hdpi/people_menu_button_dark_blue_on.png differ diff --git a/astrid/res/drawable-hdpi/people_menu_button_red_off.png b/astrid/res/drawable-hdpi/people_menu_button_red_off.png new file mode 100644 index 000000000..0cf8523b5 Binary files /dev/null and b/astrid/res/drawable-hdpi/people_menu_button_red_off.png differ diff --git a/astrid/res/drawable-hdpi/people_menu_button_red_on.png b/astrid/res/drawable-hdpi/people_menu_button_red_on.png new file mode 100644 index 000000000..5a0e865ad Binary files /dev/null and b/astrid/res/drawable-hdpi/people_menu_button_red_on.png differ diff --git a/astrid/res/drawable/icn_menu_friends.png b/astrid/res/drawable/icn_menu_friends.png new file mode 100644 index 000000000..d04d6058e Binary files /dev/null and b/astrid/res/drawable/icn_menu_friends.png differ diff --git a/astrid/res/drawable/icn_menu_friends_dark.png b/astrid/res/drawable/icn_menu_friends_dark.png new file mode 100644 index 000000000..3a698aeac Binary files /dev/null and b/astrid/res/drawable/icn_menu_friends_dark.png differ diff --git a/astrid/res/drawable/people_menu_button_blue.xml b/astrid/res/drawable/people_menu_button_blue.xml new file mode 100644 index 000000000..25dff3d5d --- /dev/null +++ b/astrid/res/drawable/people_menu_button_blue.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/astrid/res/drawable/people_menu_button_blue_off.png b/astrid/res/drawable/people_menu_button_blue_off.png new file mode 100644 index 000000000..ccf838127 Binary files /dev/null and b/astrid/res/drawable/people_menu_button_blue_off.png differ diff --git a/astrid/res/drawable/people_menu_button_blue_on.png b/astrid/res/drawable/people_menu_button_blue_on.png new file mode 100644 index 000000000..48521e6c3 Binary files /dev/null and b/astrid/res/drawable/people_menu_button_blue_on.png differ diff --git a/astrid/res/drawable/people_menu_button_dark_blue.xml b/astrid/res/drawable/people_menu_button_dark_blue.xml new file mode 100644 index 000000000..daad105da --- /dev/null +++ b/astrid/res/drawable/people_menu_button_dark_blue.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/astrid/res/drawable/people_menu_button_dark_blue_off.png b/astrid/res/drawable/people_menu_button_dark_blue_off.png new file mode 100644 index 000000000..e78e8af09 Binary files /dev/null and b/astrid/res/drawable/people_menu_button_dark_blue_off.png differ diff --git a/astrid/res/drawable/people_menu_button_dark_blue_on.png b/astrid/res/drawable/people_menu_button_dark_blue_on.png new file mode 100644 index 000000000..d1a6afc28 Binary files /dev/null and b/astrid/res/drawable/people_menu_button_dark_blue_on.png differ diff --git a/astrid/res/drawable/people_menu_button_red.xml b/astrid/res/drawable/people_menu_button_red.xml new file mode 100644 index 000000000..a2ed1592b --- /dev/null +++ b/astrid/res/drawable/people_menu_button_red.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/astrid/res/drawable/people_menu_button_red_off.png b/astrid/res/drawable/people_menu_button_red_off.png new file mode 100644 index 000000000..4fbdeb11d Binary files /dev/null and b/astrid/res/drawable/people_menu_button_red_off.png differ diff --git a/astrid/res/drawable/people_menu_button_red_on.png b/astrid/res/drawable/people_menu_button_red_on.png new file mode 100644 index 000000000..edefe1fe3 Binary files /dev/null and b/astrid/res/drawable/people_menu_button_red_on.png differ diff --git a/astrid/res/layout/header_people_view.xml b/astrid/res/layout/header_people_view.xml new file mode 100644 index 000000000..4d049fd58 --- /dev/null +++ b/astrid/res/layout/header_people_view.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + +