Remove ActFm synchronization code

* Remove client<->server messages
* Remove SyncService, SyncThread, Invoker
pull/46/head
Alex Baker 12 years ago
parent 580ab99d91
commit 30c972d7dc

@ -1,53 +0,0 @@
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.ConstructTaskOutstandingTableFromMasterTable;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskOutstanding;
import com.todoroo.astrid.tags.TaskToTagMetadata;
public class ConstructOutstandingFromMasterTest extends NewSyncTestCase {
public void testConstructOutstandingConstructsOutstanding() {
Task t = createTask(true);
Metadata m = TaskToTagMetadata.newTagMetadata(t.getId(), t.getUuid(), "Tag", "2");
m.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
metadataDao.createNew(m);
TodorooCursor<TaskOutstanding> to = taskOutstandingDao.query(Query.select(TaskOutstanding.PROPERTIES));
try {
assertEquals(0, to.getCount());
} finally {
to.close();
}
new ConstructTaskOutstandingTableFromMasterTable(NameMaps.TABLE_ID_TASKS, taskDao, taskOutstandingDao, metadataDao, 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();
}
}
to = taskOutstandingDao.query(Query.select(TaskOutstanding.PROPERTIES).where(TaskOutstanding.COLUMN_STRING.eq(NameMaps.TAG_ADDED_COLUMN)));
try {
assertEquals(1, to.getCount());
to.moveToFirst();
assertEquals("2", to.get(TaskOutstanding.VALUE_STRING));
} finally {
to.close();
}
}
}

@ -1,172 +0,0 @@
package com.todoroo.astrid.sync;
import org.json.JSONException;
import org.json.JSONObject;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.ModelType;
import com.todoroo.astrid.actfm.sync.messages.ChangesHappened;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.actfm.sync.messages.ReplayOutstandingEntries;
import com.todoroo.astrid.actfm.sync.messages.ServerToClientMessage;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskOutstanding;
public class SyncMessageTest extends NewSyncTestCase {
public void testTaskChangesHappenedConstructor() {
Task t = createTask();
try {
ChangesHappened<?, ?> changes = ChangesHappened.instantiateChangesHappened(t.getId(), ModelType.TYPE_TASK);
assertNotNull(changes.serializeToJSON(null));
assertTrue(changes.getChanges().size() > 0);
assertFalse(RemoteModel.NO_UUID.equals(changes.getUUID()));
assertEquals(t.getValue(Task.UUID), changes.getUUID());
} catch (Exception e) {
fail("ChangesHappened constructor threw exception " + e);
}
}
private static final String MAKE_CHANGES_TITLE = "Made changes to title";
private JSONObject getMakeChanges(String... extraChanges) throws JSONException {
JSONObject makeChanges = new JSONObject();
makeChanges.put("type", ServerToClientMessage.TYPE_MAKE_CHANGES);
makeChanges.put("table", NameMaps.TABLE_ID_TASKS);
JSONObject changes = new JSONObject();
changes.put("title", MAKE_CHANGES_TITLE);
changes.put("importance", Task.IMPORTANCE_DO_OR_DIE);
if (extraChanges != null) {
for (int i = 0; i < extraChanges.length - 1; i+=2) {
String key = extraChanges[i];
String value = extraChanges[i + 1];
changes.put(key, value);
}
}
makeChanges.put("changes", changes);
return makeChanges;
}
public void testMakeChangesMakesChanges() {
Task t = createTask();
try {
JSONObject makeChanges = getMakeChanges();
makeChanges.put("uuid", t.getValue(Task.UUID));
ServerToClientMessage message = ServerToClientMessage.instantiateMessage(makeChanges);
message.processMessage(null);
t = taskDao.fetch(t.getId(), Task.TITLE, Task.IMPORTANCE);
assertEquals(MAKE_CHANGES_TITLE, t.getValue(Task.TITLE));
assertEquals(Task.IMPORTANCE_DO_OR_DIE, t.getValue(Task.IMPORTANCE).intValue());
} catch (JSONException e) {
e.printStackTrace();
fail("JSONException");
}
}
public void testMakeChangesMakesNewTasks() {
try {
JSONObject makeChanges = getMakeChanges();
makeChanges.put("uuid", "1");
ServerToClientMessage message = ServerToClientMessage.instantiateMessage(makeChanges);
message.processMessage(null);
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID, Task.UUID, Task.TITLE, Task.IMPORTANCE).where(Task.UUID.eq("1")));
try {
assertEquals(1, cursor.getCount());
cursor.moveToFirst();
Task t = new Task(cursor);
assertEquals(MAKE_CHANGES_TITLE, t.getValue(Task.TITLE));
assertEquals(Task.IMPORTANCE_DO_OR_DIE, t.getValue(Task.IMPORTANCE).intValue());
assertEquals("1", t.getValue(Task.UUID));
} finally {
cursor.close();
}
} catch (JSONException e) {
e.printStackTrace();
fail("JSONException");
}
}
public void testMakeChangesWithUuidCollision() {
Task t = createTask();
String oldUuid = t.getUuid();
try {
String newUuid = oldUuid + "blorp";
JSONObject makeChanges = getMakeChanges("uuid", newUuid);
makeChanges.put("uuid", oldUuid);
ServerToClientMessage message = ServerToClientMessage.instantiateMessage(makeChanges);
message.processMessage(null);
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.UUID).where(Task.UUID.eq(newUuid)));
try {
assertEquals(1, cursor.getCount());
} finally {
cursor.close();
}
cursor = taskDao.query(Query.select(Task.UUID).where(Task.UUID.eq(oldUuid)));
try {
assertEquals(0, cursor.getCount());
} finally {
cursor.close();
}
} catch (JSONException e) {
e.printStackTrace();
fail("JSONException");
}
}
public void testReplayOutstandingEntries() {
Task t = createTask();
t.setValue(Task.TITLE, "change title");
t.setValue(Task.IMPORTANCE, Task.IMPORTANCE_NONE);
t.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
taskDao.save(t);
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));
assertEquals(SYNC_TASK_IMPORTANCE, t.getValue(Task.IMPORTANCE).intValue());
}
public void testUserMigratedUpdatesUserIds() {
Task t = createTask("Someone else's", true);
TagData td = createTagData("Someone else's tag", true);
t.setValue(Task.USER_ID, "1");
taskDao.save(t);
td.setValue(TagData.USER_ID, "1");
tagDataDao.saveExisting(td);
JSONObject userMigrated = new JSONObject();
try {
userMigrated.put("type", ServerToClientMessage.TYPE_USER_MIGRATED);
userMigrated.put("new_user_id", "1");
} catch (JSONException e) {
fail("JSONException");
}
ServerToClientMessage message = ServerToClientMessage.instantiateMessage(userMigrated);
message.processMessage(null);
t = taskDao.fetch(t.getId(), Task.USER_ID);
td = tagDataDao.fetch(td.getId(), TagData.USER_ID);
assertEquals("1", ActFmPreferenceService.userId());
assertEquals(Task.USER_ID_SELF, t.getValue(Task.USER_ID));
assertEquals(Task.USER_ID_SELF, td.getValue(TagData.USER_ID));
}
}

