diff --git a/app/schemas/com.todoroo.astrid.dao.Database/55.json b/app/schemas/com.todoroo.astrid.dao.Database/55.json
index aa4af4b18..ff51ec570 100644
--- a/app/schemas/com.todoroo.astrid.dao.Database/55.json
+++ b/app/schemas/com.todoroo.astrid.dao.Database/55.json
@@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 55,
- "identityHash": "298da0475e0b181e5298ea1e05302000",
+ "identityHash": "13c156cbb4c26b323967670f04502f53",
"entities": [
{
"tableName": "notification",
@@ -690,7 +690,7 @@
},
{
"tableName": "caldav_account",
- "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uuid` TEXT, `name` TEXT, `color` INTEGER NOT NULL, `deleted` INTEGER NOT NULL, `ctag` TEXT, `url` TEXT, `username` TEXT)",
+ "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`_id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `uuid` TEXT, `name` TEXT, `color` INTEGER NOT NULL, `ctag` TEXT, `url` TEXT, `username` TEXT)",
"fields": [
{
"fieldPath": "id",
@@ -716,12 +716,6 @@
"affinity": "INTEGER",
"notNull": true
},
- {
- "fieldPath": "deleted",
- "columnName": "deleted",
- "affinity": "INTEGER",
- "notNull": true
- },
{
"fieldPath": "ctag",
"columnName": "ctag",
@@ -809,7 +803,7 @@
],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
- "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"298da0475e0b181e5298ea1e05302000\")"
+ "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, \"13c156cbb4c26b323967670f04502f53\")"
]
}
}
\ No newline at end of file
diff --git a/app/src/amazon/java/org/tasks/gtasks/SyncAdapterHelper.java b/app/src/amazon/java/org/tasks/gtasks/SyncAdapterHelper.java
deleted file mode 100644
index 43af07826..000000000
--- a/app/src/amazon/java/org/tasks/gtasks/SyncAdapterHelper.java
+++ /dev/null
@@ -1,32 +0,0 @@
-package org.tasks.gtasks;
-
-import com.todoroo.astrid.activity.TaskListFragment;
-
-import javax.inject.Inject;
-
-public class SyncAdapterHelper {
- @Inject
- public SyncAdapterHelper() {
-
- }
-
- public boolean shouldShowBackgroundSyncWarning() {
- return false;
- }
-
- public void checkPlayServices(TaskListFragment taskListFragment) {
-
- }
-
- public boolean initiateManualSync() {
- return false;
- }
-
- public boolean isEnabled() {
- return false;
- }
-
- public void requestSynchronization() {
-
- }
-}
diff --git a/app/src/amazon/java/org/tasks/injection/ActivityComponent.java b/app/src/amazon/java/org/tasks/injection/ActivityComponent.java
index 5422257a0..f2b3af3e9 100644
--- a/app/src/amazon/java/org/tasks/injection/ActivityComponent.java
+++ b/app/src/amazon/java/org/tasks/injection/ActivityComponent.java
@@ -21,6 +21,7 @@ import org.tasks.activities.FilterSettingsActivity;
import org.tasks.activities.GoogleTaskListSettingsActivity;
import org.tasks.activities.TagSettingsActivity;
import org.tasks.activities.TimePickerActivity;
+import org.tasks.caldav.CalDAVSettingsActivity;
import org.tasks.dashclock.DashClockSettings;
import org.tasks.files.FileExplore;
import org.tasks.files.MyFilePickerActivity;
@@ -123,6 +124,8 @@ public interface ActivityComponent {
void inject(GoogleTaskListSettingsActivity googleTaskListSettingsActivity);
+ void inject(CalDAVSettingsActivity calDAVSettingsActivity);
+
void inject(TaskerCreateTaskActivity taskerCreateTaskActivity);
void inject(TaskListViewModel viewModel);
diff --git a/app/src/amazon/java/org/tasks/injection/DialogFragmentComponent.java b/app/src/amazon/java/org/tasks/injection/DialogFragmentComponent.java
index e1c2cd1ec..a321480ae 100644
--- a/app/src/amazon/java/org/tasks/injection/DialogFragmentComponent.java
+++ b/app/src/amazon/java/org/tasks/injection/DialogFragmentComponent.java
@@ -2,6 +2,8 @@ package org.tasks.injection;
import org.tasks.activities.CalendarSelectionDialog;
import org.tasks.activities.RemoteListSupportPicker;
+import org.tasks.caldav.DeleteAccountDialog;
+import org.tasks.caldav.RenameAccountDialog;
import org.tasks.dialogs.AddAttachmentDialog;
import org.tasks.dialogs.ColorPickerDialog;
import org.tasks.dialogs.RecordAudioDialog;
@@ -34,4 +36,8 @@ public interface DialogFragmentComponent {
void inject(CustomRecurrenceDialog customRecurrenceDialog);
void inject(RemoteListSupportPicker remoteListSupportPicker);
+
+ void inject(DeleteAccountDialog deleteAccountDialog);
+
+ void inject(RenameAccountDialog renameAccountDialog);
}
diff --git a/app/src/amazon/java/org/tasks/sync/SyncAdapters.java b/app/src/amazon/java/org/tasks/sync/SyncAdapters.java
new file mode 100644
index 000000000..9f9ec03eb
--- /dev/null
+++ b/app/src/amazon/java/org/tasks/sync/SyncAdapters.java
@@ -0,0 +1,42 @@
+package org.tasks.sync;
+
+import android.content.ContentResolver;
+
+import com.todoroo.astrid.activity.TaskListFragment;
+
+import org.tasks.caldav.CaldavAccountManager;
+
+import javax.inject.Inject;
+
+public class SyncAdapters {
+ private CaldavAccountManager caldavAccountManager;
+
+ @Inject
+ public SyncAdapters(CaldavAccountManager caldavAccountManager) {
+ this.caldavAccountManager = caldavAccountManager;
+ }
+
+ public boolean initiateManualSync() {
+ return caldavAccountManager.initiateManualSync();
+ }
+
+ public void requestSynchronization() {
+ caldavAccountManager.requestSynchronization();
+ }
+
+ public boolean isGoogleTaskSyncEnabled() {
+ return false;
+ }
+
+ public void checkPlayServices(TaskListFragment taskListFragment) {
+
+ }
+
+ public boolean isMasterSyncEnabled() {
+ return ContentResolver.getMasterSyncAutomatically();
+ }
+
+ public boolean isSyncEnabled() {
+ return caldavAccountManager.getAccounts().size() > 0;
+ }
+}
diff --git a/app/src/generic/java/org/tasks/injection/ActivityComponent.java b/app/src/generic/java/org/tasks/injection/ActivityComponent.java
index 5422257a0..f2b3af3e9 100644
--- a/app/src/generic/java/org/tasks/injection/ActivityComponent.java
+++ b/app/src/generic/java/org/tasks/injection/ActivityComponent.java
@@ -21,6 +21,7 @@ import org.tasks.activities.FilterSettingsActivity;
import org.tasks.activities.GoogleTaskListSettingsActivity;
import org.tasks.activities.TagSettingsActivity;
import org.tasks.activities.TimePickerActivity;
+import org.tasks.caldav.CalDAVSettingsActivity;
import org.tasks.dashclock.DashClockSettings;
import org.tasks.files.FileExplore;
import org.tasks.files.MyFilePickerActivity;
@@ -123,6 +124,8 @@ public interface ActivityComponent {
void inject(GoogleTaskListSettingsActivity googleTaskListSettingsActivity);
+ void inject(CalDAVSettingsActivity calDAVSettingsActivity);
+
void inject(TaskerCreateTaskActivity taskerCreateTaskActivity);
void inject(TaskListViewModel viewModel);
diff --git a/app/src/generic/java/org/tasks/injection/DialogFragmentComponent.java b/app/src/generic/java/org/tasks/injection/DialogFragmentComponent.java
index e1c2cd1ec..a321480ae 100644
--- a/app/src/generic/java/org/tasks/injection/DialogFragmentComponent.java
+++ b/app/src/generic/java/org/tasks/injection/DialogFragmentComponent.java
@@ -2,6 +2,8 @@ package org.tasks.injection;
import org.tasks.activities.CalendarSelectionDialog;
import org.tasks.activities.RemoteListSupportPicker;
+import org.tasks.caldav.DeleteAccountDialog;
+import org.tasks.caldav.RenameAccountDialog;
import org.tasks.dialogs.AddAttachmentDialog;
import org.tasks.dialogs.ColorPickerDialog;
import org.tasks.dialogs.RecordAudioDialog;
@@ -34,4 +36,8 @@ public interface DialogFragmentComponent {
void inject(CustomRecurrenceDialog customRecurrenceDialog);
void inject(RemoteListSupportPicker remoteListSupportPicker);
+
+ void inject(DeleteAccountDialog deleteAccountDialog);
+
+ void inject(RenameAccountDialog renameAccountDialog);
}
diff --git a/app/src/generic/java/org/tasks/sync/SyncAdapters.java b/app/src/generic/java/org/tasks/sync/SyncAdapters.java
new file mode 100644
index 000000000..9f9ec03eb
--- /dev/null
+++ b/app/src/generic/java/org/tasks/sync/SyncAdapters.java
@@ -0,0 +1,42 @@
+package org.tasks.sync;
+
+import android.content.ContentResolver;
+
+import com.todoroo.astrid.activity.TaskListFragment;
+
+import org.tasks.caldav.CaldavAccountManager;
+
+import javax.inject.Inject;
+
+public class SyncAdapters {
+ private CaldavAccountManager caldavAccountManager;
+
+ @Inject
+ public SyncAdapters(CaldavAccountManager caldavAccountManager) {
+ this.caldavAccountManager = caldavAccountManager;
+ }
+
+ public boolean initiateManualSync() {
+ return caldavAccountManager.initiateManualSync();
+ }
+
+ public void requestSynchronization() {
+ caldavAccountManager.requestSynchronization();
+ }
+
+ public boolean isGoogleTaskSyncEnabled() {
+ return false;
+ }
+
+ public void checkPlayServices(TaskListFragment taskListFragment) {
+
+ }
+
+ public boolean isMasterSyncEnabled() {
+ return ContentResolver.getMasterSyncAutomatically();
+ }
+
+ public boolean isSyncEnabled() {
+ return caldavAccountManager.getAccounts().size() > 0;
+ }
+}
diff --git a/app/src/googleplay/AndroidManifest.xml b/app/src/googleplay/AndroidManifest.xml
index 57af1cc1e..ea148cbac 100644
--- a/app/src/googleplay/AndroidManifest.xml
+++ b/app/src/googleplay/AndroidManifest.xml
@@ -16,19 +16,10 @@
-
-
-
-
-
-
-
-
-
@@ -93,7 +84,7 @@
+ android:resource="@xml/sync_adapter_gtask" />
diff --git a/app/src/googleplay/java/org/tasks/injection/ActivityComponent.java b/app/src/googleplay/java/org/tasks/injection/ActivityComponent.java
index 7e708b7cf..8656e256c 100644
--- a/app/src/googleplay/java/org/tasks/injection/ActivityComponent.java
+++ b/app/src/googleplay/java/org/tasks/injection/ActivityComponent.java
@@ -25,6 +25,7 @@ import org.tasks.activities.FilterSettingsActivity;
import org.tasks.activities.GoogleTaskListSettingsActivity;
import org.tasks.activities.TagSettingsActivity;
import org.tasks.activities.TimePickerActivity;
+import org.tasks.caldav.CalDAVSettingsActivity;
import org.tasks.dashclock.DashClockSettings;
import org.tasks.files.FileExplore;
import org.tasks.files.MyFilePickerActivity;
@@ -132,6 +133,8 @@ public interface ActivityComponent {
void inject(GoogleTaskListSettingsActivity googleTaskListSettingsActivity);
+ void inject(CalDAVSettingsActivity calDAVSettingsActivity);
+
void inject(TaskerCreateTaskActivity taskerCreateTaskActivity);
void inject(TaskListViewModel taskListViewModel);
diff --git a/app/src/googleplay/java/org/tasks/injection/DialogFragmentComponent.java b/app/src/googleplay/java/org/tasks/injection/DialogFragmentComponent.java
index a6b2da604..0c20f8fd5 100644
--- a/app/src/googleplay/java/org/tasks/injection/DialogFragmentComponent.java
+++ b/app/src/googleplay/java/org/tasks/injection/DialogFragmentComponent.java
@@ -2,6 +2,8 @@ package org.tasks.injection;
import org.tasks.activities.CalendarSelectionDialog;
import org.tasks.activities.RemoteListSupportPicker;
+import org.tasks.caldav.DeleteAccountDialog;
+import org.tasks.caldav.RenameAccountDialog;
import org.tasks.dialogs.AddAttachmentDialog;
import org.tasks.dialogs.ColorPickerDialog;
import org.tasks.dialogs.RecordAudioDialog;
@@ -44,4 +46,8 @@ public interface DialogFragmentComponent {
void inject(RenameListDialog renameListDialog);
void inject(CustomRecurrenceDialog customRecurrenceDialog);
+
+ void inject(DeleteAccountDialog deleteAccountDialog);
+
+ void inject(RenameAccountDialog renameAccountDialog);
}
diff --git a/app/src/googleplay/java/org/tasks/sync/SyncAdapters.java b/app/src/googleplay/java/org/tasks/sync/SyncAdapters.java
new file mode 100644
index 000000000..fb6f62fd7
--- /dev/null
+++ b/app/src/googleplay/java/org/tasks/sync/SyncAdapters.java
@@ -0,0 +1,51 @@
+package org.tasks.sync;
+
+import android.content.ContentResolver;
+
+import com.todoroo.astrid.activity.TaskListFragment;
+
+import org.tasks.caldav.CaldavAccountManager;
+import org.tasks.gtasks.GtaskSyncAdapterHelper;
+
+import javax.inject.Inject;
+
+public class SyncAdapters {
+
+ private final GtaskSyncAdapterHelper gtaskSyncAdapterHelper;
+ private final CaldavAccountManager caldavAccountManager;
+
+ @Inject
+ public SyncAdapters(GtaskSyncAdapterHelper gtaskSyncAdapterHelper, CaldavAccountManager caldavAccountManager) {
+ this.gtaskSyncAdapterHelper = gtaskSyncAdapterHelper;
+ this.caldavAccountManager = caldavAccountManager;
+ }
+
+ public void requestSynchronization() {
+ gtaskSyncAdapterHelper.requestSynchronization();
+ caldavAccountManager.requestSynchronization();
+ }
+
+ public boolean initiateManualSync() {
+ return gtaskSyncAdapterHelper.initiateManualSync() | caldavAccountManager.initiateManualSync();
+ }
+
+ public boolean isMasterSyncEnabled() {
+ return ContentResolver.getMasterSyncAutomatically();
+ }
+
+ public boolean isSyncEnabled() {
+ return isGoogleTaskSyncEnabled() || isCaldavSyncEnabled();
+ }
+
+ public boolean isGoogleTaskSyncEnabled() {
+ return gtaskSyncAdapterHelper.isSyncEnabled();
+ }
+
+ public boolean isCaldavSyncEnabled() {
+ return caldavAccountManager.getAccounts().size() > 0;
+ }
+
+ public void checkPlayServices(TaskListFragment taskListFragment) {
+ gtaskSyncAdapterHelper.checkPlayServices(taskListFragment);
+ }
+}
diff --git a/app/src/main/res/xml/syncadapter.xml b/app/src/googleplay/res/xml/sync_adapter_gtask.xml
similarity index 100%
rename from app/src/main/res/xml/syncadapter.xml
rename to app/src/googleplay/res/xml/sync_adapter_gtask.xml
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index c80ae27f5..6385bec43 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -53,6 +53,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -297,6 +310,8 @@
+
+
@@ -508,6 +523,18 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskListActivity.java b/app/src/main/java/com/todoroo/astrid/activity/TaskListActivity.java
index 6cafe833a..19fe7a21a 100644
--- a/app/src/main/java/com/todoroo/astrid/activity/TaskListActivity.java
+++ b/app/src/main/java/com/todoroo/astrid/activity/TaskListActivity.java
@@ -28,7 +28,6 @@ import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksListService;
import com.todoroo.astrid.gtasks.GtasksSubtaskListFragment;
import com.todoroo.astrid.repeats.RepeatControlSet;
-import com.todoroo.astrid.service.TaskCreator;
import com.todoroo.astrid.subtasks.SubtasksHelper;
import com.todoroo.astrid.subtasks.SubtasksListFragment;
import com.todoroo.astrid.subtasks.SubtasksTagListFragment;
@@ -48,13 +47,13 @@ import org.tasks.data.TagDataDao;
import org.tasks.dialogs.SortDialog;
import org.tasks.fragments.CommentBarFragment;
import org.tasks.gtasks.RemoteListSelectionHandler;
-import org.tasks.gtasks.GtaskSyncAdapterHelper;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingAppCompatActivity;
import org.tasks.intents.TaskIntents;
import org.tasks.preferences.DefaultFilterProvider;
import org.tasks.preferences.Preferences;
import org.tasks.receivers.RepeatConfirmationReceiver;
+import org.tasks.sync.SyncAdapters;
import org.tasks.tasklist.GtasksListFragment;
import org.tasks.tasklist.TagListFragment;
import org.tasks.themes.Theme;
@@ -97,9 +96,8 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
@Inject TagDataDao tagDataDao;
@Inject Theme theme;
@Inject ThemeCache themeCache;
- @Inject GtaskSyncAdapterHelper gtaskSyncAdapterHelper;
+ @Inject SyncAdapters syncAdapters;
@Inject Tracker tracker;
- @Inject TaskCreator taskCreator;
@Inject TaskDao taskDao;
@Inject CaldavDao caldavDao;
@Inject LocalBroadcastManager localBroadcastManager;
@@ -274,7 +272,7 @@ public class TaskListActivity extends InjectingAppCompatActivity implements
localBroadcastManager.registerRepeatReceiver(repeatConfirmationReceiver);
- gtaskSyncAdapterHelper.checkPlayServices(getTaskListFragment());
+ syncAdapters.checkPlayServices(getTaskListFragment());
}
public void restart() {
diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java
index 470cc2d7d..fbce11a8f 100644
--- a/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java
+++ b/app/src/main/java/com/todoroo/astrid/activity/TaskListFragment.java
@@ -50,12 +50,12 @@ import org.tasks.analytics.Tracker;
import org.tasks.analytics.Tracking;
import org.tasks.dialogs.DialogBuilder;
import org.tasks.dialogs.SortDialog;
-import org.tasks.gtasks.GtaskSyncAdapterHelper;
import org.tasks.injection.ForActivity;
import org.tasks.injection.FragmentComponent;
import org.tasks.injection.InjectingFragment;
import org.tasks.preferences.Device;
import org.tasks.preferences.Preferences;
+import org.tasks.sync.SyncAdapters;
import org.tasks.tasklist.TaskListRecyclerAdapter;
import org.tasks.tasklist.ViewHolderFactory;
import org.tasks.ui.CheckBoxes;
@@ -97,7 +97,7 @@ public class TaskListFragment extends InjectingFragment implements
// --- instance variables
- @Inject GtaskSyncAdapterHelper gtaskSyncAdapterHelper;
+ @Inject SyncAdapters syncAdapters;
@Inject TaskDeleter taskDeleter;
@Inject TaskDuplicator taskDuplicator;
@Inject @ForActivity Context context;
@@ -135,7 +135,7 @@ public class TaskListFragment extends InjectingFragment implements
@Override
public void onRefresh() {
- if (!gtaskSyncAdapterHelper.initiateManualSync()) {
+ if (!syncAdapters.initiateManualSync()) {
refresh();
}
}
@@ -477,7 +477,7 @@ public class TaskListFragment extends InjectingFragment implements
for (Task task : tasks) {
onTaskCreated(task.getUuid());
}
- gtaskSyncAdapterHelper.requestSynchronization();
+ syncAdapters.requestSynchronization();
}
public void onTaskCreated(String uuid) {
diff --git a/app/src/main/java/com/todoroo/astrid/adapter/FilterAdapter.java b/app/src/main/java/com/todoroo/astrid/adapter/FilterAdapter.java
index c40bde2ed..196bb5f99 100644
--- a/app/src/main/java/com/todoroo/astrid/adapter/FilterAdapter.java
+++ b/app/src/main/java/com/todoroo/astrid/adapter/FilterAdapter.java
@@ -32,6 +32,7 @@ import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import org.tasks.R;
import org.tasks.activities.GoogleTaskListSettingsActivity;
import org.tasks.activities.TagSettingsActivity;
+import org.tasks.caldav.CalDAVSettingsActivity;
import org.tasks.filters.FilterCounter;
import org.tasks.filters.FilterProvider;
import org.tasks.filters.NavigationDrawerAction;
@@ -319,6 +320,14 @@ public class FilterAdapter extends ArrayAdapter {
addSubMenu(R.string.CalDAV, filterProvider.getCalDAVFilters(), false);
+ if (navigationDrawer) {
+ add(new NavigationDrawerAction(
+ activity.getResources().getString(R.string.add_account),
+ R.drawable.ic_add_24dp,
+ new Intent(activity, CalDAVSettingsActivity.class),
+ NavigationDrawerFragment.REQUEST_NEW_CALDAV_ACCOUNT));
+ }
+
if (navigationDrawer) {
add(new NavigationDrawerSeparator());
diff --git a/app/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java b/app/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java
index f4f14f778..79b6b0756 100644
--- a/app/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java
+++ b/app/src/main/java/com/todoroo/astrid/core/DefaultsPreferences.java
@@ -13,7 +13,6 @@ import android.support.annotation.NonNull;
import com.todoroo.astrid.api.CaldavFilter;
import com.todoroo.astrid.api.Filter;
import com.todoroo.astrid.api.GtasksFilter;
-import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import org.tasks.R;
import org.tasks.activities.CalendarSelectionActivity;
@@ -21,7 +20,6 @@ import org.tasks.analytics.Tracker;
import org.tasks.analytics.Tracking;
import org.tasks.calendars.AndroidCalendar;
import org.tasks.calendars.CalendarProvider;
-import org.tasks.gtasks.GtaskSyncAdapterHelper;
import org.tasks.gtasks.RemoteListSelectionHandler;
import org.tasks.injection.ActivityComponent;
import org.tasks.injection.InjectingPreferenceActivity;
@@ -29,6 +27,7 @@ import org.tasks.preferences.ActivityPermissionRequestor;
import org.tasks.preferences.DefaultFilterProvider;
import org.tasks.preferences.PermissionRequestor;
import org.tasks.preferences.Preferences;
+import org.tasks.sync.SyncAdapters;
import javax.inject.Inject;
@@ -45,8 +44,7 @@ public class DefaultsPreferences extends InjectingPreferenceActivity implements
@Inject CalendarProvider calendarProvider;
@Inject ActivityPermissionRequestor permissionRequester;
@Inject Tracker tracker;
- @Inject GtasksPreferenceService gtasksPreferenceService;
- @Inject GtaskSyncAdapterHelper gtaskSyncAdapterHelper;
+ @Inject SyncAdapters syncAdapters;
@Inject DefaultFilterProvider defaultFilterProvider;
private Preference defaultCalendarPref;
@@ -69,7 +67,7 @@ public class DefaultsPreferences extends InjectingPreferenceActivity implements
? getString(R.string.dont_add_to_calendar)
: defaultCalendarName);
- if (gtaskSyncAdapterHelper.isEnabled()) {
+ if (syncAdapters.isSyncEnabled()) {
findPreference(R.string.p_default_remote_list).setOnPreferenceClickListener(preference -> {
newRemoteListNativePicker(defaultFilterProvider.getDefaultRemoteList())
.show(getFragmentManager(), FRAG_TAG_REMOTE_LIST_SELECTION);
diff --git a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java
index 4f27f85c9..d9f74688b 100644
--- a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java
+++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java
@@ -166,6 +166,9 @@ public abstract class TaskDao {
@android.arch.persistence.room.Query("SELECT tasks.* FROM tasks INNER JOIN google_tasks ON google_tasks.task = tasks._id WHERE google_tasks.list_id = :googleTaskList")
public abstract List getGoogleTasks(String googleTaskList);
+ @android.arch.persistence.room.Query("SELECT tasks.* FROM tasks INNER JOIN caldav_tasks ON caldav_tasks.task = tasks._id WHERE caldav_tasks.account = :caldavAccount")
+ public abstract List getCaldavTasks(String caldavAccount);
+
// --- save
/**
diff --git a/app/src/main/java/org/tasks/caldav/Account.java b/app/src/main/java/org/tasks/caldav/Account.java
new file mode 100644
index 000000000..1a92a511f
--- /dev/null
+++ b/app/src/main/java/org/tasks/caldav/Account.java
@@ -0,0 +1,65 @@
+package org.tasks.caldav;
+
+import android.accounts.AccountManager;
+import android.content.ContentResolver;
+import android.os.Bundle;
+
+import java.util.concurrent.TimeUnit;
+
+public class Account {
+
+ private static final String AUTHORITY = "org.tasks";
+ public static final String EXTRA_UUID = "uuid";
+
+ private AccountManager accountManager;
+ private android.accounts.Account account;
+
+ public Account(AccountManager accountManager, android.accounts.Account account) {
+ this.accountManager = accountManager;
+ this.account = account;
+ }
+
+ public String getName() {
+ return account.name;
+ }
+
+ public String getUuid() {
+ return accountManager.getUserData(account, EXTRA_UUID);
+ }
+
+ String getPassword() {
+ return accountManager.getPassword(account);
+ }
+
+ public android.accounts.Account getAccount() {
+ return account;
+ }
+
+ void setPassword(String password) {
+ accountManager.setPassword(account, password);
+ }
+
+ public void setUuid(String uuid) {
+ accountManager.setUserData(account, EXTRA_UUID, uuid);
+ }
+
+ boolean isBackgroundSyncEnabled() {
+ return ContentResolver.getSyncAutomatically(account, AUTHORITY);
+ }
+
+ void setSynchronizationEnabled(boolean enabled) {
+ ContentResolver.setSyncAutomatically(account, AUTHORITY, enabled);
+ if (enabled) {
+ ContentResolver.addPeriodicSync(account, AUTHORITY, Bundle.EMPTY, TimeUnit.HOURS.toSeconds(1));
+ } else {
+ ContentResolver.removePeriodicSync(account, AUTHORITY, Bundle.EMPTY);
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "Account{" +
+ "account=" + account +
+ '}';
+ }
+}
diff --git a/app/src/main/java/org/tasks/caldav/CalDAVAccountAuthenticator.java b/app/src/main/java/org/tasks/caldav/CalDAVAccountAuthenticator.java
new file mode 100644
index 000000000..abcc78827
--- /dev/null
+++ b/app/src/main/java/org/tasks/caldav/CalDAVAccountAuthenticator.java
@@ -0,0 +1,59 @@
+package org.tasks.caldav;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class CalDAVAccountAuthenticator extends AbstractAccountAuthenticator {
+
+ private final Context context;
+
+ public CalDAVAccountAuthenticator(Context context) {
+ super(context);
+ this.context = context;
+ }
+
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+ return null;
+ }
+
+ @Override
+ public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
+ Intent intent = new Intent(context, CalDAVSettingsActivity.class);
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+ return bundle;
+ }
+
+ @Override
+ public Bundle confirmCredentials(AccountAuthenticatorResponse response, Account account, Bundle options) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public String getAuthTokenLabel(String authTokenType) {
+ return null;
+ }
+
+ @Override
+ public Bundle updateCredentials(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle hasFeatures(AccountAuthenticatorResponse response, Account account, String[] features) throws NetworkErrorException {
+ return null;
+ }
+}
diff --git a/app/src/main/java/org/tasks/caldav/CalDAVAccountAuthenticatorService.java b/app/src/main/java/org/tasks/caldav/CalDAVAccountAuthenticatorService.java
new file mode 100644
index 000000000..d449b5dd2
--- /dev/null
+++ b/app/src/main/java/org/tasks/caldav/CalDAVAccountAuthenticatorService.java
@@ -0,0 +1,25 @@
+package org.tasks.caldav;
+
+import android.accounts.AccountManager;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.support.annotation.Nullable;
+
+public class CalDAVAccountAuthenticatorService extends Service {
+
+ private CalDAVAccountAuthenticator authenticator;
+
+ @Override
+ public void onCreate() {
+ authenticator = new CalDAVAccountAuthenticator(this);
+ }
+
+ @Nullable
+ @Override
+ public IBinder onBind(Intent intent) {
+ return AccountManager.ACTION_AUTHENTICATOR_INTENT.equals(intent.getAction())
+ ? authenticator.getIBinder()
+ : null;
+ }
+}
diff --git a/app/src/main/java/org/tasks/caldav/CalDAVSettingsActivity.java b/app/src/main/java/org/tasks/caldav/CalDAVSettingsActivity.java
new file mode 100644
index 000000000..d67453aac
--- /dev/null
+++ b/app/src/main/java/org/tasks/caldav/CalDAVSettingsActivity.java
@@ -0,0 +1,464 @@
+package org.tasks.caldav;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.design.widget.Snackbar;
+import android.support.design.widget.TextInputEditText;
+import android.support.design.widget.TextInputLayout;
+import android.support.v4.content.ContextCompat;
+import android.support.v7.widget.Toolbar;
+import android.text.InputType;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.CheckBox;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import com.todoroo.astrid.activity.TaskListActivity;
+import com.todoroo.astrid.api.CaldavFilter;
+import com.todoroo.astrid.helper.UUIDHelper;
+
+import org.tasks.R;
+import org.tasks.activities.ColorPickerActivity;
+import org.tasks.analytics.Tracker;
+import org.tasks.analytics.Tracking;
+import org.tasks.data.CaldavAccount;
+import org.tasks.data.CaldavDao;
+import org.tasks.dialogs.ColorPickerDialog;
+import org.tasks.dialogs.DialogBuilder;
+import org.tasks.injection.ActivityComponent;
+import org.tasks.injection.ThemedInjectingAppCompatActivity;
+import org.tasks.preferences.Preferences;
+import org.tasks.sync.SyncAdapters;
+import org.tasks.themes.ThemeCache;
+import org.tasks.themes.ThemeColor;
+
+import java.net.IDN;
+import java.net.URI;
+import java.net.URISyntaxException;
+
+import javax.inject.Inject;
+
+import butterknife.BindView;
+import butterknife.ButterKnife;
+import butterknife.OnClick;
+import butterknife.OnFocusChange;
+import butterknife.OnTextChanged;
+import timber.log.Timber;
+
+import static android.text.TextUtils.isEmpty;
+import static org.tasks.caldav.DeleteAccountDialog.newDeleteAccountDialog;
+import static org.tasks.caldav.RenameAccountDialog.newRenameAccountDialog;
+import static org.tasks.time.DateTimeUtils.currentTimeMillis;
+
+public class CalDAVSettingsActivity extends ThemedInjectingAppCompatActivity
+ implements Toolbar.OnMenuItemClickListener, DeleteAccountDialog.DeleteAccountDialogCallback,
+ RenameAccountDialog.RenameAccountDialogCallback {
+
+ private static final String EXTRA_SELECTED_THEME = "extra_selected_theme";
+ private static final String FRAG_TAG_RENAME_ACCOUNT = "frag_tag_rename_account";
+ private static final String FRAG_TAG_DELETE_ACCOUNT = "frag_tag_delete_account";
+
+ private static final int REQUEST_COLOR_PICKER = 10109;
+
+ public static final String EXTRA_CALDAV_DATA = "caldavData"; //$NON-NLS-1$
+ public static final String EXTRA_CALDAV_UUID = "uuid"; //$NON-NLS-1$
+
+ public static final String ACTION_RELOAD = "accountRenamed";
+ public static final String ACTION_DELETED = "accountDeleted";
+
+ private CaldavAccount caldavAccount;
+ private Account localAccount;
+ private int selectedTheme;
+
+ @Inject DialogBuilder dialogBuilder;
+ @Inject Preferences preferences;
+ @Inject ThemeCache themeCache;
+ @Inject ThemeColor themeColor;
+ @Inject Tracker tracker;
+ @Inject CaldavDao caldavDao;
+ @Inject CaldavAccountManager caldavAccountManager;
+ @Inject SyncAdapters syncAdapters;
+
+ @BindView(R.id.root_layout) LinearLayout root;
+ @BindView(R.id.name) TextInputEditText name;
+ @BindView(R.id.url) TextInputEditText url;
+ @BindView(R.id.user) TextInputEditText user;
+ @BindView(R.id.password) TextInputEditText password;
+ @BindView(R.id.name_layout) TextInputLayout nameLayout;
+ @BindView(R.id.url_layout) TextInputLayout urlLayout;
+ @BindView(R.id.user_layout) TextInputLayout userLayout;
+ @BindView(R.id.password_layout) TextInputLayout passwordLayout;
+ @BindView(R.id.color) TextInputEditText color;
+ @BindView(R.id.toolbar) Toolbar toolbar;
+ @BindView(R.id.background_sync) CheckBox backgroundSync;
+ @BindView(R.id.master_sync_warning) TextView masterSyncWarning;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.activity_caldav_settings);
+ ButterKnife.bind(this);
+
+ caldavAccount = getIntent().getParcelableExtra(EXTRA_CALDAV_DATA);
+
+ if (caldavAccount != null) {
+ localAccount = caldavAccountManager.getAccount(caldavAccount.getUuid());
+ }
+
+ if (savedInstanceState == null) {
+ if (caldavAccount != null) {
+ selectedTheme = caldavAccount.getColor();
+ name.setText(caldavAccount.getName());
+ url.setText(caldavAccount.getUrl());
+ user.setText(caldavAccount.getUsername());
+ }
+ backgroundSync.setChecked(localAccount == null || localAccount.isBackgroundSyncEnabled());
+ } else {
+ selectedTheme = savedInstanceState.getInt(EXTRA_SELECTED_THEME);
+ }
+
+ final boolean backButtonSavesTask = preferences.backButtonSavesTask();
+ toolbar.setTitle(caldavAccount == null ? getString(R.string.add_account) : caldavAccount.getName());
+ toolbar.setNavigationIcon(ContextCompat.getDrawable(this,
+ backButtonSavesTask ? R.drawable.ic_close_24dp : R.drawable.ic_save_24dp));
+ toolbar.setNavigationOnClickListener(v -> {
+ if (backButtonSavesTask) {
+ discard();
+ } else {
+ save();
+ }
+ });
+ toolbar.inflateMenu(R.menu.menu_tag_settings);
+ toolbar.setOnMenuItemClickListener(this);
+ toolbar.showOverflowMenu();
+
+ color.setInputType(InputType.TYPE_NULL);
+
+ if (caldavAccount == null) {
+ toolbar.getMenu().findItem(R.id.delete).setVisible(false);
+ name.requestFocus();
+ InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.showSoftInput(name, InputMethodManager.SHOW_IMPLICIT);
+ }
+
+ updateTheme();
+ }
+
+ @OnTextChanged(R.id.name)
+ void onNameChanged(CharSequence text) {
+ nameLayout.setError(null);
+ }
+
+ @OnTextChanged(R.id.url)
+ void onUrlChanged(CharSequence text) {
+ urlLayout.setError(null);
+ }
+
+ @OnTextChanged(R.id.user)
+ void onUserChanged(CharSequence text) {
+ userLayout.setError(null);
+ }
+
+ @OnTextChanged(R.id.password)
+ void onPasswordChanged(CharSequence text) {
+ passwordLayout.setError(null);
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+
+ outState.putInt(EXTRA_SELECTED_THEME, selectedTheme);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ masterSyncWarning.setVisibility(syncAdapters.isMasterSyncEnabled() ? View.GONE : View.VISIBLE);
+ }
+
+ @OnFocusChange(R.id.color)
+ void onFocusChange(boolean focused) {
+ if (focused) {
+ color.clearFocus();
+ showThemePicker();
+ }
+ }
+
+ @OnClick(R.id.color)
+ protected void showThemePicker() {
+ Intent intent = new Intent(CalDAVSettingsActivity.this, ColorPickerActivity.class);
+ intent.putExtra(ColorPickerActivity.EXTRA_PALETTE, ColorPickerDialog.ColorPalette.COLORS);
+ intent.putExtra(ColorPickerActivity.EXTRA_SHOW_NONE, true);
+ startActivityForResult(intent, REQUEST_COLOR_PICKER);
+ }
+
+ @Override
+ public void inject(ActivityComponent component) {
+ component.inject(this);
+ }
+
+ private String getNewName() {
+ return name.getText().toString().trim();
+ }
+
+ private String getNewURL() {
+ return url.getText().toString().trim();
+ }
+
+ private String getNewUsername() {
+ return user.getText().toString().trim();
+ }
+
+ private String getNewPassword() {
+ String input = password.getText().toString().trim();
+ return localAccount == null || !isEmpty(input) ? input : localAccount.getPassword();
+ }
+
+ private boolean clashes(String newName) {
+ CaldavAccount existing = caldavDao.getAccountByName(newName);
+ return caldavAccount != null && existing != null && caldavAccount.getId() != existing.getId();
+ }
+
+ private void save() {
+ String newName = getNewName();
+ String username = getNewUsername();
+ String url = getNewURL();
+ String password = getNewPassword();
+
+ boolean failed = false;
+
+ if (isEmpty(newName)) {
+ nameLayout.setError(getString(R.string.name_cannot_be_empty));
+ failed = true;
+ } else if (clashes(newName)) {
+ nameLayout.setError(getString(R.string.tag_already_exists));
+ failed = true;
+ }
+
+ if (isEmpty(url)) {
+ urlLayout.setError(getString(R.string.url_required));
+ failed = true;
+ } else {
+ Uri baseURL = Uri.parse(url);
+ String scheme = baseURL.getScheme();
+ if ("https".equalsIgnoreCase(scheme) || "http".equalsIgnoreCase(scheme)) {
+ String host = baseURL.getHost();
+ if (isEmpty(host)) {
+ urlLayout.setError(getString(R.string.url_host_name_required));
+ failed = true;
+ } else {
+ try {
+ host = IDN.toASCII(host);
+ } catch(Exception e) {
+ Timber.e(e.getMessage(), e);
+ }
+ String path = baseURL.getEncodedPath();
+ int port = baseURL.getPort();
+ try {
+ new URI(scheme, null, host, port, path, null, null);
+ } catch(URISyntaxException e) {
+ urlLayout.setError(e.getLocalizedMessage());
+ failed = true;
+ }
+ }
+ } else {
+ urlLayout.setError(getString(R.string.url_invalid_scheme));
+ failed = true;
+ }
+ }
+
+ if (isEmpty(username)) {
+ userLayout.setError(getString(R.string.username_required));
+ failed = true;
+ }
+
+ if (localAccount == null && isEmpty(password)) {
+ passwordLayout.setError(getString(R.string.password_required));
+ failed = true;
+ }
+
+ if (failed) {
+ return;
+ }
+
+ if (caldavAccount == null) {
+ CaldavAccount newAccount = new CaldavAccount(newName, UUIDHelper.newUUID());
+ newAccount.setColor(selectedTheme);
+ newAccount.setUrl(url);
+ newAccount.setUsername(username);
+ if (caldavAccountManager.addAccount(newAccount, password)) {
+ Account account = caldavAccountManager.getAccount(newAccount.getUuid());
+ if (account == null) {
+ showErrorSnackbar();
+ } else {
+ newAccount.setId(caldavDao.insert(newAccount));
+ setResult(RESULT_OK, new Intent().putExtra(TaskListActivity.OPEN_FILTER, new CaldavFilter(newAccount)));
+ finish();
+ }
+ } else {
+ showErrorSnackbar();
+ }
+ } else if (hasChanges()) {
+ if (localAccount == null) {
+ if (!caldavAccountManager.addAccount(caldavAccount, password)) {
+ localAccount = caldavAccountManager.getAccount(caldavAccount.getUuid());
+ if (localAccount == null) {
+ showErrorSnackbar();
+ return;
+ }
+ }
+ } else if (!newName.equals(localAccount.getName())) {
+ newRenameAccountDialog(caldavAccount.getUuid(), newName)
+ .show(getSupportFragmentManager(), FRAG_TAG_RENAME_ACCOUNT);
+ return;
+ }
+
+ caldavAccount.setName(newName);
+ caldavAccount.setColor(selectedTheme);
+ caldavAccount.setUrl(url);
+ caldavAccount.setUsername(username);
+ caldavDao.update(caldavAccount);
+ if (!isEmpty(password)) {
+ localAccount.setPassword(password);
+ }
+ localAccount.setSynchronizationEnabled(backgroundSync.isChecked());
+ setResult(RESULT_OK, new Intent(ACTION_RELOAD).putExtra(TaskListActivity.OPEN_FILTER, new CaldavFilter(caldavAccount)));
+ finish();
+ } else {
+ finish();
+ }
+ }
+
+ private void showErrorSnackbar() {
+ Snackbar snackbar = Snackbar.make(root, getString(R.string.error_adding_account), 8000)
+ .setActionTextColor(ContextCompat.getColor(this, R.color.snackbar_text_color));
+ snackbar.getView().setBackgroundColor(ContextCompat.getColor(this, R.color.snackbar_background));
+ snackbar.show();
+ }
+
+ private boolean hasChanges() {
+ if (caldavAccount == null) {
+ return selectedTheme >= 0 || !isEmpty(getNewName()) ||
+ !isEmpty(getNewPassword()) || !isEmpty(getNewURL()) ||
+ !isEmpty(getNewUsername()) || !backgroundSync.isChecked();
+ }
+ return localAccount == null ||
+ selectedTheme != caldavAccount.getColor() ||
+ !getNewName().equals(caldavAccount.getName()) ||
+ !getNewURL().equals(caldavAccount.getUrl()) ||
+ !getNewUsername().equals(caldavAccount.getUsername()) ||
+ !getNewPassword().equals(localAccount.getPassword()) ||
+ backgroundSync.isChecked() != localAccount.isBackgroundSyncEnabled();
+ }
+
+ @Override
+ public void finish() {
+ InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
+ imm.hideSoftInputFromWindow(name.getWindowToken(), 0);
+ super.finish();
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (preferences.backButtonSavesTask()) {
+ save();
+ } else {
+ discard();
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_COLOR_PICKER) {
+ if (resultCode == RESULT_OK) {
+ int index = data.getIntExtra(ColorPickerActivity.EXTRA_THEME_INDEX, 0);
+ tracker.reportEvent(Tracking.Events.SET_TAG_COLOR, Integer.toString(index));
+ selectedTheme = index;
+ updateTheme();
+ }
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
+ private void deleteAccount() {
+ dialogBuilder.newMessageDialog(R.string.delete_tag_confirmation, caldavAccount.getName())
+ .setPositiveButton(R.string.delete, (dialog, which) -> {
+ if (localAccount == null) {
+ onListDeleted();
+ } else {
+ newDeleteAccountDialog(localAccount.getUuid())
+ .show(getSupportFragmentManager(), FRAG_TAG_DELETE_ACCOUNT);
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+
+ private void discard() {
+ if (!hasChanges()) {
+ finish();
+ } else {
+ dialogBuilder.newMessageDialog(R.string.discard_changes)
+ .setPositiveButton(R.string.discard, (dialog, which) -> finish())
+ .setNegativeButton(android.R.string.cancel, null)
+ .show();
+ }
+ }
+
+ private void updateTheme() {
+ ThemeColor themeColor;
+ if (selectedTheme < 0) {
+ themeColor = this.themeColor;
+ color.setText(R.string.none);
+ } else {
+ themeColor = themeCache.getThemeColor(selectedTheme);
+ color.setText(themeColor.getName());
+ }
+ themeColor.apply(toolbar);
+ themeColor.applyToStatusBar(this);
+ }
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.delete:
+ deleteAccount();
+ break;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onListDeleted() {
+ if (caldavAccount != null) {
+ caldavAccountManager.deleteAccount(caldavAccount);
+ setResult(RESULT_OK, new Intent(ACTION_DELETED).putExtra(EXTRA_CALDAV_UUID, caldavAccount.getUuid()));
+ }
+ finish();
+ }
+
+ @Override
+ public void onListRenamed() {
+ localAccount = caldavAccountManager.getAccount(caldavAccount.getUuid());
+ save();
+ }
+
+ @Override
+ public void renameFailed() {
+ nameLayout.setError(getString(R.string.error_renaming_account));
+ }
+
+ @Override
+ public void deleteAccountFailed() {
+ Toast.makeText(this, R.string.error_deleting_account, Toast.LENGTH_LONG).show();
+ }
+}
diff --git a/app/src/main/java/org/tasks/caldav/CaldavAccountManager.java b/app/src/main/java/org/tasks/caldav/CaldavAccountManager.java
new file mode 100644
index 000000000..43c4fff64
--- /dev/null
+++ b/app/src/main/java/org/tasks/caldav/CaldavAccountManager.java
@@ -0,0 +1,164 @@
+package org.tasks.caldav;
+
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.Bundle;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Strings;
+import com.todoroo.astrid.dao.TaskDao;
+import com.todoroo.astrid.data.Task;
+import com.todoroo.astrid.service.TaskDeleter;
+
+import org.tasks.LocalBroadcastManager;
+import org.tasks.data.CaldavAccount;
+import org.tasks.data.CaldavDao;
+import org.tasks.injection.ApplicationScope;
+import org.tasks.injection.ForApplication;
+import org.tasks.preferences.PermissionChecker;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import timber.log.Timber;
+
+import static com.google.common.collect.Iterables.tryFind;
+import static org.tasks.caldav.Account.EXTRA_UUID;
+
+@ApplicationScope
+public class CaldavAccountManager {
+
+ private static final String AUTHORITY = "org.tasks";
+ private static final String ACCOUNT_TYPE = "org.tasks.caldav";
+
+ private final PermissionChecker permissionChecker;
+ private final android.accounts.AccountManager accountManager;
+ private final LocalBroadcastManager localBroadcastManager;
+ private final TaskDeleter taskDeleter;
+ private final CaldavDao caldavDao;
+ private final TaskDao taskDao;
+
+ @Inject
+ public CaldavAccountManager(@ForApplication Context context, PermissionChecker permissionChecker,
+ CaldavDao caldavDao, TaskDeleter taskDeleter,
+ LocalBroadcastManager localBroadcastManager, TaskDao taskDao) {
+ this.permissionChecker = permissionChecker;
+ this.caldavDao = caldavDao;
+ this.taskDao = taskDao;
+ this.taskDeleter = taskDeleter;
+ this.localBroadcastManager = localBroadcastManager;
+ accountManager = android.accounts.AccountManager.get(context);
+ syncAccountList();
+ }
+
+ public String getUuid(android.accounts.Account account) {
+ return accountManager.getUserData(account, EXTRA_UUID);
+ }
+
+ public Account getAccount(String uuid) {
+ for (Account account : getAccounts()) {
+ if (uuid.equals(account.getUuid())) {
+ return account;
+ }
+ }
+ return null;
+ }
+
+ public List getAccounts() {
+ if (!permissionChecker.canAccessAccounts()) {
+ return Collections.emptyList();
+ }
+
+ List accounts = new ArrayList<>();
+ for (android.accounts.Account account : accountManager.getAccountsByType(ACCOUNT_TYPE)) {
+ accounts.add(new Account(accountManager, account));
+ }
+ return accounts;
+ }
+
+ boolean removeAccount(Account account) {
+ return removeAccount(account.getAccount());
+ }
+
+ boolean removeAccount(android.accounts.Account account) {
+ try {
+ return accountManager
+ .removeAccount(account, null, null)
+ .getResult();
+ } catch (OperationCanceledException | IOException | AuthenticatorException e) {
+ Timber.e(e.getMessage(), e);
+ }
+ return false;
+ }
+
+ boolean addAccount(CaldavAccount caldavAccount, String password) {
+ Timber.d("Adding %s", caldavAccount);
+ android.accounts.Account account = new android.accounts.Account(caldavAccount.getName(), ACCOUNT_TYPE);
+ Bundle userdata = new Bundle();
+ userdata.putString(EXTRA_UUID, caldavAccount.getUuid());
+ return accountManager.addAccountExplicitly(account, password, userdata);
+ }
+
+ private void createAccount(Account account) {
+ Timber.d("Adding %s", account);
+ String uuid = account.getUuid();
+ if (!Strings.isNullOrEmpty(uuid)) {
+ caldavDao.insert(new CaldavAccount(account.getName(), uuid));
+ }
+ }
+
+ private void syncAccountList() {
+ List oldAccountList = caldavDao.getAllOrderedByName();
+ List newAccountList = getAccounts();
+
+ for (CaldavAccount local : oldAccountList) {
+ Optional match = tryFind(newAccountList, remote -> local.getUuid().equals(remote.getUuid()));
+ if (match.isPresent()) {
+ Timber.d("found %s", match.get());
+ } else {
+ addAccount(local, null);
+ }
+ }
+
+ for (Account remote : newAccountList) {
+ Optional match = tryFind(oldAccountList, local -> remote.getUuid().equals(local.getUuid()));
+ if (match.isPresent()) {
+ Timber.d("found %s", match.get());
+ } else {
+ createAccount(remote);
+ }
+ }
+ }
+
+ void deleteAccount(CaldavAccount account) {
+ String uuid = account.getUuid();
+ for (Task task : taskDao.getCaldavTasks(uuid)) {
+ taskDeleter.markDeleted(task);
+ }
+ caldavDao.deleteTasksForAccount(uuid);
+ caldavDao.delete(account);
+ localBroadcastManager.broadcastRefreshList();
+ }
+
+ public boolean initiateManualSync() {
+ for (org.tasks.caldav.Account account : getAccounts()) {
+ Bundle extras = new Bundle();
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
+ extras.putBoolean(ContentResolver.SYNC_EXTRAS_EXPEDITED, true);
+ ContentResolver.requestSync(account.getAccount(), AUTHORITY, extras);
+ }
+ return true;
+ }
+
+ public void requestSynchronization() {
+ for (org.tasks.caldav.Account account : getAccounts()) {
+ ContentResolver.requestSync(account.getAccount(), AUTHORITY, new Bundle());
+ }
+ }
+}
diff --git a/app/src/main/java/org/tasks/caldav/CaldavListFragment.java b/app/src/main/java/org/tasks/caldav/CaldavListFragment.java
index fd0ced12d..a441009ab 100644
--- a/app/src/main/java/org/tasks/caldav/CaldavListFragment.java
+++ b/app/src/main/java/org/tasks/caldav/CaldavListFragment.java
@@ -1,15 +1,22 @@
package org.tasks.caldav;
+import android.content.Intent;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+import com.todoroo.astrid.activity.TaskListActivity;
import com.todoroo.astrid.activity.TaskListFragment;
import com.todoroo.astrid.api.CaldavFilter;
+import com.todoroo.astrid.api.Filter;
import org.tasks.R;
import org.tasks.data.CaldavAccount;
import org.tasks.injection.FragmentComponent;
+import static android.app.Activity.RESULT_OK;
+import static org.tasks.caldav.CalDAVSettingsActivity.EXTRA_CALDAV_DATA;
+
public class CaldavListFragment extends TaskListFragment {
public static TaskListFragment newCaldavListFragment(CaldavFilter filter, CaldavAccount account) {
@@ -20,6 +27,7 @@ public class CaldavListFragment extends TaskListFragment {
}
private static final String EXTRA_CALDAV_ACCOUNT = "extra_caldav_account";
+ private static final int REQUEST_ACCOUNT_SETTINGS = 10101;
protected CaldavAccount account;
@@ -37,7 +45,39 @@ public class CaldavListFragment extends TaskListFragment {
super.inflateMenu(toolbar);
toolbar.inflateMenu(R.menu.menu_caldav_list_fragment);
}
-
+
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ switch(item.getItemId()) {
+ case R.id.menu_caldav_list_fragment:
+ Intent intent = new Intent(getActivity(), CalDAVSettingsActivity.class);
+ intent.putExtra(EXTRA_CALDAV_DATA, account);
+ startActivityForResult(intent, REQUEST_ACCOUNT_SETTINGS);
+ return true;
+ default:
+ return super.onMenuItemClick(item);
+ }
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == REQUEST_ACCOUNT_SETTINGS) {
+ if (resultCode == RESULT_OK) {
+ TaskListActivity activity = (TaskListActivity) getActivity();
+ String action = data.getAction();
+ if (CalDAVSettingsActivity.ACTION_DELETED.equals(action)) {
+ activity.onFilterItemClicked(null);
+ } else if (CalDAVSettingsActivity.ACTION_RELOAD.equals(action)) {
+ activity.getIntent().putExtra(TaskListActivity.OPEN_FILTER,
+ (Filter) data.getParcelableExtra(TaskListActivity.OPEN_FILTER));
+ activity.recreate();
+ }
+ }
+ } else {
+ super.onActivityResult(requestCode, resultCode, data);
+ }
+ }
+
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
diff --git a/app/src/main/java/org/tasks/caldav/DeleteAccountDialog.java b/app/src/main/java/org/tasks/caldav/DeleteAccountDialog.java
new file mode 100644
index 000000000..dfbddc9ee
--- /dev/null
+++ b/app/src/main/java/org/tasks/caldav/DeleteAccountDialog.java
@@ -0,0 +1,93 @@
+package org.tasks.caldav;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import org.tasks.R;
+import org.tasks.dialogs.DialogBuilder;
+import org.tasks.injection.DialogFragmentComponent;
+import org.tasks.injection.InjectingDialogFragment;
+
+import javax.inject.Inject;
+
+public class DeleteAccountDialog extends InjectingDialogFragment {
+
+ public static DeleteAccountDialog newDeleteAccountDialog(String uuid) {
+ DeleteAccountDialog dialog = new DeleteAccountDialog();
+ Bundle args = new Bundle();
+ args.putString(EXTRA_UUID, uuid);
+ dialog.setArguments(args);
+ return dialog;
+ }
+
+ public interface DeleteAccountDialogCallback {
+ void onListDeleted();
+
+ void deleteAccountFailed();
+ }
+
+ private static final String EXTRA_UUID = "extra_uuid";
+
+ @Inject DialogBuilder dialogBuilder;
+ @Inject CaldavAccountManager caldavAccountManager;
+
+ private DeleteAccountDialogCallback callback;
+ private String uuid;
+ private ProgressDialog dialog;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ Bundle arguments = getArguments();
+ uuid = arguments.getString(EXTRA_UUID);
+ dialog = dialogBuilder.newProgressDialog(R.string.deleting_list);
+ execute();
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return dialog;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+
+ callback = (DeleteAccountDialogCallback) activity;
+ }
+
+ @Override
+ protected void inject(DialogFragmentComponent component) {
+ component.inject(this);
+ }
+
+ private void execute() {
+ new AsyncTask() {
+ @Override
+ protected Boolean doInBackground(Void... voids) {
+ Account account = caldavAccountManager.getAccount(uuid);
+ return account == null || caldavAccountManager.removeAccount(account);
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (dialog.isShowing()) {
+ dialog.dismiss();
+ }
+
+ if (result) {
+ callback.onListDeleted();
+ } else {
+ callback.deleteAccountFailed();
+ }
+ }
+ }.execute();
+ }
+}
diff --git a/app/src/main/java/org/tasks/caldav/RenameAccountDialog.java b/app/src/main/java/org/tasks/caldav/RenameAccountDialog.java
new file mode 100644
index 000000000..709acd4f4
--- /dev/null
+++ b/app/src/main/java/org/tasks/caldav/RenameAccountDialog.java
@@ -0,0 +1,112 @@
+package org.tasks.caldav;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.todoroo.astrid.helper.UUIDHelper;
+
+import org.tasks.R;
+import org.tasks.data.CaldavAccount;
+import org.tasks.data.CaldavDao;
+import org.tasks.dialogs.DialogBuilder;
+import org.tasks.injection.DialogFragmentComponent;
+import org.tasks.injection.InjectingDialogFragment;
+
+import javax.inject.Inject;
+
+import static org.tasks.time.DateTimeUtils.currentTimeMillis;
+
+public class RenameAccountDialog extends InjectingDialogFragment {
+
+ public static RenameAccountDialog newRenameAccountDialog(String uuid, String name) {
+ RenameAccountDialog dialog = new RenameAccountDialog();
+ Bundle args = new Bundle();
+ args.putString(EXTRA_NAME, name);
+ args.putString(EXTRA_UUID, uuid);
+ dialog.setArguments(args);
+ return dialog;
+ }
+
+ public interface RenameAccountDialogCallback {
+ void onListRenamed();
+
+ void renameFailed();
+ }
+
+ private static final String EXTRA_NAME = "extra_name";
+ private static final String EXTRA_UUID = "extra_uuid";
+
+ @Inject DialogBuilder dialogBuilder;
+ @Inject CaldavAccountManager caldavAccountManager;
+ @Inject CaldavDao caldavDao;
+
+ private RenameAccountDialogCallback callback;
+ private String name;
+ private String uuid;
+ private ProgressDialog dialog;
+
+ @Override
+ public void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setRetainInstance(true);
+ Bundle arguments = getArguments();
+ name = arguments.getString(EXTRA_NAME);
+ uuid = arguments.getString(EXTRA_UUID);
+ dialog = dialogBuilder.newProgressDialog(R.string.renaming_list);
+ execute();
+ }
+
+ @NonNull
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ return dialog;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+
+ callback = (RenameAccountDialogCallback) activity;
+ }
+
+ @Override
+ protected void inject(DialogFragmentComponent component) {
+ component.inject(this);
+ }
+
+ private void execute() {
+ new AsyncTask() {
+ @Override
+ protected Boolean doInBackground(Void... voids) {
+ CaldavAccount caldavAccount = caldavDao.getAccount(uuid);
+ caldavAccount.setName(name);
+ Account old = caldavAccountManager.getAccount(uuid);
+ if (!caldavAccountManager.addAccount(caldavAccount, old.getPassword())) {
+ return false;
+ }
+ caldavDao.update(caldavAccount);
+ old.setUuid(null);
+ caldavAccountManager.removeAccount(old);
+ return true;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ if (dialog.isShowing()) {
+ dialog.dismiss();
+ }
+
+ if (result) {
+ callback.onListRenamed();
+ } else {
+ callback.renameFailed();
+ }
+ }
+ }.execute();
+ }
+}
diff --git a/app/src/main/java/org/tasks/data/CaldavAccount.java b/app/src/main/java/org/tasks/data/CaldavAccount.java
index 2bece0b82..36efd0c0f 100644
--- a/app/src/main/java/org/tasks/data/CaldavAccount.java
+++ b/app/src/main/java/org/tasks/data/CaldavAccount.java
@@ -26,29 +26,31 @@ public final class CaldavAccount implements Parcelable {
@ColumnInfo(name = "color")
private int color = -1;
- @ColumnInfo(name = "deleted")
- private long deleted;
-
@ColumnInfo(name = "ctag")
private String ctag;
@ColumnInfo(name = "url")
- private String url;
+ private String url = "";
@ColumnInfo(name = "username")
- private String username;
+ private String username = "";
public CaldavAccount() {
}
+ @Ignore
+ public CaldavAccount(String name, String uuid) {
+ this.name = name;
+ this.uuid = uuid;
+ }
+
@Ignore
public CaldavAccount(Parcel source) {
id = source.readLong();
uuid = source.readString();
name = source.readString();
color = source.readInt();
- deleted = source.readLong();
ctag = source.readString();
url = source.readString();
username = source.readString();
@@ -86,14 +88,6 @@ public final class CaldavAccount implements Parcelable {
this.color = color;
}
- public long getDeleted() {
- return deleted;
- }
-
- public void setDeleted(long deleted) {
- this.deleted = deleted;
- }
-
public String getCtag() {
return ctag;
}
@@ -118,10 +112,6 @@ public final class CaldavAccount implements Parcelable {
this.username = username;
}
- public boolean isDeleted() {
- return deleted > 0;
- }
-
public static Parcelable.Creator CREATOR = new Parcelable.Creator() {
@Override
public CaldavAccount createFromParcel(Parcel source) {
@@ -145,7 +135,6 @@ public final class CaldavAccount implements Parcelable {
dest.writeString(uuid);
dest.writeString(name);
dest.writeInt(color);
- dest.writeLong(deleted);
dest.writeString(ctag);
dest.writeString(url);
dest.writeString(username);
@@ -158,7 +147,6 @@ public final class CaldavAccount implements Parcelable {
", uuid='" + uuid + '\'' +
", name='" + name + '\'' +
", color=" + color +
- ", deleted=" + deleted +
", ctag='" + ctag + '\'' +
", url='" + url + '\'' +
", username='" + username + '\'' +
diff --git a/app/src/main/java/org/tasks/data/CaldavDao.java b/app/src/main/java/org/tasks/data/CaldavDao.java
index 700333a2b..462d62d4b 100644
--- a/app/src/main/java/org/tasks/data/CaldavDao.java
+++ b/app/src/main/java/org/tasks/data/CaldavDao.java
@@ -17,18 +17,15 @@ public interface CaldavDao {
@Query("SELECT * FROM caldav_account WHERE uuid = :uuid LIMIT 1")
CaldavAccount getByUuid(String uuid);
- @Query("SELECT * FROM caldav_account WHERE deleted = 0 ORDER BY UPPER(name) ASC")
+ @Query("SELECT * FROM caldav_account ORDER BY UPPER(name) ASC")
List getAllOrderedByName();
@Insert
- void insert(CaldavAccount caldavAccount);
+ long insert(CaldavAccount caldavAccount);
@Update
void update(CaldavAccount caldavAccount);
- @Query("UPDATE caldav_account SET deleted = (strftime('%s','now')*1000) WHERE uuid = :uuid")
- void markAccountDeleted(String uuid);
-
@Insert
void insert(CaldavTask caldavTask);
@@ -55,4 +52,13 @@ public interface CaldavDao {
@Query("SELECT * FROM caldav_account")
List getAccounts();
+
+ @Delete
+ void delete(CaldavAccount caldavAccount);
+
+ @Query("SELECT * FROM caldav_account WHERE uuid = :uuid LIMIT 1")
+ CaldavAccount getAccount(String uuid);
+
+ @Query("DELETE FROM caldav_tasks WHERE account = :uuid")
+ void deleteTasksForAccount(String uuid);
}
diff --git a/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.java b/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.java
index f0bee4397..42131594b 100644
--- a/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.java
+++ b/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.java
@@ -21,8 +21,8 @@ import org.tasks.data.GoogleTask;
import org.tasks.data.GoogleTaskList;
import org.tasks.data.Tag;
import org.tasks.data.TagData;
-import org.tasks.gtasks.GtaskSyncAdapterHelper;
import org.tasks.injection.ForApplication;
+import org.tasks.sync.SyncAdapters;
import java.util.HashMap;
import java.util.List;
@@ -47,15 +47,15 @@ public class FilterCriteriaProvider {
private final TagService tagService;
private final GtasksListService gtasksListService;
private final Resources r;
- private final GtaskSyncAdapterHelper gtaskSyncAdapterHelper;
+ private final SyncAdapters syncAdapters;
@Inject
public FilterCriteriaProvider(@ForApplication Context context, TagService tagService,
- GtasksListService gtasksListService, GtaskSyncAdapterHelper gtaskSyncAdapterHelper) {
+ GtasksListService gtasksListService, SyncAdapters syncAdapters) {
this.context = context;
this.tagService = tagService;
this.gtasksListService = gtasksListService;
- this.gtaskSyncAdapterHelper = gtaskSyncAdapterHelper;
+ this.syncAdapters = syncAdapters;
r = context.getResources();
}
@@ -68,7 +68,7 @@ public class FilterCriteriaProvider {
result.add(getDueDateFilter());
result.add(getImportanceFilter());
result.add(getTaskTitleContainsFilter());
- if (gtaskSyncAdapterHelper.isEnabled()) {
+ if (syncAdapters.isGoogleTaskSyncEnabled()) {
result.add(getGtasksFilterCriteria());
}
diff --git a/app/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.java b/app/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.java
index 6be89f958..783732668 100644
--- a/app/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.java
+++ b/app/src/main/java/org/tasks/fragments/TaskEditControlSetFragmentManager.java
@@ -16,8 +16,8 @@ import com.todoroo.astrid.ui.ReminderControlSet;
import org.tasks.BuildConfig;
import org.tasks.R;
-import org.tasks.gtasks.GtaskSyncAdapterHelper;
import org.tasks.preferences.Preferences;
+import org.tasks.sync.SyncAdapters;
import org.tasks.ui.CalendarControlSet;
import org.tasks.ui.DeadlineControlSet;
import org.tasks.ui.DescriptionControlSet;
@@ -72,11 +72,11 @@ public class TaskEditControlSetFragmentManager {
private final Map controlSetFragments = new LinkedHashMap<>();
private final List displayOrder;
- private final GtaskSyncAdapterHelper gtaskSyncAdapterHelper;
+ private final SyncAdapters syncAdapters;
private int numRows;
- public TaskEditControlSetFragmentManager(Activity activity, Preferences preferences, GtaskSyncAdapterHelper gtaskSyncAdapterHelper) {
- this.gtaskSyncAdapterHelper = gtaskSyncAdapterHelper;
+ public TaskEditControlSetFragmentManager(Activity activity, Preferences preferences, SyncAdapters syncAdapters) {
+ this.syncAdapters = syncAdapters;
displayOrder = BeastModePreferences.constructOrderedControlList(preferences, activity);
displayOrder.add(0, activity.getString(EditTitleControlSet.TAG));
displayOrder.add(1, activity.getString(CommentBarFragment.TAG));
@@ -151,7 +151,7 @@ public class TaskEditControlSetFragmentManager {
case CommentBarFragment.TAG:
return new CommentBarFragment();
case RemoteListFragment.TAG:
- return gtaskSyncAdapterHelper.isEnabled()
+ return syncAdapters.isSyncEnabled()
? new RemoteListFragment()
: null;
default:
diff --git a/app/src/main/java/org/tasks/injection/ActivityModule.java b/app/src/main/java/org/tasks/injection/ActivityModule.java
index 041070251..f72b68631 100644
--- a/app/src/main/java/org/tasks/injection/ActivityModule.java
+++ b/app/src/main/java/org/tasks/injection/ActivityModule.java
@@ -5,8 +5,8 @@ import android.content.Context;
import org.tasks.R;
import org.tasks.fragments.TaskEditControlSetFragmentManager;
-import org.tasks.gtasks.GtaskSyncAdapterHelper;
import org.tasks.preferences.Preferences;
+import org.tasks.sync.SyncAdapters;
import org.tasks.themes.ThemeAccent;
import org.tasks.themes.ThemeBase;
import org.tasks.themes.ThemeCache;
@@ -55,7 +55,7 @@ public class ActivityModule {
@Provides
@ActivityScope
- public TaskEditControlSetFragmentManager getTaskEditControlSetFragmentManager(Preferences preferences, GtaskSyncAdapterHelper gtaskSyncAdapterHelper) {
- return new TaskEditControlSetFragmentManager(activity, preferences, gtaskSyncAdapterHelper);
+ public TaskEditControlSetFragmentManager getTaskEditControlSetFragmentManager(Preferences preferences, SyncAdapters syncAdapters) {
+ return new TaskEditControlSetFragmentManager(activity, preferences, syncAdapters);
}
}
diff --git a/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.java b/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.java
index 6509beb5e..1de929f28 100644
--- a/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.java
+++ b/app/src/main/java/org/tasks/ui/NavigationDrawerFragment.java
@@ -40,6 +40,7 @@ public class NavigationDrawerFragment extends InjectingFragment {
public static final int REQUEST_NEW_LIST = 4;
public static final int ACTIVITY_REQUEST_NEW_FILTER = 5;
public static final int REQUEST_NEW_GTASK_LIST = 6;
+ public static final int REQUEST_NEW_CALDAV_ACCOUNT = 7;
private final RefreshReceiver refreshReceiver = new RefreshReceiver();
@@ -82,7 +83,8 @@ public class NavigationDrawerFragment extends InjectingFragment {
}
} else if (requestCode == REQUEST_NEW_LIST ||
requestCode == ACTIVITY_REQUEST_NEW_FILTER ||
- requestCode == REQUEST_NEW_GTASK_LIST) {
+ requestCode == REQUEST_NEW_GTASK_LIST ||
+ requestCode == REQUEST_NEW_CALDAV_ACCOUNT) {
if (resultCode == RESULT_OK && data != null) {
Filter newList = data.getParcelableExtra(TaskListActivity.OPEN_FILTER);
if (newList != null) {
diff --git a/app/src/main/res/layout/activity_caldav_settings.xml b/app/src/main/res/layout/activity_caldav_settings.xml
new file mode 100644
index 000000000..264b1583d
--- /dev/null
+++ b/app/src/main/res/layout/activity_caldav_settings.xml
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
index 035d44786..99ee50a64 100644
--- a/app/src/main/res/values/dimens.xml
+++ b/app/src/main/res/values/dimens.xml
@@ -11,6 +11,7 @@
18dp
17dp
16sp
+ 18sp
- 12
diff --git a/app/src/main/res/values/keys.xml b/app/src/main/res/values/keys.xml
index 2c3611def..67a7ec559 100644
--- a/app/src/main/res/values/keys.xml
+++ b/app/src/main/res/values/keys.xml
@@ -287,6 +287,7 @@
Debug
start_of_week
use_native_datetime_pickers
+ org.tasks.caldav
gtask_background_sync
bundle_notifications
strict_mode
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 927f846db..f03edf49f 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -756,6 +756,11 @@ File %1$s contained %2$s.\n\n
Send anonymous usage statistics and crash reports to help improve Tasks. No personal data will be collected.
Tag already exists
Name cannot be empty
+ Username required
+ Password required
+ URL required
+ Host name required
+ Must begin with http(s)://
(No title)
Back button saves task
Default list
@@ -832,6 +837,13 @@ File %1$s contained %2$s.\n\n
Use locale default
Use native date and time pickers
CalDAV
+ Add account
+ User
+ Password
+ URL
+ Error adding account
+ Error renaming account
+ Error deleting account
Account settings
Manage notifications
Manage battery optimizations
diff --git a/app/src/main/res/xml/account_authenticator.xml b/app/src/main/res/xml/account_authenticator.xml
new file mode 100644
index 000000000..7e3dd2637
--- /dev/null
+++ b/app/src/main/res/xml/account_authenticator.xml
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/sync_adapter_caldav.xml b/app/src/main/res/xml/sync_adapter_caldav.xml
new file mode 100644
index 000000000..6dd0a24ca
--- /dev/null
+++ b/app/src/main/res/xml/sync_adapter_caldav.xml
@@ -0,0 +1,7 @@
+
+
\ No newline at end of file