Merge remote-tracking branch 'upstream/master' into 130221_sb_gtasks_new_sync

pull/14/head
Sam Bosley 11 years ago
commit 8d298dda58

@ -139,6 +139,18 @@ public abstract class AbstractModel implements Parcelable, Cloneable {
return getMergedValues().hashCode() ^ getClass().hashCode();
}
@Override
@SuppressWarnings("nls")
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(getClass().getSimpleName()).append("\n")
.append("set values:\n")
.append(setValues).append("\n")
.append("values:\n")
.append(values).append("\n");
return builder.toString();
}
@Override
public AbstractModel clone() {
AbstractModel clone;

@ -266,4 +266,9 @@ public class AstridApiConstants {
*/
public static final String BROADCAST_EVENT_TAG_DELETED = API_PACKAGE + ".TAG_DELETED";
/**
* Action name for broadcast intent notifying that tag was renamed
*/
public static final String BROADCAST_EVENT_TAG_RENAMED = API_PACKAGE + ".TAG_RENAMED";
}

@ -134,6 +134,7 @@ public final class TagData extends RemoteModel {
TABLE, "activities_pushed_at", Property.PROP_FLAG_DATE);
/** Tag ordering */
@Deprecated
public static final StringProperty TAG_ORDERING = new StringProperty(
TABLE, "tagOrdering");

@ -133,16 +133,20 @@ public final class User extends RemoteModel {
return getDisplayName(NAME, FIRST_NAME, LAST_NAME);
}
private String getCheckedString(StringProperty stringProperty) {
return containsNonNullValue(stringProperty) ? getValue(stringProperty) : null;
}
public String getDisplayName(StringProperty nameProperty, StringProperty firstNameProperty, StringProperty lastNameProperty) {
String name = getValue(nameProperty);
String name = getCheckedString(nameProperty);
if (!(TextUtils.isEmpty(name) || "null".equals(name)))
return name;
String firstName = getValue(firstNameProperty);
String firstName = getCheckedString(firstNameProperty);
boolean firstNameEmpty = TextUtils.isEmpty(firstName) || "null".equals(firstName);
String lastName = getValue(lastNameProperty);
String lastName = getCheckedString(lastNameProperty);
boolean lastNameEmpty = TextUtils.isEmpty(lastName) || "null".equals(lastName);
if (firstNameEmpty && lastNameEmpty)
return getValue(EMAIL);
return getCheckedString(EMAIL);
StringBuilder nameBuilder = new StringBuilder();
if (!firstNameEmpty)
nameBuilder.append(firstName).append(" ");

@ -64,7 +64,25 @@ import com.todoroo.astrid.actfm.sync.ActFmInvoker;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmServiceException;
import com.todoroo.astrid.actfm.sync.ActFmSyncMonitor;
import com.todoroo.astrid.actfm.sync.messages.ConstructOutstandingTableFromMasterTable;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.activity.Eula;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TagOutstandingDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskListMetadataDao;
import com.todoroo.astrid.dao.TaskListMetadataOutstandingDao;
import com.todoroo.astrid.dao.TaskOutstandingDao;
import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.dao.UserActivityOutstandingDao;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.TagOutstanding;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.TaskListMetadataOutstanding;
import com.todoroo.astrid.data.TaskOutstanding;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.data.UserActivityOutstanding;
import com.todoroo.astrid.gtasks.auth.ModernAuthManager;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.MarketStrategy.AmazonMarketStrategy;
@ -90,6 +108,25 @@ public class ActFmLoginActivity extends FragmentActivity implements AuthListener
@Autowired
protected ActFmPreferenceService actFmPreferenceService;
@Autowired
private TaskDao taskDao;
@Autowired
private TaskOutstandingDao taskOutstandingDao;
@Autowired
private TagDataDao tagDataDao;
@Autowired
private TagOutstandingDao tagOutstandingDao;
@Autowired
private UserActivityDao userActivityDao;
@Autowired
private UserActivityOutstandingDao userActivityOutstandingDao;
@Autowired
private TaskListMetadataDao taskListMetadataDao;
@Autowired
private TaskListMetadataOutstandingDao taskListMetadataOutstandingDao;
@Autowired protected SyncV2Service syncService;
private final ActFmInvoker actFmInvoker = new ActFmInvoker();
private Random rand;
@ -527,6 +564,13 @@ public class ActFmLoginActivity extends FragmentActivity implements AuthListener
if (result.optBoolean("new")) { // Report new user statistic
StatisticsService.reportEvent(StatisticsConstants.ACTFM_NEW_USER, "provider", provider);
}
// Successful login, create outstanding entries
if (!TextUtils.isEmpty(token)) {
new ConstructOutstandingTableFromMasterTable<Task, TaskOutstanding>(NameMaps.TABLE_ID_TASKS, taskDao, taskOutstandingDao, Task.CREATION_DATE).execute();
new ConstructOutstandingTableFromMasterTable<TagData, TagOutstanding>(NameMaps.TABLE_ID_TAGS, tagDataDao, tagOutstandingDao, TagData.CREATION_DATE).execute();
new ConstructOutstandingTableFromMasterTable<UserActivity, UserActivityOutstanding>(NameMaps.TABLE_ID_USER_ACTIVITY, userActivityDao, userActivityOutstandingDao, UserActivity.CREATED_AT).execute();
new ConstructOutstandingTableFromMasterTable<TaskListMetadata, TaskListMetadataOutstanding>(NameMaps.TABLE_ID_TASK_LIST_METADATA, taskListMetadataDao, taskListMetadataOutstandingDao, null).execute();
}
runOnUiThread(new Runnable() {
public void run() {
DialogUtilities.dismissDialog(ActFmLoginActivity.this, progressDialog);

@ -370,6 +370,18 @@ public class EditPeopleControlSet extends PopupControlSet {
});
}
private String getLongOrStringId(JSONObject obj, String defaultValue) {
try {
long value = obj.getLong("id"); //$NON-NLS-1$
return Long.toString(value);
} catch (JSONException e) {
String value = obj.optString("id"); //$NON-NLS-1$
if (TextUtils.isEmpty(value))
value = defaultValue;
return value;
}
}
@SuppressWarnings("nls")
private ArrayList<AssignedToUser> convertJsonUsersToAssignedUsers(ArrayList<JSONObject> jsonUsers,
HashSet<String> userIds, HashSet<String> emails, HashMap<String, AssignedToUser> names) {
@ -378,7 +390,7 @@ public class EditPeopleControlSet extends PopupControlSet {
JSONObject person = jsonUsers.get(i);
if(person == null)
continue;
String id = Long.toString(person.optLong("id", -2));
String id = getLongOrStringId(person, Task.USER_ID_EMAIL);
if(ActFmPreferenceService.userId().equals(id) || ((Task.USER_ID_UNASSIGNED.equals(id) || Task.isRealUserId(id)) && userIds.contains(id)))
continue;
userIds.add(id);
@ -418,11 +430,11 @@ public class EditPeopleControlSet extends PopupControlSet {
@SuppressWarnings("nls")
private int findAssignedIndex(Task t, ArrayList<AssignedToUser>... userLists) {
String assignedStr = t.getValue(Task.USER);
long assignedId = -2;
String assignedId = Task.USER_ID_IGNORE;
String assignedEmail = t.getValue(Task.USER_ID);
try {
JSONObject assigned = new JSONObject(assignedStr);
assignedId = assigned.optLong("id", -2);
assignedId = getLongOrStringId(assigned, Task.USER_ID_EMAIL);
assignedEmail = assigned.optString("email");
} catch (JSONException e) {
User assignedUser = userDao.fetch(t.getValue(Task.USER_ID), User.PROPERTIES);
@ -430,8 +442,14 @@ public class EditPeopleControlSet extends PopupControlSet {
try {
if (assignedUser != null) {
ActFmSyncService.JsonHelper.jsonFromUser(assigned, assignedUser);
assignedId = assigned.optLong("id", -2);
try {
assignedId = assigned.getString("id");
} catch (JSONException e2) {
assignedId = getLongOrStringId(assigned, Task.USER_ID_EMAIL);
}
assignedEmail = assigned.optString("email");
} else if (!t.getValue(Task.USER_ID).contains("@")) {
assignedId = t.getValue(Task.USER_ID);
}
} catch (JSONException e2) {
//
@ -443,7 +461,7 @@ public class EditPeopleControlSet extends PopupControlSet {
for (int i = 0; i < userList.size(); i++) {
JSONObject user = userList.get(i).user;
if (user != null) {
if (user.optLong("id") == assignedId ||
if (getLongOrStringId(user, Task.USER_ID_EMAIL).equals(assignedId) ||
(user.optString("email").equals(assignedEmail) &&
!(TextUtils.isEmpty(assignedEmail))))
return index;
@ -649,23 +667,22 @@ public class EditPeopleControlSet extends PopupControlSet {
activity.getString(R.string.actfm_EPA_invalid_email, userJson.optString("email")));
}
if(userJson == null || Task.USER_ID_SELF.equals(Long.toString(userJson.optLong("id", -2)))) {
dirty = task.getValue(Task.USER_ID) == Task.USER_ID_SELF ? dirty : true;
if(userJson == null || Task.USER_ID_SELF.equals(getLongOrStringId(userJson, Task.USER_ID_EMAIL))) {
dirty = Task.USER_ID_SELF.equals(task.getValue(Task.USER_ID)) ? dirty : true;
task.setValue(Task.USER_ID, Task.USER_ID_SELF);
task.setValue(Task.USER, "");
assignedToMe = true;
} else if(Task.USER_ID_UNASSIGNED.equals(Long.toString(userJson.optLong("id")))) {
dirty = task.getValue(Task.USER_ID) == Task.USER_ID_UNASSIGNED ? dirty : true;
} else if(Task.USER_ID_UNASSIGNED.equals(getLongOrStringId(userJson, Task.USER_ID_SELF))) {
dirty = Task.USER_ID_UNASSIGNED.equals(task.getValue(Task.USER_ID)) ? dirty : true;
task.setValue(Task.USER_ID, Task.USER_ID_UNASSIGNED);
task.setValue(Task.USER, "");
} else {
String user = userJson.toString();
String taskUserId = Task.USER_ID_EMAIL;
String taskUserEmail = "";
try {
@SuppressWarnings("deprecation") // For backwards compatibility
JSONObject taskUser = new JSONObject(task.getValue(Task.USER));
taskUserId = Long.toString(taskUser.optLong("id", -2));
taskUserId = getLongOrStringId(taskUser, Task.USER_ID_EMAIL);
taskUserEmail = taskUser.optString("email");
} catch (JSONException e) {
// sad times
@ -673,14 +690,14 @@ public class EditPeopleControlSet extends PopupControlSet {
if (Task.userIdIsEmail(taskUserId))
taskUserEmail = taskUserId;
}
String userId = Long.toString(userJson.optLong("id", -2));
String userId = getLongOrStringId(userJson, Task.USER_ID_EMAIL);
String userEmail = userJson.optString("email");
boolean match = userId.equals(taskUserId);
match = match || (userEmail.equals(taskUserEmail) && !TextUtils.isEmpty(userEmail));
dirty = match ? dirty : true;
String willAssignToId = Long.toString(userJson.optLong("id", -2));
String willAssignToId = getLongOrStringId(userJson, Task.USER_ID_EMAIL);
task.setValue(Task.USER_ID, willAssignToId);
if (Task.USER_ID_EMAIL.equals(task.getValue(Task.USER_ID)))
task.setValue(Task.USER_ID, userEmail);
@ -760,7 +777,7 @@ public class EditPeopleControlSet extends PopupControlSet {
userJson = item.user;
}
if(userJson == null || Task.USER_ID_SELF.equals(Long.toString(userJson.optLong("id", -2)))) { //$NON-NLS-1$
if(userJson == null || Task.USER_ID_SELF.equals(getLongOrStringId(userJson, Task.USER_ID_EMAIL))) {
return true;
}

@ -274,13 +274,13 @@ public class TagSettingsActivity extends FragmentActivity {
if (nameChanged) {
if (oldName.equalsIgnoreCase(newName)) { // Change the capitalization of a list manually
tagData.setValue(TagData.NAME, newName);
service.renameCaseSensitive(oldName, newName);
service.rename(tagData.getUuid(), newName);
} else { // Rename list--check for existing name
newName = service.getTagWithCase(newName);
tagName.setText(newName);
if (!newName.equals(oldName)) {
tagData.setValue(TagData.NAME, newName);
service.rename(oldName, newName);
service.rename(tagData.getUuid(), newName);
} else {
nameChanged = false;
}
@ -354,14 +354,15 @@ public class TagSettingsActivity extends FragmentActivity {
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(tagName.getWindowToken(), 0);
tagDataService.save(tagData);
tagMetadataDao.synchronizeMembers(tagData.getId(), tagData.getUuid(), members);
if (isNewTag) {
setResult(RESULT_OK, new Intent().putExtra(TOKEN_NEW_FILTER,
TagFilterExposer.filterFromTagData(TagSettingsActivity.this, tagData)));
} else {
setResult(RESULT_OK);
}
tagDataService.save(tagData);
tagMetadataDao.synchronizeMembers(tagData.getId(), tagData.getUuid(), members);
refreshSettingsPage();
finish();
@ -539,6 +540,15 @@ public class TagSettingsActivity extends FragmentActivity {
return super.onCreateOptionsMenu(menu);
}
@Override
public void onBackPressed() {
if (tagName.getText().length() == 0) {
finish();
} else {
saveSettings();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
@ -579,7 +589,7 @@ public class TagSettingsActivity extends FragmentActivity {
}
protected boolean deleteTag() {
boolean result = tagService.deleteOrLeaveTag(this, tagData.getValue(TagData.NAME), TagService.SHOW_ACTIVE_TASKS);
boolean result = tagService.deleteOrLeaveTag(this, tagData.getValue(TagData.NAME), tagData.getUuid());
setResult(Activity.RESULT_OK);
finish();
return result;

@ -242,9 +242,13 @@ public class TagViewFragment extends TaskListFragment {
if(tag == null && RemoteModel.NO_UUID.equals(uuid))
return;
TodorooCursor<TagData> cursor = tagDataService.query(Query.select(TagData.PROPERTIES).where(
Criterion.or(TagData.NAME.eqCaseInsensitive(tag),
TagData.UUID.eq(uuid))));
TodorooCursor<TagData> cursor;
if (!RemoteModel.isUuidEmpty(uuid)) {
cursor = tagDataService.query(Query.select(TagData.PROPERTIES).where(TagData.UUID.eq(uuid)));
} else {
cursor = tagDataService.query(Query.select(TagData.PROPERTIES).where(TagData.NAME.eqCaseInsensitive(tag)));
}
try {
tagData = new TagData();
if(cursor.getCount() == 0) {
@ -329,7 +333,7 @@ public class TagViewFragment extends TaskListFragment {
/** refresh the list with latest data from the web */
private void refreshData() {
if (actFmPreferenceService.isLoggedIn()) {
if (actFmPreferenceService.isLoggedIn() && tagData != null && !RemoteModel.isUuidEmpty(tagData.getUuid())) {
((TextView)taskListView.findViewById(android.R.id.empty)).setText(R.string.DLG_loading);
Runnable callback = new Runnable() {
@ -468,6 +472,11 @@ public class TagViewFragment extends TaskListFragment {
} catch (JSONException e) {
e.printStackTrace();
}
} else {
membersView.removeAllViews();
membersView.setOnClickListener(settingsListener);
TextView textView = (TextView) getActivity().getLayoutInflater().inflate(R.layout.no_members_text_view, null);
membersView.addView(textView);
}
View filterAssigned = getView().findViewById(R.id.filter_assigned);

@ -40,7 +40,7 @@ import com.todoroo.astrid.utility.Constants;
public class ActFmInvoker {
/** NOTE: these values are development values & will not work on production */
private static final String URL = "//192.168.0.160:3000/api/";
private static final String URL = "//10.0.2.2:3000/api/";
private static final String APP_ID = "a4732a32859dbcd3e684331acd36432c";
private static final String APP_SECRET = "e389bfc82a0d932332f9a8bd8203735f";

@ -13,6 +13,7 @@ import android.text.TextUtils;
import com.timsu.astrid.R;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.billing.BillingConstants;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
import com.todoroo.astrid.sync.SyncProviderUtilities;
@ -54,6 +55,15 @@ public class ActFmPreferenceService extends SyncProviderUtilities {
// --- user management
@Override
public void setToken(String setting) {
super.setToken(setting);
if (TextUtils.isEmpty(setting))
RemoteModelDao.outstandingEntryFlag = -1;
else
RemoteModelDao.outstandingEntryFlag = 1;
}
/**
* @return get user id
*/

@ -25,7 +25,9 @@ import com.todoroo.astrid.actfm.sync.messages.ChangesHappened;
import com.todoroo.astrid.actfm.sync.messages.ClientToServerMessage;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.actfm.sync.messages.ReplayOutstandingEntries;
import com.todoroo.astrid.actfm.sync.messages.ReplayTaskListMetadataOutstanding;
import com.todoroo.astrid.actfm.sync.messages.ServerToClientMessage;
import com.todoroo.astrid.actfm.sync.messages.TaskListMetadataChangesHappened;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.OutstandingEntryDao;
@ -181,7 +183,7 @@ public class ActFmSyncThread {
}
}
private final Runnable defaultRefreshRunnable = new Runnable() {
public static final Runnable DEFAULT_REFRESH_RUNNABLE = new Runnable() {
@Override
public void run() {
Intent refresh = new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH);
@ -211,10 +213,10 @@ public class ActFmSyncThread {
if (timeForBackgroundSync()) {
repopulateQueueFromOutstandingTables();
enqueueMessage(BriefMe.instantiateBriefMeForClass(TaskListMetadata.class, NameMaps.PUSHED_AT_TASK_LIST_METADATA), defaultRefreshRunnable);
enqueueMessage(BriefMe.instantiateBriefMeForClass(Task.class, NameMaps.PUSHED_AT_TASKS), defaultRefreshRunnable);
enqueueMessage(BriefMe.instantiateBriefMeForClass(TagData.class, NameMaps.PUSHED_AT_TAGS), defaultRefreshRunnable);
enqueueMessage(BriefMe.instantiateBriefMeForClass(User.class, NameMaps.PUSHED_AT_USERS), defaultRefreshRunnable);
enqueueMessage(BriefMe.instantiateBriefMeForClass(TaskListMetadata.class, NameMaps.PUSHED_AT_TASK_LIST_METADATA), DEFAULT_REFRESH_RUNNABLE);
enqueueMessage(BriefMe.instantiateBriefMeForClass(Task.class, NameMaps.PUSHED_AT_TASKS), DEFAULT_REFRESH_RUNNABLE);
enqueueMessage(BriefMe.instantiateBriefMeForClass(TagData.class, NameMaps.PUSHED_AT_TAGS), DEFAULT_REFRESH_RUNNABLE);
enqueueMessage(BriefMe.instantiateBriefMeForClass(User.class, NameMaps.PUSHED_AT_USERS), DEFAULT_REFRESH_RUNNABLE);
setTimeForBackgroundSync(false);
}
@ -270,7 +272,7 @@ public class ActFmSyncThread {
try {
Runnable r = pendingCallbacks.remove(message);
if (r != null) {
if (r == defaultRefreshRunnable) {
if (r == DEFAULT_REFRESH_RUNNABLE) {
if (didDefaultRefreshThisLoop)
continue;
didDefaultRefreshThisLoop = true;
@ -298,9 +300,9 @@ public class ActFmSyncThread {
// Called after a batch has finished processing
private void replayOutstandingChanges(boolean afterErrors) {
syncLog("Replaying outstanding changes"); //$NON-NLS-1$
new ReplayOutstandingEntries<Task, TaskOutstanding>(Task.class, NameMaps.TABLE_ID_TASKS, taskDao, taskOutstandingDao, this, afterErrors).execute();
new ReplayOutstandingEntries<TagData, TagOutstanding>(TagData.class, NameMaps.TABLE_ID_TAGS, tagDataDao, tagOutstandingDao, this, afterErrors).execute();
new ReplayOutstandingEntries<TaskListMetadata, TaskListMetadataOutstanding>(TaskListMetadata.class, NameMaps.TABLE_ID_TASK_LIST_METADATA, taskListMetadataDao, taskListMetadataOutstandingDao, this, afterErrors).execute();
new ReplayOutstandingEntries<Task, TaskOutstanding>(Task.class, NameMaps.TABLE_ID_TASKS, taskDao, taskOutstandingDao, afterErrors).execute();
new ReplayOutstandingEntries<TagData, TagOutstanding>(TagData.class, NameMaps.TABLE_ID_TAGS, tagDataDao, tagOutstandingDao, afterErrors).execute();
new ReplayTaskListMetadataOutstanding(taskListMetadataDao, taskListMetadataOutstandingDao, afterErrors).execute();
}
private boolean timeForBackgroundSync() {
@ -308,9 +310,11 @@ public class ActFmSyncThread {
}
public void repopulateQueueFromOutstandingTables() {
syncLog("Constructing queue from outstanding tables"); //$NON-NLS-1$
constructChangesHappenedFromOutstandingTable(Task.class, taskDao, taskOutstandingDao);
constructChangesHappenedFromOutstandingTable(TagData.class, tagDataDao, tagOutstandingDao);
constructChangesHappenedFromOutstandingTable(UserActivity.class, userActivityDao, userActivityOutstandingDao);
constructChangesHappenedForTaskListMetadata(taskListMetadataDao, taskListMetadataOutstandingDao);
}
private <T extends RemoteModel, OE extends OutstandingEntry<T>> void constructChangesHappenedFromOutstandingTable(Class<T> modelClass, RemoteModelDao<T> modelDao, OutstandingEntryDao<OE> oustandingDao) {
@ -318,8 +322,19 @@ public class ActFmSyncThread {
try {
for (outstanding.moveToFirst(); !outstanding.isAfterLast(); outstanding.moveToNext()) {
Long id = outstanding.get(OutstandingEntry.ENTITY_ID_PROPERTY);
ChangesHappened<T, OE> ch = new ChangesHappened<T, OE>(id, modelClass, modelDao, oustandingDao);
enqueueMessage(ch, null);
enqueueMessage(new ChangesHappened<T, OE>(id, modelClass, modelDao, oustandingDao), null);
}
} finally {
outstanding.close();
}
}
private void constructChangesHappenedForTaskListMetadata(TaskListMetadataDao dao, TaskListMetadataOutstandingDao outstandingDao) {
TodorooCursor<TaskListMetadataOutstanding> outstanding = outstandingDao.query(Query.select(OutstandingEntry.ENTITY_ID_PROPERTY).groupBy(OutstandingEntry.ENTITY_ID_PROPERTY));
try {
for (outstanding.moveToFirst(); !outstanding.isAfterLast(); outstanding.moveToNext()) {
Long id = outstanding.get(OutstandingEntry.ENTITY_ID_PROPERTY);
ActFmSyncWaitingPool.getInstance().enqueueMessage(new TaskListMetadataChangesHappened(id, TaskListMetadata.class, dao, outstandingDao));
}
} finally {
outstanding.close();

@ -35,7 +35,7 @@ public class ActFmSyncWaitingPool {
return;
AndroidUtilities.sleepDeep(WAIT_TIME);
while (!pendingMessages.isEmpty()) {
ActFmSyncThread.getInstance().enqueueMessage(pendingMessages.remove(0), null);
ActFmSyncThread.getInstance().enqueueMessage(pendingMessages.remove(0), ActFmSyncThread.DEFAULT_REFRESH_RUNNABLE);
}
}
};

@ -20,6 +20,7 @@ import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.OutstandingEntryDao;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TagOutstandingDao;
import com.todoroo.astrid.dao.TaskAttachmentDao;
@ -133,7 +134,6 @@ public class AstridNewSyncMigrator {
// --------------
// Then ensure that every remote model has a remote id, by generating one using the uuid generator for all those without one
// --------------
final Set<Long> tagsThatNeedOrderingSync = new HashSet<Long>();
final Set<Long> tasksThatNeedTagSync = new HashSet<Long>();
try {
Query tagsQuery = Query.select(TagData.ID, TagData.UUID, TagData.MODIFICATION_DATE).where(Criterion.or(TagData.UUID.eq(RemoteModel.NO_UUID), TagData.UUID.isNull()));
@ -146,14 +146,12 @@ public class AstridNewSyncMigrator {
@Override
public boolean shouldCreateOutstandingEntries(TagData instance) {
return lastFetchTime == 0 || (instance.containsNonNullValue(TagData.MODIFICATION_DATE) && instance.getValue(TagData.MODIFICATION_DATE) > lastFetchTime);
boolean result = lastFetchTime == 0 || (instance.containsNonNullValue(TagData.MODIFICATION_DATE) && instance.getValue(TagData.MODIFICATION_DATE) > lastFetchTime);
return result && RemoteModelDao.getOutstandingEntryFlag();
}
@Override
public void afterSave(TagData instance, boolean createdOutstanding) {
if (createdOutstanding)
tagsThatNeedOrderingSync.add(instance.getId());
}
public void afterSave(TagData instance, boolean createdOutstanding) {/**/}
});
Query tasksQuery = Query.select(Task.ID, Task.UUID, Task.RECURRENCE, Task.FLAGS, Task.MODIFICATION_DATE, Task.LAST_SYNC).where(Criterion.all);
@ -185,8 +183,9 @@ public class AstridNewSyncMigrator {
@Override
public boolean shouldCreateOutstandingEntries(Task instance) {
if (!instance.containsNonNullValue(Task.MODIFICATION_DATE) || instance.getValue(Task.LAST_SYNC) == 0)
return true;
return instance.getValue(Task.LAST_SYNC) < instance.getValue(Task.MODIFICATION_DATE);
return RemoteModelDao.getOutstandingEntryFlag();
return (instance.getValue(Task.LAST_SYNC) < instance.getValue(Task.MODIFICATION_DATE)) && RemoteModelDao.getOutstandingEntryFlag();
}
@Override
@ -350,8 +349,6 @@ public class AstridNewSyncMigrator {
tlm.setValue(TaskListMetadata.TASK_IDS, tagOrdering);
tlm.setValue(TaskListMetadata.TAG_UUID, td.getUuid());
if (!tagsThatNeedOrderingSync.contains(td.getId()))
tlm.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
taskListMetadataDao.createNew(tlm);
}
} finally {
@ -515,7 +512,7 @@ public class AstridNewSyncMigrator {
private void updateTagUuid(Metadata m) {
String tag = m.getValue(TaskToTagMetadata.TAG_NAME);
TagData tagData = tagDataService.getTag(tag, TagData.UUID);
TagData tagData = tagDataService.getTagByName(tag, TagData.UUID);
if (tagData != null) {
if (ActFmInvoker.SYNC_DEBUG)
Log.w(LOG_TAG, "Linking with tag uuid " + tagData.getValue(TagData.UUID));

@ -0,0 +1,61 @@
package com.todoroo.astrid.actfm.sync.messages;
import android.util.Log;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.OutstandingEntryDao;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.OutstandingEntry;
import com.todoroo.astrid.data.RemoteModel;
@SuppressWarnings("nls")
public class ConstructOutstandingTableFromMasterTable<TYPE extends RemoteModel, OE extends OutstandingEntry<TYPE>> {
private final String table;
private final RemoteModelDao<TYPE> dao;
private final OutstandingEntryDao<OE> outstandingDao;
private final LongProperty createdAtProperty;
public ConstructOutstandingTableFromMasterTable(String table, RemoteModelDao<TYPE> dao,
OutstandingEntryDao<OE> outstandingDao, LongProperty createdAtProperty) {
this.table = table;
this.dao = dao;
this.outstandingDao = outstandingDao;
this.createdAtProperty = createdAtProperty;
}
public void execute() {
Property<?>[] syncableProperties = NameMaps.syncableProperties(table);
TodorooCursor<TYPE> items = dao.query(Query.select(AndroidUtilities.addToArray(syncableProperties, AbstractModel.ID_PROPERTY, RemoteModel.UUID_PROPERTY)));
try {
OE oe = outstandingDao.getModelClass().newInstance();
for (items.moveToFirst(); !items.isAfterLast(); items.moveToNext()) {
long itemId = items.get(AbstractModel.ID_PROPERTY);
for (Property<?> p : syncableProperties) {
oe.clear();
oe.setValue(OutstandingEntry.ENTITY_ID_PROPERTY, itemId);
oe.setValue(OutstandingEntry.COLUMN_STRING_PROPERTY, p.name);
oe.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, items.get(p).toString());
if (createdAtProperty != null)
oe.setValue(OutstandingEntry.CREATED_AT_PROPERTY, items.get(createdAtProperty));
else
oe.setValue(OutstandingEntry.CREATED_AT_PROPERTY, DateUtilities.now());
outstandingDao.createNew(oe);
}
}
} catch (IllegalAccessException e) {
Log.e("ConstructOutstanding", "Error instantiating outstanding model class", e);
} catch (InstantiationException e2) {
Log.e("ConstructOutstanding", "Error instantiating outstanding model class", e2);
} finally {
items.close();
}
}
}

@ -118,8 +118,11 @@ public class MakeChanges<TYPE extends RemoteModel> extends ServerToClientMessage
}
private Criterion getMatchCriterion(TYPE model) {
if (NameMaps.TABLE_ID_TASK_LIST_METADATA.equals(table) && model.getSetValues().containsKey(TaskListMetadata.FILTER.name)) {
return TaskListMetadata.FILTER.eq(model.getSetValues().getAsString(TaskListMetadata.FILTER.name));
if (NameMaps.TABLE_ID_TASK_LIST_METADATA.equals(table)) {
if (model.getSetValues().containsKey(TaskListMetadata.FILTER.name))
return TaskListMetadata.FILTER.eq(model.getSetValues().getAsString(TaskListMetadata.FILTER.name));
else if (model.getSetValues().containsKey(TaskListMetadata.TAG_UUID.name))
return TaskListMetadata.TAG_UUID.eq(model.getSetValues().getAsString(TaskListMetadata.TAG_UUID.name));
}
return null;
}

@ -20,22 +20,19 @@ public class ReplayOutstandingEntries<T extends RemoteModel, OE extends Outstand
private static final String ERROR_TAG = "actfm-replay-outstanding";
private final Class<T> modelClass;
protected final Class<T> modelClass;
private final Class<OE> outstandingClass;
private final String table;
private final RemoteModelDao<T> dao;
private final OutstandingEntryDao<OE> outstandingDao;
private final ActFmSyncThread actFmSyncThread;
protected final RemoteModelDao<T> dao;
protected final OutstandingEntryDao<OE> outstandingDao;
private final boolean afterErrors;
public ReplayOutstandingEntries(Class<T> modelClass, String table, RemoteModelDao<T> dao, OutstandingEntryDao<OE> outstandingDao,
ActFmSyncThread actFmSyncThread, boolean afterErrors) {
public ReplayOutstandingEntries(Class<T> modelClass, String table, RemoteModelDao<T> dao, OutstandingEntryDao<OE> outstandingDao, boolean afterErrors) {
this.modelClass = modelClass;
this.outstandingClass = DaoReflectionHelpers.getOutstandingClass(modelClass);
this.table = table;
this.dao = dao;
this.outstandingDao = outstandingDao;
this.actFmSyncThread = actFmSyncThread;
this.afterErrors = afterErrors;
}
@ -58,6 +55,14 @@ public class ReplayOutstandingEntries<T extends RemoteModel, OE extends Outstand
}
}
protected void enqueueChangesHappenedMessage(long id) {
ActFmSyncThread.getInstance().enqueueMessage(new ChangesHappened<T, OE>(id, modelClass, dao, outstandingDao), null);
}
protected boolean shouldSaveModel(T model) {
return true;
}
private void processItem(long id, OE instance, TodorooCursor<OE> outstanding) {
try {
T model = modelClass.newInstance();
@ -78,11 +83,12 @@ public class ReplayOutstandingEntries<T extends RemoteModel, OE extends Outstand
}
model.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
dao.saveExisting(model);
if (shouldSaveModel(model)) {
dao.saveExisting(model);
if (count > 0 && !afterErrors && actFmSyncThread != null) {
ChangesHappened<T, OE> ch = new ChangesHappened<T, OE>(id, modelClass, dao, outstandingDao);
actFmSyncThread.enqueueMessage(ch, null);
if (count > 0 && !afterErrors) {
enqueueChangesHappenedMessage(id);
}
}
outstanding.moveToPrevious(); // Move back one to undo the last iteration of the for loop

@ -0,0 +1,27 @@
package com.todoroo.astrid.actfm.sync.messages;
import com.todoroo.astrid.dao.TaskListMetadataDao;
import com.todoroo.astrid.dao.TaskListMetadataOutstandingDao;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.TaskListMetadataOutstanding;
public class ReplayTaskListMetadataOutstanding extends ReplayOutstandingEntries<TaskListMetadata, TaskListMetadataOutstanding> {
public ReplayTaskListMetadataOutstanding(TaskListMetadataDao dao, TaskListMetadataOutstandingDao outstandingDao, boolean afterErrors) {
super(TaskListMetadata.class, NameMaps.TABLE_ID_TASK_LIST_METADATA, dao, outstandingDao, afterErrors);
}
@Override
protected boolean shouldSaveModel(TaskListMetadata model) {
if (model.containsNonNullValue(TaskListMetadata.TASK_IDS) &&
TaskListMetadata.taskIdsIsEmpty(model.getValue(TaskListMetadata.TASK_IDS)))
return false;
return true;
}
@Override
protected void enqueueChangesHappenedMessage(long id) {
// Do nothing
}
}

@ -5,13 +5,17 @@ import java.util.Set;
import com.todoroo.astrid.dao.TaskListMetadataDao;
import com.todoroo.astrid.dao.TaskListMetadataOutstandingDao;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.TaskListMetadataOutstanding;
public class TaskListMetadataChangesHappened extends ChangesHappened<TaskListMetadata, TaskListMetadataOutstanding> {
private final Throwable throwable;
public TaskListMetadataChangesHappened(long id, Class<TaskListMetadata> modelClass, TaskListMetadataDao modelDao, TaskListMetadataOutstandingDao outstandingDao) {
super(id, modelClass, modelDao, outstandingDao);
throwable = new Throwable();
}
@Override
@ -23,13 +27,19 @@ public class TaskListMetadataChangesHappened extends ChangesHappened<TaskListMet
boolean foundOrderChange = false;
for (int i = changes.size() - 1; i >= 0; i--) {
TaskListMetadataOutstanding oe = changes.get(i);
if (TaskListMetadata.TASK_IDS.name.equals(oe.getValue(TaskListMetadataOutstanding.COLUMN_STRING))) {
if (foundOrderChange) {
String column = oe.getValue(TaskListMetadataOutstanding.COLUMN_STRING);
if (TaskListMetadata.TASK_IDS.name.equals(column)) {
if (foundOrderChange || TaskListMetadata.taskIdsIsEmpty(oe.getValue(TaskListMetadataOutstanding.VALUE_STRING))) {
changes.remove(i);
removedChanges.add(oe.getId());
} else {
foundOrderChange = true;
}
} else if (TaskListMetadata.FILTER.name.equals(column) || TaskListMetadata.TAG_UUID.name.equals(column)) {
if (RemoteModel.isUuidEmpty(oe.getValue(TaskListMetadataOutstanding.VALUE_STRING))) {
changes.remove(i);
removedChanges.add(oe.getId());
}
}
}

@ -10,6 +10,7 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.HistoryDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
@ -101,6 +102,9 @@ public final class PluginServices {
@Autowired
TaskListMetadataOutstandingDao taskListMetadataOutstandingDao;
@Autowired
ActFmPreferenceService actFmPreferenceService;
private static volatile PluginServices instance;
static {
@ -204,6 +208,10 @@ public final class PluginServices {
return getInstance().taskListMetadataOutstandingDao;
}
public static ActFmPreferenceService getActFmPreferenceService() {
return getInstance().actFmPreferenceService;
}
// -- helpers
/**

@ -178,7 +178,7 @@ public class CalendarReminderActivity extends Activity {
@Override
public void onClick(View v) {
String listName = getString(R.string.CRA_default_list_name, eventName);
TagData existing = tagDataService.getTag(listName, TagData.PROPERTIES);
TagData existing = tagDataService.getTagByName(listName, TagData.PROPERTIES);
if (existing != null) {
listExists(existing);
} else {

@ -300,6 +300,7 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
String type = updates.getString(UpdateAdapter.TYPE_PROPERTY_INDEX);
NoteOrUpdate noa;
UpdateAdapter.readUserProperties(updates, user);
if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(type)) {
UpdateAdapter.readUserActivityProperties(updates, update);
noa = NoteOrUpdate.fromUpdateOrHistory(activity, update, null, user, linkColor);
@ -307,7 +308,6 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
UpdateAdapter.readHistoryProperties(updates, history);
noa = NoteOrUpdate.fromUpdateOrHistory(activity, null, history, user, linkColor);
}
UpdateAdapter.readUserProperties(updates, user);
if(noa != null)
items.add(noa);
}

@ -12,8 +12,6 @@ import com.todoroo.astrid.ui.MainMenuPopover;
public class PeopleFilterMode implements FilterModeSpec {
// private AsyncImageView imageView;
@Override
public Filter getDefaultFilter(Context context) {
Filter defaultFilter = PeopleFilterExposer.mySharedTasks(context);
@ -26,18 +24,7 @@ public class PeopleFilterMode implements FilterModeSpec {
}
@Override
public void onFilterItemClickedCallback(FilterListItem item) {
// if (imageView == null)
// return;
// if (item instanceof FilterWithUpdate)
// imageView.setUrl(((FilterWithUpdate) item).imageUrl);
// else
// imageView.setUrl(null);
}
//
// public void setImageView(AsyncImageView imageView) {
// this.imageView = imageView;
// }
public void onFilterItemClickedCallback(FilterListItem item) {/**/}
@Override
public int[] getForbiddenMenuItems() {

@ -83,7 +83,9 @@ public abstract class AstridOrderedListUpdater<LIST> {
currentIds.add(id);
}
Set<String> idsInQuery = new HashSet<String>();
TodorooCursor<Task> tasks = taskService.fetchFiltered(filter.getSqlQuery(), null, Task.UUID);
String sql = filter.getSqlQuery().replaceAll("ORDER BY .*", ""); //$NON-NLS-1$//$NON-NLS-2$
sql = sql + String.format(" ORDER BY %s", Task.CREATION_DATE); //$NON-NLS-1$
TodorooCursor<Task> tasks = taskService.fetchFiltered(sql, null, Task.UUID);
try {
for (tasks.moveToFirst(); !tasks.isAfterLast(); tasks.moveToNext()) {
String id = tasks.getString(0);
@ -93,7 +95,7 @@ public abstract class AstridOrderedListUpdater<LIST> {
changedThings = true;
Node newNode = new Node(id, treeRoot, 0);
treeRoot.children.add(newNode);
treeRoot.children.add(0, newNode);
idToNode.put(id, newNode);
}
@ -331,7 +333,7 @@ public abstract class AstridOrderedListUpdater<LIST> {
return;
Node newNode = new Node(uuid, treeRoot, 0);
treeRoot.children.add(newNode);
treeRoot.children.add(0, newNode);
idToNode.put(uuid, newNode);
writeSerialization(list, serializeTree(), true);
applyToFilter(filter);

@ -12,7 +12,6 @@ import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.TagViewFragment;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterWithCustomIntent;
@ -21,9 +20,11 @@ import com.todoroo.astrid.core.CustomFilterExposer;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.dao.TaskListMetadataDao;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.subtasks.AstridOrderedListUpdater.Node;
import com.todoroo.astrid.utility.AstridPreferences;
@ -55,25 +56,25 @@ public class SubtasksHelper {
return false;
}
@SuppressWarnings("nls")
public static String serverFilterOrderId(String localFilterOrderId) {
if (SubtasksUpdater.ACTIVE_TASKS_ORDER.equals(localFilterOrderId))
return "all";
else if (SubtasksUpdater.TODAY_TASKS_ORDER.equals(localFilterOrderId))
return "today";
return null;
}
@SuppressWarnings("nls")
public static String applySubtasksToWidgetFilter(Filter filter, String query, String tagName, int limit) {
if (SubtasksHelper.shouldUseSubtasksFragmentForFilter(filter)) {
// care for manual ordering
TagData tagData = PluginServices.getTagDataService().getTag(tagName, TagData.TAG_ORDERING);
TagData tagData = PluginServices.getTagDataService().getTagByName(tagName, TagData.UUID, TagData.TAG_ORDERING);
TaskListMetadataDao tlmd = PluginServices.getTaskListMetadataDao();
TaskListMetadata tlm = null;
if (tagData != null) {
tlm = tlmd.fetchByTagId(tagData.getUuid(), TaskListMetadata.TASK_IDS);
} else if (CoreFilterExposer.isInbox(filter)) {
tlm = tlmd.fetchByTagId(TaskListMetadata.FILTER_ID_ALL, TaskListMetadata.TASK_IDS);
} else if (CustomFilterExposer.isTodayFilter(filter)) {
tlm = tlmd.fetchByTagId(TaskListMetadata.FILTER_ID_TODAY, TaskListMetadata.TASK_IDS);
}
query = query.replaceAll("ORDER BY .*", "");
query = query + String.format(" ORDER BY %s, %s, %s, %s",
Task.DELETION_DATE, Task.COMPLETION_DATE,
getOrderString(tagData), Task.CREATION_DATE);
getOrderString(tagData, tlm), Task.CREATION_DATE);
if (limit > 0)
query = query + " LIMIT " + limit;
query = query.replace(TaskCriteria.isVisible().toString(),
@ -84,12 +85,14 @@ public class SubtasksHelper {
return query;
}
private static String getOrderString(TagData tagData) {
private static String getOrderString(TagData tagData, TaskListMetadata tlm) {
String serialized;
if (tagData != null)
serialized = tagData.getValue(TagData.TAG_ORDERING);
if (tlm != null)
serialized = tlm.getValue(TaskListMetadata.TASK_IDS);
else if (tagData != null)
serialized = convertTreeToRemoteIds(tagData.getValue(TagData.TAG_ORDERING));
else
serialized = Preferences.getStringValue(SubtasksUpdater.ACTIVE_TASKS_ORDER);
serialized = "[]"; //$NON-NLS-1$
return AstridOrderedListUpdater.buildOrderString(getStringIdArray(serialized));
}
@ -113,7 +116,7 @@ public class SubtasksHelper {
@SuppressWarnings("nls")
public static String[] getStringIdArray(String serializedTree) {
ArrayList<String> ids = new ArrayList<String>();
String[] values = serializedTree.split("[\\[\\],\\s]"); // Split on [ ] , or whitespace chars
String[] values = serializedTree.split("[\\[\\],\"\\s]"); // Split on [ ] , or whitespace chars
for (String idString : values) {
if (!TextUtils.isEmpty(idString))
ids.add(idString);

@ -53,6 +53,7 @@ public class SubtasksTagListFragment extends TagViewFragment {
helper.beforeSetUpTaskList(filter);
super.setUpTaskList();
setUpMembersGallery();
unregisterForContextMenu(getListView());
}

@ -13,6 +13,7 @@ import com.todoroo.andlib.data.TodorooCursor;
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.Join;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.Preferences;
@ -23,6 +24,7 @@ import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.Flags;
public class TagCaseMigrator {
@ -59,7 +61,7 @@ public class TagCaseMigrator {
}
for (String key : renameMap.keySet()) {
TagService.getInstance().renameCaseSensitive(key, renameMap.get(key));
renameCaseSensitive(key, renameMap.get(key));
updateTagData(key);
}
@ -138,6 +140,40 @@ public class TagCaseMigrator {
} finally {
tasks.close();
}
}
@Deprecated
private int renameCaseSensitive(String oldTag, String newTag) { // Need this for tag case migration process
return renameHelper(oldTag, newTag, true);
}
@Deprecated
private int renameHelper(String oldTag, String newTag, boolean caseSensitive) {
// First remove newTag from all tasks that have both oldTag and newTag.
metadataService.deleteWhere(
Criterion.and(
Metadata.VALUE1.eq(newTag),
Metadata.TASK.in(rowsWithTag(oldTag, Metadata.TASK))));
// Then rename all instances of oldTag to newTag.
Metadata metadata = new Metadata();
metadata.setValue(TaskToTagMetadata.TAG_NAME, newTag);
int ret;
if (caseSensitive)
ret = metadataService.update(tagEq(oldTag, Criterion.all), metadata);
else
ret = metadataService.update(TagService.tagEqIgnoreCase(oldTag, Criterion.all), metadata);
invalidateTaskCache(newTag);
return ret;
}
private Query rowsWithTag(String tag, Field... projections) {
return Query.select(projections).from(Metadata.TABLE).where(Metadata.VALUE1.eq(tag));
}
private void invalidateTaskCache(String tag) {
taskService.clearDetails(Task.ID.in(rowsWithTag(tag, Task.ID)));
Flags.set(Flags.REFRESH);
}
}

@ -38,6 +38,8 @@ import com.todoroo.astrid.api.FilterCategory;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.api.FilterWithCustomIntent;
import com.todoroo.astrid.api.FilterWithUpdate;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TagMetadataDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
@ -74,7 +76,7 @@ public class TagFilterExposer extends BroadcastReceiver implements AstridFilterE
ContentValues contentValues = new ContentValues();
contentValues.put(Metadata.KEY.name, TaskToTagMetadata.KEY);
contentValues.put(TaskToTagMetadata.TAG_NAME.name, tag.tag);
contentValues.put(TaskToTagMetadata.TAG_UUID.name, tag.uuid.toString());
contentValues.put(TaskToTagMetadata.TAG_UUID.name, tag.uuid);
FilterWithUpdate filter = new FilterWithUpdate(tag.tag,
title, tagTemplate,
@ -94,8 +96,8 @@ public class TagFilterExposer extends BroadcastReceiver implements AstridFilterE
context.getString(deleteIntentLabel)
};
filter.contextMenuIntents = new Intent[] {
newTagIntent(context, RenameTagActivity.class, tag, tagTemplate.toString()),
newTagIntent(context, DeleteTagActivity.class, tag, tagTemplate.toString())
newTagIntent(context, RenameTagActivity.class, tag, tag.uuid),
newTagIntent(context, DeleteTagActivity.class, tag, tag.uuid)
};
filter.customTaskList = new ComponentName(ContextManager.getContext(), TagViewFragment.class);
@ -115,10 +117,10 @@ public class TagFilterExposer extends BroadcastReceiver implements AstridFilterE
return filterFromTag(context, tag, TaskCriteria.activeAndVisible());
}
private static Intent newTagIntent(Context context, Class<? extends Activity> activity, Tag tag, String sql) {
private static Intent newTagIntent(Context context, Class<? extends Activity> activity, Tag tag, String uuid) {
Intent ret = new Intent(context, activity);
ret.putExtra(TAG, tag.tag);
ret.putExtra(TagService.TOKEN_TAG_SQL, sql);
ret.putExtra(TagViewFragment.EXTRA_TAG_UUID, uuid);
return ret;
}
@ -197,10 +199,11 @@ public class TagFilterExposer extends BroadcastReceiver implements AstridFilterE
public abstract static class TagActivity extends Activity {
protected String tag;
protected String sql;
protected String uuid;
@Autowired public TagService tagService;
@Autowired public TagDataService tagDataService;
@Autowired public TagDataDao tagDataDao;
@Autowired public TagMetadataDao tagMetadataDao;
static {
AstridDependencyInjector.initialize();
@ -211,19 +214,16 @@ public class TagFilterExposer extends BroadcastReceiver implements AstridFilterE
super.onCreate(savedInstanceState);
tag = getIntent().getStringExtra(TAG);
sql = getIntent().getStringExtra(TagService.TOKEN_TAG_SQL);
if(tag == null) {
uuid = getIntent().getStringExtra(TagViewFragment.EXTRA_TAG_UUID);
if(tag == null || RemoteModel.isUuidEmpty(uuid)) {
finish();
return;
}
DependencyInjectionService.getInstance().inject(this);
TagData tagData = tagDataService.getTag(tag, TagData.MEMBER_COUNT, TagData.USER_ID);
if(tagData != null && tagData.getValue(TagData.MEMBER_COUNT) > 0 && Task.USER_ID_SELF.equals(tagData.getValue(TagData.USER_ID))) {
DialogUtilities.okCancelDialog(this, getString(R.string.actfm_tag_operation_owner_delete), getOkListener(), getCancelListener());
return;
}
TagData tagData = tagDataDao.fetch(uuid, TagData.MEMBER_COUNT, TagData.USER_ID);
showDialog(tagData);
}
@ -275,8 +275,12 @@ public class TagFilterExposer extends BroadcastReceiver implements AstridFilterE
@Override
protected void showDialog(TagData tagData) {
int string;
if (tagData != null && tagData.getValue(TagData.MEMBER_COUNT) > 0)
string = R.string.DLG_leave_this_shared_tag_question;
if (tagData != null && (tagMetadataDao.tagHasMembers(uuid) || tagData.getValue(TagData.MEMBER_COUNT) > 0)) {
if (Task.USER_ID_SELF.equals(tagData.getValue(TagData.USER_ID)))
string = R.string.actfm_tag_operation_owner_delete;
else
string = R.string.DLG_leave_this_shared_tag_question;
}
else
string = R.string.DLG_delete_this_tag_question;
DialogUtilities.okCancelDialog(this, getString(string, tag), getOkListener(), getCancelListener());
@ -284,7 +288,7 @@ public class TagFilterExposer extends BroadcastReceiver implements AstridFilterE
@Override
protected boolean ok() {
return tagService.deleteOrLeaveTag(this, tag, sql);
return tagService.deleteOrLeaveTag(this, tag, uuid);
}
}
@ -308,12 +312,7 @@ public class TagFilterExposer extends BroadcastReceiver implements AstridFilterE
if (text == null || text.length() == 0) {
return false;
} else {
int renamed = tagService.rename(tag, text);
TagData tagData = tagDataService.getTag(tag, TagData.ID, TagData.NAME);
if (tagData != null) {
tagData.setValue(TagData.NAME, text);
tagDataService.save(tagData);
}
int renamed = tagService.rename(uuid, text);
Toast.makeText(this, getString(R.string.TEA_tags_renamed, tag, text, renamed),
Toast.LENGTH_SHORT).show();
return true;

@ -22,6 +22,7 @@ import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.CountProperty;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Field;
@ -36,6 +37,7 @@ import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
@ -45,7 +47,6 @@ import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.Flags;
/**
* Provides operations for working with tags
@ -84,6 +85,8 @@ public final class TagService {
@Autowired TagDataService tagDataService;
@Autowired TagDataDao tagDataDao;
public TagService() {
DependencyInjectionService.getInstance().inject(this);
}
@ -187,7 +190,6 @@ public final class TagService {
* @param activeStatus criterion for specifying completed or uncompleted
* @return empty array if no tags, otherwise array
*/
@Deprecated
public Tag[] getGroupedTags(Order order, Criterion activeStatus) {
Criterion criterion = Criterion.and(activeStatus, MetadataCriteria.withKey(TaskToTagMetadata.KEY));
Query query = Query.select(TaskToTagMetadata.TAG_NAME, TaskToTagMetadata.TAG_UUID, COUNT).
@ -372,21 +374,20 @@ public final class TagService {
return tagBuilder.toString();
}
public boolean deleteOrLeaveTag(Context context, String tag, String sql) {
int deleted = deleteTagMetadata(tag);
TagData tagData = PluginServices.getTagDataService().getTag(tag, TagData.ID, TagData.DELETION_DATE, TagData.MEMBER_COUNT, TagData.USER_ID);
public boolean deleteOrLeaveTag(Context context, String tag, String uuid) {
int deleted = deleteTagMetadata(uuid);
TagData tagData = tagDataDao.fetch(uuid, TagData.ID, TagData.UUID, TagData.DELETION_DATE, TagData.MEMBER_COUNT, TagData.USER_ID);
boolean shared = false;
Intent tagDeleted = new Intent(AstridApiConstants.BROADCAST_EVENT_TAG_DELETED);
if(tagData != null) {
tagData.setValue(TagData.DELETION_DATE, DateUtilities.now());
PluginServices.getTagDataService().save(tagData);
tagDeleted.putExtra(TagViewFragment.EXTRA_TAG_UUID, tagData.getUuid());
shared = tagData.getValue(TagData.MEMBER_COUNT) > 0 && !Task.USER_ID_SELF.equals(tagData.getValue(TagData.USER_ID)); // Was I a list member and NOT owner?
}
Toast.makeText(context, context.getString(shared ? R.string.TEA_tags_left : R.string.TEA_tags_deleted, tag, deleted),
Toast.LENGTH_SHORT).show();
Intent tagDeleted = new Intent(AstridApiConstants.BROADCAST_EVENT_TAG_DELETED);
tagDeleted.putExtra(TagViewFragment.EXTRA_TAG_NAME, tag);
tagDeleted.putExtra(TOKEN_TAG_SQL, sql);
context.sendBroadcast(tagDeleted);
return true;
}
@ -531,51 +532,38 @@ public final class TagService {
return null;
}
private int deleteTagMetadata(String tag) {
invalidateTaskCache(tag);
private int deleteTagMetadata(String uuid) {
Metadata deleted = new Metadata();
deleted.setValue(Metadata.DELETION_DATE, DateUtilities.now());
return metadataDao.update(tagEqIgnoreCase(tag, Criterion.all), deleted);
return metadataDao.update(Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY), TaskToTagMetadata.TAG_UUID.eq(uuid)), deleted);
}
public int rename(String oldTag, String newTag) {
return renameHelper(oldTag, newTag, false);
public int rename(String uuid, String newName) {
return rename(uuid, newName, false);
}
public int renameCaseSensitive(String oldTag, String newTag) { // Need this for tag case migration process
return renameHelper(oldTag, newTag, true);
}
public int rename(String uuid, String newName, boolean suppressSync) {
TagData template = new TagData();
template.setValue(TagData.NAME, newName);
if (suppressSync)
template.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
int result = tagDataDao.update(TagData.UUID.eq(uuid), template);
@Deprecated
private int renameHelper(String oldTag, String newTag, boolean caseSensitive) {
// First remove newTag from all tasks that have both oldTag and newTag.
MetadataService metadataService = PluginServices.getMetadataService();
metadataService.deleteWhere(
Criterion.and(
Metadata.VALUE1.eq(newTag),
Metadata.TASK.in(rowsWithTag(oldTag, Metadata.TASK))));
// Then rename all instances of oldTag to newTag.
Metadata metadata = new Metadata();
metadata.setValue(TaskToTagMetadata.TAG_NAME, newTag);
int ret;
if (caseSensitive)
ret = metadataService.update(tagEq(oldTag, Criterion.all), metadata);
else
ret = metadataService.update(tagEqIgnoreCase(oldTag, Criterion.all), metadata);
invalidateTaskCache(newTag);
return ret;
}
boolean tagRenamed = result > 0;
Metadata metadataTemplate = new Metadata();
metadataTemplate.setValue(TaskToTagMetadata.TAG_NAME, newName);
result = metadataDao.update(Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY), TaskToTagMetadata.TAG_UUID.eq(uuid)), metadataTemplate);
tagRenamed = tagRenamed || result > 0;
private Query rowsWithTag(String tag, Field... projections) {
return Query.select(projections).from(Metadata.TABLE).where(Metadata.VALUE1.eq(tag));
}
if (tagRenamed) {
Intent intent = new Intent(AstridApiConstants.BROADCAST_EVENT_TAG_RENAMED);
intent.putExtra(TagViewFragment.EXTRA_TAG_UUID, uuid);
ContextManager.getContext().sendBroadcast(intent);
}
private void invalidateTaskCache(String tag) {
taskService.clearDetails(Task.ID.in(rowsWithTag(tag, Task.ID)));
Flags.set(Flags.REFRESH);
return result;
}
public static int getDefaultImageIDForTag(String nameOrUUID) {

@ -140,6 +140,7 @@ public class FeaturedTaskListFragment extends TagViewFragment {
} else {
clone = new TagData();
clone.setValue(TagData.NAME, localName);
tagDataService.save(clone);
}
} finally {

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/no_members"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
style="@style/TextAppearance"
android:textStyle="bold"
android:textColor="#333333"
android:text="@string/actfm_TVA_no_members_alert"/>

@ -74,7 +74,6 @@
android:layout_alignParentTop="true"
android:layout_marginLeft="10dip"
android:layout_toRightOf="@id/picture"
android:capitalize="sentences"
android:text="@string/actfm_TVA_tag_label" />
<LinearLayout
@ -96,6 +95,7 @@
android:background="#00000000"
android:hint="@string/actfm_TVA_tag_name_hint"
android:singleLine="true"
android:capitalize="sentences"
android:textCursorDrawable="@null"
android:textSize="15sp" />
</LinearLayout>

@ -31,16 +31,8 @@
android:id="@+id/shared_with"
android:layout_width="wrap_content"
android:paddingLeft="6dip"
android:layout_height="fill_parent">
<TextView
android:id="@+id/no_members"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center_vertical"
style="@style/TextAppearance"
android:textStyle="bold"
android:textColor="#333333"
android:text="@string/actfm_TVA_no_members_alert"/>
android:layout_height="fill_parent"
android:gravity="center_vertical">
</LinearLayout>
</HorizontalScrollView>
<ImageView

@ -52,6 +52,7 @@ import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.FilterListItem;
import com.todoroo.astrid.core.CustomFilterExposer;
import com.todoroo.astrid.dao.TagMetadataDao;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.people.PeopleFilterMode;
@ -60,7 +61,6 @@ import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.StatisticsService;
import com.todoroo.astrid.service.ThemeService;
import com.todoroo.astrid.service.abtesting.ABTestEventReportingService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TagsPlugin;
import com.todoroo.astrid.tags.reusable.FeaturedListFilterMode;
import com.todoroo.astrid.ui.DateChangedAlerts;
@ -120,6 +120,7 @@ public class TaskListActivity extends AstridActivity implements MainMenuListener
private boolean swipeEnabled = false;
private final TagDeletedReceiver tagDeletedReceiver = new TagDeletedReceiver();
private final TagRenamedReceiver tagRenamedReceiver = new TagRenamedReceiver();
private final OnClickListener mainMenuClickListener = new OnClickListener() {
@Override
@ -518,6 +519,7 @@ public class TaskListActivity extends AstridActivity implements MainMenuListener
protected void onResume() {
super.onResume();
registerReceiver(tagDeletedReceiver, new IntentFilter(AstridApiConstants.BROADCAST_EVENT_TAG_DELETED));
registerReceiver(tagRenamedReceiver, new IntentFilter(AstridApiConstants.BROADCAST_EVENT_TAG_RENAMED));
}
@Override
@ -531,6 +533,7 @@ public class TaskListActivity extends AstridActivity implements MainMenuListener
protected void onStop() {
super.onStop();
AndroidUtilities.tryUnregisterReceiver(this, tagDeletedReceiver);
AndroidUtilities.tryUnregisterReceiver(this, tagRenamedReceiver);
}
public void setSelectedItem(Filter item) {
@ -693,7 +696,7 @@ public class TaskListActivity extends AstridActivity implements MainMenuListener
boolean memberFound = false;
if (TextUtils.isEmpty(members))
memberFound = td.getValue(TagData.USER_ID).equals(assignedId) || tagMetadataDao.memberOfTagData(assignedEmail, assignedId);
memberFound = td.getValue(TagData.USER_ID).equals(assignedId) || tagMetadataDao.memberOfTagData(assignedEmail, td.getUuid(), assignedId);
else {
JSONObject user = new JSONObject();
JSONArray membersArray = null;
@ -914,27 +917,36 @@ public class TaskListActivity extends AstridActivity implements MainMenuListener
return super.onKeyDown(keyCode, event);
}
private class TagRenamedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
TaskListFragment tlf = getTaskListFragment();
if (tlf != null)
tlf.refresh();
FilterListFragment flf = getFilterListFragment();
if (flf != null)
flf.refresh();
}
}
private class TagDeletedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
String deletedTag = intent.getStringExtra(TagViewFragment.EXTRA_TAG_NAME);
String deletedTagSql = intent.getStringExtra(TagService.TOKEN_TAG_SQL);
String uuid = intent.getStringExtra(TagViewFragment.EXTRA_TAG_UUID);
TaskListFragment tlf = getTaskListFragment();
FilterListFragment fl = getFilterListFragment();
if (deletedTagSql.equals(TagService.SHOW_ACTIVE_TASKS)) {
fl.switchToActiveTasks();
fl.clear(); // Should auto refresh
}
else if (fl != null) {
Filter currentlyShowing = getIntent().getParcelableExtra(TaskListFragment.TOKEN_FILTER);
if (currentlyShowing != null) {
boolean titlesMatch = currentlyShowing.title != null && currentlyShowing.title.equals(deletedTag);
boolean sqlMatches = currentlyShowing.getSqlQuery() != null && currentlyShowing.getSqlQuery().equals(deletedTagSql);
if (titlesMatch && sqlMatches)
fl.switchToActiveTasks();
if (tlf != null) {
TagData tagData = tlf.getActiveTagData();
String activeUuid = RemoteModel.NO_UUID;
if (tagData != null)
activeUuid = tagData.getUuid();
if (activeUuid.equals(uuid)) {
fl.switchToActiveTasks();
fl.clear(); // Should auto refresh
}
fl.clear(); // Should auto refresh
}
}
}
}

@ -637,7 +637,7 @@ public class TaskListFragment extends ListFragment implements OnScrollListener,
@Override
public void run() {
try {
loadTaskListContent(true);
refresh();
} catch (IllegalStateException e) {
// view may have been destroyed
}

@ -103,6 +103,7 @@ public class UpdateAdapter extends CursorAdapter {
UserActivity.TARGET_ID,
UserActivity.TARGET_NAME,
UserActivity.PICTURE,
UserActivity.USER_UUID,
UserActivity.ID,
ACTIVITY_TYPE_PROPERTY,
};
@ -115,6 +116,7 @@ public class UpdateAdapter extends CursorAdapter {
History.OLD_VALUE,
History.NEW_VALUE,
History.TASK,
History.USER_UUID,
History.ID,
HISTORY_TYPE_PROPERTY,
};
@ -222,6 +224,7 @@ public class UpdateAdapter extends CursorAdapter {
activity.setValue(UserActivity.TARGET_ID, unionCursor.getString(4));
activity.setValue(UserActivity.TARGET_NAME, unionCursor.getString(5));
activity.setValue(UserActivity.PICTURE, unionCursor.getString(6));
activity.setValue(UserActivity.USER_UUID, unionCursor.getString(7));
}
public static void readHistoryProperties(TodorooCursor<UserActivity> unionCursor, History history) {
@ -232,6 +235,7 @@ public class UpdateAdapter extends CursorAdapter {
history.setValue(History.OLD_VALUE, unionCursor.getString(4));
history.setValue(History.NEW_VALUE, unionCursor.getString(5));
history.setValue(History.TASK, unionCursor.getString(6));
history.setValue(History.USER_UUID, unionCursor.getString(7));
}
public static void readUserProperties(TodorooCursor<UserActivity> joinCursor, User user) {

@ -86,7 +86,8 @@ public class MetadataDao extends DatabaseDao<Metadata> {
((cv.containsKey(Metadata.KEY.name) &&
TaskToTagMetadata.KEY.equals(item.getValue(Metadata.KEY))) ||
(cv.containsKey(Metadata.DELETION_DATE.name) &&
item.getValue(Metadata.DELETION_DATE) > 0));
item.getValue(Metadata.DELETION_DATE) > 0)) &&
RemoteModelDao.getOutstandingEntryFlag();
}
@Override

@ -5,6 +5,7 @@ import com.todoroo.andlib.data.DatabaseDao;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.helper.UUIDHelper;
@ -29,7 +30,26 @@ public class RemoteModelDao<RTYPE extends RemoteModel> extends DatabaseDao<RTYPE
item.setValue(RemoteModel.UUID_PROPERTY, UUIDHelper.newUUID());
}
return super.createNew(item);
};
}
public static int outstandingEntryFlag = -1;
public static boolean getOutstandingEntryFlag() {
if (outstandingEntryFlag == -1) {
synchronized (RemoteModelDao.class) {
if (PluginServices.getActFmPreferenceService().isLoggedIn())
outstandingEntryFlag = 1;
else
outstandingEntryFlag = 0;
}
}
return outstandingEntryFlag > 0;
}
@Override
protected boolean shouldRecordOutstanding(RTYPE item) {
return super.shouldRecordOutstanding(item) && getOutstandingEntryFlag();
}
/**
* Fetch a model object by UUID

@ -77,7 +77,8 @@ public class TagMetadataDao extends DatabaseDao<TagMetadata> {
((cv.containsKey(TagMetadata.KEY.name) &&
TagMemberMetadata.KEY.equals(item.getValue(TagMetadata.KEY))) ||
(cv.containsKey(TagMetadata.DELETION_DATE.name) &&
item.getValue(TagMetadata.DELETION_DATE) > 0));
item.getValue(TagMetadata.DELETION_DATE) > 0)) &&
RemoteModelDao.getOutstandingEntryFlag();
}
@Override
@ -188,19 +189,28 @@ public class TagMetadataDao extends DatabaseDao<TagMetadata> {
}
}
public boolean memberOfTagData(String email, String id) {
public boolean tagHasMembers(String uuid) {
TodorooCursor<TagMetadata> metadata = query(Query.select(TagMetadata.ID).where(Criterion.and(TagMetadataCriteria.byTagAndWithKey(uuid, TagMemberMetadata.KEY), TagMetadata.DELETION_DATE.eq(0))));
try {
return metadata.getCount() > 0;
} finally {
metadata.close();
}
}
public boolean memberOfTagData(String email, String tagId, String memberId) {
Criterion criterion;
if (!RemoteModel.isUuidEmpty(id) && !TextUtils.isEmpty(email))
criterion = Criterion.or(TagMemberMetadata.USER_UUID.eq(email), TagMemberMetadata.USER_UUID.eq(id));
else if (!RemoteModel.isUuidEmpty(id))
criterion = TagMemberMetadata.USER_UUID.eq(id);
if (!RemoteModel.isUuidEmpty(memberId) && !TextUtils.isEmpty(email))
criterion = Criterion.or(TagMemberMetadata.USER_UUID.eq(email), TagMemberMetadata.USER_UUID.eq(memberId));
else if (!RemoteModel.isUuidEmpty(memberId))
criterion = TagMemberMetadata.USER_UUID.eq(memberId);
else if (!TextUtils.isEmpty(email))
criterion = TagMemberMetadata.USER_UUID.eq(email);
else
return false;
TodorooCursor<TagMetadata> count = query(Query.select(TagMetadata.ID).where(
Criterion.and(TagMetadataCriteria.withKey(TagMemberMetadata.KEY), criterion)));
Criterion.and(TagMetadataCriteria.withKey(TagMemberMetadata.KEY), TagMetadata.TAG_UUID.eq(tagId), criterion)));
try {
return count.getCount() > 0;
} finally {

@ -31,13 +31,18 @@ import com.todoroo.astrid.service.AstridDependencyInjector;
@SuppressWarnings("nls")
public class SqlContentProvider extends ContentProvider {
// --- instance variables
private static UriMatcher uriMatcher;
static {
AstridDependencyInjector.initialize();
}
// --- instance variables
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static UriMatcher uriMatcher;
uriMatcher.addURI(AstridApiConstants.API_PACKAGE + ".private",
"sql", 0);
}
@Autowired
private Database database;
@ -56,12 +61,6 @@ public class SqlContentProvider extends ContentProvider {
}
}
static {
uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI(AstridApiConstants.API_PACKAGE + ".private",
"sql", 0);
}
public SqlContentProvider() {
DependencyInjectionService.getInstance().inject(this);

@ -89,7 +89,7 @@ public class TagDataService {
* Find a tag by name
* @return null if doesn't exist
*/
public TagData getTag(String name, Property<?>... properties) {
public TagData getTagByName(String name, Property<?>... properties) {
TodorooCursor<TagData> cursor = tagDataDao.query(Query.select(properties).where(TagData.NAME.eqCaseInsensitive(name)));
try {
if(cursor.getCount() == 0)
@ -197,7 +197,7 @@ public class TagDataService {
if (!cursor.isAfterLast()) {
tagData.readFromCursor(cursor);
if(!tagData.getValue(TagData.NAME).equals(featObject.getString("name")))
TagService.getInstance().rename(tagData.getValue(TagData.NAME), featObject.getString("name"));
TagService.getInstance().rename(tagData.getUuid(), featObject.getString("name"), true);
cursor.moveToNext();
}
ActFmSyncService.JsonHelper.featuredListFromJson(featObject, tagData);

@ -229,11 +229,13 @@ public class TaskService {
newTask.clearValue(Task.UUID);
newTask.clearValue(Task.USER);
newTask.clearValue(Task.USER_ID);
newTask.clearValue(Task.IS_READONLY);
newTask.clearValue(Task.IS_PUBLIC);
taskDao.save(newTask);
if (!RemoteModel.NO_UUID.equals(tagUuid)) {
TagService.getInstance().createLink(task, tagName, tagUuid);
if (!RemoteModel.isUuidEmpty(tagUuid)) {
TagService.getInstance().createLink(newTask, tagName, tagUuid);
}
return newTask;
}

@ -10,6 +10,7 @@ import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
@ -42,12 +43,14 @@ import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.core.CoreFilterExposer;
import com.todoroo.astrid.core.SortHelper;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.AstridDependencyInjector;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.service.ThemeService;
import com.todoroo.astrid.subtasks.SubtasksHelper;
import com.todoroo.astrid.tags.TagFilterExposer;
import com.todoroo.astrid.utility.AstridPreferences;
import com.todoroo.astrid.utility.Constants;
@ -175,7 +178,7 @@ public class TasksWidget extends AppWidgetProvider {
TodorooCursor<Task> cursor = null;
Filter filter = null;
try {
filter = getFilter(widgetId);
filter = getFilter(context, widgetId);
if (SubtasksHelper.isTagFilter(filter))
((FilterWithCustomIntent) filter).customTaskList = new ComponentName(context, TagViewFragment.class); // In case legacy widget was created with subtasks fragment
views.setTextViewText(R.id.widget_title, filter.title);
@ -377,7 +380,7 @@ public class TasksWidget extends AppWidgetProvider {
return 5;
}
private Filter getFilter(int widgetId) {
private Filter getFilter(Context context, int widgetId) {
// base our filter off the inbox filter, replace stuff if we have it
Filter filter = CoreFilterExposer.buildInboxFilter(getResources());
@ -403,6 +406,33 @@ public class TasksWidget extends AppWidgetProvider {
((FilterWithCustomIntent) filter).customExtras = extras;
}
// Validate tagData
long id = Preferences.getLong(WidgetConfigActivity.PREF_TAG_ID + widgetId, 0);
TagData tagData = null;
if (id > 0) {
tagData = tagDataService.fetchById(id, TagData.ID, TagData.NAME, TagData.TASK_COUNT, TagData.UUID, TagData.PICTURE, TagData.USER_ID, TagData.MEMBER_COUNT);
if (tagData != null && !tagData.getValue(TagData.NAME).equals(filter.title)) { // Tag has been renamed; rebuild filter
filter = TagFilterExposer.filterFromTagData(context, tagData);
Preferences.setString(WidgetConfigActivity.PREF_SQL + widgetId, filter.getSqlQuery());
Preferences.setString(WidgetConfigActivity.PREF_TITLE + widgetId, filter.title);
ContentValues newTaskValues = filter.valuesForNewTasks;
String contentValuesString = null;
if(newTaskValues != null)
contentValuesString = AndroidUtilities.contentValuesToSerializedString(newTaskValues);
Preferences.setString(WidgetConfigActivity.PREF_VALUES + widgetId, contentValuesString);
if (filter instanceof FilterWithCustomIntent) {
String flattenedExtras = AndroidUtilities.bundleToSerializedString(((FilterWithCustomIntent) filter).customExtras);
if (flattenedExtras != null)
Preferences.setString(WidgetConfigActivity.PREF_CUSTOM_EXTRAS + widgetId,
flattenedExtras);
}
}
} else {
tagData = tagDataService.getTagByName(filter.title, TagData.ID);
if (tagData != null)
Preferences.setLong(WidgetConfigActivity.PREF_TAG_ID + widgetId, tagData.getId());
}
return filter;
}

@ -34,6 +34,7 @@ abstract public class WidgetConfigActivity extends ListActivity {
static final String PREF_VALUES = "widget-values-";
static final String PREF_CUSTOM_INTENT = "widget-intent-";
static final String PREF_CUSTOM_EXTRAS = "widget-extras-";
static final String PREF_TAG_ID = "widget-tag-id-";
int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;

@ -0,0 +1,38 @@
package com.todoroo.astrid.sync;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.actfm.sync.messages.ConstructOutstandingTableFromMasterTable;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskOutstanding;
public class ConstructOutstandingFromMasterTest extends NewSyncTestCase {
public void testConstructOutstandingConstructsOutstanding() {
Task t = createTask(true);
TodorooCursor<TaskOutstanding> to = taskOutstandingDao.query(Query.select(TaskOutstanding.PROPERTIES));
try {
assertEquals(0, to.getCount());
} finally {
to.close();
}
new ConstructOutstandingTableFromMasterTable<Task, TaskOutstanding>(NameMaps.TABLE_ID_TASKS, taskDao, taskOutstandingDao, Task.CREATION_DATE).execute();
Property<?>[] syncable = NameMaps.syncableProperties(NameMaps.TABLE_ID_TASKS);
for (Property<?> p : syncable) {
to = taskOutstandingDao.query(Query.select(TaskOutstanding.PROPERTIES).where(TaskOutstanding.COLUMN_STRING.eq(p.name)));
try {
assertEquals(1, to.getCount());
to.moveToFirst();
String value = t.getValue(p).toString();
assertEquals(value, to.get(TaskOutstanding.VALUE_STRING));
} finally {
to.close();
}
}
}
}

@ -1,6 +1,7 @@
package com.todoroo.astrid.sync;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TagOutstandingDao;
import com.todoroo.astrid.dao.TaskDao;
@ -22,6 +23,12 @@ public class NewSyncTestCase extends DatabaseTestCase {
protected
TagOutstandingDao tagOutstandingDao;
@Override
protected void setUp() throws Exception {
super.setUp();
RemoteModelDao.outstandingEntryFlag = 1;
}
protected Task createTask(String title, boolean suppress) {
Task task = new Task();
task.setValue(Task.TITLE, title);

@ -133,7 +133,7 @@ public class SyncMessageTest extends NewSyncTestCase {
t.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
taskDao.save(t);
new ReplayOutstandingEntries<Task, TaskOutstanding>(Task.class, NameMaps.TABLE_ID_TASKS, taskDao, taskOutstandingDao, null, false).execute();
new ReplayOutstandingEntries<Task, TaskOutstanding>(Task.class, NameMaps.TABLE_ID_TASKS, taskDao, taskOutstandingDao, false).execute();
t = taskDao.fetch(t.getId(), Task.TITLE, Task.IMPORTANCE);
assertEquals(SYNC_TASK_TITLE, t.getValue(Task.TITLE));

@ -15,7 +15,6 @@ import com.google.ical.values.RRule;
import com.timsu.astrid.R;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.test.DatabaseTestCase;
import com.todoroo.astrid.utility.TitleParser;
@ -484,6 +483,7 @@ public class TitleParserTest extends DatabaseTestCase {
assertTrue(task.hasDueDate());
task.clearValue(Task.ID);
task.clearValue(Task.UUID);
title = "Jog every day starting from today";
task.setValue(Task.TITLE, title);
TaskService.createWithValues(task, null, title);
@ -513,6 +513,7 @@ public class TitleParserTest extends DatabaseTestCase {
assertTrue(task.hasDueDate());
task.clearValue(Task.ID);
task.clearValue(Task.UUID);
title = "Jog every week starting from today";
task.setValue(Task.TITLE, title);
TaskService.createWithValues(task, null, title);

Loading…
Cancel
Save