@ -39,9 +39,6 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback;
import com.todoroo.astrid.actfm.ActFmCameraModule.ClearImageCallback;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.SyncMessageCallback;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.activity.AstridActivity;
import com.todoroo.astrid.activity.TaskListActivity;
@ -51,12 +48,9 @@ import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.helper.AsyncImageView;
import org.json.JSONArray;
import org.json.JSONObject;
import org.tasks.R;
import java.util.List;
import edu.mit.mobile.android.imagecache.ImageCache;
public abstract class CommentsFragment extends SherlockListFragment {
@ -82,9 +76,6 @@ public abstract class CommentsFragment extends SherlockListFragment {
protected Resources resources;
@Autowired ActFmSyncService actFmSyncService;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired UserActivityDao userActivityDao;
public CommentsFragment() {
@ -120,16 +111,8 @@ public abstract class CommentsFragment extends SherlockListFragment {
protected abstract UserActivity createUpdate();
protected abstract String commentAddStatistic();
protected abstract void performFetch(boolean manual, SyncMessageCallback done);
protected abstract boolean canLoadMoreHistory();
protected abstract void loadMoreHistory(int offset, SyncMessageCallback callback);
protected abstract void refetchModel();
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
@ -286,7 +269,6 @@ public abstract class CommentsFragment extends SherlockListFragment {
historyCount++;
}
}
loadMoreHistory(historyCount, doneRunnable);
}
});
listView.addFooterView(footerView);
@ -300,24 +282,6 @@ public abstract class CommentsFragment extends SherlockListFragment {
//
}
private final SyncMessageCallback doneRunnable = new SyncMessageCallback() {
@Override
public void runOnSuccess() {
synchronized (this) {
Activity activity = getActivity();
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
refetchModel();
refreshUpdatesList();
}
});
}
}
}
};
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
if(menu.size() > 0) {

@ -15,16 +15,9 @@ import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;
import org.tasks.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.SyncMessageCallback;
import com.todoroo.astrid.actfm.sync.messages.BriefMe;
import com.todoroo.astrid.actfm.sync.messages.FetchHistory;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.adapter.UpdateAdapter;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.data.RemoteModel;
@ -32,12 +25,13 @@ import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.helper.AsyncImageView;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.utility.AstridPreferences;
import com.todoroo.astrid.utility.ResourceDrawableCache;
import org.tasks.R;
public class TagCommentsFragment extends CommentsFragment {
private TagData tagData;
@ -77,13 +71,6 @@ public class TagCommentsFragment extends CommentsFragment {
return tagData != null;
}
@Override
protected void refetchModel() {
if (tagData != null) {
tagData = tagDataService.fetchById(tagData.getId(), TagData.PROPERTIES);
}
}
@Override
protected String getModelName() {
return tagData.getValue(TagData.NAME);
@ -104,12 +91,6 @@ public class TagCommentsFragment extends CommentsFragment {
return hasModel() && tagData.getValue(TagData.HISTORY_HAS_MORE) > 0;
}
@Override
protected void loadMoreHistory(int offset, SyncMessageCallback callback) {
new FetchHistory<TagData>(tagDataDao, TagData.HISTORY_FETCH_DATE, TagData.HISTORY_HAS_MORE, NameMaps.TABLE_ID_TAGS,
tagData.getUuid(), null, 0, offset, callback).execute();
}
@Override
protected void addHeaderToListView(ListView listView) {
if (AstridPreferences.useTabletLayout(getActivity()) && tagData != null) {
@ -152,15 +133,6 @@ public class TagCommentsFragment extends CommentsFragment {
}
}
@Override
protected void performFetch(boolean manual, SyncMessageCallback done) {
if (tagData != null) {
ActFmSyncThread.getInstance().enqueueMessage(new BriefMe<UserActivity>(UserActivity.class, null, tagData.getValue(TagData.USER_ACTIVITIES_PUSHED_AT), BriefMe.TAG_ID_KEY, tagData.getUuid()), done);
new FetchHistory<TagData>(tagDataDao, TagData.HISTORY_FETCH_DATE, TagData.HISTORY_HAS_MORE, NameMaps.TABLE_ID_TAGS,
tagData.getUuid(), null, tagData.getValue(TagData.HISTORY_FETCH_DATE), 0, done).execute();
}
}
@Override
protected UserActivity createUpdate() {
UserActivity userActivity = new UserActivity();
@ -173,11 +145,6 @@ public class TagCommentsFragment extends CommentsFragment {
return userActivity;
}
@Override
protected String commentAddStatistic() {
return StatisticsConstants.ACTFM_TAG_COMMENT;
}
@Override
protected void setLastViewed() {
if(tagData != null && RemoteModel.isValidUuid(tagData.getValue(TagData.UUID))) {

@ -38,8 +38,6 @@ import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.activity.FilterListFragment;
import com.todoroo.astrid.activity.ShortcutActivity;
import com.todoroo.astrid.api.Filter;
@ -89,10 +87,6 @@ public class TagSettingsActivity extends SherlockFragmentActivity {
@Autowired TagDataService tagDataService;
@Autowired ActFmSyncService actFmSyncService;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired ExceptionService exceptionService;
@Autowired UserDao userDao;
@ -421,7 +415,7 @@ public class TagSettingsActivity extends SherlockFragmentActivity {
user.readFromCursor(members);
try {
JSONObject userJson = new JSONObject();
ActFmSyncService.JsonHelper.jsonFromUser(userJson, user);
jsonFromUser(userJson, user);
people.put(userJson);
} catch (JSONException e2) {
//
@ -457,7 +451,7 @@ public class TagSettingsActivity extends SherlockFragmentActivity {
if (u != null) {
try {
JSONObject owner = new JSONObject();
ActFmSyncService.JsonHelper.jsonFromUser(owner, u);
jsonFromUser(owner, u);
owner.put("owner", true);
people.put(owner);
} catch (JSONException e2) {
@ -562,4 +556,11 @@ public class TagSettingsActivity extends SherlockFragmentActivity {
finish();
}
private static void jsonFromUser(JSONObject json, User model) throws JSONException {
json.put("id", model.getValue(User.UUID));
json.put("name", model.getDisplayName());
json.put("email", model.getValue(User.EMAIL));
json.put("picture", model.getPictureUrl(User.PICTURE, RemoteModel.PICTURE_THUMB));
json.put("first_name", model.getValue(User.FIRST_NAME));
}
}

@ -30,8 +30,6 @@ import com.todoroo.andlib.service.NotificationManager.AndroidNotificationManager
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.activity.AstridActivity;
import com.todoroo.astrid.activity.FilterListFragment;
import com.todoroo.astrid.activity.TaskListActivity;
@ -89,10 +87,6 @@ public class TagViewFragment extends TaskListFragment {
@Autowired TagDataDao tagDataDao;
@Autowired ActFmSyncService actFmSyncService;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired SyncV2Service syncService;
@Autowired UserDao userDao;

@ -5,21 +5,16 @@ import android.database.Cursor;
import android.view.ViewGroup;
import android.widget.ListView;
import org.tasks.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.SyncMessageCallback;
import com.todoroo.astrid.actfm.sync.messages.BriefMe;
import com.todoroo.astrid.actfm.sync.messages.FetchHistory;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.adapter.UpdateAdapter;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.TaskService;
import org.tasks.R;
public class TaskCommentsFragment extends CommentsFragment {
public static final String EXTRA_TASK = "extra_task"; //$NON-NLS-1$
@ -44,13 +39,6 @@ public class TaskCommentsFragment extends CommentsFragment {
}
}
@Override
protected void refetchModel() {
if (task != null) {
task = taskDao.fetch(task.getId(), Task.PROPERTIES);
}
}
@Override
protected boolean hasModel() {
return task != null;
@ -91,21 +79,6 @@ public class TaskCommentsFragment extends CommentsFragment {
return hasModel() && task.getValue(Task.HISTORY_HAS_MORE) > 0;
}
@Override
protected void loadMoreHistory(int offset, SyncMessageCallback callback) {
new FetchHistory<Task>(taskDao, Task.HISTORY_FETCH_DATE, Task.HISTORY_HAS_MORE, NameMaps.TABLE_ID_TASKS,
task.getUuid(), task.getValue(Task.TITLE), 0, offset, callback).execute();
}
@Override
protected void performFetch(boolean manual, SyncMessageCallback done) {
if (task != null) {
ActFmSyncThread.getInstance().enqueueMessage(new BriefMe<UserActivity>(UserActivity.class, null, task.getValue(Task.USER_ACTIVITIES_PUSHED_AT), BriefMe.TASK_ID_KEY, task.getUuid()), done);
new FetchHistory<Task>(taskDao, Task.HISTORY_FETCH_DATE, Task.HISTORY_HAS_MORE, NameMaps.TABLE_ID_TASKS,
task.getUuid(), task.getValue(Task.TITLE), task.getValue(Task.HISTORY_FETCH_DATE), 0, done).execute();
}
}
@Override
protected UserActivity createUpdate() {
UserActivity update = new UserActivity();
@ -117,10 +90,4 @@ public class TaskCommentsFragment extends CommentsFragment {
update.setValue(UserActivity.CREATED_AT, DateUtilities.now());
return update;
}
@Override
protected String commentAddStatistic() {
return StatisticsConstants.ACTFM_TASK_COMMENT;
}
}

@ -1,320 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.actfm.sync;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.TimeZone;
import org.apache.http.HttpEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.StringBody;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import org.tasks.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.RestClient;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Pair;
import com.todoroo.andlib.utility.Preferences;
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 = "//10.0.2.2:3000/api/";
private static final String APP_ID = "a4732a32859dbcd3e684331acd36432c";
private static final String APP_SECRET = "e389bfc82a0d932332f9a8bd8203735f";
public static final String PROVIDER_GOOGLE= "google";
public static final String PROVIDER_PASSWORD = "password";
private static final int API_VERSION = 7;
public static final boolean SYNC_DEBUG = Constants.DEBUG || true;
@Autowired private RestClient restClient;
private String token = null;
// --- initialization, getters, setters
/**
* Create new api invoker service without a token
*/
public ActFmInvoker() {
//
DependencyInjectionService.getInstance().inject(this);
}
/**
* Create new api invoker service with a token
* @token access token
*/
public ActFmInvoker(String token) {
this.token = token;
DependencyInjectionService.getInstance().inject(this);
}
public String getToken() {
return token;
}
// --- special method invocations
/**
* Authentication user with Act.fm server, returning a token
*/
public JSONObject authenticate(String email, String firstName, String lastName, String provider,
String secret) throws ActFmServiceException, IOException {
JSONObject result = invoke(
"user_signin",
"email", email,
"first_name", firstName,
"last_name", lastName,
"provider", provider,
"secret", secret,
"timezone", TimeZone.getDefault().getID());
try {
token = result.getString("token");
} catch (JSONException e) {
throw new IOException(e.toString());
}
return result;
}
// --- invocation
/**
* Invokes API method using HTTP GET
*
* @param method
* API method to invoke
* @param getParameters
* Name/Value pairs. Values will be URL encoded.
* @return response object
*/
public JSONObject invoke(String method, Object... getParameters) throws IOException,
ActFmServiceException {
return invokeWithApi(null, method, getParameters);
}
/**
* Invokes API method using HTTP GET
*
* @param method
* API method to invoke
* @param getParameters
* Name/Value pairs. Values will be URL encoded.
* @return response object
*/
public JSONObject invokeWithApi(String api, String method, Object... getParameters) throws IOException,
ActFmServiceException {
try {
String request = createFetchUrl(api, method, getParameters);
if (SYNC_DEBUG) {
Log.e("act-fm-invoke", request);
}
String response = restClient.get(request);
JSONObject object = new JSONObject(response);
if (SYNC_DEBUG) {
AndroidUtilities.logJSONObject("act-fm-invoke-response", object);
}
if(object.getString("status").equals("error")) {
throw new ActFmServiceException(object.getString("message"), object);
}
return object;
} catch (JSONException e) {
throw new IOException(e.getMessage());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**
* Invokes API method using HTTP POST
*
* @param method
* API method to invoke
* @param data
* data to transmit
* @param getParameters
* Name/Value pairs. Values will be URL encoded.
* @return response object
*/
public JSONObject post(String method, HttpEntity data, Object... getParameters) throws IOException,
ActFmServiceException {
try {
String request = createFetchUrl(null, method, getParameters);
if (SYNC_DEBUG) {
Log.e("act-fm-post", request);
}
String response = restClient.post(request, data);
JSONObject object = new JSONObject(response);
if (SYNC_DEBUG) {
AndroidUtilities.logJSONObject("act-fm-post-response", object);
}
if(object.getString("status").equals("error")) {
throw new ActFmServiceException(object.getString("message"), object);
}
return object;
} catch (JSONException e) {
throw new IOException(e.getMessage());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public JSONObject postSync(String data, MultipartEntity entity, boolean changesHappened, String tok) throws IOException {
try {
String timeString = DateUtilities.timeToIso8601(DateUtilities.now(), true);
Object[] params = { "token", tok, "data", data, "time", timeString };
String request = createFetchUrl("api/" + API_VERSION, "synchronize", params);
if (SYNC_DEBUG) {
Log.e("act-fm-post", request);
}
Charset chars;
try {
chars = Charset.forName("UTF-8");
} catch (Exception e) {
chars = null;
}
entity.addPart("token", new StringBody(tok));
entity.addPart("data", new StringBody(data, chars));
entity.addPart("time", new StringBody(timeString));
String response = restClient.post(request, entity);
JSONObject object = new JSONObject(response);
if (SYNC_DEBUG) {
AndroidUtilities.logJSONObject("act-fm-post-response", object);
}
if(object.getString("status").equals("error")) {
throw new ActFmServiceException(object.getString("message"), object);
}
return object;
} catch (JSONException e) {
throw new IOException(e.getMessage());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
/**
* Creates a URL for invoking an HTTP GET/POST on the given method
* @param method
* @param getParameters
* @return
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
private String createFetchUrl(String api, String method, Object... getParameters) throws UnsupportedEncodingException, NoSuchAlgorithmException {
ArrayList<Pair<String, Object>> params = new ArrayList<Pair<String, Object>>();
for(int i = 0; i < getParameters.length; i += 2) {
if(getParameters[i+1] instanceof ArrayList) {
ArrayList<?> list = (ArrayList<?>) getParameters[i+1];
for(int j = 0; j < list.size(); j++) {
params.add(new Pair<String, Object>(getParameters[i].toString() + "[]",
list.get(j)));
}
} else {
params.add(new Pair<String, Object>(getParameters[i].toString(), getParameters[i + 1]));
}
}
params.add(new Pair<String, Object>("app_id", APP_ID));
boolean syncMethod = "synchronize".equals(method);
if (!syncMethod) {
params.add(new Pair<String, Object>("time", System.currentTimeMillis() / 1000L));
}
if(token != null) {
boolean foundTokenKey = false;
for (Pair<String, Object> curr : params) {
if (curr.getLeft().equals("token")) {
foundTokenKey = true;
break;
}
}
if (!foundTokenKey) {
params.add(new Pair<String, Object>("token", token));
}
}
Collections.sort(params, new Comparator<Pair<String, Object>>() {
@Override
public int compare(Pair<String, Object> object1,
Pair<String, Object> object2) {
int result = object1.getLeft().compareTo(object2.getLeft());
if(result == 0) {
return object1.getRight().toString().compareTo(object2.getRight().toString());
}
return result;
}
});
String url = URL;
boolean customApi = false;
if (api != null) {
customApi = true;
url = url.replace("api", api);
}
if (Preferences.getBoolean(R.string.actfm_https_key, false)) {
url = "https:" + url;
} else {
url = "http:" + url;
}
StringBuilder requestBuilder = new StringBuilder(url);
if (!customApi) {
requestBuilder.append(API_VERSION).append("/");
}
requestBuilder.append(method).append('?');
StringBuilder sigBuilder = new StringBuilder(method);
for(Pair<String, Object> entry : params) {
if(entry.getRight() == null) {
continue;
}
String key = entry.getLeft();
String value = entry.getRight().toString();
String encoded = URLEncoder.encode(value, "UTF-8");
if (!syncMethod || "app_id".equals(key)) {
requestBuilder.append(key).append('=').append(encoded).append('&');
}
sigBuilder.append(key).append(value);
}
sigBuilder.append(APP_SECRET);
// String signature = DigestUtils.md5Hex(sigBuilder.toString());
// requestBuilder.append("sig").append('=').append(signature);
return requestBuilder.toString();
}
}

@ -5,16 +5,10 @@
*/
package com.todoroo.astrid.actfm.sync;
import android.text.TextUtils;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.sync.SyncProviderUtilities;
import com.todoroo.astrid.utility.AstridPreferences;
import org.json.JSONException;
import org.json.JSONObject;
import org.tasks.R;
/**
* Methods for working with GTasks preferences
@ -22,44 +16,11 @@ import org.tasks.R;
* @author timsu
*
*/
public class ActFmPreferenceService extends SyncProviderUtilities {
public class ActFmPreferenceService {
/** add-on identifier */
public static final String IDENTIFIER = "actfm"; //$NON-NLS-1$
@Override
public String getIdentifier() {
return IDENTIFIER;
}
@Override
public int getSyncIntervalKey() {
return R.string.actfm_APr_interval_key;
}
@Override
public void clearLastSyncDate() {
super.clearLastSyncDate();
Preferences.setInt(ActFmPreferenceService.PREF_SERVER_TIME, 0);
}
@Override
public boolean shouldShowToast() {
return !Preferences.getBoolean(AstridPreferences.P_FIRST_TASK, true) && super.shouldShowToast();
}
// --- user management
@Override
public void setToken(String setting) {
super.setToken(setting);
if (TextUtils.isEmpty(setting)) {
RemoteModelDao.setOutstandingEntryFlags(RemoteModelDao.OUTSTANDING_FLAG_UNINITIALIZED);
} else {
RemoteModelDao.setOutstandingEntryFlags(RemoteModelDao.OUTSTANDING_ENTRY_FLAG_ENQUEUE_MESSAGES | RemoteModelDao.OUTSTANDING_ENTRY_FLAG_RECORD_OUTSTANDING);
}
}
/**
* @return get user id
*/
@ -93,15 +54,8 @@ public class ActFmPreferenceService extends SyncProviderUtilities {
/** Act.fm current user email */
public static final String PREF_EMAIL = IDENTIFIER + "_email"; //$NON-NLS-1$
/** Act.fm last sync server time */
public static final String PREF_SERVER_TIME = IDENTIFIER + "_time"; //$NON-NLS-1$
private static JSONObject user = null;
@Override
protected void reportLastErrorImpl(String lastError, String type) {
}
public synchronized static JSONObject thisUser() {
if(user == null) {
user = new JSONObject();
@ -123,28 +77,4 @@ public class ActFmPreferenceService extends SyncProviderUtilities {
throw new RuntimeException(e);
}
}
@Override
public String getLoggedInUserName() {
String name = Preferences.getStringValue(PREF_NAME);
if (TextUtils.isEmpty(name)) {
String firstName = Preferences.getStringValue(PREF_FIRST_NAME);
if (!TextUtils.isEmpty(firstName)) {
name = firstName;
}
String lastName = Preferences.getStringValue(PREF_FIRST_NAME);
if (!TextUtils.isEmpty(lastName)) {
if (!TextUtils.isEmpty(name)) {
name += " "; //$NON-NLS-1$
}
name += lastName;
}
if (name == null) {
name = ""; //$NON-NLS-1$
}
}
return name;
}
}
}

@ -1,47 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.actfm.sync;
import java.io.IOException;
import org.json.JSONObject;
/**
* Exception that wraps an exception encountered during API invocation or
* processing.
*
* @author timsu
*
*/
public class ActFmServiceException extends IOException {
private static final long serialVersionUID = -2803924196075428257L;
public JSONObject result;
public ActFmServiceException(String detailMessage, JSONObject result) {
super(detailMessage);
this.result = result;
}
public ActFmServiceException(Throwable throwable, JSONObject result) {
super(throwable.getMessage());
initCause(throwable);
this.result = result;
}
public ActFmServiceException(JSONObject result) {
super();
this.result = result;
}
@Override
public String toString() {
return getClass().getSimpleName() + ": " + getMessage(); //$NON-NLS-1$
}
}

@ -1,10 +0,0 @@
package com.todoroo.astrid.actfm.sync;
public class ActFmSyncMonitor {
private ActFmSyncMonitor() {/**/}
private static final ActFmSyncMonitor INSTANCE = new ActFmSyncMonitor();
public static ActFmSyncMonitor getInstance() {
return INSTANCE;
}
}

@ -1,156 +0,0 @@
/**
* Copyright (c) 2012 Todoroo Inc
*
* See the file "LICENSE" for the full license governing this code.
*/
package com.todoroo.astrid.actfm.sync;
import android.util.Log;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.service.TagDataService;
import com.todoroo.astrid.tags.reusable.FeaturedListFilterExposer;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
/**
* Service for synchronizing data on Astrid.com server with local.
*
* @author Tim Su <tim@todoroo.com>
*
*/
public final class ActFmSyncService {
// --- instance variables
@Autowired
private TagDataService tagDataService;
@Autowired
private ActFmPreferenceService actFmPreferenceService;
@Autowired
private ActFmInvoker actFmInvoker;
private String token;
public ActFmSyncService() {
DependencyInjectionService.getInstance().inject(this);
}
// --- data fetch methods
public int fetchFeaturedLists(int serverTime) throws JSONException, IOException {
if (!checkForToken()) {
return 0;
}
JSONObject result = actFmInvoker.invoke("featured_lists",
"token", token, "modified_after", serverTime);
JSONArray featuredLists = result.getJSONArray("list");
if (featuredLists.length() > 0) {
Preferences.setBoolean(FeaturedListFilterExposer.PREF_SHOULD_SHOW_FEATURED_LISTS, true);
}
for (int i = 0; i < featuredLists.length(); i++) {
JSONObject featObject = featuredLists.getJSONObject(i);
tagDataService.saveFeaturedList(featObject);
}
return result.optInt("time", 0);
}
// --- generic invokation
/** invoke authenticated method against the server */
public JSONObject invoke(String method, Object... getParameters) throws IOException,
ActFmServiceException {
if(!checkForToken()) {
throw new ActFmServiceException("not logged in", null);
}
Object[] parameters = new Object[getParameters.length + 2];
parameters[0] = "token";
parameters[1] = token;
for(int i = 0; i < getParameters.length; i++) {
parameters[i + 2] = getParameters[i];
}
return actFmInvoker.invoke(method, parameters);
}
protected void handleException(String message, Exception exception) {
Log.w("actfm-sync", message, exception);
}
private boolean checkForToken() {
return false;
}
// --- json reader helper
/**
* Read data models from JSON
*/
public static class JsonHelper {
protected static long readDate(JSONObject item, String key) {
return item.optLong(key, 0) * 1000L;
}
public static void jsonFromUser(JSONObject json, User model) throws JSONException {
json.put("id", model.getValue(User.UUID));
json.put("name", model.getDisplayName());
json.put("email", model.getValue(User.EMAIL));
json.put("picture", model.getPictureUrl(User.PICTURE, RemoteModel.PICTURE_THUMB));
json.put("first_name", model.getValue(User.FIRST_NAME));
}
public static void featuredListFromJson(JSONObject json, TagData model) throws JSONException {
parseTagDataFromJson(json, model, true);
}
private static void parseTagDataFromJson(JSONObject json, TagData model, boolean featuredList) throws JSONException {
model.clearValue(TagData.UUID);
model.setValue(TagData.UUID, Long.toString(json.getLong("id")));
model.setValue(TagData.NAME, json.getString("name"));
if (featuredList) {
model.setFlag(TagData.FLAGS, TagData.FLAG_FEATURED, true);
}
if(json.has("picture")) {
model.setValue(TagData.PICTURE, json.optString("picture", ""));
}
if(json.has("thumb")) {
model.setValue(TagData.THUMB, json.optString("thumb", ""));
}
if(json.has("is_silent")) {
model.setFlag(TagData.FLAGS, TagData.FLAG_SILENT, json.getBoolean("is_silent"));
}
if(!json.isNull("description")) {
model.setValue(TagData.TAG_DESCRIPTION, json.getString("description"));
}
if(json.has("members")) {
JSONArray members = json.getJSONArray("members");
model.setValue(TagData.MEMBERS, members.toString());
model.setValue(TagData.MEMBER_COUNT, members.length());
}
if (json.has("deleted_at")) {
model.setValue(TagData.DELETION_DATE, readDate(json, "deleted_at"));
}
if(json.has("tasks")) {
model.setValue(TagData.TASK_COUNT, json.getInt("tasks"));
}
}
}
}

@ -1,271 +0,0 @@
package com.todoroo.astrid.actfm.sync;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.util.Log;
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.service.NotificationManager;
import com.todoroo.andlib.service.NotificationManager.AndroidNotificationManager;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
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.TaskListMetadataChangesHappened;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices;
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;
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.OutstandingEntry;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.TaskListMetadataOutstanding;
import com.todoroo.astrid.data.UserActivity;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class ActFmSyncThread {
private static final String ERROR_TAG = "actfm-sync-thread"; //$NON-NLS-1$
private final List<ClientToServerMessage<?>> pendingMessages;
private final Map<ClientToServerMessage<?>, SyncMessageCallback> pendingCallbacks;
private final Object monitor;
private Thread thread;
@Autowired
private ActFmInvoker actFmInvoker;
@Autowired
private 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;
private final NotificationManager notificationManager;
private int notificationId = -1;
public static interface SyncMessageCallback {
public void runOnSuccess();
}
public static enum ModelType {
TYPE_TASK,
TYPE_TAG,
TYPE_ACTIVITY,
TYPE_ATTACHMENT,
TYPE_TASK_LIST_METADATA
}
private static volatile ActFmSyncThread instance;
public static ActFmSyncThread getInstance() {
if (instance == null) {
synchronized(ActFmSyncThread.class) {
if (instance == null) {
initializeSyncComponents(PluginServices.getTaskDao(), PluginServices.getTagDataDao(), PluginServices.getUserActivityDao(),
PluginServices.getTaskAttachmentDao(), PluginServices.getTaskListMetadataDao());
}
}
}
return instance;
}
public static ActFmSyncThread initializeSyncComponents(TaskDao taskDao, TagDataDao tagDataDao, UserActivityDao userActivityDao,
TaskAttachmentDao taskAttachmentDao, TaskListMetadataDao taskListMetadataDao) {
if (instance == null) {
synchronized(ActFmSyncThread.class) {
if (instance == null) {
List<ClientToServerMessage<?>> syncQueue = Collections.synchronizedList(new LinkedList<ClientToServerMessage<?>>());
ActFmSyncMonitor monitor = ActFmSyncMonitor.getInstance();
ActFmSyncWaitingPool waitingPool = ActFmSyncWaitingPool.getInstance();
instance = new ActFmSyncThread(syncQueue, monitor);
taskDao.addListener(new SyncDatabaseListener<Task>(instance, ModelType.TYPE_TASK));
tagDataDao.addListener(new SyncDatabaseListener<TagData>(instance, ModelType.TYPE_TAG));
userActivityDao.addListener(new SyncDatabaseListener<UserActivity>(instance, ModelType.TYPE_ACTIVITY));
taskAttachmentDao.addListener(new SyncDatabaseListener<TaskAttachment>(instance, ModelType.TYPE_ATTACHMENT));
taskListMetadataDao.addListener(new TaskListMetadataSyncDatabaseListener(instance, waitingPool, ModelType.TYPE_TASK_LIST_METADATA));
instance.startSyncThread();
}
}
}
return instance;
}
private ActFmSyncThread(List<ClientToServerMessage<?>> messageQueue, Object syncMonitor) {
DependencyInjectionService.getInstance().inject(this);
this.pendingMessages = messageQueue;
this.pendingCallbacks = Collections.synchronizedMap(new HashMap<ClientToServerMessage<?>, SyncMessageCallback>());
this.monitor = syncMonitor;
this.notificationManager = new AndroidNotificationManager(ContextManager.getContext());
}
public synchronized void startSyncThread() {
if (thread == null || !thread.isAlive()) {
thread = new Thread(new Runnable() {
@Override
public void run() {
sync();
}
});
thread.start();
}
}
public static void clearTablePushedAtValues() {
String[] pushedAtPrefs = new String[] { NameMaps.PUSHED_AT_TASKS, NameMaps.PUSHED_AT_TAGS, NameMaps.PUSHED_AT_ACTIVITY,
NameMaps.PUSHED_AT_USERS, NameMaps.PUSHED_AT_TASK_LIST_METADATA};
for (String key : pushedAtPrefs) {
Preferences.clear(key);
}
}
public synchronized void enqueueMessage(ClientToServerMessage<?> message, SyncMessageCallback callback) {
if (!RemoteModelDao.getOutstandingEntryFlag(RemoteModelDao.OUTSTANDING_ENTRY_FLAG_ENQUEUE_MESSAGES)) {
return;
}
if (!pendingMessages.contains(message)) {
pendingMessages.add(message);
if (callback != null) {
pendingCallbacks.put(message, callback);
}
synchronized(monitor) {
monitor.notifyAll();
}
}
}
public static final SyncMessageCallback DEFAULT_REFRESH_RUNNABLE = new SyncMessageCallback() {
@Override
public void runOnSuccess() {
Intent refresh = new Intent(AstridApiConstants.BROADCAST_EVENT_REFRESH);
ContextManager.getContext().sendBroadcast(refresh);
}
};
private void sync() {
try {
while(true) {
synchronized(monitor) {
while (true) {
try {
if (notificationId >= 0) {
notificationManager.cancel(notificationId);
notificationId = -1;
}
monitor.wait();
AndroidUtilities.sleepDeep(500L); // Wait briefly for large database operations to finish (e.g. adding a task with several tags may trigger a message before all saves are done--fix this?)
} catch (InterruptedException e) {
// Ignored
}
}
}
}
} catch (Exception e) {
// In the worst case, restart thread if something goes wrong
Log.e(ERROR_TAG, "Unexpected sync thread exception", e);
thread = null;
startSyncThread();
}
}
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) {
TodorooCursor<OE> outstanding = oustandingDao.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);
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();
}
}
public static void syncLog(String message) {
if (ActFmInvoker.SYNC_DEBUG) {
Log.e(ERROR_TAG, message);
}
}
public static class NetworkStateChangedReceiver extends BroadcastReceiver {
private static long lastSyncFromNetworkChange = 0;
private static final String PREF_LAST_SYNC_FROM_NETWORK_CHANGE = "p_last_sync_from_net_change"; //$NON-NLS-1$
@Override
public void onReceive(Context context, Intent intent) {
lastSyncFromNetworkChange = Preferences.getLong(PREF_LAST_SYNC_FROM_NETWORK_CHANGE, 0L);
if (DateUtilities.now() - lastSyncFromNetworkChange > DateUtilities.ONE_MINUTE * 10) {
intent.getParcelableExtra(ConnectivityManager.EXTRA_NETWORK_INFO);
}
}
}
}

@ -1,57 +0,0 @@
package com.todoroo.astrid.actfm.sync;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.actfm.sync.messages.ClientToServerMessage;
public class ActFmSyncWaitingPool {
private static volatile ActFmSyncWaitingPool instance;
public static ActFmSyncWaitingPool getInstance() {
if (instance == null) {
synchronized(ActFmSyncWaitingPool.class) {
if (instance == null) {
instance = new ActFmSyncWaitingPool();
}
}
}
return instance;
}
private static final long WAIT_TIME = 15 * 1000L;
private final ExecutorService singleThreadPool;
private final List<ClientToServerMessage<?>> pendingMessages;
private final Runnable delayMessageRunnable = new Runnable() {
@Override
public void run() {
if (pendingMessages.isEmpty()) {
return;
}
AndroidUtilities.sleepDeep(WAIT_TIME);
while (!pendingMessages.isEmpty()) {
ActFmSyncThread.getInstance().enqueueMessage(pendingMessages.remove(0), ActFmSyncThread.DEFAULT_REFRESH_RUNNABLE);
}
}
};
private ActFmSyncWaitingPool() {
super();
singleThreadPool = Executors.newSingleThreadExecutor();
pendingMessages = Collections.synchronizedList(new LinkedList<ClientToServerMessage<?>>());
}
public synchronized void enqueueMessage(ClientToServerMessage<?> message) {
if (!pendingMessages.contains(message)) {
pendingMessages.add(message);
singleThreadPool.submit(delayMessageRunnable);
}
}
}

@ -1,31 +0,0 @@
package com.todoroo.astrid.actfm.sync;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.DatabaseDao.ModelUpdateListener;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.ModelType;
import com.todoroo.astrid.actfm.sync.messages.ChangesHappened;
import com.todoroo.astrid.actfm.sync.messages.ClientToServerMessage;
import com.todoroo.astrid.dao.RemoteModelDao;
public class SyncDatabaseListener<MTYPE extends AbstractModel> implements ModelUpdateListener<MTYPE> {
private final ModelType modelType;
protected final ActFmSyncThread actFmSyncThread;
public SyncDatabaseListener(ActFmSyncThread actFmSyncThread, ModelType modelType) {
this.actFmSyncThread = actFmSyncThread;
this.modelType = modelType;
}
@Override
public void onModelUpdated(MTYPE model, boolean outstandingEntries) {
if (outstandingEntries && RemoteModelDao.getOutstandingEntryFlag(RemoteModelDao.OUTSTANDING_ENTRY_FLAG_ENQUEUE_MESSAGES)) {
ChangesHappened<?, ?> ch = ChangesHappened.instantiateChangesHappened(model.getId(), modelType);
enqueueMessage(model, ch);
}
}
protected void enqueueMessage(MTYPE model, ClientToServerMessage<?> message) {
actFmSyncThread.enqueueMessage(message, null);
}
}

@ -1,25 +0,0 @@
package com.todoroo.astrid.actfm.sync;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.ModelType;
import com.todoroo.astrid.actfm.sync.messages.ClientToServerMessage;
import com.todoroo.astrid.data.TaskListMetadata;
public class TaskListMetadataSyncDatabaseListener extends SyncDatabaseListener<TaskListMetadata> {
private final ActFmSyncWaitingPool waitingPool;
public TaskListMetadataSyncDatabaseListener(ActFmSyncThread actFmSyncThread, ActFmSyncWaitingPool waitingPool, ModelType modelType) {
super(actFmSyncThread, modelType);
this.waitingPool = waitingPool;
}
@Override
protected void enqueueMessage(TaskListMetadata model, ClientToServerMessage<?> message) {
if (model.getSetValues().containsKey(TaskListMetadata.TASK_IDS.name)) {
waitingPool.enqueueMessage(message);
} else {
actFmSyncThread.enqueueMessage(message, ActFmSyncThread.DEFAULT_REFRESH_RUNNABLE);
}
}
}

@ -1,60 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.OutstandingEntryDao;
public class AcknowledgeChange extends ServerToClientMessage {
private static final String ERROR_TAG = "actfm-acknowledge-change"; //$NON-NLS-1$
private final OutstandingEntryDao<?> dao;
public AcknowledgeChange(JSONObject json) {
super(json);
String table = json.optString("table"); //$NON-NLS-1$
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
dao = PluginServices.getTaskOutstandingDao();
} else if (NameMaps.TABLE_ID_TAGS.equals(table)) {
dao = PluginServices.getTagOutstandingDao();
} else if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(table)) {
dao = PluginServices.getUserActivityOutstandingDao();
} else if (NameMaps.TABLE_ID_ATTACHMENTS.equals(table)) {
dao = PluginServices.getTaskAttachmentOutstandingDao();
} else if (NameMaps.TABLE_ID_TASK_LIST_METADATA.equals(table)) {
dao = PluginServices.getTaskListMetadataOutstandingDao();
} else {
dao = null;
}
}
@Override
public void processMessage(String serverTime) {
JSONArray idsArray = json.optJSONArray("ids"); //$NON-NLS-1$
if (idsArray != null && dao != null) {
ArrayList<Long> idsList = new ArrayList<Long>();
for (int i = 0; i < idsArray.length(); i++) {
try {
Long id = idsArray.getLong(i);
if (id <= 0) {
continue;
}
idsList.add(id);
} catch (JSONException e) {
Log.e(ERROR_TAG, "Error getting long from " + idsArray + " at index " + i, e); //$NON-NLS-1$//$NON-NLS-2$
}
}
dao.deleteWhere(AbstractModel.ID_PROPERTY.in(idsList.toArray(new Long[idsList.size()])));
}
}
}

@ -1,61 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.apache.http.entity.mime.MultipartEntity;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.RemoteModel;
public class BriefMe<TYPE extends RemoteModel> extends ClientToServerMessage<TYPE> {
private static final String ERROR_TAG = "actfm-brief-me"; //$NON-NLS-1$
public static final String TASK_ID_KEY = "task_id"; //$NON-NLS-1$
public static final String TAG_ID_KEY = "tag_id"; //$NON-NLS-1$
public static final String USER_ID_KEY = "user_id"; //$NON-NLS-1$
public static <TYPE extends RemoteModel> BriefMe<TYPE> instantiateBriefMeForClass(Class<TYPE> cls, String pushedAtKey) {
long pushedAt = Preferences.getLong(pushedAtKey, 0);
return new BriefMe<TYPE>(cls, null, pushedAt);
}
public BriefMe(long id, Class<TYPE> modelClass, RemoteModelDao<TYPE> modelDao) {
super(id, modelClass, modelDao);
this.extraParameters = null;
}
private final Object[] extraParameters;
public BriefMe(Class<TYPE> modelClass, String uuid, long pushedAt, Object...extraParameters) {
super(modelClass, uuid, pushedAt);
this.extraParameters = extraParameters;
}
@Override
protected boolean serializeExtrasToJSON(JSONObject serializeTo, MultipartEntity entity) throws JSONException {
if (extraParameters != null && extraParameters.length > 0) {
for (int i = 0; i < extraParameters.length - 1; i+=2) {
try {
String key = (String) extraParameters[i];
Object value = extraParameters[i + 1];
serializeTo.put(key, value);
} catch (ClassCastException e) {
Log.e(ERROR_TAG, "ClassCastException serializing BriefMe", e); //$NON-NLS-1$
} catch (JSONException e) {
Log.e(ERROR_TAG, "JSONException serializing BriefMe", e); //$NON-NLS-1$
}
}
}
return true;
}
@Override
protected String getTypeString() {
return "BriefMe"; //$NON-NLS-1$
}
}

@ -1,322 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.text.TextUtils;
import android.util.Log;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.PropertyVisitor;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.ModelType;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.DaoReflectionHelpers;
import com.todoroo.astrid.dao.OutstandingEntryDao;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.OutstandingEntry;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.TagOutstanding;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.data.TaskAttachmentOutstanding;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.TaskOutstanding;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.data.UserActivityOutstanding;
public class ChangesHappened<TYPE extends RemoteModel, OE extends OutstandingEntry<TYPE>> extends ClientToServerMessage<TYPE> {
private static final String ERROR_TAG = "actfm-changes-happened";
protected final Class<OE> outstandingClass;
protected final List<OE> changes;
protected final OutstandingEntryDao<OE> outstandingDao;
public static final String CHANGES_KEY = "changes";
public static ChangesHappened<?, ?> instantiateChangesHappened(long id, ModelType modelType) {
switch(modelType) {
case TYPE_TASK:
return new ChangesHappened<Task, TaskOutstanding>(id, Task.class,
PluginServices.getTaskDao(), PluginServices.getTaskOutstandingDao());
case TYPE_TAG:
return new ChangesHappened<TagData, TagOutstanding>(id, TagData.class,
PluginServices.getTagDataDao(), PluginServices.getTagOutstandingDao());
case TYPE_ACTIVITY:
return new ChangesHappened<UserActivity, UserActivityOutstanding>(id, UserActivity.class,
PluginServices.getUserActivityDao(), PluginServices.getUserActivityOutstandingDao());
case TYPE_ATTACHMENT:
return new ChangesHappened<TaskAttachment, TaskAttachmentOutstanding>(id, TaskAttachment.class,
PluginServices.getTaskAttachmentDao(), PluginServices.getTaskAttachmentOutstandingDao());
case TYPE_TASK_LIST_METADATA:
return new TaskListMetadataChangesHappened(id, TaskListMetadata.class,
PluginServices.getTaskListMetadataDao(), PluginServices.getTaskListMetadataOutstandingDao());
default:
return null;
}
}
public ChangesHappened(long id, Class<TYPE> modelClass, RemoteModelDao<TYPE> modelDao,
OutstandingEntryDao<OE> outstandingDao) {
super(id, modelClass, modelDao);
this.outstandingClass = DaoReflectionHelpers.getOutstandingClass(modelClass);
this.outstandingDao = outstandingDao;
this.changes = new ArrayList<OE>();
if (!foundEntity) // Stop sending changes for entities that don't exist anymore
{
outstandingDao.deleteWhere(OutstandingEntry.ENTITY_ID_PROPERTY.eq(id));
}
}
@Override
protected boolean serializeExtrasToJSON(JSONObject serializeTo, MultipartEntity entity) throws JSONException {
// Process changes list and serialize to JSON
JSONArray changesJson = changesToJSON(entity);
if (changesJson == null || changesJson.length() == 0) {
return false;
}
serializeTo.put(CHANGES_KEY, changesJson);
return true;
}
@Override
protected String getTypeString() {
return "ChangesHappened";
}
public List<OE> getChanges() {
return changes;
}
private JSONArray changesToJSON(MultipartEntity entity) {
if (!RemoteModel.NO_UUID.equals(uuid)) {
populateChanges();
}
JSONArray array = new JSONArray();
AtomicInteger uploadCounter = new AtomicInteger();
PropertyToJSONVisitor visitor = new PropertyToJSONVisitor();
for (OE change : changes) {
try {
String localColumn = change.getValue(OutstandingEntry.COLUMN_STRING_PROPERTY);
JSONObject changeJson = new JSONObject();
changeJson.put("id", change.getId());
String serverColumn;
if (NameMaps.TAG_ADDED_COLUMN.equals(localColumn)) {
serverColumn = NameMaps.TAG_ADDED_COLUMN;
changeJson.put("value", change.getValue(OutstandingEntry.VALUE_STRING_PROPERTY));
} else if (NameMaps.TAG_REMOVED_COLUMN.equals(localColumn)) {
serverColumn = NameMaps.TAG_REMOVED_COLUMN;
changeJson.put("value", change.getValue(OutstandingEntry.VALUE_STRING_PROPERTY));
} else if (NameMaps.MEMBER_ADDED_COLUMN.equals(localColumn)) {
serverColumn = NameMaps.MEMBER_ADDED_COLUMN;
changeJson.put("value", change.getValue(OutstandingEntry.VALUE_STRING_PROPERTY));
} else if (NameMaps.MEMBER_REMOVED_COLUMN.equals(localColumn)) {
serverColumn = NameMaps.MEMBER_REMOVED_COLUMN;
changeJson.put("value", change.getValue(OutstandingEntry.VALUE_STRING_PROPERTY));
} else if (NameMaps.ATTACHMENT_ADDED_COLUMN.equals(localColumn)) {
serverColumn = NameMaps.ATTACHMENT_ADDED_COLUMN;
JSONObject fileJson = getFileJson(change.getValue(OutstandingEntry.VALUE_STRING_PROPERTY));
String name = fileJson == null ? null : addToEntityFromFileJson(entity, fileJson, uploadCounter);
if (name == null) {
PluginServices.getTaskAttachmentDao().delete(id);
PluginServices.getTaskAttachmentOutstandingDao().deleteWhere(TaskAttachmentOutstanding.ENTITY_ID_PROPERTY.eq(id));
return null;
}
changeJson.put("value", name);
} else {
Property<?> localProperty = NameMaps.localColumnNameToProperty(table, localColumn);
if (localProperty == null) {
throw new RuntimeException("No local property found for local column " + localColumn + " in table " + table);
}
serverColumn = NameMaps.localColumnNameToServerColumnName(table, localColumn);
if (serverColumn == null) {
throw new RuntimeException("No server column found for local column " + localColumn + " in table " + table);
}
Object value = localProperty.accept(visitor, change);
if (!validateValue(localProperty, value)) {
return null;
}
if (value == null) {
changeJson.put("value", JSONObject.NULL);
} else {
if (localProperty.checkFlag(Property.PROP_FLAG_PICTURE) && value instanceof JSONObject) {
JSONObject json = (JSONObject) value;
String name = addToEntityFromFileJson(entity, json, uploadCounter);
if (name != null) {
changeJson.put("value", name);
}
} else {
changeJson.put("value", value);
}
}
}
changeJson.put("column", serverColumn);
String createdAt = DateUtilities.timeToIso8601(change.getValue(OutstandingEntry.CREATED_AT_PROPERTY), true);
changeJson.put("created_at", createdAt != null ? createdAt : 0);
array.put(changeJson);
} catch (JSONException e) {
Log.e(ERROR_TAG, "Error writing change to JSON", e);
}
}
return array;
}
private String addToEntityFromFileJson(MultipartEntity entity, JSONObject json, AtomicInteger uploadCounter) {
if (json.has("path")) {
String path = json.optString("path");
String name = String.format("upload-%s-%s-%d", table, uuid, uploadCounter.get());
String type = json.optString("type");
File f = new File(path);
if (f.exists()) {
json.remove("path");
entity.addPart(name, new FileBody(f, type));
return name;
}
}
return null;
}
protected void populateChanges() {
TodorooCursor<OE> cursor = outstandingDao.query(Query.select(DaoReflectionHelpers.getModelProperties(outstandingClass))
.where(OutstandingEntry.ENTITY_ID_PROPERTY.eq(id)).orderBy(Order.asc(OutstandingEntry.CREATED_AT_PROPERTY)));
try {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
try {
OE instance = outstandingClass.newInstance();
instance.readPropertiesFromCursor(cursor);
changes.add(instance);
} catch (IllegalAccessException e) {
Log.e("ChangesHappened", "Error instantiating outstanding model class", e);
} catch (InstantiationException e2) {
Log.e("ChangesHappened", "Error instantiating outstanding model class", e2);
}
}
} finally {
cursor.close();
}
}
// Return false if value is detected to be something that would definitely cause a server error
// (e.g. empty task title, etc.)
private boolean validateValue(Property<?> property, Object value) {
if (Task.TITLE.equals(property)) {
if (!(value instanceof String) || TextUtils.isEmpty((String) value)) {
return false;
}
}
return true;
}
private JSONObject getFileJson(String value) {
try {
JSONObject obj = new JSONObject(value);
String path = obj.optString("path");
if (TextUtils.isEmpty(path)) {
return null;
}
File f = new File(path);
if (!f.exists()) {
return null;
}
return obj;
} catch (JSONException e) {
return null;
}
}
private class PropertyToJSONVisitor implements PropertyVisitor<Object, OE> {
private String getAsString(OE data) {
return data.getValue(OutstandingEntry.VALUE_STRING_PROPERTY);
}
@Override
public Object visitInteger(Property<Integer> property, OE data) {
Integer i = data.getMergedValues().getAsInteger(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (i != null) {
if (property.checkFlag(Property.PROP_FLAG_BOOLEAN)) {
return i > 0;
}
return i;
} else {
return getAsString(data);
}
}
@Override
public Object visitLong(Property<Long> property, OE data) {
Long l = data.getMergedValues().getAsLong(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (l != null) {
if (property.checkFlag(Property.PROP_FLAG_DATE)) {
boolean includeTime = true;
if (Task.DUE_DATE.equals(property) && !Task.hasDueTime(l)) {
includeTime = false;
}
return DateUtilities.timeToIso8601(l, includeTime);
}
return l;
} else {
return getAsString(data);
}
}
@Override
public Object visitDouble(Property<Double> property, OE data) {
Double d = data.getMergedValues().getAsDouble(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (d != null) {
return d;
} else {
return getAsString(data);
}
}
@Override
public Object visitString(Property<String> property, OE data) {
String value = getAsString(data);
if (RemoteModel.NO_UUID.equals(value) && property.checkFlag(Property.PROP_FLAG_USER_ID)) {
return ActFmPreferenceService.userId();
}
if (property.checkFlag(Property.PROP_FLAG_JSON)) {
if (TextUtils.isEmpty(value)) {
return null;
}
try {
if (value != null && value.startsWith("[")) {
return new JSONArray(value);
} else {
return new JSONObject(value);
}
} catch (JSONException e) {
return null;
}
}
return value;
}
}
}

@ -1,125 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.apache.http.entity.mime.MultipartEntity;
import org.json.JSONException;
import org.json.JSONObject;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.dao.DaoReflectionHelpers;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.RemoteModel;
public abstract class ClientToServerMessage<TYPE extends RemoteModel> {
protected final Class<TYPE> modelClass;
protected final String table;
protected final long id;
protected final String uuid;
protected final long pushedAt;
protected final boolean foundEntity;
public static final String TYPE_KEY = "type";
public static final String TABLE_KEY = "table";
public static final String UUID_KEY = "uuid";
public static final String PUSHED_AT_KEY = "pushed_at";
public ClientToServerMessage(Class<TYPE> modelClass, String uuid, long pushedAt) {
this.modelClass = modelClass;
Table tableClass = DaoReflectionHelpers.getStaticFieldByReflection(modelClass, Table.class, "TABLE");
this.table = NameMaps.getServerNameForTable(tableClass);
this.uuid = uuid;
this.pushedAt = pushedAt;
this.foundEntity = true;
this.id = AbstractModel.NO_ID;
}
public ClientToServerMessage(long id, Class<TYPE> modelClass, RemoteModelDao<TYPE> modelDao) {
this.id = id;
this.modelClass = modelClass;
Table tableClass = DaoReflectionHelpers.getStaticFieldByReflection(modelClass, Table.class, "TABLE");
this.table = NameMaps.getServerNameForTable(tableClass);
TYPE entity = getEntity(id, modelDao);
this.foundEntity = entity != null;
if (entity == null) {
this.uuid = RemoteModel.NO_UUID;
this.pushedAt = 0;
} else {
this.uuid = entity.getValue(RemoteModel.UUID_PROPERTY);
this.pushedAt = entity.getValue(RemoteModel.PUSHED_AT_PROPERTY);
}
}
private TYPE getEntity(long localId, RemoteModelDao<TYPE> modelDao) {
return modelDao.fetch(localId, RemoteModel.UUID_PROPERTY, RemoteModel.PUSHED_AT_PROPERTY);
}
public final String getUUID() {
return uuid;
}
public final long getPushedAt() {
return pushedAt;
}
public final JSONObject serializeToJSON(MultipartEntity entity) {
JSONObject json = new JSONObject();
try {
json.put(TYPE_KEY, getTypeString());
json.put(TABLE_KEY, table);
json.put(UUID_KEY, uuid);
String dateValue = DateUtilities.timeToIso8601(pushedAt, true);
json.put(PUSHED_AT_KEY, dateValue != null ? dateValue : 0);
if (serializeExtrasToJSON(json, entity)) {
return json;
} else {
return null;
}
} catch (JSONException e) {
return null;
}
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((table == null) ? 0 : table.hashCode());
result = prime * result + ((uuid == null) ? 0 : uuid.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
ClientToServerMessage<?> other = (ClientToServerMessage<?>) obj;
if (table == null) {
if (other.table != null) {
return false;
}
} else if (!table.equals(other.table)) {
return false;
}
if (uuid == null) {
if (other.uuid != null) {
return false;
}
} else if (!uuid.equals(other.uuid)) {
return false;
}
return true;
}
protected abstract boolean serializeExtrasToJSON(JSONObject serializeTo, MultipartEntity entity) throws JSONException;
protected abstract String getTypeString();
}

@ -1,78 +0,0 @@
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.Criterion;
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;
public class ConstructOutstandingTableFromMasterTable<TYPE extends RemoteModel, OE extends OutstandingEntry<TYPE>> {
protected final String table;
protected final RemoteModelDao<TYPE> dao;
protected final OutstandingEntryDao<OE> outstandingDao;
protected 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;
}
protected void extras(long itemId, long createdAt) {
// Subclasses can override
}
public void execute() {
execute(Criterion.all);
}
public void execute(Criterion criterion) {
Property<?>[] syncableProperties = NameMaps.syncableProperties(table);
TodorooCursor<TYPE> items = dao.query(Query.select(AndroidUtilities.addToArray(Property.class, syncableProperties, AbstractModel.ID_PROPERTY, RemoteModel.UUID_PROPERTY)).where(criterion));
try {
OE oe = outstandingDao.getModelClass().newInstance();
for (items.moveToFirst(); !items.isAfterLast(); items.moveToNext()) {
long createdAt;
if (createdAtProperty != null) {
createdAt = items.get(createdAtProperty);
} else {
createdAt = DateUtilities.now();
}
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);
Object value = items.get(p);
if (value == null) {
continue;
}
oe.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, value.toString());
oe.setValue(OutstandingEntry.CREATED_AT_PROPERTY, createdAt);
outstandingDao.createNew(oe);
}
extras(itemId, createdAt);
}
} 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();
}
}
}

@ -1,50 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.OutstandingEntryDao;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskOutstanding;
import com.todoroo.astrid.tags.TaskToTagMetadata;
public class ConstructTaskOutstandingTableFromMasterTable extends ConstructOutstandingTableFromMasterTable<Task, TaskOutstanding> {
private final MetadataDao metadataDao;
public ConstructTaskOutstandingTableFromMasterTable(String table, RemoteModelDao<Task> dao, OutstandingEntryDao<TaskOutstanding> outstandingDao, MetadataDao metadataDao, LongProperty createdAtProperty) {
super(table, dao, outstandingDao, createdAtProperty);
this.metadataDao = metadataDao;
}
@Override
protected void extras(long itemId, long createdAt) {
super.extras(itemId, createdAt);
TodorooCursor<Metadata> tagMetadata = metadataDao.query(Query.select(Metadata.PROPERTIES)
.where(Criterion.and(MetadataCriteria.byTaskAndwithKey(itemId, TaskToTagMetadata.KEY), Metadata.DELETION_DATE.eq(0))));
Metadata m = new Metadata();
try {
for (tagMetadata.moveToFirst(); !tagMetadata.isAfterLast(); tagMetadata.moveToNext()) {
m.clear();
m.readFromCursor(tagMetadata);
if (m.containsNonNullValue(TaskToTagMetadata.TAG_UUID)) {
TaskOutstanding oe = new TaskOutstanding();
oe.setValue(TaskOutstanding.ENTITY_ID_PROPERTY, itemId);
oe.setValue(TaskOutstanding.COLUMN_STRING, NameMaps.TAG_ADDED_COLUMN);
oe.setValue(TaskOutstanding.VALUE_STRING, m.getValue(TaskToTagMetadata.TAG_UUID));
oe.setValue(TaskOutstanding.CREATED_AT, createdAt);
outstandingDao.createNew(oe);
}
}
} finally {
tagMetadata.close();
}
}
}

@ -1,59 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.DatabaseDao;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.dao.HistoryDao;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.History;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.UserActivity;
public class ConvertSelfUserIdsToZero {
@Autowired
private TaskDao taskDao;
@Autowired
private TagDataDao tagDataDao;
@Autowired
private HistoryDao historyDao;
@Autowired
private UserActivityDao userActivityDao;
public ConvertSelfUserIdsToZero() {
DependencyInjectionService.getInstance().inject(this);
}
public synchronized void execute(String selfId) {
if (RemoteModel.isValidUuid(selfId)) {
updateDatabase(taskDao, new Task(), Task.CREATOR_ID, selfId);
updateDatabase(taskDao, new Task(), Task.USER_ID, selfId);
updateDatabase(tagDataDao, new TagData(), TagData.USER_ID, selfId);
updateDatabase(historyDao, new History(), History.USER_UUID, selfId);
updateDatabase(userActivityDao, new UserActivity(), UserActivity.USER_UUID, selfId);
}
}
public synchronized void execute() {
String selfId = ActFmPreferenceService.userId();
execute(selfId);
}
private <T extends AbstractModel> void updateDatabase(DatabaseDao<T> dao, T instance, StringProperty property, String selfId) {
instance.setValue(property, Task.USER_ID_SELF);
instance.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
dao.update(property.eq(selfId), instance);
}
}

@ -1,22 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.json.JSONObject;
import android.text.TextUtils;
import android.util.Log;
public class Debug extends ServerToClientMessage {
public Debug(JSONObject json) {
super(json);
}
@Override
public void processMessage(String serverTime) {
String message = json.optString("message");
if (!TextUtils.isEmpty(message)) {
Log.w("actfm-debug-message", message);
}
}
}

@ -1,16 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.json.JSONObject;
public class DoubleCheck extends ServerToClientMessage {
public DoubleCheck(JSONObject json) {
super(json);
}
@Override
public void processMessage(String serverTime) {
// TODO Auto-generated method stub
}
}

@ -1,199 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONObject;
import android.text.TextUtils;
import android.util.Log;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.astrid.actfm.sync.ActFmInvoker;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.SyncMessageCallback;
import com.todoroo.astrid.dao.HistoryDao;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.dao.UserDao;
import com.todoroo.astrid.data.History;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.User;
public class FetchHistory<TYPE extends RemoteModel> {
private static final String ERROR_TAG = "actfm-fetch-history"; //$NON-NLS-1$
private final RemoteModelDao<TYPE> dao;
private final LongProperty historyTimeProperty;
private final IntegerProperty historyHasMoreProperty;
private final String table;
private final String uuid;
private final String taskTitle;
private final long modifiedAfter;
private final int offset;
private final SyncMessageCallback done;
@Autowired
private ActFmInvoker actFmInvoker;
@Autowired
private HistoryDao historyDao;
@Autowired
private UserDao userDao;
@Autowired
private ActFmPreferenceService actFmPreferenceService;
public FetchHistory(RemoteModelDao<TYPE> dao, LongProperty historyTimeProperty, IntegerProperty historyHasMoreProperty,
String table, String uuid, String taskTitle, long modifiedAfter, int offset, SyncMessageCallback done) {
DependencyInjectionService.getInstance().inject(this);
this.dao = dao;
this.historyTimeProperty = historyTimeProperty;
this.historyHasMoreProperty = historyHasMoreProperty;
this.table = table;
this.uuid = uuid;
this.taskTitle = taskTitle;
this.modifiedAfter = modifiedAfter;
this.offset = offset;
this.done = done;
}
public void execute() {
new Thread(new Runnable() {
@Override
public void run() {
String token = actFmPreferenceService.getToken();
if (TextUtils.isEmpty(token) || TextUtils.isEmpty(uuid)) {
return;
}
ArrayList<Object> params = new ArrayList<Object>();
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
params.add("task_id");
} else if (NameMaps.TABLE_ID_TAGS.equals(table)) {
params.add("tag_id");
} else {
return;
}
params.add(uuid);
if (modifiedAfter > 0) {
params.add("modified_after"); params.add(modifiedAfter / 1000L);
}
if (offset > 0) {
params.add("offset"); params.add(offset);
}
params.add("token"); params.add(token);
try {
JSONObject result = actFmInvoker.invoke("model_history_list", params.toArray(new Object[params.size()]));
JSONArray list = result.optJSONArray("list");
boolean hasMore = result.optInt("has_more") > 0;
long time = result.optLong("time") * 1000;
if (hasMore && offset == 0) {
historyDao.deleteWhere(History.TARGET_ID.eq(uuid));
}
if (list != null) {
for (int i = 0; i < list.length(); i++) {
JSONObject historyJson = list.optJSONObject(i);
if (historyJson != null) {
History history = new History();
history.setValue(History.TABLE_ID, table);
history.setValue(History.TARGET_ID, uuid);
history.setValue(History.UUID, historyJson.optString("id") + ":" + uuid);
String userId = historyJson.optString("user_id");
if (userId.equals(ActFmPreferenceService.userId())) {
userId = Task.USER_ID_SELF;
}
history.setValue(History.USER_UUID, historyJson.optString("user_id"));
history.setValue(History.COLUMN, historyJson.optString("column"));
history.setValue(History.OLD_VALUE, historyJson.optString("prev"));
history.setValue(History.NEW_VALUE, historyJson.optString("value"));
history.setValue(History.CREATED_AT, historyJson.optLong("created_at") * 1000);
JSONArray taskObj = historyJson.optJSONArray("task");
if (taskObj != null) {
history.setValue(History.TABLE_ID, NameMaps.TABLE_ID_TASKS);
history.setValue(History.TARGET_ID, taskObj.optString(0));
history.setValue(History.TASK, taskObj.toString());
} else if (NameMaps.TABLE_ID_TASKS.equals(table) && !TextUtils.isEmpty(taskTitle)) {
taskObj = new JSONArray();
taskObj.put(uuid);
taskObj.put(taskTitle);
history.setValue(History.TASK, taskObj.toString());
}
if (NameMaps.TABLE_ID_TAGS.equals(table)) {
history.setValue(History.TAG_ID, uuid);
}
if (historyDao.update(History.UUID.eq(history.getValue(History.UUID)), history) <= 0) {
historyDao.createNew(history);
}
}
}
if (time > 0) {
TYPE template;
try {
template = dao.getModelClass().newInstance();
template.setValue(historyTimeProperty, time);
if (modifiedAfter == 0 || hasMore) {
template.setValue(historyHasMoreProperty, hasMore ? 1 : 0);
}
dao.update(RemoteModel.UUID_PROPERTY.eq(uuid), template);
} catch (InstantiationException e) {
Log.e(ERROR_TAG, "Error instantiating model for recording time", e);
} catch (IllegalAccessException e) {
Log.e(ERROR_TAG, "Error instantiating model for recording time", e);
}
}
}
JSONObject users = result.optJSONObject("users");
if (users != null) {
Iterator<String> keys = users.keys();
while (keys.hasNext()) {
String key = keys.next();
JSONObject userObj = users.optJSONObject(key);
if (userObj != null) {
String userUuid = userObj.optString("id");
if (RemoteModel.isUuidEmpty(uuid)) {
continue;
}
User user = new User();
user.setValue(User.FIRST_NAME, userObj.optString("first_name"));
user.setValue(User.LAST_NAME, userObj.optString("last_name"));
user.setValue(User.NAME, userObj.optString("name"));
user.setValue(User.PICTURE, userObj.optString("picture"));
user.setValue(User.UUID, userUuid);
if (userDao.update(User.UUID.eq(userUuid), user) <= 0) {
userDao.createNew(user);
}
}
}
}
} catch (IOException e) {
Log.e(ERROR_TAG, "Error getting model history", e);
}
if (done != null) {
done.runOnSuccess();
}
}
}).start();
}
}

@ -1,112 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.DoubleProperty;
import com.todoroo.andlib.data.Property.IntegerProperty;
import com.todoroo.andlib.data.Property.LongProperty;
import com.todoroo.andlib.data.Property.PropertyVisitor;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.data.Task;
public class JSONChangeToPropertyVisitor implements PropertyVisitor<Void, String> {
private static final String ERROR_TAG = "actfm-make-changes";
private final AbstractModel model;
private final JSONObject data;
public JSONChangeToPropertyVisitor(AbstractModel model, JSONObject data) {
this.model = model;
this.data = data;
}
@Override
public Void visitInteger(Property<Integer> property, String key) {
try {
int value;
if (property.checkFlag(Property.PROP_FLAG_BOOLEAN)) {
try {
value = data.getBoolean(key) ? 1 : 0;
} catch (JSONException e) {
value = data.getInt(key);
}
} else {
value = data.getInt(key);
}
model.setValue((IntegerProperty) property, value);
} catch (JSONException e) {
Log.e(ERROR_TAG, "Error reading int value with key " + key + " from JSON " + data, e);
}
return null;
}
@Override
public Void visitLong(Property<Long> property, String key) {
try {
long value = data.optLong(key, 0);
if (property.checkFlag(Property.PROP_FLAG_DATE)) {
String valueString = data.getString(key);
try {
value = DateUtilities.parseIso8601(valueString);
if (Task.DUE_DATE.equals(property)) {
value = Task.createDueDate(DateUtilities.isoStringHasTime(valueString) ? Task.URGENCY_SPECIFIC_DAY_TIME : Task.URGENCY_SPECIFIC_DAY, value);
}
} catch (Exception e){
value = 0;
}
}
model.setValue((LongProperty) property, value);
} catch (JSONException e) {
Log.e(ERROR_TAG, "Error reading long value with key " + key + " from JSON " + data, e);
}
return null;
}
@Override
public Void visitDouble(Property<Double> property, String key) {
try {
double value = data.getDouble(key);
model.setValue((DoubleProperty) property, value);
} catch (JSONException e) {
Log.e(ERROR_TAG, "Error reading double value with key " + key + " from JSON " + data, e);
}
return null;
}
@Override
public Void visitString(Property<String> property, String key) {
try {
String value = data.getString(key);
if ("null".equals(value)) {
value = "";
} else if (property.checkFlag(Property.PROP_FLAG_USER_ID) && ActFmPreferenceService.userId().equals(value)) {
value = Task.USER_ID_SELF;
}
if (property.equals(Task.USER_ID)) {
model.setValue(Task.USER, ""); // Clear this value for migration purposes
}
model.setValue((StringProperty) property, value);
} catch (JSONException e) {
try {
JSONObject object = data.getJSONObject(key);
if (object != null) {
model.setValue((StringProperty) property, object.toString());
}
} catch (JSONException e2) {
Log.e(ERROR_TAG, "Error reading JSON value with key " + key + " from JSON " + data, e);
}
Log.e(ERROR_TAG, "Error reading string value with key " + key + " from JSON " + data, e);
}
return null;
}
}

@ -1,56 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.apache.http.entity.mime.MultipartEntity;
import org.json.JSONObject;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
public class JSONPayloadBuilder {
private final StringBuilder sb = new StringBuilder("["); //$NON-NLS-1$
private final StringBuilder temp = new StringBuilder();
private int messageCount = 0;
public boolean addMessage(ClientToServerMessage<?> message, MultipartEntity entity) {
try {
JSONObject serialized = message.serializeToJSON(entity);
return addJSONObject(serialized);
} catch (OutOfMemoryError e) {
return false;
}
}
public boolean addJSONObject(JSONObject obj) {
try {
temp.delete(0, temp.length());
if (obj != null) {
temp.append(obj)
.append(","); //$NON-NLS-1$
ActFmSyncThread.syncLog(temp.toString());
sb.append(temp);
messageCount++;
return true;
} else {
return false;
}
} catch (OutOfMemoryError e) {
return false;
}
}
public int getMessageCount() {
return messageCount;
}
public String closeAndReturnString() {
if (messageCount > 0) {
sb.deleteCharAt(sb.length() - 1); // Remove final comma
}
sb.append("]"); //$NON-NLS-1$
return sb.toString();
}
}

@ -1,452 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Iterator;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.text.TextUtils;
import android.util.Log;
import org.tasks.R;
import com.todoroo.andlib.data.AbstractModel;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.StringProperty;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmInvoker;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.HistoryDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.dao.TagMetadataDao;
import com.todoroo.astrid.dao.TaskListMetadataDao;
import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.History;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.TagMetadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.reminders.Notifications;
import com.todoroo.astrid.reminders.ReminderService;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TaskToTagMetadata;
public class MakeChanges<TYPE extends RemoteModel> extends ServerToClientMessage {
private static final String ERROR_TAG = "actfm-make-changes";
private final RemoteModelDao<TYPE> dao;
private final String table;
public MakeChanges(JSONObject json, RemoteModelDao<TYPE> dao) {
super(json);
this.table = json.optString("table");
this.dao = dao;
}
public static <T extends RemoteModel> T changesToModel(RemoteModelDao<T> dao, JSONObject changes, String table) throws IllegalAccessException, InstantiationException {
T model = dao.getModelClass().newInstance();
JSONChangeToPropertyVisitor visitor = new JSONChangeToPropertyVisitor(model, changes);
Iterator<String> keys = changes.keys();
while (keys.hasNext()) {
String column = keys.next();
Property<?> property = NameMaps.serverColumnNameToLocalProperty(table, column);
if (property != null) { // Unsupported property
property.accept(visitor, column);
}
}
return model;
}
private static <T extends RemoteModel> void saveOrUpdateModelAfterChanges(RemoteModelDao<T> dao, T model, String oldUuid, String uuid, String serverTime, Criterion orCriterion) {
Criterion uuidCriterion;
if (oldUuid == null) {
uuidCriterion = RemoteModel.UUID_PROPERTY.eq(uuid);
} else {
uuidCriterion = RemoteModel.UUID_PROPERTY.eq(oldUuid);
}
if (orCriterion != null) {
uuidCriterion = Criterion.or(uuidCriterion, orCriterion);
}
if (model.getSetValues() != null && model.getSetValues().size() > 0) {
long pushedAt;
try {
pushedAt = DateUtilities.parseIso8601(serverTime);
} catch (ParseException e) {
pushedAt = 0;
}
if (pushedAt > 0) {
model.setValue(RemoteModel.PUSHED_AT_PROPERTY, pushedAt);
}
model.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
if (dao.update(uuidCriterion, model) <= 0) { // If update doesn't update rows. create a new model
model.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
dao.createNew(model);
}
}
}
@Override
public void processMessage(String serverTime) {
JSONObject changes = json.optJSONObject("changes");
String uuid = json.optString("uuid");
if (changes != null && !TextUtils.isEmpty(uuid)) {
if (dao != null) {
try {
TYPE model = changesToModel(dao, changes, table);
StringProperty uuidProperty = (StringProperty) NameMaps.serverColumnNameToLocalProperty(table, "uuid");
String oldUuid = null; // For indicating that a uuid collision has occurred
if (model.getSetValues() != null && model.getSetValues().containsKey(uuidProperty.name)) {
oldUuid = uuid;
uuid = model.getValue(uuidProperty);
}
beforeSaveChanges(changes, model, uuid);
if (model.getSetValues() != null && !model.getSetValues().containsKey(uuidProperty.name)) {
model.setValue(uuidProperty, uuid);
}
saveOrUpdateModelAfterChanges(dao, model, oldUuid, uuid, serverTime, getMatchCriterion(model));
afterSaveChanges(changes, model, uuid, oldUuid);
} catch (IllegalAccessException e) {
Log.e(ERROR_TAG, "Error instantiating model for MakeChanges", e);
} catch (InstantiationException e) {
Log.e(ERROR_TAG, "Error instantiating model for MakeChanges", e);
}
}
}
}
private Criterion getMatchCriterion(TYPE model) {
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;
}
private void beforeSaveChanges(JSONObject changes, TYPE model, String uuid) {
ChangeHooks beforeSaveChanges = null;
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
beforeSaveChanges = new BeforeSaveTaskChanges(model, changes, uuid);
} else if (NameMaps.TABLE_ID_TAGS.equals(table)) {
beforeSaveChanges = new BeforeSaveTagChanges(model, changes, uuid);
}
if (beforeSaveChanges != null) {
beforeSaveChanges.performChanges();
}
}
private void afterSaveChanges(JSONObject changes, TYPE model, String uuid, String oldUuid) {
ChangeHooks afterSaveChanges = null;
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
afterSaveChanges = new AfterSaveTaskChanges(model, changes, uuid, oldUuid);
} else if (NameMaps.TABLE_ID_TAGS.equals(table)) {
afterSaveChanges = new AfterSaveTagChanges(model, changes, uuid, oldUuid);
} else if (NameMaps.TABLE_ID_USERS.equals(table)) {
afterSaveChanges = new AfterSaveUserChanges(model, changes, uuid);
}
if (afterSaveChanges != null) {
afterSaveChanges.performChanges();
}
}
private abstract class ChangeHooks {
protected final TYPE model;
protected final JSONObject changes;
protected final String uuid;
public ChangeHooks(TYPE model, JSONObject changes, String uuid) {
this.model = model;
this.changes = changes;
this.uuid = uuid;
}
public abstract void performChanges();
protected long getLocalId() {
long localId;
if (!model.isSaved()) { // We don't have the local task id
localId = dao.localIdFromUuid(uuid);
model.setId(localId);
} else {
localId = model.getId();
}
return localId;
}
}
private class BeforeSaveTaskChanges extends ChangeHooks {
public BeforeSaveTaskChanges(TYPE model, JSONObject changes, String uuid) {
super(model, changes, uuid);
}
@Override
public void performChanges() {
//
}
}
private class BeforeSaveTagChanges extends ChangeHooks {
public BeforeSaveTagChanges(TYPE model, JSONObject changes, String uuid) {
super(model, changes, uuid);
}
@Override
public void performChanges() {
JSONArray addMembers = changes.optJSONArray("member_added");
boolean membersAdded = (addMembers != null && addMembers.length() > 0);
if (membersAdded) {
model.setValue(TagData.MEMBERS, ""); // Clear this value for migration purposes
}
}
}
private class AfterSaveTaskChanges extends ChangeHooks {
private final String oldUuid;
public AfterSaveTaskChanges(TYPE model, JSONObject changes, String uuid, String oldUuid) {
super(model, changes, uuid);
this.oldUuid = oldUuid;
}
@Override
public void performChanges() {
if (!TextUtils.isEmpty(oldUuid) && !oldUuid.equals(uuid)) {
uuidChanged(oldUuid, uuid);
}
if (changes.has(NameMaps.localPropertyToServerColumnName(NameMaps.TABLE_ID_TASKS, Task.DUE_DATE)) ||
changes.has(NameMaps.localPropertyToServerColumnName(NameMaps.TABLE_ID_TASKS, Task.COMPLETION_DATE))) {
Task t = PluginServices.getTaskDao().fetch(uuid, ReminderService.NOTIFICATION_PROPERTIES);
if (t != null) {
if ((changes.has("task_repeated") && t.getValue(Task.DUE_DATE) > DateUtilities.now()) || t.getValue(Task.COMPLETION_DATE) > 0) {
Notifications.cancelNotifications(t.getId());
}
ReminderService.getInstance().scheduleAlarm(t);
}
}
JSONArray addTags = changes.optJSONArray("tag_added");
JSONArray removeTags = changes.optJSONArray("tag_removed");
boolean tagsAdded = (addTags != null && addTags.length() > 0);
boolean tagsRemoved = (removeTags != null && removeTags.length() > 0);
if (!tagsAdded && !tagsRemoved) {
return;
}
long localId = AbstractModel.NO_ID;
if (tagsAdded || tagsRemoved) {
localId = getLocalId();
}
if (tagsAdded) {
if (model.isSaved()) {
TagService tagService = TagService.getInstance();
for (int i = 0; i < addTags.length(); i++) {
try {
String tagUuid = addTags.getString(i);
tagService.createLink(model.getId(), uuid, tagUuid, true);
} catch (JSONException e) {
//
}
}
}
}
if (tagsRemoved) {
ArrayList<String> toRemove = new ArrayList<String>(removeTags.length());
for (int i = 0; i < removeTags.length(); i++) {
try {
String tagUuid = removeTags.getString(i);
toRemove.add(tagUuid);
} catch (JSONException e) {
//
}
}
TagService.getInstance().deleteLinks(localId, uuid, toRemove.toArray(new String[toRemove.size()]), true);
}
}
private void uuidChanged(String fromUuid, String toUuid) {
if (ActFmInvoker.SYNC_DEBUG) {
Log.e(ERROR_TAG, "Task UUID collision -- old uuid: " + fromUuid + ", new uuid: " + toUuid);
}
// Update reference from UserActivity to task uuid
UserActivityDao activityDao = PluginServices.getUserActivityDao();
UserActivity activityTemplate = new UserActivity();
activityTemplate.setValue(UserActivity.TARGET_ID, toUuid);
activityTemplate.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
activityDao.update(Criterion.and(UserActivity.ACTION.eq(UserActivity.ACTION_TASK_COMMENT), UserActivity.TARGET_ID.eq(fromUuid)), activityTemplate);
// Update reference from task to tag metadata to task uuid
MetadataService metadataService = PluginServices.getMetadataService();
Metadata taskToTagTemplate = new Metadata();
taskToTagTemplate.setValue(TaskToTagMetadata.TASK_UUID, toUuid);
taskToTagTemplate.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
metadataService.update(Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY), TaskToTagMetadata.TASK_UUID.eq(fromUuid)), taskToTagTemplate);
HistoryDao historyDao = PluginServices.getHistoryDao();
History histTemplate = new History();
histTemplate.setValue(History.TARGET_ID, toUuid);
historyDao.update(Criterion.and(History.TABLE_ID.eq(NameMaps.TABLE_ID_TAGS), History.TARGET_ID.eq(oldUuid)), histTemplate);
}
}
private class AfterSaveTagChanges extends ChangeHooks {
private final String oldUuid;
public AfterSaveTagChanges(TYPE model, JSONObject changes, String uuid, String oldUuid) {
super(model, changes, uuid);
this.oldUuid = oldUuid;
}
@Override
public void performChanges() {
if (!TextUtils.isEmpty(oldUuid) && !oldUuid.equals(uuid)) {
uuidChanged(oldUuid, uuid);
}
String nameCol = NameMaps.localPropertyToServerColumnName(NameMaps.TABLE_ID_TAGS, TagData.NAME);
String deletedCol = NameMaps.localPropertyToServerColumnName(NameMaps.TABLE_ID_TAGS, TagData.DELETION_DATE);
if (changes.has(nameCol)) {
Metadata template = new Metadata();
template.setValue(TaskToTagMetadata.TAG_NAME, changes.optString(nameCol));
PluginServices.getMetadataService().update(
Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY),
TaskToTagMetadata.TAG_UUID.eq(uuid)), template);
} else if (changes.has(deletedCol)) {
Metadata template = new Metadata();
String valueString = changes.optString(deletedCol);
long deletedValue = 0;
if (!TextUtils.isEmpty(valueString)) {
try {
deletedValue = DateUtilities.parseIso8601(valueString);
} catch (Exception e){
//
}
}
template.setValue(Metadata.DELETION_DATE, deletedValue);
template.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
PluginServices.getMetadataService().update(
Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY),
TaskToTagMetadata.TAG_UUID.eq(uuid)), template);
}
TagMetadataDao tagMetadataDao = PluginServices.getTagMetadataDao();
JSONArray addMembers = changes.optJSONArray("member_added");
JSONArray removeMembers = changes.optJSONArray("member_removed");
boolean membersAdded = (addMembers != null && addMembers.length() > 0);
boolean membersRemoved = (removeMembers != null && removeMembers.length() > 0);
long localId = AbstractModel.NO_ID;
if (membersAdded || membersRemoved) {
localId = getLocalId();
}
if (membersAdded) {
for (int i = 0; i < addMembers.length(); i++) {
try {
String memberId = addMembers.getString(i);
tagMetadataDao.createMemberLink(localId, uuid, memberId, true);
} catch (JSONException e) {
//
}
}
}
if (membersRemoved) {
ArrayList<String> toRemove = new ArrayList<String>(removeMembers.length());
for (int i = 0; i < removeMembers.length(); i++) {
try {
String tagUuid = removeMembers.getString(i);
toRemove.add(tagUuid);
} catch (JSONException e) {
//
}
}
tagMetadataDao.removeMemberLinks(localId, uuid, toRemove.toArray(new String[toRemove.size()]), true);
}
}
private void uuidChanged(String fromUuid, String toUuid) {
if (ActFmInvoker.SYNC_DEBUG) {
Log.e(ERROR_TAG, "Tag UUID collision -- old uuid: " + fromUuid + ", new uuid: " + toUuid);
}
UserActivityDao activityDao = PluginServices.getUserActivityDao();
UserActivity activityTemplate = new UserActivity();
activityTemplate.setValue(UserActivity.TARGET_ID, toUuid);
activityTemplate.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
activityDao.update(Criterion.and(UserActivity.ACTION.eq(UserActivity.ACTION_TAG_COMMENT), UserActivity.TARGET_ID.eq(fromUuid)), activityTemplate);
// Update reference from task to tag metadata to tag uuid
MetadataService metadataService = PluginServices.getMetadataService();
Metadata taskToTagTemplate = new Metadata();
taskToTagTemplate.setValue(TaskToTagMetadata.TAG_UUID, toUuid);
taskToTagTemplate.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
metadataService.update(Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY), TaskToTagMetadata.TAG_UUID.eq(fromUuid)), taskToTagTemplate);
// Update reference from tag metadata to tag uuid
TagMetadataDao tagMetadataDao = PluginServices.getTagMetadataDao();
TagMetadata memberMetadataTemplate = new TagMetadata();
memberMetadataTemplate.setValue(TagMetadata.TAG_UUID, toUuid);
memberMetadataTemplate.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
tagMetadataDao.update(TagMetadata.TAG_UUID.eq(fromUuid), memberMetadataTemplate);
HistoryDao historyDao = PluginServices.getHistoryDao();
History histTemplate = new History();
histTemplate.setValue(History.TARGET_ID, toUuid);
historyDao.update(Criterion.and(History.TABLE_ID.eq(NameMaps.TABLE_ID_TAGS), History.TARGET_ID.eq(oldUuid)), histTemplate);
TaskListMetadataDao taskListMetadataDao = PluginServices.getTaskListMetadataDao();
TaskListMetadata tlm = new TaskListMetadata();
tlm.setValue(TaskListMetadata.TAG_UUID, toUuid);
tlm.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
taskListMetadataDao.update(TaskListMetadata.TAG_UUID.eq(fromUuid), tlm);
}
}
private class AfterSaveUserChanges extends ChangeHooks {
public AfterSaveUserChanges(TYPE model, JSONObject changes, String uuid) {
super(model, changes, uuid);
}
@Override
public void performChanges() {
}
}
}

@ -1,14 +1,6 @@
package com.todoroo.astrid.actfm.sync.messages;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Table;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.data.History;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskAttachment;
@ -16,13 +8,16 @@ import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.data.UserActivity;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
public class NameMaps {
// --------------------------------
// ---- Table name mappings -------
// --------------------------------
private static final Map<Table, String> TABLE_LOCAL_TO_SERVER;
private static final Map<String, Table> TABLE_SERVER_TO_LOCAL;
// Universal table identifiers
public static final String TABLE_ID_TASKS = "tasks";
@ -33,37 +28,6 @@ public class NameMaps {
public static final String TABLE_ID_ATTACHMENTS = "task_attachments";
public static final String TABLE_ID_TASK_LIST_METADATA = "task_list_metadata";
private static final String PUSHED_AT_PREFIX = "pushed_at";
public static final String PUSHED_AT_TASKS = PUSHED_AT_PREFIX + "_" + TABLE_ID_TASKS;
public static final String PUSHED_AT_TAGS = PUSHED_AT_PREFIX + "_" + TABLE_ID_TAGS;
public static final String PUSHED_AT_USERS = PUSHED_AT_PREFIX + "_" + TABLE_ID_USERS;
public static final String PUSHED_AT_ACTIVITY = PUSHED_AT_PREFIX + "_" + TABLE_ID_USER_ACTIVITY;
public static final String PUSHED_AT_TASK_LIST_METADATA = PUSHED_AT_PREFIX + "_" + TABLE_ID_TASK_LIST_METADATA;
static {
// Hardcoded local tables mapped to corresponding server names
TABLE_LOCAL_TO_SERVER = new HashMap<Table, String>();
TABLE_LOCAL_TO_SERVER.put(Task.TABLE, TABLE_ID_TASKS);
TABLE_LOCAL_TO_SERVER.put(TagData.TABLE, TABLE_ID_TAGS);
TABLE_LOCAL_TO_SERVER.put(User.TABLE, TABLE_ID_USERS);
TABLE_LOCAL_TO_SERVER.put(History.TABLE, TABLE_ID_HISTORY);
TABLE_LOCAL_TO_SERVER.put(UserActivity.TABLE, TABLE_ID_USER_ACTIVITY);
TABLE_LOCAL_TO_SERVER.put(TaskAttachment.TABLE, TABLE_ID_ATTACHMENTS);
TABLE_LOCAL_TO_SERVER.put(TaskListMetadata.TABLE, TABLE_ID_TASK_LIST_METADATA);
// Reverse the mapping to construct the server to local map
TABLE_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TABLE_LOCAL_TO_SERVER);
}
public static String getServerNameForTable(Table table) {
return TABLE_LOCAL_TO_SERVER.get(table);
}
public static Table getLocalTableForServerName(String serverName) {
return TABLE_SERVER_TO_LOCAL.get(serverName);
}
// --------------------------------
// ---- Column name mappings -------
// --------------------------------
@ -78,31 +42,6 @@ public class NameMaps {
}
}
public static Property<?>[] syncableProperties(String table) {
if (TABLE_ID_TASKS.equals(table)) {
return computeSyncableProperties(TASK_PROPERTIES_LOCAL_TO_SERVER.keySet(), TASK_PROPERTIES_EXCLUDED);
} else if (TABLE_ID_TAGS.equals(table)) {
return computeSyncableProperties(TAG_DATA_PROPERTIES_LOCAL_TO_SERVER.keySet(), TAG_PROPERTIES_EXCLUDED);
} else if (TABLE_ID_USER_ACTIVITY.equals(table)) {
return computeSyncableProperties(USER_ACTIVITY_PROPERTIES_LOCAL_TO_SERVER.keySet(), USER_ACTIVITY_PROPERTIES_EXCLUDED);
} else if (TABLE_ID_ATTACHMENTS.equals(table)) {
return computeSyncableProperties(TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER.keySet(), TASK_ATTACHMENT_PROPERTIES_EXCLUDED);
} else if (TABLE_ID_TASK_LIST_METADATA.equals(table)) {
return computeSyncableProperties(TASK_LIST_METADATA_PROPERTIES_LOCAL_TO_SERVER.keySet(), TASK_LIST_METADATA_PROPERTIES_EXCLUDED);
}
return null;
}
private static Property<?>[] computeSyncableProperties(Set<Property<?>> baseSet, Set<String> excluded) {
Set<Property<?>> result = new HashSet<Property<?>>();
for (Property<?> elem : baseSet) {
if (!excluded.contains(elem.name)) {
result.add(elem);
}
}
return result.toArray(new Property<?>[result.size()]);
}
// ----------
// Tasks
// ----------
@ -110,7 +49,6 @@ public class NameMaps {
private static final Map<Property<?>, String> TASK_PROPERTIES_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> TASK_COLUMN_NAMES_TO_PROPERTIES;
private static final Map<String, String> TASK_COLUMNS_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> TASK_PROPERTIES_SERVER_TO_LOCAL;
private static final Set<String> TASK_PROPERTIES_EXCLUDED;
@ -142,8 +80,6 @@ public class NameMaps {
putTaskPropertyToServerName(Task.IS_PUBLIC, "public", true);
putTaskPropertyToServerName(Task.IS_READONLY, "read_only", false);
putTaskPropertyToServerName(Task.CLASSIFICATION, "classification", false);
TASK_PROPERTIES_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TASK_PROPERTIES_LOCAL_TO_SERVER);
}
public static final String TAG_ADDED_COLUMN = "tag_added";
@ -157,7 +93,6 @@ public class NameMaps {
private static final Map<Property<?>, String> TAG_DATA_PROPERTIES_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> TAG_DATA_COLUMN_NAMES_TO_PROPERTIES;
private static final Map<String, String> TAG_DATA_COLUMNS_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> TAG_DATA_PROPERTIES_SERVER_TO_LOCAL;
private static final Set<String> TAG_PROPERTIES_EXCLUDED;
private static void putTagPropertyToServerName(Property<?> property, String serverName, boolean writeable) {
@ -180,23 +115,17 @@ public class NameMaps {
putTagPropertyToServerName(TagData.TAG_DESCRIPTION, "description", true);
putTagPropertyToServerName(TagData.PICTURE, "picture", true);
putTagPropertyToServerName(TagData.IS_FOLDER, "is_folder", false);
// Reverse the mapping to construct the server to local map
TAG_DATA_PROPERTIES_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TAG_DATA_PROPERTIES_LOCAL_TO_SERVER);
}
public static final String MEMBER_ADDED_COLUMN = "member_added";
public static final String MEMBER_REMOVED_COLUMN = "member_removed";
// ----------
// Users
// ----------
private static final Map<Property<?>, String> USER_PROPERTIES_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> USER_COLUMN_NAMES_TO_PROPERTIES;
private static final Map<String, String> USER_COLUMNS_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> USER_PROPERTIES_SERVER_TO_LOCAL;
private static final Set<String> USER_PROPERTIES_EXCLUDED;
private static void putUserPropertyToServerName(Property<?> property, String serverName, boolean writeable) {
@ -215,10 +144,6 @@ public class NameMaps {
putUserPropertyToServerName(User.FIRST_NAME, "first_name", false);
putUserPropertyToServerName(User.LAST_NAME, "last_name", false);
putUserPropertyToServerName(User.STATUS, "connection", true);
// Reverse the mapping to construct the server to local map
USER_PROPERTIES_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(USER_PROPERTIES_LOCAL_TO_SERVER);
}
// ----------
@ -227,7 +152,6 @@ public class NameMaps {
private static final Map<Property<?>, String> USER_ACTIVITY_PROPERTIES_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> USER_ACTIVITY_COLUMN_NAMES_TO_PROPERTIES;
private static final Map<String, String> USER_ACTIVITY_COLUMNS_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> USER_ACTIVITY_PROPERTIES_SERVER_TO_LOCAL;
private static final Set<String> USER_ACTIVITY_PROPERTIES_EXCLUDED;
private static void putUserActivityPropertyToServerName(Property<?> property, String serverName, boolean writeable) {
@ -250,10 +174,6 @@ public class NameMaps {
putUserActivityPropertyToServerName(UserActivity.TARGET_NAME, "target_name", false);
putUserActivityPropertyToServerName(UserActivity.CREATED_AT, "created_at", true);
putUserActivityPropertyToServerName(UserActivity.DELETED_AT, "deleted_at", true);
// Reverse the mapping to construct the server to local map
USER_ACTIVITY_PROPERTIES_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(USER_ACTIVITY_PROPERTIES_LOCAL_TO_SERVER);
}
// ----------
@ -262,7 +182,6 @@ public class NameMaps {
private static final Map<Property<?>, String> TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> TASK_ATTACHMENT_COLUMN_NAMES_TO_PROPERTIES;
private static final Map<String, String> TASK_ATTACHMENT_COLUMNS_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> TASK_ATTACHMENT_PROPERTIES_SERVER_TO_LOCAL;
private static final Set<String> TASK_ATTACHMENT_PROPERTIES_EXCLUDED;
public static final String ATTACHMENT_ADDED_COLUMN = "file";
@ -287,10 +206,6 @@ public class NameMaps {
putTaskAttachmentPropertyToServerName(TaskAttachment.CONTENT_TYPE, "content_type", false);
putTaskAttachmentPropertyToServerName(TaskAttachment.CREATED_AT, "created_at", true);
putTaskAttachmentPropertyToServerName(TaskAttachment.DELETED_AT, "deleted_at", true);
// Reverse the mapping to construct the server to local map
TASK_ATTACHMENT_PROPERTIES_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER);
}
// ----------
@ -299,7 +214,6 @@ public class NameMaps {
private static final Map<Property<?>, String> TASK_LIST_METADATA_PROPERTIES_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> TASK_LIST_METADATA_COLUMN_NAMES_TO_PROPERTIES;
private static final Map<String, String> TASK_LIST_METADATA_COLUMNS_LOCAL_TO_SERVER;
private static final Map<String, Property<?>> TASK_LIST_METADATA_PROPERTIES_SERVER_TO_LOCAL;
private static final Set<String> TASK_LIST_METADATA_PROPERTIES_EXCLUDED;
private static void putTaskListMetadataPropertyToServerName(Property<?> property, String serverName, boolean writeable) {
@ -321,39 +235,12 @@ public class NameMaps {
putTaskListMetadataPropertyToServerName(TaskListMetadata.SETTINGS, "settings", false);
putTaskListMetadataPropertyToServerName(TaskListMetadata.CHILD_TAG_IDS, "child_tag_ids", false);
putTaskListMetadataPropertyToServerName(TaskListMetadata.IS_COLLAPSED, "is_collapsed", false);
// Reverse the mapping to construct the server to local map
TASK_LIST_METADATA_PROPERTIES_SERVER_TO_LOCAL = AndroidUtilities.reverseMap(TASK_LIST_METADATA_PROPERTIES_LOCAL_TO_SERVER);
}
// ----------
// Mapping helpers
// ----------
private static <A, B> B mapColumnName(String table, A col, Map<A, B> taskMap, Map<A, B> tagMap, Map<A, B> userMap,
Map<A, B> userActivityMap, Map<A, B> taskAttachmentMap, Map<A, B> taskListMetadataMap) {
Map<A, B> map = null;
if (TABLE_ID_TASKS.equals(table)) {
map = taskMap;
} else if (TABLE_ID_TAGS.equals(table)) {
map = tagMap;
} else if (TABLE_ID_USERS.equals(table)) {
map = userMap;
} else if (TABLE_ID_USER_ACTIVITY.equals(table)) {
map = userActivityMap;
} else if (TABLE_ID_ATTACHMENTS.equals(table)) {
map = taskAttachmentMap;
} else if (TABLE_ID_TASK_LIST_METADATA.equals(table)) {
map = taskListMetadataMap;
}
if (map == null) {
return null;
}
return map.get(col);
}
public static boolean shouldRecordOutstandingColumnForTable(String table, String column) {
if (TABLE_ID_TASKS.equals(table)) {
if (TASK_COLUMN_NAMES_TO_PROPERTIES.containsKey(column)) {
@ -382,29 +269,4 @@ public class NameMaps {
}
return false;
}
public static String localPropertyToServerColumnName(String table, Property<?> localProperty) {
return mapColumnName(table, localProperty, TASK_PROPERTIES_LOCAL_TO_SERVER, TAG_DATA_PROPERTIES_LOCAL_TO_SERVER,
USER_PROPERTIES_LOCAL_TO_SERVER, USER_ACTIVITY_PROPERTIES_LOCAL_TO_SERVER,
TASK_ATTACHMENT_PROPERTIES_LOCAL_TO_SERVER, TASK_LIST_METADATA_PROPERTIES_LOCAL_TO_SERVER);
}
public static String localColumnNameToServerColumnName(String table, String localColumn) {
return mapColumnName(table, localColumn, TASK_COLUMNS_LOCAL_TO_SERVER, TAG_DATA_COLUMNS_LOCAL_TO_SERVER,
USER_COLUMNS_LOCAL_TO_SERVER, USER_ACTIVITY_COLUMNS_LOCAL_TO_SERVER,
TASK_ATTACHMENT_COLUMNS_LOCAL_TO_SERVER, TASK_LIST_METADATA_COLUMNS_LOCAL_TO_SERVER);
}
public static Property<?> localColumnNameToProperty(String table, String localColumn) {
return mapColumnName(table, localColumn, TASK_COLUMN_NAMES_TO_PROPERTIES, TAG_DATA_COLUMN_NAMES_TO_PROPERTIES,
USER_COLUMN_NAMES_TO_PROPERTIES, USER_ACTIVITY_COLUMN_NAMES_TO_PROPERTIES,
TASK_ATTACHMENT_COLUMN_NAMES_TO_PROPERTIES, TASK_LIST_METADATA_COLUMN_NAMES_TO_PROPERTIES);
}
public static Property<?> serverColumnNameToLocalProperty(String table, String serverColumn) {
return mapColumnName(table, serverColumn, TASK_PROPERTIES_SERVER_TO_LOCAL, TAG_DATA_PROPERTIES_SERVER_TO_LOCAL,
USER_PROPERTIES_SERVER_TO_LOCAL, USER_ACTIVITY_PROPERTIES_SERVER_TO_LOCAL,
TASK_ATTACHMENT_PROPERTIES_SERVER_TO_LOCAL, TASK_LIST_METADATA_PROPERTIES_SERVER_TO_LOCAL);
}
}

@ -1,116 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import java.text.ParseException;
import org.json.JSONObject;
import android.text.TextUtils;
import android.util.Log;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.User;
public class NowBriefed<TYPE extends RemoteModel> extends ServerToClientMessage {
private static final String ERROR_TAG = "actfm-now-briefed";
private final RemoteModelDao<TYPE> dao;
private final String table;
private final String uuid;
private final String taskId;
private final String tagId;
private final String userId;
private long pushedAt;
public NowBriefed(JSONObject json, RemoteModelDao<TYPE> dao) {
super(json);
this.table = json.optString("table");
this.uuid = json.optString("uuid");
this.taskId = json.optString(BriefMe.TASK_ID_KEY);
this.tagId = json.optString(BriefMe.TAG_ID_KEY);
this.userId = json.optString(BriefMe.USER_ID_KEY);
this.dao = dao;
try {
this.pushedAt = DateUtilities.parseIso8601(json.optString("pushed_at"));
} catch (ParseException e) {
this.pushedAt = 0;
}
}
@Override
public void processMessage(String serverTime) {
if (pushedAt > 0) {
if (TextUtils.isEmpty(uuid)) {
if (!TextUtils.isEmpty(taskId)) {
Task template = new Task();
if (NameMaps.TABLE_ID_ATTACHMENTS.equals(table)) {
template.setValue(Task.ATTACHMENTS_PUSHED_AT, pushedAt);
} else if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(table)) {
template.setValue(Task.USER_ACTIVITIES_PUSHED_AT, pushedAt);
}
if (template.getSetValues() != null) {
PluginServices.getTaskDao().update(Task.UUID.eq(taskId), template);
}
} else if (!TextUtils.isEmpty(tagId)) {
TagData template = new TagData();
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
template.setValue(TagData.TASKS_PUSHED_AT, pushedAt);
}
if (NameMaps.TABLE_ID_TASK_LIST_METADATA.equals(table)) {
template.setValue(TagData.METADATA_PUSHED_AT, pushedAt);
} else if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(table)) {
template.setValue(TagData.USER_ACTIVITIES_PUSHED_AT, pushedAt);
}
if (template.getSetValues() != null) {
PluginServices.getTagDataDao().update(TagData.UUID.eq(tagId), template);
}
} else if (!TextUtils.isEmpty(userId)) {
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
User template = new User();
template.setValue(User.TASKS_PUSHED_AT, pushedAt);
PluginServices.getUserDao().update(User.UUID.eq(userId), template);
}
} else {
String pushedAtKey = null;
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
pushedAtKey = NameMaps.PUSHED_AT_TASKS;
} else if (NameMaps.TABLE_ID_TAGS.equals(table)) {
pushedAtKey = NameMaps.PUSHED_AT_TAGS;
} else if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(table)) {
pushedAtKey = NameMaps.PUSHED_AT_ACTIVITY;
} else if (NameMaps.TABLE_ID_USERS.equals(table)) {
pushedAtKey = NameMaps.PUSHED_AT_USERS;
} else if (NameMaps.TABLE_ID_TASK_LIST_METADATA.equals(table)) {
pushedAtKey = NameMaps.PUSHED_AT_TASK_LIST_METADATA;
}
if (pushedAtKey != null) {
Preferences.setLong(pushedAtKey, pushedAt);
}
}
} else {
try {
TYPE instance = dao.getModelClass().newInstance();
instance.setValue(RemoteModel.PUSHED_AT_PROPERTY, pushedAt);
dao.update(RemoteModel.UUID_PROPERTY.eq(uuid), instance);
} catch (IllegalAccessException e) {
Log.e(ERROR_TAG, "Error instantiating model for NowBriefed", e);
} catch (InstantiationException e) {
Log.e(ERROR_TAG, "Error instantiating model for NowBriefed", e);
}
}
}
}
}

@ -1,147 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import android.util.Log;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.data.Property.PropertyVisitor;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.dao.DaoReflectionHelpers;
import com.todoroo.astrid.dao.OutstandingEntryDao;
import com.todoroo.astrid.dao.RemoteModelDao;
import com.todoroo.astrid.data.OutstandingEntry;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags;
public class ReplayOutstandingEntries<T extends RemoteModel, OE extends OutstandingEntry<T>> {
private static final String ERROR_TAG = "actfm-replay-outstanding";
protected final Class<T> modelClass;
private final Class<OE> outstandingClass;
private final String table;
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, boolean afterErrors) {
this.modelClass = modelClass;
this.outstandingClass = DaoReflectionHelpers.getOutstandingClass(modelClass);
this.table = table;
this.dao = dao;
this.outstandingDao = outstandingDao;
this.afterErrors = afterErrors;
}
public void execute() {
TodorooCursor<OE> outstanding = outstandingDao.query(Query.select(DaoReflectionHelpers.getModelProperties(outstandingClass))
.orderBy(Order.asc(OutstandingEntry.ENTITY_ID_PROPERTY), Order.asc(OutstandingEntry.CREATED_AT_PROPERTY)));
try {
OE instance = outstandingClass.newInstance();
for (outstanding.moveToFirst(); !outstanding.isAfterLast(); outstanding.moveToNext()) {
instance.clear();
instance.readPropertiesFromCursor(outstanding);
processItem(instance.getValue(OutstandingEntry.ENTITY_ID_PROPERTY), instance, outstanding);
}
} catch (InstantiationException e) {
Log.e(ERROR_TAG, "Error instantiating outstanding entry", e);
} catch (IllegalAccessException e) {
Log.e(ERROR_TAG, "Error instantiating outstanding entry", e);
} catch (Exception e) {
Log.e(ERROR_TAG, "Unexpected exception in replay outstanding entries", e);
}
}
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();
model.setId(id);
OutstandingToModelVisitor<T> visitor = new OutstandingToModelVisitor<T>(model);
int count = 0;
for (; !outstanding.isAfterLast(); outstanding.moveToNext()) {
instance.clear();
instance.readPropertiesFromCursor(outstanding);
if (instance.getValue(OutstandingEntry.ENTITY_ID_PROPERTY) != id) {
break;
}
count ++;
String column = instance.getValue(OutstandingEntry.COLUMN_STRING_PROPERTY);
Property<?> property = NameMaps.localColumnNameToProperty(table, column);
// set values to model
if (property != null) {
property.accept(visitor, instance);
}
}
model.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
if (shouldSaveModel(model)) {
dao.saveExisting(model);
if (count > 0 && !afterErrors) {
enqueueChangesHappenedMessage(id);
}
}
outstanding.moveToPrevious(); // Move back one to undo the last iteration of the for loop
} catch (InstantiationException e) {
Log.e(ERROR_TAG, "Error instantiating model", e);
} catch (IllegalAccessException e) {
Log.e(ERROR_TAG, "Error instantiating model", e);
}
}
private class OutstandingToModelVisitor<MTYPE extends T> implements PropertyVisitor<Void, OE> {
private final MTYPE model;
public OutstandingToModelVisitor(MTYPE model) {
this.model = model;
}
@Override
public Void visitInteger(Property<Integer> property, OE data) {
Integer i = data.getMergedValues().getAsInteger(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (i != null) {
model.setValue(property, i);
}
return null;
}
@Override
public Void visitLong(Property<Long> property, OE data) {
Long l = data.getMergedValues().getAsLong(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (l != null) {
model.setValue(property, l);
}
return null;
}
@Override
public Void visitDouble(Property<Double> property, OE data) {
Double d = data.getMergedValues().getAsDouble(OutstandingEntry.VALUE_STRING_PROPERTY.name);
if (d != null) {
model.setValue(property, d);
}
return null;
}
@Override
public Void visitString(Property<String> property, OE data) {
String s = data.getValue(OutstandingEntry.VALUE_STRING_PROPERTY);
model.setValue(property, s);
return null;
}
}
}

@ -1,28 +0,0 @@
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
}
}

@ -1,90 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.json.JSONObject;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.data.TaskListMetadata;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.data.UserActivity;
public abstract class ServerToClientMessage {
public abstract void processMessage(String serverTime);
public static final String TYPE_MAKE_CHANGES = "MakeChanges";
public static final String TYPE_NOW_BRIEFED = "NowBriefed";
public static final String TYPE_ACKNOWLEDGE_CHANGE = "AcknowledgeChange";
public static final String TYPE_USER_DATA = "UserData";
public static final String TYPE_DOUBLE_CHECK = "DoubleCheck";
public static final String TYPE_USER_MIGRATED = "UserMigrated";
public static final String TYPE_DEBUG = "Debug";
protected final JSONObject json;
public ServerToClientMessage(JSONObject json) {
this.json = json;
}
public static ServerToClientMessage instantiateMessage(JSONObject json) {
String type = json.optString("type");
if (TYPE_MAKE_CHANGES.equals(type)) {
return instantiateMakeChanges(json);
} else if (TYPE_NOW_BRIEFED.equals(type)) {
return instantiateNowBriefed(json);
} else if (TYPE_ACKNOWLEDGE_CHANGE.equals(type)) {
return new AcknowledgeChange(json);
} else if (TYPE_USER_DATA.equals(type)) {
return new UserData(json);
} else if (TYPE_DOUBLE_CHECK.equals(type)) {
return new DoubleCheck(json);
} else if (TYPE_USER_MIGRATED.equals(type)) {
return new UserMigrated(json);
} else if (TYPE_DEBUG.equals(type)) {
return new Debug(json);
}
return null;
}
private static MakeChanges<?> instantiateMakeChanges(JSONObject json) {
String table = json.optString("table");
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
return new MakeChanges<Task>(json, PluginServices.getTaskDao());
} else if (NameMaps.TABLE_ID_TAGS.equals(table)) {
return new MakeChanges<TagData>(json, PluginServices.getTagDataDao());
} else if (NameMaps.TABLE_ID_USERS.equals(table)) {
return new MakeChanges<User>(json, PluginServices.getUserDao());
} else if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(table)) {
return new MakeChanges<UserActivity>(json, PluginServices.getUserActivityDao());
} else if (NameMaps.TABLE_ID_ATTACHMENTS.equals(table)) {
return new MakeChanges<TaskAttachment>(json, PluginServices.getTaskAttachmentDao());
} else if (NameMaps.TABLE_ID_TASK_LIST_METADATA.equals(table)) {
return new MakeChanges<TaskListMetadata>(json, PluginServices.getTaskListMetadataDao());
} else {
return null;
}
}
private static NowBriefed<?> instantiateNowBriefed(JSONObject json) {
String table = json.optString("table");
if (NameMaps.TABLE_ID_TASKS.equals(table)) {
return new NowBriefed<Task>(json, PluginServices.getTaskDao());
} else if (NameMaps.TABLE_ID_TAGS.equals(table)) {
return new NowBriefed<TagData>(json, PluginServices.getTagDataDao());
} else if (NameMaps.TABLE_ID_USER_ACTIVITY.equals(table)) {
return new NowBriefed<UserActivity>(json, PluginServices.getUserActivityDao());
} else if (NameMaps.TABLE_ID_USERS.equals(table)) {
return new NowBriefed<User>(json, PluginServices.getUserDao());
} else if (NameMaps.TABLE_ID_ATTACHMENTS.equals(table)) {
return new NowBriefed<TaskAttachment>(json, PluginServices.getTaskAttachmentDao());
} else if (NameMaps.TABLE_ID_TASK_LIST_METADATA.equals(table)) {
return new NowBriefed<TaskListMetadata>(json, PluginServices.getTaskListMetadataDao());
} else {
return null;
}
}
}

