From 9b1e1acc60db8a4769a312d1b6d8d07328f0bf5e Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Wed, 29 May 2019 14:29:18 -0500 Subject: [PATCH] Add custom order synchronization hack Workaround for https://issuetracker.google.com/issues/132432317. When enabled Tasks will synchronize parents and positions for all active tasks. --- .../astrid/gtasks/api/GtasksInvoker.java | 13 +++++++++ .../java/org/tasks/data/GoogleTaskDao.java | 4 +++ .../tasks/gtasks/GoogleTaskSynchronizer.java | 27 +++++++++++++++++++ .../org/tasks/preferences/Preferences.java | 5 ++++ .../sync/SynchronizationPreferences.java | 16 +++++++++++ app/src/main/res/values/keys.xml | 3 +++ .../res/xml/preferences_synchronization.xml | 5 ++++ 7 files changed, 73 insertions(+) diff --git a/app/src/main/java/com/todoroo/astrid/gtasks/api/GtasksInvoker.java b/app/src/main/java/com/todoroo/astrid/gtasks/api/GtasksInvoker.java index e6a90d96a..beb4df286 100644 --- a/app/src/main/java/com/todoroo/astrid/gtasks/api/GtasksInvoker.java +++ b/app/src/main/java/com/todoroo/astrid/gtasks/api/GtasksInvoker.java @@ -103,6 +103,19 @@ public class GtasksInvoker { GtasksApiUtilities.unixTimeToGtasksCompletionTime(lastSyncDate).toStringRfc3339())); } + public com.google.api.services.tasks.model.Tasks getAllPositions( + String listId, @Nullable String pageToken) throws IOException { + return execute( + service + .tasks() + .list(listId) + .setMaxResults(100L) + .setShowDeleted(false) + .setShowHidden(true) + .setPageToken(pageToken) + .setFields("items(id,parent,position)")); + } + public @Nullable Task createGtask( String listId, Task task, @Nullable String parent, @Nullable String previous) throws IOException { diff --git a/app/src/main/java/org/tasks/data/GoogleTaskDao.java b/app/src/main/java/org/tasks/data/GoogleTaskDao.java index ffefa22fc..5eccf54ee 100644 --- a/app/src/main/java/org/tasks/data/GoogleTaskDao.java +++ b/app/src/main/java/org/tasks/data/GoogleTaskDao.java @@ -116,6 +116,10 @@ public abstract class GoogleTaskDao { "UPDATE google_tasks SET gt_parent = IFNULL((SELECT gt_task FROM google_tasks AS p WHERE p.gt_remote_id = google_tasks.gt_remote_parent), gt_parent) WHERE gt_list_id = :listId AND gt_moved = 0 AND gt_remote_parent IS NOT NULL AND gt_remote_parent != ''") abstract void updateParents(String listId); + @Query( + "UPDATE google_tasks SET gt_remote_parent = :parent, gt_remote_order = :position WHERE gt_remote_id = :id") + public abstract void updatePosition(String id, String parent, String position); + @Transaction public void reposition(String listId) { updateParents(listId); diff --git a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java index 9aae6aa9f..59b6b8531 100644 --- a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java +++ b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java @@ -216,9 +216,36 @@ public class GoogleTaskSynchronizer { fetchAndApplyRemoteChanges(gtasksInvoker, list); googleTaskDao.reposition(list.getRemoteId()); } + if (preferences.isPositionHackEnabled()) { + for (TaskList list : gtaskLists) { + List tasks = fetchPositions(gtasksInvoker, list.getId()); + for (com.google.api.services.tasks.model.Task task : tasks) { + googleTaskDao.updatePosition(task.getId(), task.getParent(), task.getPosition()); + } + googleTaskDao.reposition(list.getId()); + } + } account.setEtag(eTag); } + private List fetchPositions(GtasksInvoker gtasksInvoker, String listId) + throws IOException { + List tasks = new ArrayList<>(); + String nextPageToken = null; + do { + Tasks taskList = gtasksInvoker.getAllPositions(listId, nextPageToken); + if (taskList == null) { + break; + } + List items = taskList.getItems(); + if (items != null) { + tasks.addAll(items); + } + nextPageToken = taskList.getNextPageToken(); + } while (!Strings.isNullOrEmpty(nextPageToken)); + return tasks; + } + private void pushLocalChanges(GoogleTaskAccount account, GtasksInvoker gtasksInvoker) throws IOException { List tasks = taskDao.getGoogleTasksToPush(account.getAccount()); diff --git a/app/src/main/java/org/tasks/preferences/Preferences.java b/app/src/main/java/org/tasks/preferences/Preferences.java index b531d2d51..15ba0702f 100644 --- a/app/src/main/java/org/tasks/preferences/Preferences.java +++ b/app/src/main/java/org/tasks/preferences/Preferences.java @@ -5,6 +5,7 @@ import static com.google.common.collect.Iterables.filter; import static com.google.common.collect.Iterables.transform; import static com.google.common.collect.Sets.newHashSet; import static com.todoroo.andlib.utility.AndroidUtilities.atLeastKitKat; +import static com.todoroo.andlib.utility.DateUtilities.now; import static java.util.Collections.emptySet; import android.content.ContentResolver; @@ -511,4 +512,8 @@ public class Preferences { public boolean isFlipperEnabled() { return BuildConfig.DEBUG && getBoolean(R.string.p_flipper, false); } + + public boolean isPositionHackEnabled() { + return getLong(R.string.p_google_tasks_position_hack, 0) > now() - TimeUnit.DAYS.toMillis(7); + } } diff --git a/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java b/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java index 32da1ada8..ffecc0f9e 100644 --- a/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java +++ b/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java @@ -6,11 +6,13 @@ package org.tasks.sync; +import static com.todoroo.andlib.utility.DateUtilities.now; import static java.util.Arrays.asList; import static org.tasks.PermissionUtil.verifyPermissions; import android.content.Intent; import android.os.Bundle; +import android.preference.CheckBoxPreference; import android.preference.Preference; import android.preference.PreferenceCategory; import androidx.annotation.NonNull; @@ -98,6 +100,20 @@ public class SynchronizationPreferences extends InjectingPreferenceActivity { return false; }); } + + CheckBoxPreference positionHack = + (CheckBoxPreference) findPreference(R.string.google_tasks_position_hack); + positionHack.setChecked(preferences.isPositionHackEnabled()); + positionHack.setOnPreferenceChangeListener( + (preference, newValue) -> { + if (newValue == null) { + return false; + } + preferences.setLong( + R.string.p_google_tasks_position_hack, ((Boolean) newValue) ? now() : 0); + return true; + }); + Preference addCaldavAccount = findPreference(R.string.p_add_caldav_account); if (inventory.hasPro()) { addCaldavAccount.setOnPreferenceClickListener( diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml index 43283c649..f538fa295 100644 --- a/app/src/main/res/values/keys.xml +++ b/app/src/main/res/values/keys.xml @@ -311,4 +311,7 @@ add_google_task_account add_caldav_account google_tasks_add_to_top + google_tasks_position_hack + Custom order synchronization fix + Always perform a full synchronization to workaround https://issuetracker.google.com/issues/132432317. This setting will disable itself after seven days. diff --git a/app/src/main/res/xml/preferences_synchronization.xml b/app/src/main/res/xml/preferences_synchronization.xml index 398f51e50..ffbc0290d 100644 --- a/app/src/main/res/xml/preferences_synchronization.xml +++ b/app/src/main/res/xml/preferences_synchronization.xml @@ -18,6 +18,11 @@ android:key="@string/p_google_tasks_add_to_top" android:title="@string/google_tasks_add_to_top"/> + +