diff --git a/api/src/com/todoroo/astrid/data/User.java b/api/src/com/todoroo/astrid/data/User.java index 308f94e38..0d6d6e2cc 100644 --- a/api/src/com/todoroo/astrid/data/User.java +++ b/api/src/com/todoroo/astrid/data/User.java @@ -53,18 +53,6 @@ public final class User extends RemoteModel { public static final StringProperty PICTURE = new StringProperty( TABLE, "picture"); - /** User picture thumbnail */ - public static final StringProperty THUMB = new StringProperty( - TABLE, "thumb"); - - /** User last activity string */ - public static final StringProperty LAST_ACTIVITY = new StringProperty( - TABLE, "lastActivity"); - - /** User last activity date */ - public static final LongProperty LAST_ACTIVITY_DATE = new LongProperty( - TABLE, "lastActivityDate"); - /** Remote id */ public static final LongProperty REMOTE_ID = new LongProperty( TABLE, REMOTE_ID_PROPERTY_NAME); @@ -81,9 +69,6 @@ public final class User extends RemoteModel { defaultValues.put(NAME.name, ""); defaultValues.put(EMAIL.name, ""); defaultValues.put(PICTURE.name, ""); - defaultValues.put(THUMB.name, ""); - defaultValues.put(LAST_ACTIVITY.name, ""); - defaultValues.put(LAST_ACTIVITY_DATE.name, 0); } @Override diff --git a/astrid/.classpath b/astrid/.classpath index cc10d291f..a20a47fca 100644 --- a/astrid/.classpath +++ b/astrid/.classpath @@ -30,5 +30,6 @@ + diff --git a/astrid/libs/CWAC-SackOfViewsAdapter.jar b/astrid/libs/CWAC-SackOfViewsAdapter.jar new file mode 100644 index 000000000..0b43a064f Binary files /dev/null and b/astrid/libs/CWAC-SackOfViewsAdapter.jar differ diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java b/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java index 8db6b7c99..0eb7153ca 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/EditPeopleControlSet.java @@ -15,7 +15,10 @@ import android.app.Dialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.database.Cursor; import android.graphics.Color; +import android.net.Uri; +import android.provider.ContactsContract; import android.support.v4.app.Fragment; import android.text.TextUtils; import android.util.DisplayMetrics; @@ -37,17 +40,23 @@ import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; +import com.commonsware.cwac.merge.MergeAdapter; import com.timsu.astrid.R; import com.todoroo.andlib.data.TodorooCursor; import com.todoroo.andlib.service.Autowired; import com.todoroo.andlib.service.DependencyInjectionService; import com.todoroo.andlib.service.ExceptionService; +import com.todoroo.andlib.sql.Order; +import com.todoroo.andlib.sql.Query; import com.todoroo.andlib.utility.DialogUtilities; import com.todoroo.astrid.actfm.sync.ActFmPreferenceService; import com.todoroo.astrid.actfm.sync.ActFmSyncService; +import com.todoroo.astrid.activity.TaskEditFragment; +import com.todoroo.astrid.dao.UserDao; 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.helper.AsyncImageView; import com.todoroo.astrid.service.AstridDependencyInjector; import com.todoroo.astrid.service.MetadataService; @@ -64,6 +73,8 @@ public class EditPeopleControlSet extends PopupControlSet { public static final String EXTRA_TASK_ID = "task"; //$NON-NLS-1$ + private static final String CONTACT_CHOOSER_USER = "the_contact_user"; //$NON-NLS-1$ + private Task task; private final ArrayList nonSharedTags = new ArrayList(); @@ -74,6 +85,8 @@ public class EditPeopleControlSet extends PopupControlSet { @Autowired TaskService taskService; + @Autowired UserDao userDao; + @Autowired MetadataService metadataService; @Autowired ExceptionService exceptionService; @@ -102,16 +115,18 @@ public class EditPeopleControlSet extends PopupControlSet { private final View assignedClear; - private final ArrayList listValues = new ArrayList(); - private final int loginRequestCode; private boolean assignedToMe = false; private AssignedToUser taskRabbitUser = null; + private AssignedToUser contactPickerUser = null; + private boolean loadedUI = false; + private boolean dontClearAssignedCustom = false; + private final List listeners = new LinkedList(); public interface AssignedChangedListener { @@ -175,7 +190,9 @@ public class EditPeopleControlSet extends PopupControlSet { @Override public void readFromTask(Task sourceTask) { setTask(sourceTask); - assignedCustom.setText(""); //$NON-NLS-1$ + if (!dontClearAssignedCustom) + assignedCustom.setText(""); //$NON-NLS-1$ + dontClearAssignedCustom = false; setUpData(task, null); } @@ -333,112 +350,200 @@ public class EditPeopleControlSet extends PopupControlSet { HashSet emails = new HashSet(); HashMap names = new HashMap(); + ArrayList coreUsers = new ArrayList(); + ArrayList listUsers = new ArrayList(); + ArrayList astridUsers = new ArrayList(); + int assignedIndex = 0; try { - if(t.getValue(Task.USER_ID) > 0) { - JSONObject user = new JSONObject(t.getValue(Task.USER)); - sharedPeople.add(0, user); - } - + ArrayList coreUsersJson = new ArrayList(); JSONObject myself = new JSONObject(); myself.put("id", Task.USER_ID_SELF); - sharedPeople.add(0, myself); + myself.put("picture", ActFmPreferenceService.thisUser().optString("picture")); + coreUsersJson.add(myself); - boolean hasTags = t.getTransitory(TaskService.TRANS_TAGS) != null && - ((HashSet)t.getTransitory(TaskService.TRANS_TAGS)).size() > 0; - if (actFmPreferenceService.isLoggedIn() && hasTags) { + boolean hasTags = t.getTransitory("tags") != null && + ((HashSet)t.getTransitory("tags")).size() > 0; + boolean addUnassigned = actFmPreferenceService.isLoggedIn() && hasTags; + if (addUnassigned) { JSONObject unassigned = new JSONObject(); unassigned.put("id", Task.USER_ID_UNASSIGNED); - sharedPeople.add(1, unassigned); + unassigned.put("default_picture", R.drawable.icn_anyone); + coreUsersJson.add(unassigned); } - // de-duplicate by user id and/or email - listValues.clear(); - for(int i = 0; i < sharedPeople.size(); i++) { - JSONObject person = sharedPeople.get(i); - if(person == null) - continue; - long id = person.optLong("id", -2); - if(id == ActFmPreferenceService.userId() || (id >= -1 && userIds.contains(id))) - continue; - userIds.add(id); - - String email = person.optString("email"); - if(!TextUtils.isEmpty(email) && emails.contains(email)) - continue; - emails.add(email); - - String name = person.optString("name"); - if(id == 0) - name = activity.getString(R.string.actfm_EPA_assign_me); - if (id == -1) - name = activity.getString(R.string.actfm_EPA_unassigned); - - AssignedToUser atu = new AssignedToUser(name, person); - listValues.add(atu); - if(names.containsKey(name)) { - AssignedToUser user = names.get(name); - if(user != null && user.user.has("email")) { - user.label += " (" + user.user.optString("email") + ")"; - names.put(name, null); - } - if(!TextUtils.isEmpty("email")) - atu.label += " (" + email + ")"; - } else if(TextUtils.isEmpty(name)) { - if(!TextUtils.isEmpty("email")) - atu.label = email; - else - listValues.remove(atu); - } else - names.put(name, atu); + if(t.getValue(Task.USER_ID) > 0) { + JSONObject user = new JSONObject(t.getValue(Task.USER)); + coreUsersJson.add(0, user); } - String assignedStr = t.getValue(Task.USER); - if (!TextUtils.isEmpty(assignedStr)) { - JSONObject assigned = new JSONObject(assignedStr); - long assignedId = assigned.optLong("id", -2); - String assignedEmail = assigned.optString("email"); - for (int i = 0; i < listValues.size(); i++) { - JSONObject user = listValues.get(i).user; - if (user != null) { - if (user.optLong("id") == assignedId || - (user.optString("email").equals(assignedEmail) && - !(TextUtils.isEmpty(assignedEmail)))) - assignedIndex = i; - } - } - } + ArrayList astridFriends = getAstridFriends(); + + // de-duplicate by user id and/or email + coreUsers = convertJsonUsersToAssignedUsers(coreUsersJson, userIds, emails, names); + listUsers = convertJsonUsersToAssignedUsers(sharedPeople, userIds, emails, names); + astridUsers = convertJsonUsersToAssignedUsers(astridFriends, userIds, emails, names); + + contactPickerUser = new AssignedToUser(activity.getString(R.string.actfm_EPA_choose_contact), + new JSONObject().put("default_picture", R.drawable.icn_friends) + .put(CONTACT_CHOOSER_USER, true)); + int contactsIndex = addUnassigned ? 2 : 1; + coreUsers.add(contactsIndex, contactPickerUser); for (AssignedChangedListener l : listeners) { if (l.shouldShowTaskRabbit()) { taskRabbitUser = new AssignedToUser(activity.getString(R.string.actfm_EPA_task_rabbit), new JSONObject().put("default_picture", R.drawable.task_rabbit_image)); - listValues.add(taskRabbitUser); + int taskRabbitIndex = addUnassigned ? 3 : 2; + coreUsers.add(taskRabbitIndex, taskRabbitUser); if(l.didPostToTaskRabbit()){ - assignedIndex = listValues.size()-1; + assignedIndex = taskRabbitIndex; } } } + + if (assignedIndex == 0) { + assignedIndex = findAssignedIndex(t, coreUsers, listUsers, astridUsers); + } + } catch (JSONException e) { exceptionService.reportError("json-reading-data", e); } selected = assignedIndex; - final AssignedUserAdapter usersAdapter = new AssignedUserAdapter(activity, listValues); + final MergeAdapter mergeAdapter = new MergeAdapter(); + AssignedUserAdapter coreUserAdapter = new AssignedUserAdapter(activity, coreUsers, 0); + AssignedUserAdapter listUserAdapter = new AssignedUserAdapter(activity, listUsers, coreUserAdapter.getCount() + 1); + int offsetForAstridUsers = listUserAdapter.getCount() > 0 ? 2 : 1; + AssignedUserAdapter astridUserAdapter = new AssignedUserAdapter(activity, astridUsers, coreUserAdapter.getCount() + listUserAdapter.getCount() + offsetForAstridUsers); + + LayoutInflater inflater = activity.getLayoutInflater(); + TextView header1 = (TextView) inflater.inflate(R.layout.list_header, null); + header1.setText(R.string.actfm_EPA_assign_header_members); + TextView header2 = (TextView) inflater.inflate(R.layout.list_header, null); + header2.setText(R.string.actfm_EPA_assign_header_friends); + + mergeAdapter.addAdapter(coreUserAdapter); + if (listUserAdapter.getCount() > 0) { + mergeAdapter.addView(header1); + mergeAdapter.addAdapter(listUserAdapter); + } + if (astridUserAdapter.getCount() > 0) { + mergeAdapter.addView(header2); + mergeAdapter.addAdapter(astridUserAdapter); + } + activity.runOnUiThread(new Runnable() { @Override public void run() { - assignedList.setAdapter(usersAdapter); + assignedList.setAdapter(mergeAdapter); assignedList.setItemChecked(selected, true); refreshDisplayView(); } }); } + @SuppressWarnings("nls") + private ArrayList convertJsonUsersToAssignedUsers(ArrayList jsonUsers, + HashSet userIds, HashSet emails, HashMap names) { + ArrayList users = new ArrayList(); + for(int i = 0; i < jsonUsers.size(); i++) { + JSONObject person = jsonUsers.get(i); + if(person == null) + continue; + long id = person.optLong("id", -2); + if(id == ActFmPreferenceService.userId() || (id >= -1 && userIds.contains(id))) + continue; + userIds.add(id); + + String email = person.optString("email"); + if(!TextUtils.isEmpty(email) && emails.contains(email)) + continue; + emails.add(email); + + String name = person.optString("name"); + if(id == 0) + name = activity.getString(R.string.actfm_EPA_assign_me); + if (id == -1) + name = activity.getString(R.string.actfm_EPA_unassigned); + + AssignedToUser atu = new AssignedToUser(name, person); + users.add(atu); + if(names.containsKey(name)) { + AssignedToUser user = names.get(name); + if(user != null && user.user.has("email")) { + user.label += " (" + user.user.optString("email") + ")"; + names.put(name, null); + } + if(!TextUtils.isEmpty("email")) + atu.label += " (" + email + ")"; + } else if(TextUtils.isEmpty(name)) { + if(!TextUtils.isEmpty("email")) + atu.label = email; + else + users.remove(atu); + } else + names.put(name, atu); + } + return users; + } + + @SuppressWarnings("nls") + private int findAssignedIndex(Task t, ArrayList... userLists) throws JSONException { + String assignedStr = t.getValue(Task.USER); + if (!TextUtils.isEmpty(assignedStr)) { + JSONObject assigned = new JSONObject(assignedStr); + long assignedId = assigned.optLong("id", -2); + String assignedEmail = assigned.optString("email"); + + int index = 0; + for (ArrayList userList : userLists) { + for (int i = 0; i < userList.size(); i++) { + JSONObject user = userList.get(i).user; + if (user != null) { + if (user.optLong("id") == assignedId || + (user.optString("email").equals(assignedEmail) && + !(TextUtils.isEmpty(assignedEmail)))) + return index; + } + index++; + } + index++; // Add one for headers separating user lists + } + } + return 0; + } + + private ArrayList getAstridFriends() { + ArrayList astridFriends = new ArrayList(); + TodorooCursor users = userDao.query(Query.select(User.PROPERTIES).orderBy(Order.asc(User.NAME))); + try { + User user = new User(); + for (users.moveToFirst(); !users.isAfterLast(); users.moveToNext()) { + user.readFromCursor(users); + JSONObject userJson = new JSONObject(); + try { + ActFmSyncService.JsonHelper.jsonFromUser(userJson, user); + astridFriends.add(userJson); + } catch (JSONException e) { + // Ignored + } + } + } finally { + users.close(); + } + return astridFriends; + } + + + private class AssignedUserAdapter extends ArrayAdapter { - public AssignedUserAdapter(Context context, ArrayList people) { + private final int positionOffset; + + public AssignedUserAdapter(Context context, ArrayList people, int positionOffset) { super(context, R.layout.assigned_adapter_row, people); + this.positionOffset = positionOffset; } @SuppressWarnings("nls") @@ -448,21 +553,14 @@ public class EditPeopleControlSet extends PopupControlSet { convertView = activity.getLayoutInflater().inflate(R.layout.assigned_adapter_row, parent, false); CheckedTextView ctv = (CheckedTextView) convertView.findViewById(android.R.id.text1); super.getView(position, ctv, parent); - if (assignedList.getCheckedItemPosition() == position) { + if (assignedList.getCheckedItemPosition() == position + positionOffset) { ctv.setChecked(true); } else { ctv.setChecked(false); } AsyncImageView image = (AsyncImageView) convertView.findViewById(R.id.person_image); image.setDefaultImageResource(R.drawable.icn_default_person_image); - if (position == 0) { - image.setUrl(ActFmPreferenceService.thisUser().optString("picture")); - } else if (position == 1) { - image.setUrl(""); - image.setDefaultImageResource(R.drawable.icn_anyone); - } else { - image.setUrl(getItem(position).user.optString("picture")); - } + image.setUrl(getItem(position).user.optString("picture")); if (getItem(position).user.optInt("default_picture", 0) > 0) { image.setDefaultImageResource(getItem(position).user.optInt("default_picture")); } @@ -487,8 +585,6 @@ public class EditPeopleControlSet extends PopupControlSet { for (AssignedChangedListener l : listeners) { if(l.showTaskRabbitForUser(user.label, user.user)) { -// assignedList.setItemChecked(selected, true); -// assignedList.setItemChecked(position, false); assignedDisplay.setText(user.toString()); assignedCustom.setText(""); //$NON-NLS-1$ DialogUtilities.dismissDialog(activity, dialog); @@ -496,6 +592,13 @@ public class EditPeopleControlSet extends PopupControlSet { } } + + if (user.user.has(CONTACT_CHOOSER_USER)) { + Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.Contacts.CONTENT_URI); + fragment.startActivityForResult(intent, TaskEditFragment.REQUEST_CODE_CONTACT); + return; + } + assignedDisplay.setText(user.toString()); assignedCustom.setText(""); //$NON-NLS-1$ selected = position; @@ -584,10 +687,7 @@ public class EditPeopleControlSet extends PopupControlSet { return true; AssignedToUser item = (AssignedToUser) assignedList.getAdapter().getItem(assignedList.getCheckedItemPosition()); if (item != null) { - if (item.equals(taskRabbitUser)) { //don't want to ever set the user as the task rabbit user - - /*item = (AssignedToUser) assignedList.getAdapter().getItem(0); - selected = 0;*/ + if (item.equals(taskRabbitUser) || item.equals(contactPickerUser)) { //don't want to ever set the user as the task rabbit user return true; } userJson = item.user; @@ -811,9 +911,42 @@ public class EditPeopleControlSet extends PopupControlSet { // clear user values & reset them to trigger a save task.clearValue(Task.USER_ID); task.clearValue(Task.USER); - } - else if (requestCode == loginRequestCode) + } else if (requestCode == loginRequestCode) { makePrivateTask(); + } else if (requestCode == TaskEditFragment.REQUEST_CODE_CONTACT && resultCode == Activity.RESULT_OK) { + Uri contactData = data.getData(); + String contactId = contactData.getLastPathSegment(); + String[] args = { contactId }; + String[] projection = { ContactsContract.CommonDataKinds.Email.DATA }; + String selection = ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?"; //$NON-NLS-1$ + Cursor emailCursor = activity.managedQuery(ContactsContract.CommonDataKinds.Email.CONTENT_URI, projection, selection, args, null); + if (emailCursor.getCount() > 0) { + emailCursor.moveToFirst(); + int emailIndex = emailCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA); + String email = emailCursor.getString(emailIndex); + if (!TextUtils.isEmpty(email)) { + String[] nameProjection = { ContactsContract.Contacts.DISPLAY_NAME }; + Cursor nameCursor = activity.managedQuery(contactData, nameProjection, null, null, null); + if (nameCursor.getCount() > 0) { + nameCursor.moveToFirst(); + int nameIndex = nameCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME); + String name = nameCursor.getString(nameIndex); + if (!TextUtils.isEmpty(name)) { + StringBuilder fullName = new StringBuilder(); + fullName.append(name).append(" <").append(email).append('>'); //$NON-NLS-1$ + email = fullName.toString(); + } + } + assignedCustom.setText(email); + dontClearAssignedCustom = true; + dialog.dismiss(); + } else { + DialogUtilities.okDialog(activity, activity.getString(R.string.TEA_contact_error), null); + } + } else { + DialogUtilities.okDialog(activity, activity.getString(R.string.TEA_contact_error), null); + } + } } @Override @@ -828,6 +961,21 @@ public class EditPeopleControlSet extends PopupControlSet { } } + @Override + protected boolean onOkClick() { + if (!TextUtils.isEmpty(assignedCustom.getText())) { + JSONObject assigned = PeopleContainer.createUserJson(assignedCustom); + String email = assigned.optString("email"); //$NON-NLS-1$ + if (!TextUtils.isEmpty(email) && email.indexOf('@') == -1) { + assignedCustom.requestFocus(); + DialogUtilities.okDialog(activity, activity.getString(R.string.actfm_EPA_invalid_email, + assigned.optString("email")), null); //$NON-NLS-1$ + return false; + } + } + return super.onOkClick(); + } + @Override protected void additionalDialogSetup() { super.additionalDialogSetup(); diff --git a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmDataService.java b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmDataService.java index 49b9168b8..1621a5ac1 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmDataService.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmDataService.java @@ -22,9 +22,11 @@ import com.todoroo.andlib.sql.Query; import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.dao.TaskDao.TaskCriteria; +import com.todoroo.astrid.dao.UserDao; 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.notes.NoteMetadata; import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.TagDataService; @@ -46,6 +48,8 @@ public final class ActFmDataService { @Autowired TaskDao taskDao; + @Autowired UserDao userDao; + @Autowired MetadataService metadataService; @Autowired ActFmPreferenceService actFmPreferenceService; @@ -198,4 +202,26 @@ public final class ActFmDataService { } } + /** + * Save / Merge JSON user + * @param userObject + * @throws JSONException + */ + @SuppressWarnings("nls") + public void saveUserData(JSONObject userObject) throws JSONException { + TodorooCursor cursor = userDao.query(Query.select(User.PROPERTIES).where( + User.REMOTE_ID.eq(userObject.get("id")))); + try { + cursor.moveToFirst(); + User user = new User(); + if (!cursor.isAfterLast()) { + user.readFromCursor(cursor); + } + ActFmSyncService.JsonHelper.userFromJson(userObject, user); + userDao.persist(user); + + } finally { + cursor.close(); + } + } } 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 74960799a..e218524ac 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncService.java @@ -59,6 +59,7 @@ import com.todoroo.astrid.data.TagData; import com.todoroo.astrid.data.Task; import com.todoroo.astrid.data.TaskApiDao; import com.todoroo.astrid.data.Update; +import com.todoroo.astrid.data.User; import com.todoroo.astrid.helper.ImageDiskCache; import com.todoroo.astrid.service.MetadataService; import com.todoroo.astrid.service.StatisticsConstants; @@ -727,6 +728,29 @@ public final class ActFmSyncService { return result.optInt("time", 0); } + public int fetchUsers(int serverTime) throws JSONException, IOException { + if (!checkForToken()) + return 0; + + JSONObject result = actFmInvoker.invoke("user_list", + "token", token, "modified_after", serverTime); + JSONArray users = result.getJSONArray("list"); + HashSet ids = new HashSet(); + for (int i = 0; i < users.length(); i++) { + JSONObject userObject = users.getJSONObject(i); + ids.add(userObject.optLong("id")); + actFmDataService.saveUserData(userObject); + } + + if (serverTime == 0) { + Long[] allIds = ids.toArray(new Long[ids.size()]); + actFmDataService.userDao.deleteWhere(Criterion.not(User.REMOTE_ID.in(allIds))); + } + + return result.optInt("time", 0); + } + + /** * Fetch active tasks asynchronously * @param manual @@ -1134,6 +1158,20 @@ public final class ActFmSyncService { return item.optLong(key, 0) * 1000L; } + public static void userFromJson(JSONObject json, User model) throws JSONException { + model.setValue(User.REMOTE_ID, json.getLong("id")); + model.setValue(User.NAME, json.optString("name")); + model.setValue(User.EMAIL, json.optString("email")); + model.setValue(User.PICTURE, json.optString("picture")); + } + + public static void jsonFromUser(JSONObject json, User model) throws JSONException { + json.put("id", model.getValue(User.REMOTE_ID)); + json.put("name", model.getValue(User.NAME)); + json.put("email", model.getValue(User.EMAIL)); + json.put("picture", model.getValue(User.PICTURE)); + } + public static void updateFromJson(JSONObject json, Update model) throws JSONException { model.setValue(Update.REMOTE_ID, json.getLong("id")); readUser(json.getJSONObject("user"), model, Update.USER_ID, Update.USER); 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 3912c4107..b295c842f 100644 --- a/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java +++ b/astrid/plugin-src/com/todoroo/astrid/actfm/sync/ActFmSyncV2Provider.java @@ -103,6 +103,8 @@ public class ActFmSyncV2Provider extends SyncV2Provider { private static final String LAST_TAG_FETCH_TIME = "actfm_lastTag"; //$NON-NLS-1$ + private static final String LAST_USERS_FETCH_TIME = "actfm_lastUsers"; //$NON-NLS-1$ + // --- synchronize active tasks @Override @@ -112,12 +114,15 @@ public class ActFmSyncV2Provider extends SyncV2Provider { new Thread(new Runnable() { public void run() { callback.started(); - callback.incrementMax(100); + callback.incrementMax(120); - final AtomicInteger finisher = new AtomicInteger(2); + final AtomicInteger finisher = new AtomicInteger(3); actFmPreferenceService.recordSyncStart(); + + startUsersFetcher(manual, callback, finisher); + startTagFetcher(callback, finisher); actFmSyncService.waitUntilEmpty(); @@ -128,6 +133,31 @@ public class ActFmSyncV2Provider extends SyncV2Provider { }).start(); } + /** fetch changes to users/friends */ + private void startUsersFetcher(final boolean manual, final SyncResultCallback callback, + final AtomicInteger finisher) { + new Thread(new Runnable() { + @Override + public void run() { + int time = manual ? 0 : Preferences.getInt(LAST_USERS_FETCH_TIME, 0); + try { + time = actFmSyncService.fetchUsers(time); + Preferences.setInt(LAST_USERS_FETCH_TIME, time); + } catch (JSONException e) { + handler.handleException("actfm-sync", e, e.toString()); //$NON-NLS-1$ + } catch (IOException e) { + handler.handleException("actfm-sync", e, e.toString()); //$NON-NLS-1$ + } finally { + callback.incrementProgress(20); + if(finisher.decrementAndGet() == 0) { + actFmPreferenceService.recordSuccessfulSync(); + callback.finished(); + } + } + } + }).start(); + } + /** fetch changes to tags */ private void startTagFetcher(final SyncResultCallback callback, final AtomicInteger finisher) { diff --git a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java index c1ffacc9c..4b714bdfd 100644 --- a/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/repeats/RepeatControlSet.java @@ -389,17 +389,17 @@ public class RepeatControlSet extends PopupControlSet { } @Override - protected Dialog buildDialog(String title, final DialogInterface.OnClickListener okListener, final DialogInterface.OnCancelListener cancelListener) { + protected Dialog buildDialog(String title, final PopupDialogClickListener okListener, final DialogInterface.OnCancelListener cancelListener) { - DialogInterface.OnClickListener doRepeatButton = new DialogInterface.OnClickListener() { + PopupDialogClickListener doRepeatButton = new PopupDialogClickListener() { @Override - public void onClick(DialogInterface d, int which) { + public boolean onClick(DialogInterface d, int which) { doRepeat = true; - okListener.onClick(d, which); for (RepeatChangedListener l : listeners) { l.repeatChanged(doRepeat); } + return okListener.onClick(d, which); } }; final Dialog d = super.buildDialog(title, doRepeatButton, cancelListener); diff --git a/astrid/plugin-src/com/todoroo/astrid/taskrabbit/TaskRabbitNameControlSet.java b/astrid/plugin-src/com/todoroo/astrid/taskrabbit/TaskRabbitNameControlSet.java index d1720247d..37ecedf47 100644 --- a/astrid/plugin-src/com/todoroo/astrid/taskrabbit/TaskRabbitNameControlSet.java +++ b/astrid/plugin-src/com/todoroo/astrid/taskrabbit/TaskRabbitNameControlSet.java @@ -176,10 +176,10 @@ public class TaskRabbitNameControlSet extends PopupControlSet implements TaskRab } @Override - protected void onOkClick() { - super.onOkClick(); + protected boolean onOkClick() { InputMethodManager imm = (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); + return super.onOkClick(); } @Override diff --git a/astrid/res/drawable/btn_add.xml b/astrid/res/drawable/btn_add.xml new file mode 100644 index 000000000..eb597adab --- /dev/null +++ b/astrid/res/drawable/btn_add.xml @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/astrid/res/drawable/btn_add_normal.png b/astrid/res/drawable/btn_add_normal.png new file mode 100644 index 000000000..56cf1c7b2 Binary files /dev/null and b/astrid/res/drawable/btn_add_normal.png differ diff --git a/astrid/res/drawable/btn_add_pressed.png b/astrid/res/drawable/btn_add_pressed.png new file mode 100644 index 000000000..25e764d8f Binary files /dev/null and b/astrid/res/drawable/btn_add_pressed.png differ diff --git a/astrid/res/layout/assigned_adapter_row.xml b/astrid/res/layout/assigned_adapter_row.xml index 95dbffd16..a8644ccda 100644 --- a/astrid/res/layout/assigned_adapter_row.xml +++ b/astrid/res/layout/assigned_adapter_row.xml @@ -2,12 +2,12 @@ +