@ -1,83 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import java.util.HashSet;
import java.util.Set;
import android.text.TextUtils;
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 TaskListMetadataDao dao;
public TaskListMetadataChangesHappened(long id, Class<TaskListMetadata> modelClass, TaskListMetadataDao modelDao, TaskListMetadataOutstandingDao outstandingDao) {
super(id, modelClass, modelDao, outstandingDao);
this.dao = modelDao;
}
@Override
protected void populateChanges() {
super.populateChanges();
// Collapses/removes redundant task list orders from the list--only send the most recent ordering
Set<Long> removedChanges = new HashSet<Long>();
boolean foundOrderChange = false;
boolean foundTagOrFilterId = false;
for (int i = changes.size() - 1; i >= 0; i--) {
TaskListMetadataOutstanding oe = changes.get(i);
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());
} else {
foundTagOrFilterId = true;
}
}
}
if (pushedAt == 0 && !foundTagOrFilterId) { // Try to validate message
TaskListMetadata tlm = dao.fetch(id, TaskListMetadata.FILTER, TaskListMetadata.TAG_UUID);
if (tlm != null) {
String filterId = tlm.getValue(TaskListMetadata.FILTER);
String tagUuid = tlm.getValue(TaskListMetadata.TAG_UUID);
TaskListMetadataOutstanding tlmo = new TaskListMetadataOutstanding();
boolean validChange = false;
if (!TextUtils.isEmpty(filterId)) {
validChange = true;
tlmo.setValue(TaskListMetadataOutstanding.ENTITY_ID_PROPERTY, id);
tlmo.setValue(TaskListMetadataOutstanding.COLUMN_STRING, TaskListMetadata.FILTER.name);
tlmo.setValue(TaskListMetadataOutstanding.VALUE_STRING, filterId);
tlmo.setValue(TaskListMetadataOutstanding.CREATED_AT, 0L);
} else if (!RemoteModel.isUuidEmpty(tagUuid)) {
validChange = true;
tlmo.setValue(TaskListMetadataOutstanding.ENTITY_ID_PROPERTY, id);
tlmo.setValue(TaskListMetadataOutstanding.COLUMN_STRING, TaskListMetadata.TAG_UUID.name);
tlmo.setValue(TaskListMetadataOutstanding.VALUE_STRING, tagUuid);
tlmo.setValue(TaskListMetadataOutstanding.CREATED_AT, 0L);
}
if (validChange) {
changes.add(tlmo);
}
}
}
outstandingDao.deleteWhere(TaskListMetadataOutstanding.ID.in(removedChanges.toArray(new Long[removedChanges.size()])));
}
}

