+ *
+ */
+public class SyncV2Service {
+ /*
+ * At present, sync provider interactions are handled through code. If
+ * there is enough interest, the Astrid team could create an interface
+ * for responding to sync requests through this new API.
+ */
+ private final SyncExecutor syncExecutor;
+ private final SyncAdapterHelper syncAdapterHelper;
+ private final GtasksSyncService gtasksSyncService;
+
+ @Inject
+ public SyncV2Service(SyncExecutor syncExecutor, SyncAdapterHelper syncAdapterHelper, GtasksSyncService gtasksSyncService) {
+ this.syncExecutor = syncExecutor;
+ this.syncAdapterHelper = syncAdapterHelper;
+ this.gtasksSyncService = gtasksSyncService;
+ }
+
+ public void clearCompleted(final GtasksList list, final SyncResultCallback callback) {
+ if (syncAdapterHelper.isEnabled()) {
+ syncExecutor.execute(callback, new Runnable() {
+ @Override
+ public void run() {
+ callback.started();
+ try {
+ gtasksSyncService.clearCompleted(list.getRemoteId());
+ } finally {
+ callback.finished();
+ }
+ }
+ });
+ }
+ }
+}
diff --git a/src/googleplay/java/org/tasks/FlavorSetup.java b/src/googleplay/java/org/tasks/FlavorSetup.java
index aa785df37..789150508 100644
--- a/src/googleplay/java/org/tasks/FlavorSetup.java
+++ b/src/googleplay/java/org/tasks/FlavorSetup.java
@@ -2,11 +2,14 @@ package org.tasks;
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.GtasksTaskListUpdater;
+import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
import org.tasks.billing.InventoryHelper;
import org.tasks.billing.PurchaseHelper;
+import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.preferences.Preferences;
import org.tasks.receivers.TeslaUnreadReceiver;
+import org.tasks.sync.SyncExecutor;
import javax.inject.Inject;
@@ -16,21 +19,26 @@ public class FlavorSetup {
private final GtasksPreferenceService gtasksPreferenceService;
private final TeslaUnreadReceiver teslaUnreadReceiver;
private final InventoryHelper inventoryHelper;
+ private final SyncAdapterHelper syncAdapterHelper;
@Inject
public FlavorSetup(Preferences preferences, GtasksPreferenceService gtasksPreferenceService,
@SuppressWarnings("UnusedParameters") GtasksTaskListUpdater gtasksTaskListUpdater,
@SuppressWarnings("UnusedParameters") PurchaseHelper purchaseHelper,
- TeslaUnreadReceiver teslaUnreadReceiver, InventoryHelper inventoryHelper) {
+ @SuppressWarnings("UnusedParameters") SyncExecutor syncExecutor,
+ TeslaUnreadReceiver teslaUnreadReceiver, InventoryHelper inventoryHelper,
+ SyncAdapterHelper syncAdapterHelper) {
this.preferences = preferences;
this.gtasksPreferenceService = gtasksPreferenceService;
this.teslaUnreadReceiver = teslaUnreadReceiver;
this.inventoryHelper = inventoryHelper;
+ this.syncAdapterHelper = syncAdapterHelper;
}
public void setup() {
inventoryHelper.initialize();
teslaUnreadReceiver.setEnabled(preferences.getBoolean(R.string.p_tesla_unread_enabled, false));
gtasksPreferenceService.stopOngoing(); // if sync ongoing flag was set, clear it
+ syncAdapterHelper.enableSynchronization(syncAdapterHelper.isEnabled());
}
}
diff --git a/src/googleplay/java/org/tasks/activities/ClearGtaskDataActivity.java b/src/googleplay/java/org/tasks/activities/ClearGtaskDataActivity.java
index 94ba6ef5a..8ef802e96 100644
--- a/src/googleplay/java/org/tasks/activities/ClearGtaskDataActivity.java
+++ b/src/googleplay/java/org/tasks/activities/ClearGtaskDataActivity.java
@@ -3,7 +3,8 @@ package org.tasks.activities;
import android.content.DialogInterface;
import android.os.Bundle;
-import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider;
+import com.todoroo.astrid.gtasks.GtasksMetadataService;
+import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
@@ -14,8 +15,9 @@ import javax.inject.Inject;
public class ClearGtaskDataActivity extends InjectingAppCompatActivity {
- @Inject GtasksSyncV2Provider gtasksSyncV2Provider;
@Inject DialogBuilder dialogBuilder;
+ @Inject GtasksPreferenceService gtasksPreferenceService;
+ @Inject GtasksMetadataService gtasksMetadataService;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -25,7 +27,9 @@ public class ClearGtaskDataActivity extends InjectingAppCompatActivity {
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
- gtasksSyncV2Provider.signOut();
+ gtasksPreferenceService.clearLastSyncDate();
+ gtasksPreferenceService.setUserName(null);
+ gtasksMetadataService.clearMetadata();
setResult(RESULT_OK);
}
})
diff --git a/src/googleplay/java/org/tasks/gtasks/GoogleTaskSyncAdapter.java b/src/googleplay/java/org/tasks/gtasks/GoogleTaskSyncAdapter.java
new file mode 100644
index 000000000..bd0e25fe4
--- /dev/null
+++ b/src/googleplay/java/org/tasks/gtasks/GoogleTaskSyncAdapter.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.tasks.gtasks;
+
+import android.accounts.Account;
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.SyncResult;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import com.google.api.services.tasks.model.TaskList;
+import com.google.api.services.tasks.model.TaskLists;
+import com.google.api.services.tasks.model.Tasks;
+import com.todoroo.andlib.data.AbstractModel;
+import com.todoroo.andlib.data.TodorooCursor;
+import com.todoroo.andlib.sql.Criterion;
+import com.todoroo.andlib.sql.Join;
+import com.todoroo.andlib.sql.Query;
+import com.todoroo.andlib.utility.DateUtilities;
+import com.todoroo.astrid.dao.MetadataDao;
+import com.todoroo.astrid.dao.StoreObjectDao;
+import com.todoroo.astrid.dao.TaskDao;
+import com.todoroo.astrid.data.Metadata;
+import com.todoroo.astrid.data.SyncFlags;
+import com.todoroo.astrid.data.Task;
+import com.todoroo.astrid.gtasks.GtasksList;
+import com.todoroo.astrid.gtasks.GtasksListService;
+import com.todoroo.astrid.gtasks.GtasksMetadata;
+import com.todoroo.astrid.gtasks.GtasksMetadataService;
+import com.todoroo.astrid.gtasks.GtasksPreferenceService;
+import com.todoroo.astrid.gtasks.GtasksTaskListUpdater;
+import com.todoroo.astrid.gtasks.api.GtasksInvoker;
+import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
+import com.todoroo.astrid.gtasks.sync.GtasksTaskContainer;
+import com.todoroo.astrid.service.TaskService;
+
+import org.tasks.Broadcaster;
+import org.tasks.R;
+import org.tasks.injection.InjectingAbstractThreadedSyncAdapter;
+import org.tasks.injection.SyncAdapterComponent;
+import org.tasks.preferences.Preferences;
+import org.tasks.sync.RecordSyncStatusCallback;
+import org.tasks.time.DateTime;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import timber.log.Timber;
+
+import static org.tasks.date.DateTimeUtils.newDateTime;
+
+/**
+ * Define a sync adapter for the app.
+ *
+ * This class is instantiated in {@link GoogleTaskSyncService}, which also binds SyncAdapter to the system.
+ * SyncAdapter should only be initialized in SyncService, never anywhere else.
+ *
+ *
The system calls onPerformSync() via an RPC call through the IBinder object supplied by
+ * SyncService.
+ */
+public class GoogleTaskSyncAdapter extends InjectingAbstractThreadedSyncAdapter {
+
+ @Inject GtasksPreferenceService gtasksPreferenceService;
+ @Inject Broadcaster broadcaster;
+ @Inject TaskService taskService;
+ @Inject StoreObjectDao storeObjectDao;
+ @Inject GtasksSyncService gtasksSyncService;
+ @Inject GtasksListService gtasksListService;
+ @Inject GtasksMetadataService gtasksMetadataService;
+ @Inject GtasksTaskListUpdater gtasksTaskListUpdater;
+ @Inject Preferences preferences;
+ @Inject GtasksInvoker gtasksInvoker;
+
+
+ public GoogleTaskSyncAdapter(Context context, boolean autoInitialize) {
+ super(context, autoInitialize);
+ }
+
+ public GoogleTaskSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
+ super(context, autoInitialize, allowParallelSyncs);
+ }
+
+ /**
+ * Called by the Android system in response to a request to run the sync adapter. The work
+ * required to read data from the network, parse it, and store it in the content provider is
+ * done here. Extending AbstractThreadedSyncAdapter ensures that all methods within SyncAdapter
+ * run on a background thread. For this reason, blocking I/O and other long-running tasks can be
+ * run in situ, and you don't have to set up a separate thread for them.
+ .
+ *
+ *
This is where we actually perform any work required to perform a sync.
+ * {@link android.content.AbstractThreadedSyncAdapter} guarantees that this will be called on a non-UI thread,
+ * so it is safe to peform blocking I/O here.
+ *
+ *
The syncResult argument allows you to pass information back to the method that triggered
+ * the sync.
+ */
+ @Override
+ public void onPerformSync(Account account, Bundle extras, String authority,
+ ContentProviderClient provider, SyncResult syncResult) {
+ if (!account.name.equals(gtasksPreferenceService.getUserName())) {
+ Timber.d("Sync not enabled for %s", account);
+ syncResult.stats.numAuthExceptions++;
+ return;
+ }
+ if (!extras.getBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, false)) {
+ preferences.setBoolean(R.string.p_sync_warning_shown, false);
+ }
+ Timber.d("%s: start sync", account);
+ RecordSyncStatusCallback callback = new RecordSyncStatusCallback(gtasksPreferenceService, broadcaster);
+ try {
+ callback.started();
+ synchronize();
+ gtasksPreferenceService.recordSuccessfulSync();
+ } catch (Exception e) {
+ Timber.e(e, e.getMessage());
+ } finally {
+ callback.finished();
+ Timber.d("%s: end sync", account);
+ }
+ }
+
+ private void synchronize() {
+ TaskLists remoteLists = null;
+ try {
+ List gtaskLists = new ArrayList<>();
+ String nextPageToken = null;
+ do {
+ remoteLists = gtasksInvoker.allGtaskLists(nextPageToken);
+ if (remoteLists == null) {
+ break;
+ }
+ List items = remoteLists.getItems();
+ if (items != null) {
+ gtaskLists.addAll(items);
+ }
+ nextPageToken = remoteLists.getNextPageToken();
+ } while (nextPageToken != null);
+ gtasksListService.updateLists(gtaskLists);
+ if (gtasksListService.getList(gtasksPreferenceService.getDefaultList()) == null) {
+ gtasksPreferenceService.setDefaultList(null);
+ }
+ } catch (IOException e) {
+ Timber.e(e, e.getMessage());
+ }
+
+ if (remoteLists == null) {
+ return;
+ }
+
+ for (final GtasksList list : gtasksListService.getListsToUpdate(remoteLists)) {
+ synchronizeListHelper(list, gtasksInvoker);
+ }
+
+ pushUpdated(gtasksInvoker);
+ }
+
+ private synchronized void pushUpdated(GtasksInvoker invoker) {
+ TodorooCursor queued = taskService.query(Query.select(Task.PROPERTIES).
+ join(Join.left(Metadata.TABLE, Criterion.and(MetadataDao.MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY), Task.ID.eq(Metadata.TASK)))).where(
+ Criterion.or(Task.MODIFICATION_DATE.gt(GtasksMetadata.LAST_SYNC), Metadata.KEY.isNull())));
+ pushTasks(queued, invoker);
+ }
+
+ private synchronized void pushTasks(TodorooCursor queued, GtasksInvoker invoker) {
+ try {
+ for (queued.moveToFirst(); !queued.isAfterLast(); queued.moveToNext()) {
+ Task task = new Task(queued);
+ try {
+ gtasksSyncService.pushTaskOnSave(task, task.getMergedValues(), invoker);
+ } catch (IOException e) {
+ Timber.e(e, e.getMessage());
+ }
+ }
+ } finally {
+ queued.close();
+ }
+ }
+
+ private synchronized void synchronizeListHelper(GtasksList list, GtasksInvoker invoker) {
+ String listId = list.getRemoteId();
+ long lastSyncDate = list.getLastSync();
+
+ /**
+ * Find tasks which have been associated with the list internally, but have not yet been
+ * pushed to Google Tasks (and so haven't yet got a valid ID).
+ */
+ Criterion not_pushed_tasks = Criterion.and(
+ Metadata.KEY.eq(GtasksMetadata.METADATA_KEY),
+ GtasksMetadata.LIST_ID.eq(listId),
+ GtasksMetadata.ID.eq("")
+ );
+ TodorooCursor qs = taskService.query(Query.select(Task.PROPERTIES).
+ join(Join.left(Metadata.TABLE, Criterion.and(MetadataDao.MetadataCriteria.withKey(GtasksMetadata.METADATA_KEY), Task.ID.eq(Metadata.TASK)))).where(not_pushed_tasks)
+ );
+ pushTasks(qs, invoker);
+
+ boolean includeDeletedAndHidden = lastSyncDate != 0;
+ try {
+ List tasks = new ArrayList<>();
+ String nextPageToken = null;
+ do {
+ Tasks taskList = invoker.getAllGtasksFromListId(listId, includeDeletedAndHidden,
+ includeDeletedAndHidden, lastSyncDate + 1000L, nextPageToken);
+ if (taskList == null) {
+ break;
+ }
+ List items = taskList.getItems();
+ if (items != null) {
+ tasks.addAll(items);
+ }
+ nextPageToken = taskList.getNextPageToken();
+ } while (nextPageToken != null);
+
+ if (!tasks.isEmpty()) {
+ for (com.google.api.services.tasks.model.Task t : tasks) {
+ GtasksTaskContainer container = new GtasksTaskContainer(t, listId, GtasksMetadata.createEmptyMetadataWithoutList(AbstractModel.NO_ID));
+ gtasksMetadataService.findLocalMatch(container);
+ container.gtaskMetadata.setValue(GtasksMetadata.GTASKS_ORDER, Long.parseLong(t.getPosition()));
+ container.gtaskMetadata.setValue(GtasksMetadata.PARENT_TASK, gtasksMetadataService.localIdForGtasksId(t.getParent()));
+ container.gtaskMetadata.setValue(GtasksMetadata.LAST_SYNC, DateUtilities.now() + 1000L);
+ write(container);
+ lastSyncDate = Math.max(lastSyncDate, container.getUpdateTime());
+ }
+ list.setLastSync(lastSyncDate);
+ storeObjectDao.persist(list);
+ gtasksTaskListUpdater.correctOrderAndIndentForList(listId);
+ }
+ } catch (IOException e) {
+ Timber.e(e, e.getMessage());
+ }
+ }
+
+ private void write(GtasksTaskContainer task) {
+ // merge astrid dates with google dates
+
+ if(task.task.isSaved()) {
+ Task local = taskService.fetchById(task.task.getId(), Task.PROPERTIES);
+ if (local == null) {
+ task.task.clearValue(Task.ID);
+ task.task.clearValue(Task.UUID);
+ } else {
+ mergeDates(task.task, local);
+ }
+ } else { // Set default importance and reminders for remotely created tasks
+ task.task.setImportance(preferences.getIntegerFromString(
+ R.string.p_default_importance_key, Task.IMPORTANCE_SHOULD_DO));
+ TaskDao.setDefaultReminders(preferences, task.task);
+ }
+ if (!TextUtils.isEmpty(task.task.getTitle())) {
+ task.task.putTransitory(SyncFlags.GTASKS_SUPPRESS_SYNC, true);
+ gtasksMetadataService.saveTaskAndMetadata(task);
+ }
+ }
+
+ static void mergeDates(Task remote, Task local) {
+ if (remote.hasDueDate() && local.hasDueTime()) {
+ DateTime oldDate = newDateTime(local.getDueDate());
+ DateTime newDate = newDateTime(remote.getDueDate())
+ .withHourOfDay(oldDate.getHourOfDay())
+ .withMinuteOfHour(oldDate.getMinuteOfHour())
+ .withSecondOfMinute(oldDate.getSecondOfMinute());
+ local.setDueDateAdjustingHideUntil(
+ Task.createDueDate(Task.URGENCY_SPECIFIC_DAY_TIME, newDate.getMillis()));
+ } else {
+ local.setDueDateAdjustingHideUntil(remote.getDueDate());
+ }
+
+ remote.setHideUntil(local.getHideUntil());
+ remote.setDueDate(local.getDueDate());
+ }
+
+ @Override
+ protected void inject(SyncAdapterComponent component) {
+ component.inject(this);
+ }
+}
diff --git a/src/googleplay/java/org/tasks/gtasks/GoogleTaskSyncService.java b/src/googleplay/java/org/tasks/gtasks/GoogleTaskSyncService.java
new file mode 100644
index 000000000..18b41b868
--- /dev/null
+++ b/src/googleplay/java/org/tasks/gtasks/GoogleTaskSyncService.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.tasks.gtasks;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+import timber.log.Timber;
+
+/** Service to handle sync requests.
+ *
+ * This service is invoked in response to Intents with action android.content.SyncAdapter, and
+ * returns a Binder connection to SyncAdapter.
+ *
+ *
For performance, only one sync adapter will be initialized within this application's context.
+ *
+ *
Note: The SyncService itself is not notified when a new sync occurs. It's role is to
+ * manage the lifecycle of our {@link GoogleTaskSyncAdapter} and provide a handle to said SyncAdapter to the
+ * OS on request.
+ */
+public class GoogleTaskSyncService extends Service {
+ private static final Object sSyncAdapterLock = new Object();
+ private static GoogleTaskSyncAdapter sGoogleTaskSyncAdapter = null;
+
+ /**
+ * Thread-safe constructor, creates static {@link GoogleTaskSyncAdapter} instance.
+ */
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Timber.d("Service created");
+ synchronized (sSyncAdapterLock) {
+ if (sGoogleTaskSyncAdapter == null) {
+ sGoogleTaskSyncAdapter = new GoogleTaskSyncAdapter(getApplicationContext(), true);
+ }
+ }
+ }
+
+ @Override
+ /**
+ * Logging-only destructor.
+ */
+ public void onDestroy() {
+ super.onDestroy();
+ Timber.d("Service destroyed");
+ }
+
+ /**
+ * Return Binder handle for IPC communication with {@link GoogleTaskSyncAdapter}.
+ *
+ *
New sync requests will be sent directly to the SyncAdapter using this channel.
+ *
+ * @param intent Calling intent
+ * @return Binder handle for {@link GoogleTaskSyncAdapter}
+ */
+ @Override
+ public IBinder onBind(Intent intent) {
+ return sGoogleTaskSyncAdapter.getSyncAdapterBinder();
+ }
+}
diff --git a/src/googleplay/java/org/tasks/injection/ApplicationComponent.java b/src/googleplay/java/org/tasks/injection/ApplicationComponent.java
new file mode 100644
index 000000000..67139d230
--- /dev/null
+++ b/src/googleplay/java/org/tasks/injection/ApplicationComponent.java
@@ -0,0 +1,11 @@
+package org.tasks.injection;
+
+import javax.inject.Singleton;
+
+import dagger.Component;
+
+@Singleton
+@Component(modules = ApplicationModule.class)
+public interface ApplicationComponent extends BaseApplicationComponent {
+ SyncAdapterComponent plus(SyncAdapterModule syncAdapterModule);
+}
diff --git a/src/googleplay/java/org/tasks/injection/InjectingAbstractThreadedSyncAdapter.java b/src/googleplay/java/org/tasks/injection/InjectingAbstractThreadedSyncAdapter.java
new file mode 100644
index 000000000..ee6498f4d
--- /dev/null
+++ b/src/googleplay/java/org/tasks/injection/InjectingAbstractThreadedSyncAdapter.java
@@ -0,0 +1,25 @@
+package org.tasks.injection;
+
+import android.content.AbstractThreadedSyncAdapter;
+import android.content.Context;
+
+public abstract class InjectingAbstractThreadedSyncAdapter extends AbstractThreadedSyncAdapter {
+
+ public InjectingAbstractThreadedSyncAdapter(Context context, boolean autoInitialize) {
+ super(context, autoInitialize);
+ inject(context);
+ }
+
+ public InjectingAbstractThreadedSyncAdapter(Context context, boolean autoInitialize, boolean allowParallelSyncs) {
+ super(context, autoInitialize, allowParallelSyncs);
+ inject(context);
+ }
+
+ private void inject(Context context) {
+ inject(((InjectingApplication) context.getApplicationContext())
+ .getComponent()
+ .plus(new SyncAdapterModule()));
+ }
+
+ protected abstract void inject(SyncAdapterComponent component);
+}
diff --git a/src/googleplay/java/org/tasks/injection/SyncAdapterComponent.java b/src/googleplay/java/org/tasks/injection/SyncAdapterComponent.java
new file mode 100644
index 000000000..ad2775991
--- /dev/null
+++ b/src/googleplay/java/org/tasks/injection/SyncAdapterComponent.java
@@ -0,0 +1,10 @@
+package org.tasks.injection;
+
+import org.tasks.gtasks.GoogleTaskSyncAdapter;
+
+import dagger.Subcomponent;
+
+@Subcomponent(modules = SyncAdapterModule.class)
+public interface SyncAdapterComponent {
+ void inject(GoogleTaskSyncAdapter googleTaskSyncAdapter);
+}
diff --git a/src/googleplay/java/org/tasks/injection/SyncAdapterModule.java b/src/googleplay/java/org/tasks/injection/SyncAdapterModule.java
new file mode 100644
index 000000000..8ff2ffea0
--- /dev/null
+++ b/src/googleplay/java/org/tasks/injection/SyncAdapterModule.java
@@ -0,0 +1,7 @@
+package org.tasks.injection;
+
+import dagger.Module;
+
+@Module
+public class SyncAdapterModule {
+}
diff --git a/src/googleplay/java/org/tasks/receivers/GoogleTaskPushReceiver.java b/src/googleplay/java/org/tasks/receivers/GoogleTaskPushReceiver.java
index 67fc0e054..088e60de4 100644
--- a/src/googleplay/java/org/tasks/receivers/GoogleTaskPushReceiver.java
+++ b/src/googleplay/java/org/tasks/receivers/GoogleTaskPushReceiver.java
@@ -16,6 +16,7 @@ import com.todoroo.astrid.gtasks.api.GtasksInvoker;
import com.todoroo.astrid.gtasks.sync.GtasksSyncService;
import com.todoroo.astrid.service.TaskService;
+import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.injection.BroadcastComponent;
import org.tasks.injection.InjectingBroadcastReceiver;
@@ -31,12 +32,13 @@ public class GoogleTaskPushReceiver extends InjectingBroadcastReceiver {
@Inject GtasksPreferenceService gtasksPreferenceService;
@Inject GtasksSyncService gtasksSyncService;
@Inject TaskDao taskDao;
+ @Inject SyncAdapterHelper syncAdapterHelper;
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
- if(!gtasksPreferenceService.isLoggedIn()) {
+ if(!syncAdapterHelper.isEnabled()) {
return;
}
diff --git a/src/googleplay/java/org/tasks/scheduling/GtasksBackgroundService.java b/src/googleplay/java/org/tasks/scheduling/GtasksBackgroundService.java
deleted file mode 100644
index 214c5967a..000000000
--- a/src/googleplay/java/org/tasks/scheduling/GtasksBackgroundService.java
+++ /dev/null
@@ -1,60 +0,0 @@
-package org.tasks.scheduling;
-
-import com.todoroo.astrid.gtasks.GtasksPreferenceService;
-import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider;
-
-import org.tasks.Broadcaster;
-import org.tasks.R;
-import org.tasks.injection.IntentServiceComponent;
-import org.tasks.preferences.Preferences;
-import org.tasks.sync.RecordSyncStatusCallback;
-
-import javax.inject.Inject;
-
-import timber.log.Timber;
-
-import static java.util.concurrent.TimeUnit.SECONDS;
-
-public class GtasksBackgroundService extends RecurringIntervalIntentService {
-
- @Inject Preferences preferences;
- @Inject GtasksPreferenceService gtasksPreferenceService;
- @Inject GtasksSyncV2Provider gtasksSyncV2Provider;
- @Inject Broadcaster broadcaster;
-
- public GtasksBackgroundService() {
- super(GtasksBackgroundService.class.getSimpleName());
- }
-
- @Override
- void run() {
- if (gtasksPreferenceService.isOngoing()) {
- Timber.d("aborting: sync ongoing");
- return;
- }
- if(gtasksSyncV2Provider.isActive()) {
- gtasksSyncV2Provider.synchronizeActiveTasks(new RecordSyncStatusCallback(gtasksPreferenceService, broadcaster));
- }
- }
-
- @Override
- long intervalMillis() {
- try {
- return SECONDS.toMillis(preferences.getIntegerFromString(R.string.gtasks_GPr_interval_key, 0));
- } catch(Exception e) {
- Timber.e(e, e.getMessage());
- preferences.setString(R.string.gtasks_GPr_interval_key, "0");
- return 0;
- }
- }
-
- @Override
- String getLastRunPreference() {
- return "gtasks_last_sync";
- }
-
- @Override
- protected void inject(IntentServiceComponent component) {
- component.inject(this);
- }
-}
diff --git a/src/googleplay/res/values/bools.xml b/src/googleplay/res/values/bools.xml
index 0c80a8b43..515c5e1fd 100644
--- a/src/googleplay/res/values/bools.xml
+++ b/src/googleplay/res/values/bools.xml
@@ -1,6 +1,5 @@
- true
true
true
\ No newline at end of file
diff --git a/src/main/java/com/todoroo/astrid/actfm/TagViewFragment.java b/src/main/java/com/todoroo/astrid/actfm/TagViewFragment.java
index e1d11e263..35b88fe68 100644
--- a/src/main/java/com/todoroo/astrid/actfm/TagViewFragment.java
+++ b/src/main/java/com/todoroo/astrid/actfm/TagViewFragment.java
@@ -11,7 +11,6 @@ import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
-import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.AstridApiConstants;
@@ -117,17 +116,6 @@ public class TagViewFragment extends TaskListFragment {
outState.putParcelable(EXTRA_TAG_DATA, tagData);
}
- @Override
- protected void initiateAutomaticSyncImpl() {
- if (tagData != null) {
- long lastAutosync = tagData.getLastAutosync();
- if(DateUtilities.now() - lastAutosync > AUTOSYNC_INTERVAL) {
- tagData.setLastAutosync(DateUtilities.now());
- tagDataDao.saveExisting(tagData);
- }
- }
- }
-
@Override
protected boolean hasDraggableOption() {
return tagData != null;
diff --git a/src/main/java/com/todoroo/astrid/activity/TaskListActivity.java b/src/main/java/com/todoroo/astrid/activity/TaskListActivity.java
index 52e6c91b5..49368f3d8 100644
--- a/src/main/java/com/todoroo/astrid/activity/TaskListActivity.java
+++ b/src/main/java/com/todoroo/astrid/activity/TaskListActivity.java
@@ -12,6 +12,8 @@ import android.content.ContentValues;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.provider.Settings;
+import android.support.design.widget.Snackbar;
import android.support.v4.widget.DrawerLayout;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
@@ -46,6 +48,7 @@ import org.tasks.dialogs.SortDialog;
import org.tasks.fragments.CommentBarFragment;
import org.tasks.fragments.TaskEditControlSetFragmentManager;
import org.tasks.gtasks.GoogleTaskListSelectionHandler;
+import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.intents.TaskIntents;
@@ -94,6 +97,7 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
@Inject Theme theme;
@Inject Broadcaster broadcaster;
@Inject ThemeCache themeCache;
+ @Inject SyncAdapterHelper syncAdapterHelper;
@BindView(R.id.drawer_layout) DrawerLayout drawerLayout;
@@ -233,6 +237,28 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
registerReceiver(
repeatConfirmationReceiver,
new IntentFilter(AstridApiConstants.BROADCAST_EVENT_TASK_REPEATED));
+
+ if (syncAdapterHelper.shouldShowBackgroundSyncWarning() && !preferences.getBoolean(R.string.p_sync_warning_shown, false)) {
+ TaskListFragment taskListFragment = getTaskListFragment();
+ if (taskListFragment != null) {
+ taskListFragment.makeSnackbar(R.string.master_sync_warning)
+ .setAction(R.string.TLA_menu_settings, new View.OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ startActivity(new Intent(Settings.ACTION_SYNC_SETTINGS) {{
+ setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }});
+ }
+ })
+ .setCallback(new Snackbar.Callback() {
+ @Override
+ public void onShown(Snackbar snackbar) {
+ preferences.setBoolean(R.string.p_sync_warning_shown, true);
+ }
+ })
+ .show();
+ }
+ }
}
@Override
diff --git a/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java b/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java
index 1b6581979..b696c5798 100644
--- a/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java
+++ b/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java
@@ -14,6 +14,8 @@ import android.content.IntentFilter;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.os.Bundle;
+import android.support.design.widget.CoordinatorLayout;
+import android.support.design.widget.Snackbar;
import android.support.v4.view.MenuItemCompat;
import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.widget.SearchView;
@@ -57,7 +59,6 @@ import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.data.TaskAttachment;
import com.todoroo.astrid.gtasks.GtasksListFragment;
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
-import com.todoroo.astrid.helper.SyncActionHelper;
import com.todoroo.astrid.service.TaskCreator;
import com.todoroo.astrid.service.TaskDeleter;
import com.todoroo.astrid.service.TaskDuplicator;
@@ -73,6 +74,7 @@ import org.tasks.Broadcaster;
import org.tasks.R;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.dialogs.SortDialog;
+import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.injection.ForActivity;
import org.tasks.injection.FragmentComponent;
import org.tasks.injection.InjectingListFragment;
@@ -120,7 +122,6 @@ public class TaskListFragment extends InjectingListFragment implements
// --- activities
- public static final long AUTOSYNC_INTERVAL = 90000L;
public static final int ACTIVITY_REQUEST_NEW_FILTER = 5;
// --- menu codes
@@ -132,6 +133,7 @@ public class TaskListFragment extends InjectingListFragment implements
// --- instance variables
+ @Inject SyncAdapterHelper syncAdapterHelper;
@Inject TaskService taskService;
@Inject TaskDeleter taskDeleter;
@Inject TaskDuplicator taskDuplicator;
@@ -141,7 +143,6 @@ public class TaskListFragment extends InjectingListFragment implements
@Inject TaskAttachmentDao taskAttachmentDao;
@Inject GtasksPreferenceService gtasksPreferenceService;
@Inject DialogBuilder dialogBuilder;
- @Inject SyncActionHelper syncActionHelper;
@Inject CheckBoxes checkBoxes;
@Inject VoiceInputAssistant voiceInputAssistant;
@Inject TaskCreator taskCreator;
@@ -152,6 +153,7 @@ public class TaskListFragment extends InjectingListFragment implements
@BindView(R.id.swipe_layout) SwipeRefreshLayout swipeRefreshLayout;
@BindView(R.id.swipe_layout_empty) SwipeRefreshLayout emptyView;
@BindView(R.id.toolbar) Toolbar toolbar;
+ @BindView(R.id.task_list_coordinator) CoordinatorLayout coordinatorLayout;
private TaskAdapter taskAdapter = null;
private RefreshReceiver refreshReceiver = new RefreshReceiver();
@@ -168,7 +170,7 @@ public class TaskListFragment extends InjectingListFragment implements
@Override
public void onRefresh() {
- if (!syncActionHelper.performSyncAction()) {
+ if (!syncAdapterHelper.initiateManualSync()) {
refresh();
}
}
@@ -470,19 +472,18 @@ public class TaskListFragment extends InjectingListFragment implements
getActivity().registerReceiver(refreshReceiver, new IntentFilter(AstridApiConstants.BROADCAST_EVENT_REFRESH));
- initiateAutomaticSyncImpl();
-
refresh();
}
- /**
- * Implementation of initiation automatic sync. Subclasses should override this method;
- * the above method takes care of calling it in the correct way
- */
- protected void initiateAutomaticSyncImpl() {
- if (BuiltInFilterExposer.isInbox(context, filter)) {
- syncActionHelper.initiateAutomaticSync();
- }
+ public Snackbar makeSnackbar(int resId) {
+ return makeSnackbar(getString(resId));
+ }
+
+ public Snackbar makeSnackbar(String text) {
+ Snackbar snackbar = Snackbar.make(coordinatorLayout, text, 8000)
+ .setActionTextColor(getResources().getColor(R.color.snackbar_text_color));
+ snackbar.getView().setBackgroundColor(getResources().getColor(R.color.snackbar_background));
+ return snackbar;
}
@Override
diff --git a/src/main/java/com/todoroo/astrid/gtasks/GtasksPreferenceService.java b/src/main/java/com/todoroo/astrid/gtasks/GtasksPreferenceService.java
index a1dbc7e50..a68724441 100644
--- a/src/main/java/com/todoroo/astrid/gtasks/GtasksPreferenceService.java
+++ b/src/main/java/com/todoroo/astrid/gtasks/GtasksPreferenceService.java
@@ -5,17 +5,12 @@
*/
package com.todoroo.astrid.gtasks;
-import android.content.Context;
-
import com.todoroo.andlib.utility.DateUtilities;
-import org.tasks.AccountManager;
import org.tasks.R;
-import org.tasks.injection.ForApplication;
import org.tasks.preferences.Preferences;
import javax.inject.Inject;
-import javax.inject.Singleton;
/**
* Methods for working with GTasks preferences
@@ -23,12 +18,9 @@ import javax.inject.Singleton;
* @author timsu
*
*/
-@Singleton
public class GtasksPreferenceService {
- private final Context context;
private final Preferences preferences;
- private final AccountManager accountManager;
public static final String IDENTIFIER = "gtasks"; //$NON-NLS-1$
@@ -36,11 +28,8 @@ public class GtasksPreferenceService {
private static final String PREF_USER_NAME = IDENTIFIER + "_user"; //$NON-NLS-1$
@Inject
- public GtasksPreferenceService(@ForApplication Context context, Preferences preferences,
- AccountManager accountManager) {
- this.context = context;
+ public GtasksPreferenceService(Preferences preferences) {
this.preferences = preferences;
- this.accountManager = accountManager;
}
public String getDefaultList() {
@@ -63,15 +52,6 @@ public class GtasksPreferenceService {
protected static final String PREF_ONGOING = "_ongoing"; //$NON-NLS-1$
- /**
- * @return true if we have a token for this user, false otherwise
- */
- public boolean isLoggedIn() {
- return context.getResources().getBoolean(R.bool.sync_supported) &&
- preferences.getBoolean(R.string.sync_gtasks, false) &&
- accountManager.hasAccount(preferences.getStringValue(PREF_USER_NAME));
- }
-
/** @return Last Successful Sync Date, or 0 */
public long getLastSyncDate() {
return preferences.getLong(IDENTIFIER + PREF_LAST_SYNC, 0);
@@ -101,4 +81,8 @@ public class GtasksPreferenceService {
public void recordSyncStart() {
preferences.setBoolean(IDENTIFIER + PREF_ONGOING, true);
}
+
+ public int getSyncInterval() {
+ return preferences.getIntegerFromString(R.string.gtasks_GPr_interval_key, 0);
+ }
}
diff --git a/src/main/java/com/todoroo/astrid/helper/SyncActionHelper.java b/src/main/java/com/todoroo/astrid/helper/SyncActionHelper.java
deleted file mode 100644
index 15a1ba049..000000000
--- a/src/main/java/com/todoroo/astrid/helper/SyncActionHelper.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/**
- * Copyright (c) 2012 Todoroo Inc
- *
- * See the file "LICENSE" for the full license governing this code.
- */
-package com.todoroo.astrid.helper;
-
-import com.todoroo.andlib.utility.DateUtilities;
-import com.todoroo.astrid.activity.TaskListFragment;
-import com.todoroo.astrid.gtasks.GtasksPreferenceService;
-import com.todoroo.astrid.service.SyncV2Service;
-import com.todoroo.astrid.sync.SyncResultCallback;
-
-import org.tasks.Broadcaster;
-import org.tasks.preferences.Preferences;
-import org.tasks.sync.RecordSyncStatusCallback;
-
-import javax.inject.Inject;
-
-/**
- * SyncActionHelper is a helper class for encapsulating UI actions
- * responsible for performing sync and prompting user to sign up for a new
- * sync service.
- *
- * In order to make this work you need to call register() and unregister() in
- * onResume and onPause, respectively.
- *
- * @author Tim Su
- */
-public class SyncActionHelper {
-
- public static final String PREF_LAST_AUTO_SYNC = "taskListLastAutoSync"; //$NON-NLS-1$
-
- public final SyncResultCallback syncResultCallback;
-
- private final SyncV2Service syncService;
- private final Preferences preferences;
-
- // --- boilerplate
-
- @Inject
- public SyncActionHelper(GtasksPreferenceService gtasksPreferenceService, SyncV2Service syncService,
- Preferences preferences, Broadcaster broadcaster) {
- this.syncService = syncService;
- this.preferences = preferences;
- syncResultCallback = new RecordSyncStatusCallback(gtasksPreferenceService, broadcaster);
- }
-
- // --- automatic sync logic
-
- public void initiateAutomaticSync() {
- long tasksPushedAt = preferences.getLong(PREF_LAST_AUTO_SYNC, 0);
- if (DateUtilities.now() - tasksPushedAt > TaskListFragment.AUTOSYNC_INTERVAL) {
- performSyncServiceV2Sync();
- }
- }
-
- // --- sync logic
-
- protected void performSyncServiceV2Sync() {
- boolean syncOccurred = syncService.synchronizeActiveTasks(syncResultCallback);
- if (syncOccurred) {
- preferences.setLong(PREF_LAST_AUTO_SYNC, DateUtilities.now());
- }
- }
-
- public boolean performSyncAction() {
- if (syncService.isActive()) {
- syncService.synchronizeActiveTasks(syncResultCallback);
- return true;
- } else {
- return false;
- }
- }
-}
-
-
diff --git a/src/main/java/com/todoroo/astrid/service/SyncV2Service.java b/src/main/java/com/todoroo/astrid/service/SyncV2Service.java
deleted file mode 100644
index 206834be8..000000000
--- a/src/main/java/com/todoroo/astrid/service/SyncV2Service.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/**
- * Copyright (c) 2012 Todoroo Inc
- *
- * See the file "LICENSE" for the full license governing this code.
- */
-package com.todoroo.astrid.service;
-
-import com.todoroo.astrid.gtasks.GtasksList;
-import com.todoroo.astrid.gtasks.sync.GtasksSyncV2Provider;
-import com.todoroo.astrid.sync.SyncResultCallback;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-/**
- * SyncV2Service is a simplified synchronization interface for supporting
- * next-generation sync interfaces such as Google Tasks and Astrid.com
- *
- * @author Tim Su
- *
- */
-@Singleton
-public class SyncV2Service {
-
- /*
- * At present, sync provider interactions are handled through code. If
- * there is enough interest, the Astrid team could create an interface
- * for responding to sync requests through this new API.
- */
- private final GtasksSyncV2Provider provider;
-
- @Inject
- public SyncV2Service(GtasksSyncV2Provider gtasksSyncV2Provider) {
- provider = gtasksSyncV2Provider;
- }
-
- public boolean isActive() {
- return provider.isActive();
- }
-
- /**
- * Initiate synchronization of active tasks
- *
- * @param callback result callback
- * @return true if any servide was logged in and initiated a sync
- */
- public boolean synchronizeActiveTasks(SyncResultCallback callback) {
- if (provider.isActive()) {
- provider.synchronizeActiveTasks(callback);
- return true;
- }
- return false;
- }
-
- /**
- * Initiate synchronization of task list
- *
- * @param list list object
- * @param callback result callback
- */
- public void synchronizeList(GtasksList list, SyncResultCallback callback) {
- if(provider.isActive()) {
- provider.synchronizeList(list, callback);
- }
- }
-
- public void clearCompleted(GtasksList list, SyncResultCallback callback) {
- if (provider.isActive()) {
- provider.clearCompleted(list, callback);
- }
- }
-}
diff --git a/src/main/java/org/tasks/Tasks.java b/src/main/java/org/tasks/Tasks.java
index 3c7dacfa3..2009ee692 100644
--- a/src/main/java/org/tasks/Tasks.java
+++ b/src/main/java/org/tasks/Tasks.java
@@ -8,16 +8,13 @@ import com.todoroo.astrid.dao.TaskAttachmentDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskListMetadataDao;
import com.todoroo.astrid.dao.UserActivityDao;
-import com.todoroo.astrid.service.SyncV2Service;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagService;
import org.tasks.analytics.Tracker;
-import org.tasks.filters.FilterCounter;
import org.tasks.injection.ApplicationComponent;
import org.tasks.injection.InjectingApplication;
import org.tasks.preferences.Preferences;
-import org.tasks.sync.SyncThrottle;
import javax.inject.Inject;
@@ -33,10 +30,8 @@ public class Tasks extends InjectingApplication {
@Inject TaskAttachmentDao taskAttachmentDao;
@Inject TaskListMetadataDao taskListMetadataDao;
@Inject TaskService taskService;
- @Inject SyncV2Service syncV2Service;
@Inject TagService tagService;
@Inject Broadcaster broadcaster;
- @Inject SyncThrottle syncThrottle;
@Inject Preferences preferences;
@Inject Tracker tracker;
@Inject FlavorSetup flavorSetup;
diff --git a/src/main/java/org/tasks/filters/FilterCriteriaProvider.java b/src/main/java/org/tasks/filters/FilterCriteriaProvider.java
index 3870af445..ef54264bc 100644
--- a/src/main/java/org/tasks/filters/FilterCriteriaProvider.java
+++ b/src/main/java/org/tasks/filters/FilterCriteriaProvider.java
@@ -22,11 +22,11 @@ import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksList;
import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksMetadata;
-import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.tags.TagService;
import com.todoroo.astrid.tags.TaskToTagMetadata;
import org.tasks.R;
+import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.injection.ForApplication;
import java.util.List;
@@ -48,18 +48,20 @@ public class FilterCriteriaProvider {
private Context context;
private TagService tagService;
- private GtasksPreferenceService gtasksPreferenceService;
private GtasksListService gtasksListService;
private GtasksMetadata gtasksMetadata;
private Resources r;
+ private final SyncAdapterHelper syncAdapterHelper;
@Inject
- public FilterCriteriaProvider(@ForApplication Context context, TagService tagService, GtasksPreferenceService gtasksPreferenceService, GtasksListService gtasksListService, GtasksMetadata gtasksMetadata) {
+ public FilterCriteriaProvider(@ForApplication Context context, TagService tagService,
+ GtasksListService gtasksListService,
+ GtasksMetadata gtasksMetadata, SyncAdapterHelper syncAdapterHelper) {
this.context = context;
this.tagService = tagService;
- this.gtasksPreferenceService = gtasksPreferenceService;
this.gtasksListService = gtasksListService;
this.gtasksMetadata = gtasksMetadata;
+ this.syncAdapterHelper = syncAdapterHelper;
r = context.getResources();
}
@@ -72,7 +74,7 @@ public class FilterCriteriaProvider {
result.add(getDueDateFilter());
result.add(getImportanceFilter());
result.add(getTaskTitleContainsFilter());
- if (gtasksPreferenceService.isLoggedIn()) {
+ if (syncAdapterHelper.isEnabled()) {
result.add(getGtasksFilterCriteria());
}
diff --git a/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.java b/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.java
index 4dd075222..87a0708c6 100644
--- a/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.java
+++ b/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.java
@@ -6,7 +6,6 @@ import android.app.FragmentManager;
import com.todoroo.astrid.activity.BeastModePreferences;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.files.FilesControlSet;
-import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.repeats.RepeatControlSet;
import com.todoroo.astrid.tags.TagsControlSet;
import com.todoroo.astrid.timers.TimerControlSet;
@@ -16,6 +15,7 @@ import com.todoroo.astrid.ui.ReminderControlSet;
import org.tasks.BuildConfig;
import org.tasks.R;
+import org.tasks.gtasks.SyncAdapterHelper;
import org.tasks.preferences.Preferences;
import org.tasks.ui.CalendarControlSet;
import org.tasks.ui.DeadlineControlSet;
@@ -78,12 +78,12 @@ public class TaskEditControlSetFragmentManager {
private final Map controlSetFragments = new LinkedHashMap<>();
private final List displayOrder;
private final FragmentManager fragmentManager;
+ private final SyncAdapterHelper syncAdapterHelper;
private int numRows;
- private GtasksPreferenceService gtasksPreferenceService;
@Inject
- public TaskEditControlSetFragmentManager(Activity activity, Preferences preferences, GtasksPreferenceService gtasksPreferenceService) {
- this.gtasksPreferenceService = gtasksPreferenceService;
+ public TaskEditControlSetFragmentManager(Activity activity, Preferences preferences, SyncAdapterHelper syncAdapterHelper) {
+ this.syncAdapterHelper = syncAdapterHelper;
displayOrder = BeastModePreferences.constructOrderedControlList(preferences, activity);
displayOrder.add(0, activity.getString(EditTitleControlSet.TAG));
displayOrder.add(1, activity.getString(CommentBarFragment.TAG));
@@ -166,7 +166,7 @@ public class TaskEditControlSetFragmentManager {
case CommentBarFragment.TAG:
return new CommentBarFragment();
case GoogleTaskListFragment.TAG:
- return gtasksPreferenceService.isLoggedIn()
+ return syncAdapterHelper.isEnabled()
? new GoogleTaskListFragment()
: null;
default:
diff --git a/src/main/java/org/tasks/gtasks/SyncAdapterHelper.java b/src/main/java/org/tasks/gtasks/SyncAdapterHelper.java
new file mode 100644
index 000000000..a65135876
--- /dev/null
+++ b/src/main/java/org/tasks/gtasks/SyncAdapterHelper.java
@@ -0,0 +1,99 @@
+package org.tasks.gtasks;
+
+import android.accounts.Account;
+import android.content.ContentResolver;
+import android.os.Bundle;
+
+import com.todoroo.astrid.gtasks.GtasksPreferenceService;
+
+import org.tasks.AccountManager;
+import org.tasks.R;
+import org.tasks.preferences.Preferences;
+
+import javax.inject.Inject;
+
+import timber.log.Timber;
+
+public class SyncAdapterHelper {
+
+ private static final String AUTHORITY = "org.tasks";
+
+ private final AccountManager accountManager;
+ private final Preferences preferences;
+ private final GtasksPreferenceService gtasksPreferenceService;
+
+ @Inject
+ public SyncAdapterHelper(AccountManager accountManager, Preferences preferences,
+ GtasksPreferenceService gtasksPreferenceService) {
+ this.accountManager = accountManager;
+ this.preferences = preferences;
+ this.gtasksPreferenceService = gtasksPreferenceService;
+ }
+
+ /**
+ * Helper method to trigger an immediate sync ("refresh").
+ *
+ * This should only be used when we need to preempt the normal sync schedule. Typically, this
+ * means the user has pressed the "refresh" button.
+ *
+ * Note that SYNC_EXTRAS_MANUAL will cause an immediate sync, without any optimization to
+ * preserve battery life. If you know new data is available (perhaps via a GCM notification),
+ * but the user is not actively waiting for that data, you should omit this flag; this will give
+ * the OS additional freedom in scheduling your sync request.
+ */
+ public boolean initiateManualSync() {
+ Account account = getAccount();
+ if (account == null) {
+ return false;
+ }
+ Bundle extras = new Bundle();
+ // Disable sync backoff and ignore sync preferences. In other words...perform sync NOW!
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ ContentResolver.requestSync(account, AUTHORITY, extras);
+ return true;
+ }
+
+ public boolean isEnabled() {
+ return preferences.getBoolean(R.string.sync_gtasks, false) && getAccount() != null;
+ }
+
+ public boolean masterSyncEnabled() {
+ return ContentResolver.getMasterSyncAutomatically();
+ }
+
+ public void enableSynchronization(boolean enabled) {
+ Account account = getAccount();
+ if (account != null) {
+ Timber.d("enableSynchronization=%s", enabled);
+ ContentResolver.setIsSyncable(account, AUTHORITY, 1);
+ if (enabled) {
+ setSynchronizationInterval(preferences.getIntegerFromString(R.string.gtasks_GPr_interval_key, 0));
+ } else {
+ setSynchronizationInterval(0);
+ }
+ }
+ }
+
+ public void setSynchronizationInterval(int seconds) {
+ Account account = getAccount();
+ if (account != null) {
+ boolean syncAutomatically = seconds > 0;
+ ContentResolver.setSyncAutomatically(account, AUTHORITY, syncAutomatically);
+ Timber.d("syncAutomatically=%s, syncInterval=%s", syncAutomatically, seconds);
+ if (syncAutomatically) {
+ ContentResolver.addPeriodicSync(account, AUTHORITY, Bundle.EMPTY, seconds);
+ } else {
+ ContentResolver.removePeriodicSync(account, AUTHORITY, Bundle.EMPTY);
+ }
+ }
+ }
+
+ private Account getAccount() {
+ return accountManager.getAccount(gtasksPreferenceService.getUserName());
+ }
+
+ public boolean shouldShowBackgroundSyncWarning() {
+ return isEnabled() && !masterSyncEnabled() && !ContentResolver.getPeriodicSyncs(getAccount(), AUTHORITY).isEmpty();
+ }
+}
diff --git a/src/main/java/org/tasks/injection/ApplicationComponent.java b/src/main/java/org/tasks/injection/BaseApplicationComponent.java
similarity index 79%
rename from src/main/java/org/tasks/injection/ApplicationComponent.java
rename to src/main/java/org/tasks/injection/BaseApplicationComponent.java
index d0c690963..718581f6c 100644
--- a/src/main/java/org/tasks/injection/ApplicationComponent.java
+++ b/src/main/java/org/tasks/injection/BaseApplicationComponent.java
@@ -6,10 +6,7 @@ import javax.inject.Singleton;
import dagger.Component;
-@Singleton
-@Component(modules = ApplicationModule.class)
-public interface ApplicationComponent {
-
+public interface BaseApplicationComponent {
Tasks inject(Tasks tasks);
ActivityComponent plus(ActivityModule module);
diff --git a/src/main/java/org/tasks/injection/IntentServiceComponent.java b/src/main/java/org/tasks/injection/IntentServiceComponent.java
index dd6fcaa90..3400b6a1f 100644
--- a/src/main/java/org/tasks/injection/IntentServiceComponent.java
+++ b/src/main/java/org/tasks/injection/IntentServiceComponent.java
@@ -4,7 +4,6 @@ import org.tasks.location.GeofenceTransitionsIntentService;
import org.tasks.scheduling.BackupIntentService;
import org.tasks.scheduling.CalendarNotificationIntentService;
import org.tasks.scheduling.GeofenceSchedulingIntentService;
-import org.tasks.scheduling.GtasksBackgroundService;
import org.tasks.scheduling.RefreshSchedulerIntentService;
import org.tasks.scheduling.ReminderSchedulerIntentService;
@@ -23,6 +22,4 @@ public interface IntentServiceComponent {
void inject(BackupIntentService backupIntentService);
void inject(GeofenceTransitionsIntentService geofenceTransitionsIntentService);
-
- void inject(GtasksBackgroundService gtasksBackgroundService);
}
diff --git a/src/main/java/org/tasks/receivers/RepeatConfirmationReceiver.java b/src/main/java/org/tasks/receivers/RepeatConfirmationReceiver.java
index 4f8d0cd06..c463e9c83 100644
--- a/src/main/java/org/tasks/receivers/RepeatConfirmationReceiver.java
+++ b/src/main/java/org/tasks/receivers/RepeatConfirmationReceiver.java
@@ -6,10 +6,11 @@ import android.content.Context;
import android.content.Intent;
import android.support.design.widget.Snackbar;
import android.view.View;
-import android.view.WindowManager;
import com.todoroo.andlib.data.Property;
import com.todoroo.andlib.utility.DateUtilities;
+import com.todoroo.astrid.activity.TaskListActivity;
+import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.TaskService;
@@ -45,6 +46,14 @@ public class RepeatConfirmationReceiver extends BroadcastReceiver {
@Override
public void onReceive(final Context context, final Intent intent) {
+ TaskListFragment taskListFragment = null;
+ if (activity instanceof TaskListActivity) {
+ taskListFragment = ((TaskListActivity) activity).getTaskListFragment();
+ }
+ if (taskListFragment == null) {
+ Timber.d("No task list fragment");
+ return;
+ }
long taskId = intent.getLongExtra(AstridApiConstants.EXTRAS_TASK_ID, 0);
if (taskId > 0) {
@@ -53,15 +62,7 @@ public class RepeatConfirmationReceiver extends BroadcastReceiver {
Task task = taskService.fetchById(taskId, REPEAT_RESCHEDULED_PROPERTIES);
try {
- showSnackbar(activity.findViewById(R.id.task_list_coordinator), task, oldDueDate, newDueDate);
- } catch (WindowManager.BadTokenException e) { // Activity not running when tried to show dialog--rebroadcast
- Timber.e(e, e.getMessage());
- new Thread() {
- @Override
- public void run() {
- context.sendBroadcast(intent);
- }
- }.start();
+ showSnackbar(taskListFragment, task, oldDueDate, newDueDate);
} catch (Exception e) {
Timber.e(e, e.getMessage());
tracker.reportException(e);
@@ -69,12 +70,10 @@ public class RepeatConfirmationReceiver extends BroadcastReceiver {
}
}
- private void showSnackbar(View view, final Task task, final long oldDueDate, final long newDueDate) {
+ private void showSnackbar(TaskListFragment taskListFragment, final Task task, final long oldDueDate, final long newDueDate) {
String dueDateString = getRelativeDateAndTimeString(activity, newDueDate);
String snackbarText = activity.getString(R.string.repeat_snackbar, task.getTitle(), dueDateString);
-
- Snackbar snackbar = Snackbar.make(view, snackbarText, Snackbar.LENGTH_LONG)
- .setActionTextColor(activity.getResources().getColor(R.color.snackbar_text_color))
+ taskListFragment.makeSnackbar(snackbarText)
.setAction(R.string.DLG_undo, new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -82,9 +81,8 @@ public class RepeatConfirmationReceiver extends BroadcastReceiver {
task.setCompletionDate(0L);
taskService.save(task);
}
- });
- snackbar.getView().setBackgroundColor(activity.getResources().getColor(R.color.snackbar_background));
- snackbar.show();
+ })
+ .show();
}
private String getRelativeDateAndTimeString(Context context, long date) {
diff --git a/src/main/java/org/tasks/scheduling/BackgroundScheduler.java b/src/main/java/org/tasks/scheduling/BackgroundScheduler.java
index d4ce1dbb8..987a0c383 100644
--- a/src/main/java/org/tasks/scheduling/BackgroundScheduler.java
+++ b/src/main/java/org/tasks/scheduling/BackgroundScheduler.java
@@ -3,7 +3,6 @@ package org.tasks.scheduling;
import android.content.Context;
import android.content.Intent;
-import org.tasks.R;
import org.tasks.injection.ForApplication;
import javax.inject.Inject;
@@ -22,9 +21,6 @@ public class BackgroundScheduler {
scheduleBackupService();
scheduleMidnightRefresh();
scheduleCalendarNotifications();
- if (context.getResources().getBoolean(R.bool.sync_supported)) {
- scheduleGtaskSync();
- }
}
public void scheduleBackupService() {
@@ -35,10 +31,6 @@ public class BackgroundScheduler {
context.startService(new Intent(context, RefreshSchedulerIntentService.class));
}
- public void scheduleGtaskSync() {
- context.startService(new Intent(context, GtasksBackgroundService.class));
- }
-
public void scheduleCalendarNotifications() {
context.startService(new Intent(context, CalendarNotificationIntentService.class));
}
diff --git a/src/main/java/org/tasks/sync/IndeterminateProgressBarSyncResultCallback.java b/src/main/java/org/tasks/sync/IndeterminateProgressBarSyncResultCallback.java
deleted file mode 100644
index 0d515b954..000000000
--- a/src/main/java/org/tasks/sync/IndeterminateProgressBarSyncResultCallback.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.tasks.sync;
-
-import com.todoroo.astrid.activity.TaskListFragment;
-import com.todoroo.astrid.gtasks.GtasksPreferenceService;
-
-import org.tasks.Broadcaster;
-
-public class IndeterminateProgressBarSyncResultCallback extends RecordSyncStatusCallback {
-
- private final TaskListFragment taskListFragment;
- private final GtasksPreferenceService gtasksPreferenceService;
-
- public IndeterminateProgressBarSyncResultCallback(TaskListFragment taskListFragment, GtasksPreferenceService gtasksPreferenceService, Broadcaster broadcaster) {
- super(gtasksPreferenceService, broadcaster);
- this.taskListFragment = taskListFragment;
- this.gtasksPreferenceService = gtasksPreferenceService;
- }
-
- @Override
- public void started() {
- super.started();
-
- taskListFragment.setSyncOngoing(gtasksPreferenceService.isOngoing());
- }
-
- @Override
- public void finished() {
- super.finished();
-
- taskListFragment.setSyncOngoing(gtasksPreferenceService.isOngoing());
- }
-}
diff --git a/src/main/java/org/tasks/sync/RecordSyncStatusCallback.java b/src/main/java/org/tasks/sync/RecordSyncStatusCallback.java
index 2dd28e7a0..266df4e15 100644
--- a/src/main/java/org/tasks/sync/RecordSyncStatusCallback.java
+++ b/src/main/java/org/tasks/sync/RecordSyncStatusCallback.java
@@ -18,6 +18,7 @@ public class RecordSyncStatusCallback implements SyncResultCallback {
@Override
public void started() {
gtasksPreferenceService.recordSyncStart();
+ broadcaster.refresh();
}
@Override
diff --git a/src/main/java/org/tasks/sync/SyncExecutor.java b/src/main/java/org/tasks/sync/SyncExecutor.java
index 2dfe8e244..7f5776b86 100644
--- a/src/main/java/org/tasks/sync/SyncExecutor.java
+++ b/src/main/java/org/tasks/sync/SyncExecutor.java
@@ -9,11 +9,13 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import javax.inject.Inject;
+import javax.inject.Singleton;
import timber.log.Timber;
import static java.util.concurrent.Executors.newSingleThreadExecutor;
+@Singleton
public class SyncExecutor {
private final ExecutorService executor = newSingleThreadExecutor(
diff --git a/src/main/java/org/tasks/sync/SyncThrottle.java b/src/main/java/org/tasks/sync/SyncThrottle.java
deleted file mode 100644
index 949ac1a40..000000000
--- a/src/main/java/org/tasks/sync/SyncThrottle.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package org.tasks.sync;
-
-import org.tasks.time.DateTime;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-@Singleton
-public class SyncThrottle {
-
- private final Map lastSync = new HashMap<>();
-
- @Inject
- public SyncThrottle() {
- }
-
- public synchronized boolean canSync(long listId) {
- DateTime now = new DateTime();
- DateTime last = lastSync.get(listId);
- lastSync.put(listId, now);
- return last == null || last.isBefore(now.minusMinutes(10));
- }
-}
diff --git a/src/main/res/values-ar/strings.xml b/src/main/res/values-ar/strings.xml
index 3a9517edf..d56a8f680 100644
--- a/src/main/res/values-ar/strings.xml
+++ b/src/main/res/values-ar/strings.xml
@@ -185,16 +185,12 @@
عشوائياً
اختر تاريخ و وقت
أختر الموقع
-
- - تعطيل
- - كل 15 دقيقة
- - كل ثلاثين دقيقة
- - كل ساعة
- - كل ثلاث ساعات
- - كل ست ساعات
- - كل 12 ساعة
- - كل يوم
- - كل ثلاث أيام
- - كل أسبوع
-
+ تعطيل
+ كل ساعة
+ كل ثلاث ساعات
+ كل ست ساعات
+ كل 12 ساعة
+ كل يوم
+ كل ثلاث أيام
+ كل أسبوع
\ No newline at end of file
diff --git a/src/main/res/values-bg-rBG/strings.xml b/src/main/res/values-bg-rBG/strings.xml
index 7fcd8b3e8..c6e501da0 100644
--- a/src/main/res/values-bg-rBG/strings.xml
+++ b/src/main/res/values-bg-rBG/strings.xml
@@ -414,16 +414,12 @@
Светла
Тъмна
По подразбиране
-
- - изключено
- - на всеки 15 минути
- - на всеки 30 минути
- - на всеки час
- - на всеки три часа
- - на всеки шест часа
- - на всеки дванадесет часа
- - всеки ден
- - на всеки три дена
- - всяка седмица
-
+ изключено
+ на всеки час
+ на всеки три часа
+ на всеки шест часа
+ на всеки дванадесет часа
+ всеки ден
+ на всеки три дена
+ всяка седмица
\ No newline at end of file
diff --git a/src/main/res/values-ca/strings.xml b/src/main/res/values-ca/strings.xml
index e5cc56196..a742d8ff3 100644
--- a/src/main/res/values-ca/strings.xml
+++ b/src/main/res/values-ca/strings.xml
@@ -145,16 +145,12 @@
Surt
Esborra tota la informació de sincronització
Tancar sessió / esborra la informació de sincronització?
-
- - desactivat
- - cada quince minuts
- - cada trenta minuts
- - cada hora
- - cada tres hores
- - cada sis hores
- - cada dotze hores
- - diàriament
- - cada tres dies
- - setmanalment
-
+ desactivat
+ cada hora
+ cada tres hores
+ cada sis hores
+ cada dotze hores
+ diàriament
+ cada tres dies
+ setmanalment
\ No newline at end of file
diff --git a/src/main/res/values-cs/strings.xml b/src/main/res/values-cs/strings.xml
index b7d6467f6..939ca21ef 100644
--- a/src/main/res/values-cs/strings.xml
+++ b/src/main/res/values-cs/strings.xml
@@ -249,16 +249,12 @@
Výchozí
Nízká
Priorita oznámení
-
- - zakázat
- - každých patnáct minut
- - každých třicet minut
- - každou hodinu
- - každé tři hodiny
- - každých šest hodin
- - každých dvanáct hodin
- - každý den
- - každé tři dny
- - každý týden
-
+ zakázat
+ každou hodinu
+ každé tři hodiny
+ každých šest hodin
+ každých dvanáct hodin
+ každý den
+ každé tři dny
+ každý týden
\ No newline at end of file
diff --git a/src/main/res/values-da/strings.xml b/src/main/res/values-da/strings.xml
index 1f4ffe9b8..7fc1f81c6 100644
--- a/src/main/res/values-da/strings.xml
+++ b/src/main/res/values-da/strings.xml
@@ -132,16 +132,11 @@
Baggrunds Synk
Log af
Sletter al synkroniserings data
-
- - disable
- - every fifteen minutes
- - every thirty minutes
- - hver time
- - hver 3. time
- - hver 6. time
- - hver 12. time
- - hver dag
- - hver 3. dag
- - hver uge
-
+ hver time
+ hver 3. time
+ hver 6. time
+ hver 12. time
+ hver dag
+ hver 3. dag
+ hver uge
\ No newline at end of file
diff --git a/src/main/res/values-de/strings.xml b/src/main/res/values-de/strings.xml
index 054ec0139..d849bdbc2 100644
--- a/src/main/res/values-de/strings.xml
+++ b/src/main/res/values-de/strings.xml
@@ -398,16 +398,12 @@
Hell
Dunkel
Standard
-
- - deaktivieren
- - alle 15 Minuten
- - alle 30 Minuten
- - stündlich
- - alle 3 Stunden
- - alle 6 Stunden
- - alle 12 Stunden
- - täglich
- - jeden dritten Tag
- - wöchentlich
-
+ deaktivieren
+ stündlich
+ alle 3 Stunden
+ alle 6 Stunden
+ alle 12 Stunden
+ täglich
+ jeden dritten Tag
+ wöchentlich
\ No newline at end of file
diff --git a/src/main/res/values-el/strings.xml b/src/main/res/values-el/strings.xml
index 83a40ec05..35f3c332f 100644
--- a/src/main/res/values-el/strings.xml
+++ b/src/main/res/values-el/strings.xml
@@ -238,16 +238,11 @@
Συγχρονισμός παρασκηνίου
Αποσύνδεση
Δωρίστε
-
- - disable
- - every fifteen minutes
- - κάθε τριάντα λεπτά
- - κάθε ώρα
- - κάθε τρεις ώρες
- - κάθε έξι ώρες
- - κάθε δώδεκα ώρες
- - κάθε μέρα
- - κάθε τρεις ημέρες
- - κάθε εβδομάδα
-
+ κάθε ώρα
+ κάθε τρεις ώρες
+ κάθε έξι ώρες
+ κάθε δώδεκα ώρες
+ κάθε μέρα
+ κάθε τρεις ημέρες
+ κάθε εβδομάδα
\ No newline at end of file
diff --git a/src/main/res/values-es/strings.xml b/src/main/res/values-es/strings.xml
index d157c8535..097278c47 100644
--- a/src/main/res/values-es/strings.xml
+++ b/src/main/res/values-es/strings.xml
@@ -408,16 +408,12 @@
Claro
Oscuro
Predeterminado
-
- - deshabilitar
- - cada quince minutos
- - cada treinta minutos
- - cada hora
- - cada tres horas
- - cada seis horas
- - cada doce horas
- - cada día
- - cada tres días
- - cada semana
-
+ deshabilitar
+ cada hora
+ cada tres horas
+ cada seis horas
+ cada doce horas
+ cada día
+ cada tres días
+ cada semana
\ No newline at end of file
diff --git a/src/main/res/values-fa/strings.xml b/src/main/res/values-fa/strings.xml
index ca3268596..71f10bd21 100644
--- a/src/main/res/values-fa/strings.xml
+++ b/src/main/res/values-fa/strings.xml
@@ -272,16 +272,12 @@
خاموش کردن چراغ اعلان
(بدون عنوان)
لیست پیش فرض
-
- - غیرفعال
- - هر پانزده دقیقه
- - هر سی دقیقه
- - هر ساعت
- - هر سه ساعت
- - هر شش ساعت
- - هر دوازده ساعت
- - هر روز
- - هر سه روز
- - هر هفته
-
+ غیرفعال
+ هر ساعت
+ هر سه ساعت
+ هر شش ساعت
+ هر دوازده ساعت
+ هر روز
+ هر سه روز
+ هر هفته
\ No newline at end of file
diff --git a/src/main/res/values-fr/strings.xml b/src/main/res/values-fr/strings.xml
index e240c82ce..8ebba752a 100644
--- a/src/main/res/values-fr/strings.xml
+++ b/src/main/res/values-fr/strings.xml
@@ -369,16 +369,12 @@
Sélectionner le filtre
Filtre
Transparence
-
- - désactiver
- - toutes les quinze minutes
- - toutes les trente minutes
- - toutes les heures
- - toutes les trois heures
- - toutes les six heures
- - toutes les douze heures
- - tous les jours
- - tous les trois jours
- - toutes les semaines
-
+ désactiver
+ toutes les heures
+ toutes les trois heures
+ toutes les six heures
+ toutes les douze heures
+ tous les jours
+ tous les trois jours
+ toutes les semaines
\ No newline at end of file
diff --git a/src/main/res/values-it/strings.xml b/src/main/res/values-it/strings.xml
index c803ca830..ab4a6e579 100644
--- a/src/main/res/values-it/strings.xml
+++ b/src/main/res/values-it/strings.xml
@@ -411,16 +411,12 @@ Se visualizzi questo errore più volte, ti consigliamo di cancellare tutti i dat
Chiaro
Scuro
Predefinito
-
- - disabilita
- - ogni quindici minuti
- - ogni trenta minuti
- - ogni ora
- - ogni tre ore
- - ogni sei ore
- - ogni dodici ore
- - ogni giorno
- - ogni tre giorni
- - Ogni settimana
-
+ disabilita
+ ogni ora
+ ogni tre ore
+ ogni sei ore
+ ogni dodici ore
+ ogni giorno
+ ogni tre giorni
+ Ogni settimana
\ No newline at end of file
diff --git a/src/main/res/values-iw/strings.xml b/src/main/res/values-iw/strings.xml
index 7340ea9ec..bd243594c 100644
--- a/src/main/res/values-iw/strings.xml
+++ b/src/main/res/values-iw/strings.xml
@@ -406,16 +406,12 @@
אפור
כחול אפור
שחור
-
- - מִנְעִי
- - כל רבע שעה
- - כל חצי שעה
- - כל שעה
- - כל שלוש שעות
- - כל שש שעות
- - כל שתים עשרה שעות
- - כל יום
- - כל שלושה ימים
- - כל שבוע
-
+ מִנְעִי
+ כל שעה
+ כל שלוש שעות
+ כל שש שעות
+ כל שתים עשרה שעות
+ כל יום
+ כל שלושה ימים
+ כל שבוע
\ No newline at end of file
diff --git a/src/main/res/values-ja/strings.xml b/src/main/res/values-ja/strings.xml
index f51f0046b..14207fb9a 100644
--- a/src/main/res/values-ja/strings.xml
+++ b/src/main/res/values-ja/strings.xml
@@ -414,16 +414,12 @@
ライト
ダーク
デフォルト
-
- - 無効
- - 15分毎
- - 30分毎
- - 1時間毎
- - 3時間毎
- - 6時間毎
- - 12時間毎
- - 毎日
- - 3日に一度
- - 毎週
-
+ 無効
+ 1時間毎
+ 3時間毎
+ 6時間毎
+ 12時間毎
+ 毎日
+ 3日に一度
+ 毎週
\ No newline at end of file
diff --git a/src/main/res/values-ko/strings.xml b/src/main/res/values-ko/strings.xml
index 2350d0da9..31ecd28a1 100644
--- a/src/main/res/values-ko/strings.xml
+++ b/src/main/res/values-ko/strings.xml
@@ -409,16 +409,12 @@ Tasks의 백업에서 당신의 일정을 복구하시기 바랍니다.
회색
회청색
검정
-
- - 사용안함
- - 15분마다
- - 30분마다
- - 매시간
- - 3시간마다
- - 6시간마다
- - 12시간마다
- - 매일
- - 3일마다
- - 일주일마다
-
+ 사용안함
+ 매시간
+ 3시간마다
+ 6시간마다
+ 12시간마다
+ 매일
+ 3일마다
+ 일주일마다
\ No newline at end of file
diff --git a/src/main/res/values-nb/strings.xml b/src/main/res/values-nb/strings.xml
index 07d1b52be..a33b44376 100644
--- a/src/main/res/values-nb/strings.xml
+++ b/src/main/res/values-nb/strings.xml
@@ -124,16 +124,12 @@
Logg ut
Sletter all synkroniseringsdata
Logg ut / slett synkroniseringsdata?
-
- - deaktiver
- - hvert kvarter
- - hver halvtime
- - hver time
- - hver tredje time
- - hver sjette time
- - hver tolvte time
- - daglig
- - hver tredje dag
- - hver uke
-
+ deaktiver
+ hver time
+ hver tredje time
+ hver sjette time
+ hver tolvte time
+ daglig
+ hver tredje dag
+ hver uke
\ No newline at end of file
diff --git a/src/main/res/values-nl/strings.xml b/src/main/res/values-nl/strings.xml
index 9edff064e..e515a34f9 100644
--- a/src/main/res/values-nl/strings.xml
+++ b/src/main/res/values-nl/strings.xml
@@ -382,16 +382,12 @@
Grijs
Blauwgrijs
Zwart
-
- - uitschakelen
- - elke 15 min.
- - elke 30 min.
- - elk uur
- - elke 3 uur
- - elke 6 uur
- - elke 12 uur
- - elke dag
- - elke 3 dagen
- - elke week
-
+ uitschakelen
+ elk uur
+ elke 3 uur
+ elke 6 uur
+ elke 12 uur
+ elke dag
+ elke 3 dagen
+ elke week
\ No newline at end of file
diff --git a/src/main/res/values-pl/strings.xml b/src/main/res/values-pl/strings.xml
index 2ea285285..a16fcd639 100644
--- a/src/main/res/values-pl/strings.xml
+++ b/src/main/res/values-pl/strings.xml
@@ -276,16 +276,12 @@ i odzyskanie zadań z kopi zapasowej (Settings->Sync and backup->Backup-&g
Android będzie pozwalał na ograniczone przerwania kiedy urządzenie jest w trybie drzemki.
Tasks jest projektem na licencji open source utrzymywanym przez jednego developera. Płatne funkcje wspierają rozwój aplikacji.
Przezroczystość
-
- - Wyłączone
- - co 15 minut
- - co 30 minut
- - co godzinę
- - co 3 godziny
- - co 6 godzin
- - co 12 godzin
- - raz dziennie
- - co 3 dni
- - co tydzień
-
+ Wyłączone
+ co godzinę
+ co 3 godziny
+ co 6 godzin
+ co 12 godzin
+ raz dziennie
+ co 3 dni
+ co tydzień
\ No newline at end of file
diff --git a/src/main/res/values-pt-rBR/strings.xml b/src/main/res/values-pt-rBR/strings.xml
index a8165d062..f73339de0 100644
--- a/src/main/res/values-pt-rBR/strings.xml
+++ b/src/main/res/values-pt-rBR/strings.xml
@@ -336,16 +336,12 @@
Azul Acinzentado
Claro
Escuro
-
- - desabilitar
- - a cada quinze minutos
- - a cada trinta minutos
- - a cada hora
- - a cada três horas
- - a cada seis horas
- - a cada doze horas
- - diariamente
- - a cada três dias
- - semanalmente
-
+ desabilitar
+ a cada hora
+ a cada três horas
+ a cada seis horas
+ a cada doze horas
+ diariamente
+ a cada três dias
+ semanalmente
\ No newline at end of file
diff --git a/src/main/res/values-pt/strings.xml b/src/main/res/values-pt/strings.xml
index b8127a115..b5ada0f75 100644
--- a/src/main/res/values-pt/strings.xml
+++ b/src/main/res/values-pt/strings.xml
@@ -328,16 +328,12 @@ das tarefas através de um backup em Definições->Sincronização e backup-&
Mostrar terminadas
Reverter
%s tarefas
-
- - desativar
- - cada 15 minutos
- - cada 30 minutos
- - cada hora
- - cada 3 horas
- - cada 6 horas
- - cada 12 horas
- - todos os dias
- - cada 3 dias
- - todas as semanas
-
+ desativar
+ cada hora
+ cada 3 horas
+ cada 6 horas
+ cada 12 horas
+ todos os dias
+ cada 3 dias
+ todas as semanas
\ No newline at end of file
diff --git a/src/main/res/values-ru/strings.xml b/src/main/res/values-ru/strings.xml
index 69c1bca01..4e352083b 100644
--- a/src/main/res/values-ru/strings.xml
+++ b/src/main/res/values-ru/strings.xml
@@ -413,16 +413,12 @@
Светлая
Темная
По умолчанию
-
- - отключить
- - каждые 15 минут
- - каждые 30 минут
- - каждый час
- - каждые 3 часа
- - каждые 6 часов
- - каждые 12 часов
- - каждый день
- - каждые 3 дня
- - каждую неделю
-
+ отключить
+ каждый час
+ каждые 3 часа
+ каждые 6 часов
+ каждые 12 часов
+ каждый день
+ каждые 3 дня
+ каждую неделю
\ No newline at end of file
diff --git a/src/main/res/values-sk/strings.xml b/src/main/res/values-sk/strings.xml
index f2742c2de..0fa7d135c 100644
--- a/src/main/res/values-sk/strings.xml
+++ b/src/main/res/values-sk/strings.xml
@@ -308,16 +308,12 @@
Zobraziť skryté
Zobraziť dokončené
%s úlohy
-
- - zakázať
- - každých pätnásť minút
- - každú tretiu minútu
- - každú hodinu
- - každé tri hodiny
- - každých šesť hodín
- - každých dvanásť hodín
- - každý deň
- - každý tretí deň
- - každý týždeň
-
+ zakázať
+ každú hodinu
+ každé tri hodiny
+ každých šesť hodín
+ každých dvanásť hodín
+ každý deň
+ každý tretí deň
+ každý týždeň
\ No newline at end of file
diff --git a/src/main/res/values-sl-rSI/strings.xml b/src/main/res/values-sl-rSI/strings.xml
index d3a748b0a..6f1556b0c 100644
--- a/src/main/res/values-sl-rSI/strings.xml
+++ b/src/main/res/values-sl-rSI/strings.xml
@@ -247,16 +247,12 @@
Zbriše vse usklajene podatke
Odjava/brisanje usklajenih podatkov?
Donirajte
-
- - onemogoči
- - vsakih 15 minut
- - vsakih 30 minut
- - vsako uro
- - vsake 3 ure
- - vsakih 6 ur
- - vsakih 12 ur
- - vsak dan
- - vsake 3 dni
- - vsak teden
-
+ onemogoči
+ vsako uro
+ vsake 3 ure
+ vsakih 6 ur
+ vsakih 12 ur
+ vsak dan
+ vsake 3 dni
+ vsak teden
\ No newline at end of file
diff --git a/src/main/res/values-sv/strings.xml b/src/main/res/values-sv/strings.xml
index 58e4bebff..a16e2f4de 100644
--- a/src/main/res/values-sv/strings.xml
+++ b/src/main/res/values-sv/strings.xml
@@ -402,16 +402,12 @@ och återställer dina aktuella uppgifter från en backup
Grå
Blågrå
Svart
-
- - inaktivera
- - varje kvartstimme
- - varje halvtimme
- - varje timme
- - var tredje timme
- - var sjätte timme
- - var tolfte timme
- - varje dag
- - var tredje dag
- - varje vecka
-
+ inaktivera
+ varje timme
+ var tredje timme
+ var sjätte timme
+ var tolfte timme
+ varje dag
+ var tredje dag
+ varje vecka
\ No newline at end of file
diff --git a/src/main/res/values-tr/strings.xml b/src/main/res/values-tr/strings.xml
index 16eb40a85..955b64083 100644
--- a/src/main/res/values-tr/strings.xml
+++ b/src/main/res/values-tr/strings.xml
@@ -215,16 +215,12 @@
Çıkış Yap
Bütün eşleme verilerini temizle
Çıkış Yap / Senkron verisini sil?
-
- - devre dışı bırak
- - her 15 dakika
- - her 30 dakika
- - her saat
- - her 3 saat
- - her 6 saat
- - her 12 saat
- - hergün
- - her 3 gün
- - her hafta
-
+ devre dışı bırak
+ her saat
+ her 3 saat
+ her 6 saat
+ her 12 saat
+ hergün
+ her 3 gün
+ her hafta
\ No newline at end of file
diff --git a/src/main/res/values-uk/strings.xml b/src/main/res/values-uk/strings.xml
index b0fbc4184..d1fb3e8c4 100644
--- a/src/main/res/values-uk/strings.xml
+++ b/src/main/res/values-uk/strings.xml
@@ -277,16 +277,12 @@
Переривати режим \"Doze\" для повідомленнь
Андроїд зазвичай буде значно відкладати повідомлення коли пристрій в режимі \"Doze\"
Android дозволить деякі переривання в режимі \"Doze\"
-
- - вимкнути
- - що 15 хвилин
- - що 30 хвилин
- - кожну годину
- - кожних 3 години
- - кожних 6 годин
- - кожних 12 годин
- - щодня
- - кожного 3-го дня
- - кожного тижня
-
+ вимкнути
+ кожну годину
+ кожних 3 години
+ кожних 6 годин
+ кожних 12 годин
+ щодня
+ кожного 3-го дня
+ кожного тижня
\ No newline at end of file
diff --git a/src/main/res/values-zh-rCN/strings.xml b/src/main/res/values-zh-rCN/strings.xml
index 323bf420c..23e84035f 100644
--- a/src/main/res/values-zh-rCN/strings.xml
+++ b/src/main/res/values-zh-rCN/strings.xml
@@ -207,16 +207,12 @@
登出
清除所有同步资料
登出/清除同步资料?
-
- - 停用
- - 每15分钟
- - 每30分钟
- - 每小时
- - 每3小时
- - 每6小时
- - 每12小时
- - 每天
- - 每3天
- - 每周
-
+ 停用
+ 每小时
+ 每3小时
+ 每6小时
+ 每12小时
+ 每天
+ 每3天
+ 每周
\ No newline at end of file
diff --git a/src/main/res/values-zh-rTW/strings.xml b/src/main/res/values-zh-rTW/strings.xml
index efb0f4716..4b3772afe 100644
--- a/src/main/res/values-zh-rTW/strings.xml
+++ b/src/main/res/values-zh-rTW/strings.xml
@@ -233,16 +233,12 @@
最優先
預設
最不急迫
-
- - 停用
- - 每15分鐘
- - 每30分鐘
- - 每小時
- - 每3小時
- - 每6小時
- - 每12小時
- - 每天
- - 每3天
- - 每週
-
+ 停用
+ 每小時
+ 每3小時
+ 每6小時
+ 每12小時
+ 每天
+ 每3天
+ 每週
\ No newline at end of file
diff --git a/src/main/res/values/arrays.xml b/src/main/res/values/arrays.xml
index 1dbefc895..9521ed9a1 100644
--- a/src/main/res/values/arrays.xml
+++ b/src/main/res/values/arrays.xml
@@ -40,6 +40,18 @@
- 600
+
+
+ - @string/sync_interval_disable
+ - @string/sync_interval_one_hour
+ - @string/sync_interval_three_hours
+ - @string/sync_interval_six_hours
+ - @string/sync_interval_twelve_hours
+ - @string/sync_interval_one_day
+ - @string/sync_interval_three_days
+ - @string/sync_interval_one_week
+
+
- @string/due_date
- @string/due_time
diff --git a/src/main/res/values/bools.xml b/src/main/res/values/bools.xml
index d9688a3d4..de02aba1a 100644
--- a/src/main/res/values/bools.xml
+++ b/src/main/res/values/bools.xml
@@ -1,7 +1,6 @@
false
- false
false
false
\ No newline at end of file
diff --git a/src/main/res/values/keys.xml b/src/main/res/values/keys.xml
index a63e90ae9..779a3282b 100644
--- a/src/main/res/values/keys.xml
+++ b/src/main/res/values/keys.xml
@@ -178,8 +178,6 @@
- 0
- - 900
- - 1800
- 3600
- 10800
- 21600
@@ -306,5 +304,6 @@
theme_color
theme_accent
default_gtasks_list
+ sync_warning_shown
diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml
index 04b006194..05cbedae7 100644
--- a/src/main/res/values/strings.xml
+++ b/src/main/res/values/strings.xml
@@ -894,18 +894,14 @@ File %1$s contained %2$s.\n\n
Dark
Default
-
-
- - disable
- - every fifteen minutes
- - every thirty minutes
- - every hour
- - every three hours
- - every six hours
- - every twelve hours
- - every day
- - every three days
- - every week
-
+ disable
+ every hour
+ every three hours
+ every six hours
+ every twelve hours
+ every day
+ every three days
+ every week
+ Automatic synchronization is currently disabled by Android
diff --git a/src/main/res/xml/preferences_gtasks.xml b/src/main/res/xml/preferences_gtasks.xml
index 420f12a50..1f824e0ea 100644
--- a/src/main/res/xml/preferences_gtasks.xml
+++ b/src/main/res/xml/preferences_gtasks.xml
@@ -19,9 +19,9 @@
android:title="@string/default_list" />
diff --git a/src/main/res/xml/syncadapter.xml b/src/main/res/xml/syncadapter.xml
new file mode 100644
index 000000000..f1546ce68
--- /dev/null
+++ b/src/main/res/xml/syncadapter.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file