@ -1,43 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.json.JSONObject;
import android.text.TextUtils;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.TagMetadataDao.TagMetadataCriteria;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagMetadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.tags.TagMemberMetadata;
public class UserData extends ServerToClientMessage {
public UserData(JSONObject json) {
super(json);
}
@Override
public void processMessage(String serverTime) {
String uuid = json.optString("uuid");
String email = json.optString("email");
if (TextUtils.isEmpty(uuid)) {
return;
}
Task taskTemplate = new Task();
taskTemplate.setValue(Task.USER_ID, uuid);
taskTemplate.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
PluginServices.getTaskDao().update(Task.USER_ID.eq(email), taskTemplate);
TagMetadata metadataTemplate = new TagMetadata();
metadataTemplate.setValue(TagMemberMetadata.USER_UUID, uuid);
metadataTemplate.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
PluginServices.getTagMetadataDao().update(Criterion.and(TagMetadataCriteria.withKey(TagMemberMetadata.KEY),
TagMemberMetadata.USER_UUID.eq(email)), metadataTemplate);
}
}

@ -1,29 +0,0 @@
package com.todoroo.astrid.actfm.sync.messages;
import org.json.JSONObject;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.data.RemoteModel;
public class UserMigrated extends ServerToClientMessage {
public UserMigrated(JSONObject json) {
super(json);
}
@Override
public void processMessage(String serverTime) {
String oldUuid = json.optString("prev_user_id"); //$NON-NLS-1$
String newUuid = json.optString("new_user_id"); //$NON-NLS-1$
if (RemoteModel.isValidUuid(newUuid)) {
Preferences.setString(ActFmPreferenceService.PREF_USER_ID, newUuid);
new ConvertSelfUserIdsToZero().execute();
}
if (RemoteModel.isValidUuid(oldUuid)) {
new ConvertSelfUserIdsToZero().execute(oldUuid);
}
}
}

@ -29,7 +29,6 @@ import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.andlib.utility.TodorooPreferenceActivity;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.data.TaskAttachment;
@ -78,7 +77,6 @@ public class EditPreferences extends TodorooPreferenceActivity {
@Autowired private TaskService taskService;
@Autowired private AddOnService addOnService;
@Autowired private ActFmPreferenceService actFmPreferenceService;
@Autowired
private Database database;

@ -52,7 +52,6 @@ import com.todoroo.astrid.actfm.ActFmCameraModule;
import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback;
import com.todoroo.astrid.actfm.CommentsActivity;
import com.todoroo.astrid.actfm.TaskCommentsFragment;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.dao.TaskAttachmentDao;
import com.todoroo.astrid.dao.TaskOutstandingDao;
import com.todoroo.astrid.dao.UserDao;
@ -198,9 +197,6 @@ ViewPager.OnPageChangeListener, EditNoteActivity.UpdatesChangedListener {
@Autowired
private TaskAttachmentDao taskAttachmentDao;
@Autowired
private ActFmPreferenceService actFmPreferenceService;
@Autowired
private UserDao userDao;

@ -66,7 +66,6 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.CommentsActivity;
import com.todoroo.astrid.actfm.TagViewFragment;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.activity.SortSelectionActivity.OnSortSelectedListener;
import com.todoroo.astrid.adapter.TaskAdapter;
import com.todoroo.astrid.adapter.TaskAdapter.OnCompletedTaskListener;
@ -181,8 +180,6 @@ public class TaskListFragment extends SherlockListFragment implements OnSortSele
@Autowired TaskListMetadataDao taskListMetadataDao;
@Autowired ActFmPreferenceService actFmPreferenceService;
private final TaskContextActionExposer[] contextItemExposers = new TaskContextActionExposer[] {
new ReminderDebugContextActions.MakeNotification(),
new ReminderDebugContextActions.WhenReminder(),

@ -5,9 +5,6 @@
*/
package com.todoroo.astrid.backup;
import java.util.Date;
import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Color;
import android.os.Bundle;
@ -16,16 +13,17 @@ import android.preference.Preference.OnPreferenceClickListener;
import android.view.View;
import android.view.ViewGroup.OnHierarchyChangeListener;
import org.tasks.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.andlib.utility.TodorooPreferenceActivity;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.utility.Flags;
import org.tasks.R;
import java.util.Date;
/**
* Displays synchronization preferences and an action panel so users can
* initiate actions from the menu.
@ -41,9 +39,6 @@ public class BackupPreferences extends TodorooPreferenceActivity {
private int statusColor = Color.BLACK;
@Autowired
private ActFmPreferenceService actFmPreferenceService;
@Override
public int getPreferenceResource() {
return R.xml.preferences_backup;
@ -92,11 +87,6 @@ public class BackupPreferences extends TodorooPreferenceActivity {
BackupService.scheduleService(this);
}
/**
*
* @param resource
* if null, updates all resources
*/
@Override
public void updatePreferences(Preference preference, Object value) {
final Resources r = getResources();

@ -14,7 +14,6 @@ import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceScreen;
import org.tasks.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
@ -24,8 +23,6 @@ import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.andlib.utility.TodorooPreferenceActivity;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gcal.GCalHelper;
@ -33,6 +30,8 @@ import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.AstridPreferences;
import org.tasks.R;
/**
* Displays the preference screen for users to manage their old tasks and events
*
@ -45,8 +44,6 @@ public class OldTaskPreferences extends TodorooPreferenceActivity {
@Autowired MetadataService metadataService;
@Autowired Database database;
@Autowired ActFmSyncService actFmSyncService;
ProgressDialog pd;
@Override
@ -70,15 +67,6 @@ public class OldTaskPreferences extends TodorooPreferenceActivity {
}
});
preference = screen.findPreference(getString(R.string.EPr_reset_sync_state));
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference p) {
showResetSyncStateDialog();
return true;
}
});
preference = screen.findPreference(getString(R.string.EPr_manage_purge_deleted));
preference.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
@ -307,15 +295,6 @@ public class OldTaskPreferences extends TodorooPreferenceActivity {
}, null);
}
private void showResetSyncStateDialog() {
DialogUtilities.okCancelDialog(this, getString(R.string.EPr_reset_sync_state_detailed), new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActFmSyncThread.clearTablePushedAtValues();
}
}, null);
}
protected void showResult(int resourceText, int result) {
DialogUtilities.okDialog(this, getString(resourceText, result), null);
}

@ -9,19 +9,10 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.HistoryDao;
import com.todoroo.astrid.dao.StoreObjectDao;
import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TagMetadataDao;
import com.todoroo.astrid.dao.TagOutstandingDao;
import com.todoroo.astrid.dao.TaskAttachmentDao;
import com.todoroo.astrid.dao.TaskAttachmentOutstandingDao;
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.dao.UserDao;
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.service.AstridDependencyInjector;
@ -52,9 +43,6 @@ public final class PluginServices {
@Autowired
MetadataService metadataService;
@Autowired
TagMetadataDao tagMetadataDao;
@Autowired
TagDataService tagDataService;
@ -67,33 +55,9 @@ public final class PluginServices {
@Autowired
UserDao userDao;
@Autowired
UserActivityDao userActivityDao;
@Autowired
UserActivityOutstandingDao userActivityOutstandingDao;
@Autowired
TaskOutstandingDao taskOutstandingDao;
@Autowired
TagOutstandingDao tagOutstandingDao;
@Autowired
HistoryDao historyDao;
@Autowired
TaskAttachmentDao taskAttachmentDao;
@Autowired
TaskAttachmentOutstandingDao taskAttachmentOutstandingDao;
@Autowired
TaskListMetadataDao taskListMetadataDao;
@Autowired
TaskListMetadataOutstandingDao taskListMetadataOutstandingDao;
@Autowired
GtasksPreferenceService gtasksPreferenceService;
@ -140,26 +104,6 @@ public final class PluginServices {
return getInstance().tagDataDao;
}
public static UserActivityDao getUserActivityDao() {
return getInstance().userActivityDao;
}
public static TagMetadataDao getTagMetadataDao() {
return getInstance().tagMetadataDao;
}
public static TaskOutstandingDao getTaskOutstandingDao() {
return getInstance().taskOutstandingDao;
}
public static TagOutstandingDao getTagOutstandingDao() {
return getInstance().tagOutstandingDao;
}
public static UserActivityOutstandingDao getUserActivityOutstandingDao() {
return getInstance().userActivityOutstandingDao;
}
public static ExceptionService getExceptionService() {
return getInstance().exceptionService;
}
@ -177,26 +121,10 @@ public final class PluginServices {
return getInstance().userDao;
}
public static HistoryDao getHistoryDao() {
return getInstance().historyDao;
}
public static TaskAttachmentDao getTaskAttachmentDao() {
return getInstance().taskAttachmentDao;
}
public static TaskAttachmentOutstandingDao getTaskAttachmentOutstandingDao() {
return getInstance().taskAttachmentOutstandingDao;
}
public static TaskListMetadataDao getTaskListMetadataDao() {
return getInstance().taskListMetadataDao;
}
public static TaskListMetadataOutstandingDao getTaskListMetadataOutstandingDao() {
return getInstance().taskListMetadataOutstandingDao;
}
public static GtasksPreferenceService getGtasksPreferenceService() {
return getInstance().gtasksPreferenceService;
}

@ -22,17 +22,13 @@ import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.actfm.sync.messages.ChangesHappened;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.OutstandingEntry;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskOutstanding;
import com.todoroo.astrid.provider.Astrid2TaskProvider;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.tags.TaskToTagMetadata;
import com.todoroo.astrid.utility.AstridPreferences;
@ -109,8 +105,6 @@ public class MetadataDao extends DatabaseDao<Metadata> {
to.setValue(OutstandingEntry.COLUMN_STRING_PROPERTY, addedOrRemoved);
to.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, tagUuid);
database.insert(outstandingTable.name, null, to.getSetValues());
ActFmSyncThread.getInstance().enqueueMessage(new ChangesHappened<Task, TaskOutstanding>(taskId, Task.class,
PluginServices.getTaskDao(), PluginServices.getTaskOutstandingDao()), null);
return 1;
}
@ -183,9 +177,6 @@ public class MetadataDao extends DatabaseDao<Metadata> {
/**
* Fetch all metadata that are unattached to the task
* @param database
* @param properties
* @return
*/
public TodorooCursor<Metadata> fetchDangling(Property<?>... properties) {
Query sql = Query.select(properties).from(Metadata.TABLE).join(Join.left(Task.TABLE,
@ -193,16 +184,5 @@ public class MetadataDao extends DatabaseDao<Metadata> {
Cursor cursor = database.rawQuery(sql.toString(), null);
return new TodorooCursor<Metadata>(cursor, properties);
}
public boolean taskIsInTag(String taskUuid, String tagUuid) {
TodorooCursor<Metadata> cursor = query(Query.select(Metadata.ID).where(Criterion.and(MetadataCriteria.withKey(TaskToTagMetadata.KEY),
TaskToTagMetadata.TASK_UUID.eq(taskUuid), TaskToTagMetadata.TAG_UUID.eq(tagUuid), Metadata.DELETION_DATE.eq(0))));
try {
return cursor.getCount() > 0;
} finally {
cursor.close();
}
}
}

@ -24,8 +24,6 @@ import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.actfm.sync.messages.ChangesHappened;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.Metadata;
@ -103,8 +101,6 @@ public class TagMetadataDao extends DatabaseDao<TagMetadata> {
to.setValue(OutstandingEntry.COLUMN_STRING_PROPERTY, addedOrRemoved);
to.setValue(OutstandingEntry.VALUE_STRING_PROPERTY, memberId);
database.insert(outstandingTable.name, null, to.getSetValues());
ActFmSyncThread.getInstance().enqueueMessage(new ChangesHappened<TagData, TagOutstanding>(tagDataId, TagData.class,
PluginServices.getTagDataDao(), PluginServices.getTagOutstandingDao()), null);
return 1;
}

@ -14,7 +14,6 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.activity.EditPreferences;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.dao.TagMetadataDao;
@ -42,9 +41,6 @@ public class CalendarAlarmListCreator extends Activity {
@Autowired
private TagDataService tagDataService;
@Autowired
private ActFmPreferenceService actFmPreferenceService;
@Autowired
private TagMetadataDao tagMetadataDao;

@ -23,7 +23,6 @@ import com.todoroo.andlib.sql.Functions;
import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.api.AstridFilterExposer;
import com.todoroo.astrid.api.Filter;
@ -50,7 +49,6 @@ public class GtasksFilterExposer extends BroadcastReceiver implements AstridFilt
@Autowired private GtasksListService gtasksListService;
@Autowired private GtasksPreferenceService gtasksPreferenceService;
@Autowired private ActFmPreferenceService actFmPreferenceService;
static {
AstridDependencyInjector.initialize();

@ -5,23 +5,15 @@
*/
package com.todoroo.astrid.gtasks;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity;
import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider;
import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider.GtasksImportCallback;
import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider.GtasksImportTuple;
import com.todoroo.astrid.sync.SyncProviderPreferences;
import com.todoroo.astrid.sync.SyncProviderUtilities;
import com.todoroo.astrid.sync.SyncResultCallbackAdapter;
import com.todoroo.astrid.tags.TagService;
import org.tasks.R;
@ -36,7 +28,6 @@ import org.tasks.R;
public class GtasksPreferences extends SyncProviderPreferences {
@Autowired private GtasksPreferenceService gtasksPreferenceService;
@Autowired private ActFmPreferenceService actFmPreferenceService;
@Autowired private TagService tagService;
public GtasksPreferences() {

@ -16,7 +16,6 @@ import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
@ -44,7 +43,6 @@ public final class GtasksSyncService {
@Autowired GtasksMetadataService gtasksMetadataService;
@Autowired TaskDao taskDao;
@Autowired GtasksPreferenceService gtasksPreferenceService;
@Autowired ActFmPreferenceService actFmPreferenceService;
public GtasksSyncService() {
DependencyInjectionService.getInstance().inject(this);

@ -18,7 +18,6 @@ import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
@ -27,10 +26,8 @@ import com.todoroo.astrid.dao.TagDataDao;
import com.todoroo.astrid.dao.TagMetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.StoreObject;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksList;
import com.todoroo.astrid.gtasks.GtasksListService;
@ -66,7 +63,6 @@ public class GtasksSyncV2Provider extends SyncV2Provider {
@Autowired MetadataService metadataService;
@Autowired MetadataDao metadataDao;
@Autowired StoreObjectDao storeObjectDao;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired GtasksPreferenceService gtasksPreferenceService;
@Autowired GtasksSyncService gtasksSyncService;
@Autowired GtasksListService gtasksListService;

@ -42,12 +42,6 @@ import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.ActFmCameraModule;
import com.todoroo.astrid.actfm.ActFmCameraModule.CameraResultCallback;
import com.todoroo.astrid.actfm.ActFmCameraModule.ClearImageCallback;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread.SyncMessageCallback;
import com.todoroo.astrid.actfm.sync.messages.BriefMe;
import com.todoroo.astrid.actfm.sync.messages.FetchHistory;
import com.todoroo.astrid.actfm.sync.messages.NameMaps;
import com.todoroo.astrid.activity.AstridActivity;
import com.todoroo.astrid.activity.TaskEditFragment;
@ -60,7 +54,6 @@ import com.todoroo.astrid.data.History;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.helper.AsyncImageView;
@ -88,8 +81,6 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
private Task task;
@Autowired ActFmSyncService actFmSyncService;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired MetadataService metadataService;
@Autowired UserActivityDao userActivityDao;
@Autowired TaskService taskService;
@ -118,31 +109,6 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
private final int color;
private final int grayColor;
private final SyncMessageCallback callback = new SyncMessageCallback() {
@Override
public void runOnSuccess() {
synchronized(this) {
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (task == null) {
return;
}
fetchTask(task.getId());
if (task == null) {
return;
}
setUpListAdapter();
loadingText.setText(R.string.ENA_no_comments);
loadingText.setVisibility(items.size() == 0 ? View.VISIBLE : View.GONE);
}
});
}
}
}
};
private static boolean respondToPicture = false;
private final List<UpdatesChangedListener> listeners = new LinkedList<UpdatesChangedListener>();
@ -392,8 +358,6 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
commentItems += 10;
setUpListAdapter();
if (task.getValue(Task.HISTORY_HAS_MORE) > 0) {
new FetchHistory<Task>(taskDao, Task.HISTORY_FETCH_DATE, Task.HISTORY_HAS_MORE, NameMaps.TABLE_ID_TASKS,
task.getUuid(), task.getValue(Task.TITLE), 0, historyCount, callback).execute();
}
}
});
@ -459,26 +423,6 @@ public class EditNoteActivity extends LinearLayout implements TimerActionListene
if(!task.containsNonNullValue(Task.UUID)) {
return;
}
ActFmSyncThread.getInstance().enqueueMessage(new BriefMe<UserActivity>(UserActivity.class, null, task.getValue(Task.USER_ACTIVITIES_PUSHED_AT), BriefMe.TASK_ID_KEY, task.getUuid()), callback);
ActFmSyncThread.getInstance().enqueueMessage(new BriefMe<TaskAttachment>(TaskAttachment.class, null, task.getValue(Task.ATTACHMENTS_PUSHED_AT), BriefMe.TASK_ID_KEY, task.getUuid()), new SyncMessageCallback() {
@Override
public void runOnSuccess() {
if (activity != null) {
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
TaskEditFragment tef = activity.getTaskEditFragment();
if (tef != null) {
tef.refreshFilesDisplay();
}
}
});
}
}
});
new FetchHistory<Task>(taskDao, Task.HISTORY_FETCH_DATE, Task.HISTORY_HAS_MORE, NameMaps.TABLE_ID_TASKS,
task.getUuid(), task.getValue(Task.TITLE), task.getValue(Task.HISTORY_FETCH_DATE), 0, callback).execute();
}
private void addComment() {

@ -22,7 +22,6 @@ import com.todoroo.andlib.service.NotificationManager.AndroidNotificationManager
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.sql.QueryTemplate;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.FilterWithCustomIntent;
@ -37,8 +36,6 @@ import org.tasks.R;
public class ReengagementReceiver extends BroadcastReceiver {
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired TaskService taskService;
private static final int TASK_LIMIT = 3;

@ -5,14 +5,6 @@
*/
package com.todoroo.astrid.repeats;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@ -26,22 +18,25 @@ import com.google.ical.values.DateValueImpl;
import com.google.ical.values.Frequency;
import com.google.ical.values.RRule;
import com.google.ical.values.WeekdayNum;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.core.PluginServices;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gcal.GCalHelper;
import com.todoroo.astrid.service.StatisticsConstants;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.utility.Flags;
public class RepeatTaskCompleteListener extends BroadcastReceiver {
import java.text.ParseException;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
@Autowired ActFmPreferenceService actFmPreferenceService;
public class RepeatTaskCompleteListener extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {

@ -10,9 +10,6 @@ import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.ExceptionService.AndroidLogReporter;
import com.todoroo.andlib.service.ExceptionService.ErrorReporter;
import com.todoroo.andlib.service.HttpRestClient;
import com.todoroo.astrid.actfm.sync.ActFmInvoker;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.dao.Database;
import com.todoroo.astrid.dao.HistoryDao;
import com.todoroo.astrid.dao.MetadataDao;
@ -94,11 +91,6 @@ public class AstridDependencyInjector extends AbstractDependencyInjector {
injectables.put("addOnService", AddOnService.class);
injectables.put("syncService", SyncV2Service.class);
// com.todoroo.astrid.sharing
injectables.put("actFmPreferenceService", ActFmPreferenceService.class);
injectables.put("actFmInvoker", ActFmInvoker.class);
injectables.put("actFmSyncService", ActFmSyncService.class);
// com.todoroo.astrid.gtasks
injectables.put("gtasksPreferenceService", GtasksPreferenceService.class);
injectables.put("gtasksListService", GtasksListService.class);

@ -34,8 +34,6 @@ import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncThread;
import com.todoroo.astrid.activity.BeastModePreferences;
import com.todoroo.astrid.backup.BackupConstants;
import com.todoroo.astrid.backup.BackupService;
@ -111,8 +109,6 @@ public class StartupService {
@Autowired GtasksPreferenceService gtasksPreferenceService;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired GtasksSyncService gtasksSyncService;
/**
@ -200,7 +196,6 @@ public class StartupService {
final int finalLatestVersion = latestSetVersion;
initializeDatabaseListeners();
ActFmSyncThread.initializeSyncComponents(taskDao, tagDataDao, userActivityDao, taskAttachmentDao, taskListMetadataDao);
// perform startup activities in a background thread
new Thread(new Runnable() {
@ -219,7 +214,6 @@ public class StartupService {
// if sync ongoing flag was set, clear it
gtasksPreferenceService.stopOngoing();
actFmPreferenceService.stopOngoing();
OpencrxCoreUtils.INSTANCE.stopOngoing();
// perform initialization

@ -22,7 +22,6 @@ import com.todoroo.andlib.sql.Join;
import com.todoroo.andlib.sql.Order;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.adapter.UpdateAdapter;
import com.todoroo.astrid.api.PermaSql;
import com.todoroo.astrid.dao.MetadataDao.MetadataCriteria;
@ -32,11 +31,9 @@ import com.todoroo.astrid.dao.UserActivityDao;
import com.todoroo.astrid.data.History;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.RemoteModel;
import com.todoroo.astrid.data.SyncFlags;
import com.todoroo.astrid.data.TagData;
import com.todoroo.astrid.data.User;
import com.todoroo.astrid.data.UserActivity;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TaskToTagMetadata;
/**
@ -193,28 +190,6 @@ public class TagDataService {
return userActivityDao.query(resultQuery);
}
public void saveFeaturedList(JSONObject featObject) throws JSONException {
TodorooCursor<TagData> cursor = query(Query.select(TagData.PROPERTIES).where(
Criterion.and(Functions.bitwiseAnd(TagData.FLAGS, TagData.FLAG_FEATURED).gt(0), TagData.UUID.eq(featObject.get("id")))));
try {
cursor.moveToNext();
TagData tagData = new TagData();
if (!cursor.isAfterLast()) {
tagData.readFromCursor(cursor);
if(!tagData.getValue(TagData.NAME).equals(featObject.getString("name"))) {
TagService.getInstance().rename(tagData.getUuid(), featObject.getString("name"), true);
}
cursor.moveToNext();
}
ActFmSyncService.JsonHelper.featuredListFromJson(featObject, tagData);
tagData.putTransitory(SyncFlags.ACTFM_SUPPRESS_OUTSTANDING_ENTRIES, true);
save(tagData);
} finally {
cursor.close();
}
}
/**
* Return update
* @param tagData

@ -32,7 +32,6 @@ import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.service.RestClient;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.dao.StoreObjectDao;
import com.todoroo.astrid.dao.StoreObjectDao.StoreObjectCriteria;
import com.todoroo.astrid.data.StoreObject;
@ -63,7 +62,6 @@ public class UpdateMessageService {
@Autowired protected RestClient restClient;
@Autowired private GtasksPreferenceService gtasksPreferenceService;
@Autowired private ActFmPreferenceService actFmPreferenceService;
@Autowired private AddOnService addOnService;
@Autowired private StoreObjectDao storeObjectDao;

@ -15,7 +15,6 @@ import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.DependencyInjectionService;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.activity.AstridActivity;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.dao.Database;
@ -39,8 +38,6 @@ public final class UpgradeService {
@Autowired AddOnService addOnService;
@Autowired ActFmPreferenceService actFmPreferenceService;
public UpgradeService() {
DependencyInjectionService.getInstance().inject(this);
}

@ -7,7 +7,6 @@ package com.todoroo.astrid.subtasks;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.sql.Criterion;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.dao.TaskListMetadataDao;
@ -18,7 +17,6 @@ public abstract class SubtasksUpdater<T> extends AstridOrderedListUpdater<T> {
@Autowired TaskListMetadataDao taskListMetadataDao;
@Autowired TaskService taskService;
@Autowired ActFmSyncService actFmSyncService;
public static final String ACTIVE_TASKS_ORDER = "active_tasks_order"; //$NON-NLS-1$
public static final String TODAY_TASKS_ORDER = "today_tasks_order"; //$NON-NLS-1$

@ -38,7 +38,6 @@ import com.todoroo.andlib.service.ExceptionService;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.DialogUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.activity.AstridActivity;
import com.todoroo.astrid.activity.TaskEditFragment;
import com.todoroo.astrid.activity.TaskListFragment;
@ -83,7 +82,6 @@ public class QuickAddBar extends LinearLayout {
@Autowired AddOnService addOnService;
@Autowired ExceptionService exceptionService;
@Autowired MetadataService metadataService;
@Autowired ActFmPreferenceService actFmPreferenceService;
@Autowired
private TaskAttachmentDao taskAttachmentDao;

@ -75,7 +75,6 @@
<string name="DLG_cancel">Cancel·la</string>
<string name="DLG_undo">Desfés</string>
<string name="WID_dateButtonUnset">Prem per establir</string>
<string name="ENA_no_comments">Encara no hi ha activitat</string>
<string name="ENA_no_user">Algú</string>
<string name="ENA_refresh_comments">Actualitza els comentaris</string>
<string name="TLA_no_items">No teniu tasques! \n Voleu afegir alguna cosa?</string>

@ -66,7 +66,6 @@
<string name="DLG_cancel">Storno</string>
<string name="DLG_undo">Vrátit změny</string>
<string name="WID_dateButtonUnset">Klikni pro nastavení</string>
<string name="ENA_no_comments">Nic k zobrazení</string>
<string name="ENA_no_user">Kdosi</string>
<string name="ENA_refresh_comments">Obnovit komentáře</string>
<string name="TLA_no_items">Žádné úkoly!</string>

@ -33,9 +33,6 @@
<string name="actfm_feat_list_clone_success">Viel Erfolg!</string>
<string name="actfm_feat_list_task_clone_success">Aufgabe kopiert</string>
<string name="actfm_feat_list_clone_empty">Keine Aufgaben zum Kopieren vorhanden</string>
<string name="EPr_reset_sync_state">Synchronisation zurücksetzen</string>
<string name="EPr_reset_sync_state_summary">Setzt einige lokale Daten zur Behebung von Synchronisations-Fehlern zurück</string>
<string name="EPr_reset_sync_state_detailed">Bei der nächsten Synchronisation werden deine Aufgaben und Listen denjenigen auf Tasks.com angeglichen. Das behebt Synchronisationsfehler. Möchtest du damit beginen?</string>
<string name="alarm_ACS_label">Alarme</string>
<string name="alarm_ACS_button">Einen Alarm hinzufügen</string>
<string name="backup_status_success">Letzte Datensicherung:\n%s</string>
@ -72,7 +69,6 @@
<string name="DLG_cancel">Abbrechen</string>
<string name="DLG_undo">Rückgängig</string>
<string name="WID_dateButtonUnset">Klicken zur Bestätigung</string>
<string name="ENA_no_comments">Bisher keine Aktivität</string>
<string name="ENA_no_user">Irgendjemand</string>
<string name="ENA_refresh_comments">Kommentare aktualisieren</string>
<string name="TLA_no_items">Sie haben keine Aufgaben! \n Möchten Sie welche hinzufügen?</string>

@ -33,9 +33,6 @@
<string name="actfm_feat_list_clone_success">La operación se ha realizado correctamente.</string>
<string name="actfm_feat_list_task_clone_success">Tarea copiada</string>
<string name="actfm_feat_list_clone_empty">No hay tareas para copiar</string>
<string name="EPr_reset_sync_state">Reiniciar sincronización</string>
<string name="EPr_reset_sync_state_summary">Reinicia algunos datos locales para ayudar a resolver los problemas de sincronización</string>
<string name="EPr_reset_sync_state_detailed">La próxima ocasión que sincronices, tus tareas y listas serán cambiadas a un espejo que existe en Tareas.com, que podría ayudar a resolver los problemas de sincronización. Quieres continuar?</string>
<string name="alarm_ACS_label">Alarmas</string>
<string name="alarm_ACS_button">Añadir una alarma</string>
<string-array name="reminders_alarm">
@ -78,7 +75,6 @@
<string name="DLG_cancel">Cancelar</string>
<string name="DLG_undo">Deshacer</string>
<string name="WID_dateButtonUnset">Pulsar para establecer</string>
<string name="ENA_no_comments">Aun sin actividad</string>
<string name="ENA_no_user">Alguien</string>
<string name="ENA_refresh_comments">Actualizar Comentarios</string>
<string name="TLA_no_items">No tienes tareas! \n Quieres agregar alguna?</string>

@ -32,9 +32,6 @@
<string name="actfm_feat_list_clone_success">Opération réussie !</string>
<string name="actfm_feat_list_task_clone_success">Tâche copiée</string>
<string name="actfm_feat_list_clone_empty">Aucune tâche à copier</string>
<string name="EPr_reset_sync_state">Réinitialiser la synchronisation</string>
<string name="EPr_reset_sync_state_summary">Réinitialiser certaines données locales pour aider à la résolution de problème de synchronisation</string>
<string name="EPr_reset_sync_state_detailed">A la prochaine synchronisation, vos tâches et listes seront modifiées pour refléter ce qui existe sur Tasks.com, ce qui pourrait aider à résoudre des erreurs de synchronisation. Voulez-vous continuer?</string>
<string name="alarm_ACS_label">Alarmes</string>
<string name="alarm_ACS_button">Ajouter une alarme</string>
<string-array name="reminders_alarm">
@ -75,7 +72,6 @@
<string name="DLG_cancel">Annuler</string>
<string name="DLG_undo">Annuler Action</string>
<string name="WID_dateButtonUnset">Cliquez pour définir</string>
<string name="ENA_no_comments">Rien à afficher</string>
<string name="ENA_no_user">Quelqu\'un</string>
<string name="ENA_refresh_comments">Mettre à jour les commentaires</string>
<string name="TLA_no_items">Aucune tâche ! n Voulez vous en créer une ?</string>

@ -73,7 +73,6 @@
<string name="DLG_cancel">Annulla</string>
<string name="DLG_undo">Annulla l\'ultima azione</string>
<string name="WID_dateButtonUnset">Clicca per Impostare</string>
<string name="ENA_no_comments">Nessuna attività</string>
<string name="ENA_no_user">Qualcuno</string>
<string name="ENA_refresh_comments">Aggiorna i commenti</string>
<string name="TLA_no_items">Nessuna Attività!</string>

@ -75,7 +75,6 @@
<string name="DLG_cancel">בטל</string>
<string name="DLG_undo">בטל פעולה אחרונה</string>
<string name="WID_dateButtonUnset">הקלק כדי לקבוע</string>
<string name="ENA_no_comments">אין פעילות עדיין</string>
<string name="ENA_no_user">מישהו</string>
<string name="ENA_refresh_comments">רַעְנֵן הערות</string>
<string name="TLA_no_items">אין לך משימות!\n הֲתִּרְצֶה להוסיף משימה?</string>

@ -33,9 +33,6 @@
<string name="actfm_feat_list_clone_success">성공!</string>
<string name="actfm_feat_list_task_clone_success">일정 복사 완료</string>
<string name="actfm_feat_list_clone_empty">복사할 일정 없음</string>
<string name="EPr_reset_sync_state">동기화 초기화</string>
<string name="EPr_reset_sync_state_summary">동기화 에러를 해결하기 위해 몇가지 로컬 자료를 초기화합니다</string>
<string name="EPr_reset_sync_state_detailed">동기화 에러를 해결하기 위해, 다음 동기화 때 당신의 일정과 목록은 Tasks.com 상에 존재하는 미러로 변경될 것입니다. 계속하시겠습니까?</string>
<string name="alarm_ACS_label">알람</string>
<string name="alarm_ACS_button">알람 추가</string>
<string-array name="reminders_alarm">
@ -81,7 +78,6 @@
<string name="DLG_cancel">취소</string>
<string name="DLG_undo">실행 취소</string>
<string name="WID_dateButtonUnset">누르세요</string>
<string name="ENA_no_comments">아직 활동내역이 없음</string>
<string name="ENA_no_user">누군가</string>
<string name="ENA_refresh_comments">댓글 새로고침</string>
<string name="TLA_no_items">일정이 없네요!\n추가할까요?</string>

@ -33,9 +33,6 @@
<string name="actfm_feat_list_clone_success">Succes!</string>
<string name="actfm_feat_list_task_clone_success">Taak gekopiéerd.</string>
<string name="actfm_feat_list_clone_empty">Geen taken om te kopiéren</string>
<string name="EPr_reset_sync_state">Synchronisatie herstellen</string>
<string name="EPr_reset_sync_state_summary">Reset sommige lokale data om synchronisatie te proberen te herstellen</string>
<string name="EPr_reset_sync_state_detailed">De volgende keer dat je synchroniseert, zullen je taken en lijsten veranderen in overeenstemming met de data die aanwezig is Tasks.com, wat synchronisatie fouten kan herstellen. Wil je doorgaan?</string>
<string name="alarm_ACS_label">Herinneringen</string>
<string name="alarm_ACS_button">Voeg Herinnering toe</string>
<string-array name="reminders_alarm">
@ -76,7 +73,6 @@
<string name="DLG_cancel">Annuleren</string>
<string name="DLG_undo">Ongedaan Maken</string>
<string name="WID_dateButtonUnset">Klikken om in te stellen</string>
<string name="ENA_no_comments">Niets om weer te geven</string>
<string name="ENA_no_user">Iemand</string>
<string name="ENA_refresh_comments">Opmerkingen vernieuwen</string>
<string name="TLA_no_items">U heeft geen taken! \n Taak toevoegen?</string>

@ -33,9 +33,6 @@
<string name="actfm_feat_list_clone_success">Zakończono pomyślnie!</string>
<string name="actfm_feat_list_task_clone_success">Zadanie skopiowane</string>
<string name="actfm_feat_list_clone_empty">Brak zadań do skopiowania</string>
<string name="EPr_reset_sync_state">Resetuj synchronizację</string>
<string name="EPr_reset_sync_state_summary">Zresetuj lokalne dane aby naprawić błędy sychronizacji</string>
<string name="EPr_reset_sync_state_detailed">Podczas następnej synchronizacji Twoje zadania zostaną zamienione na kopię, która znajduje się na Tasks.com, co może pomóc rozwiązać błędy synchronizacji. Czy chcesz kontynuować?</string>
<string name="alarm_ACS_label">Alarmy</string>
<string name="alarm_ACS_button">Dodaj alarm</string>
<string name="backup_BPr_header">Kopie zapasowe</string>
@ -74,7 +71,6 @@
<string name="DLG_cancel">Anuluj</string>
<string name="DLG_undo">Cofnij</string>
<string name="WID_dateButtonUnset">Kliknij, aby ustawić</string>
<string name="ENA_no_comments">Nic do pokazania</string>
<string name="ENA_no_user">Ktoś</string>
<string name="ENA_refresh_comments">Odśwież komentarze</string>
<string name="TLA_no_items">Brak zadań!</string>

@ -73,7 +73,6 @@
<string name="DLG_cancel">Cancelar</string>
<string name="DLG_undo">Desfazer</string>
<string name="WID_dateButtonUnset">Toque para definir</string>
<string name="ENA_no_comments">Nada a exibir</string>
<string name="ENA_no_user">Alguém</string>
<string name="ENA_refresh_comments">Atualizar comentários</string>
<string name="TLA_no_items">Você não tem tarefas! \n Deseja inserir alguma?</string>

@ -33,8 +33,6 @@
<string name="actfm_feat_list_clone_success">Завершено успешно!</string>
<string name="actfm_feat_list_task_clone_success">Задача скопирована</string>
<string name="actfm_feat_list_clone_empty">Нет задач для копирования</string>
<string name="EPr_reset_sync_state">Сброс синхронизации</string>
<string name="EPr_reset_sync_state_summary">Сбросьте некоторые данные, чтобы разрешить проблему синхронизации</string>
<string name="alarm_ACS_label">Напоминания</string>
<string name="alarm_ACS_button">Добавить напоминание</string>
<string-array name="reminders_alarm">
@ -76,7 +74,6 @@
<string name="DLG_cancel">Отмена</string>
<string name="DLG_undo">Отмена</string>
<string name="WID_dateButtonUnset">Нажмите для установки</string>
<string name="ENA_no_comments">Нет данных для отображения</string>
<string name="ENA_no_user">Кто-нибудь</string>
<string name="ENA_refresh_comments">Обновить комментарии</string>
<string name="TLA_no_items">Нет задач! \n Добавить?</string>

@ -70,7 +70,6 @@
<string name="DLG_cancel">Avbryt</string>
<string name="DLG_undo">Ångra</string>
<string name="WID_dateButtonUnset">Klicka för att ställa</string>
<string name="ENA_no_comments">Ännu ingen aktivitet</string>
<string name="ENA_no_user">Någon</string>
<string name="ENA_refresh_comments">Uppdatera kommentarer</string>
<string name="TLA_no_items">Du har inga uppgifter!\n Vill du lägga till någonting?</string>

@ -72,7 +72,6 @@
<string name="DLG_cancel">Vazgeç</string>
<string name="DLG_undo">Geri al</string>
<string name="WID_dateButtonUnset">Ayar İçin Dokun</string>
<string name="ENA_no_comments">Gösterecek öğe yok</string>
<string name="ENA_no_user">Herhangi biri</string>
<string name="ENA_refresh_comments">Yorumları Yenile</string>
<string name="TLA_no_items">Hiç göreviniz yok! \n Bir şeyler eklemek nasıl olur?</string>

@ -33,9 +33,6 @@
<string name="actfm_feat_list_clone_success">Успішно!</string>
<string name="actfm_feat_list_task_clone_success">Завдання скопійовано!</string>
<string name="actfm_feat_list_clone_empty">Жодного завдання для копіювання</string>
<string name="EPr_reset_sync_state">Скинути синхронізацію</string>
<string name="EPr_reset_sync_state_summary">Скидання деяких локальних даних, щоб допомогти вирішити помилоки синхронізації</string>
<string name="EPr_reset_sync_state_detailed">Наступного разу при синхронізації ваших завдань і списків буде змінена, щоб відобразити те, що існує на Tasks.com, які можуть допомогти вирішити помилки синхронізації. Ви хочете продовжити?</string>
<string name="alarm_ACS_label">Сигнали</string>
<string name="alarm_ACS_button">Додати сигнал</string>
<string-array name="reminders_alarm">
@ -81,7 +78,6 @@
<string name="DLG_cancel">Відміна</string>
<string name="DLG_undo">Відмінити</string>
<string name="WID_dateButtonUnset">Натисніть для установки</string>
<string name="ENA_no_comments">Активність поки відсутня</string>
<string name="ENA_no_user">Хтось</string>
<string name="ENA_refresh_comments">Оновити коментарі</string>
<string name="TLA_no_items">У Вас немає завдань! \n Бажаєте щось додати?</string>

@ -74,7 +74,6 @@
<string name="DLG_cancel">取消</string>
<string name="DLG_undo">撤消</string>
<string name="WID_dateButtonUnset">点选</string>
<string name="ENA_no_comments">没有要显示的</string>
<string name="ENA_no_user">某人</string>
<string name="ENA_refresh_comments">刷新留言</string>
<string name="TLA_no_items">你没有任务</string>

@ -74,7 +74,6 @@
<string name="DLG_cancel">取消</string>
<string name="DLG_undo">撤消</string>
<string name="WID_dateButtonUnset">點選</string>
<string name="ENA_no_comments">沒有要顯示的</string>
<string name="ENA_no_user">某人</string>
<string name="ENA_refresh_comments">刷新留言</string>
<string name="TLA_no_items">無工作!</string>

@ -335,17 +335,10 @@
<!-- Preference Key (do not translate) -->
<string name="sync_SPr_key_last_error">sync_last_error</string>
<!-- ===========================================================ACTFM == -->
<string name="actfm_https_key">actfmHttps</string>
<!-- =========================================================== GTASKS == -->
<string name="gtasks_GPr_interval_key">gtasks_sync_freq</string>
<!-- ========================================================== SHARING == -->
<string name="actfm_APr_interval_key">actfm_sync_freq</string>
<!-- ============================================================ OTHER == -->
<!-- Preference Key (do not translate) -->

@ -86,14 +86,6 @@
<string name="actfm_feat_list_task_clone_success">Task copied</string>
<string name="actfm_feat_list_clone_empty">No tasks to copy</string>
<!-- ================================================ Synchronization == -->
<!-- Sync upgrade messages -->
<string name="EPr_reset_sync_state">Reset sync</string>
<string name="EPr_reset_sync_state_summary">Resets some local data to help resolve sync errors</string>
<string name="EPr_reset_sync_state_detailed">The next time you sync, your tasks and lists will be changed to mirror what exists on Tasks.com, which may help resolve sync errors. Do you wish to continue?</string>
</resources>

@ -51,9 +51,6 @@
<!-- ============================================================= notes -->
<!-- EditNoteActivity - no comments -->
<string name="ENA_no_comments">No activity yet</string>
<!-- EditNoteActivity - no username for comment -->
<string name="ENA_no_user">Someone</string>

@ -8,11 +8,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/EPr_manage_header">
<com.todoroo.astrid.ui.MultilinePreference
android:title="@string/EPr_reset_sync_state"
android:key="@string/EPr_reset_sync_state"
android:summary="@string/EPr_reset_sync_state_summary" />
<com.todoroo.astrid.ui.MultilinePreference
android:title="@string/EPr_manage_delete_completed"
android:key="@string/EPr_manage_delete_completed"

Loading…
Cancel
Save