diff --git a/app/src/androidTest/java/com/todoroo/astrid/dao/TaskDaoTests.java b/app/src/androidTest/java/com/todoroo/astrid/dao/TaskDaoTests.java index 83093e4b9..756dcf640 100644 --- a/app/src/androidTest/java/com/todoroo/astrid/dao/TaskDaoTests.java +++ b/app/src/androidTest/java/com/todoroo/astrid/dao/TaskDaoTests.java @@ -10,8 +10,10 @@ import static junit.framework.Assert.assertNotSame; import static junit.framework.Assert.assertNull; import android.support.test.runner.AndroidJUnit4; +import com.google.common.collect.ImmutableList; import com.todoroo.andlib.utility.DateUtilities; import com.todoroo.astrid.data.Task; +import com.todoroo.astrid.service.TaskDeleter; import javax.inject.Inject; import org.junit.Test; import org.junit.runner.RunWith; @@ -22,6 +24,7 @@ import org.tasks.injection.TestComponent; public class TaskDaoTests extends InjectingTestCase { @Inject TaskDao taskDao; + @Inject TaskDeleter taskDeleter; /** Test basic task creation, fetch, and save */ @Test @@ -113,8 +116,7 @@ public class TaskDaoTests extends InjectingTestCase { assertEquals(1, taskDao.getAll().size()); // delete - long happyId = task.getId(); - assertEquals(1, taskDao.deleteById(happyId)); + taskDeleter.delete(task); assertEquals(0, taskDao.getAll().size()); } @@ -138,7 +140,7 @@ public class TaskDaoTests extends InjectingTestCase { assertNull(taskDao.fetch(1)); - assertEquals(0, taskDao.deleteById(1)); + taskDeleter.delete(ImmutableList.of(1L)); // make sure db still works assertEquals(0, taskDao.getAll().size()); diff --git a/app/src/androidTest/java/org/tasks/injection/TestModule.java b/app/src/androidTest/java/org/tasks/injection/TestModule.java index d73845f30..41f75726b 100644 --- a/app/src/androidTest/java/org/tasks/injection/TestModule.java +++ b/app/src/androidTest/java/org/tasks/injection/TestModule.java @@ -9,6 +9,7 @@ import dagger.Module; import dagger.Provides; import org.tasks.data.AlarmDao; import org.tasks.data.CaldavDao; +import org.tasks.data.DeletionDao; import org.tasks.data.FilterDao; import org.tasks.data.GoogleTaskDao; import org.tasks.data.GoogleTaskListDao; @@ -101,6 +102,11 @@ public class TestModule { return database.getFilterDao(); } + @Provides + public DeletionDao getDeletionDao(Database database) { + return database.getDeletionDao(); + } + @Provides public TaskAttachmentDao getTaskAttachmentDao(Database database) { return database.getTaskAttachmentDao(); diff --git a/app/src/androidTest/java/org/tasks/makers/GtaskListMaker.java b/app/src/androidTest/java/org/tasks/makers/GtaskListMaker.java index b8739d366..06a0d7302 100644 --- a/app/src/androidTest/java/org/tasks/makers/GtaskListMaker.java +++ b/app/src/androidTest/java/org/tasks/makers/GtaskListMaker.java @@ -21,7 +21,6 @@ public class GtaskListMaker { lookup -> new GoogleTaskList() { { - setDeleted(0L); setId(lookup.valueOf(GtaskListMaker.ID, 0L)); setAccount(lookup.valueOf(ACCOUNT, "account")); setRemoteId(lookup.valueOf(REMOTE_ID, "1")); diff --git a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksIndentActionTest.java b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksIndentActionTest.java index 399862949..352117b34 100644 --- a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksIndentActionTest.java +++ b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksIndentActionTest.java @@ -166,7 +166,7 @@ public class GtasksIndentActionTest extends InjectingTestCase { googleTaskListDao.insert(account); gtasksListService.updateLists(account, items); - storeList = googleTaskListDao.getActiveLists("account").get(0); + storeList = googleTaskListDao.getLists("account").get(0); } @Override diff --git a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.java b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.java index 303886faf..c7d67ff04 100644 --- a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.java +++ b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksListServiceTest.java @@ -88,7 +88,7 @@ public class GtasksListServiceTest extends InjectingTestCase { assertEquals( singletonList(newGtaskList(with(ID, 2L), with(REMOTE_ID, "2"))), - googleTaskListDao.getActiveLists("account")); + googleTaskListDao.getLists("account")); } @Test diff --git a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksTaskListUpdaterTest.java b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksTaskListUpdaterTest.java index a063d7d5d..44fb9a7f0 100644 --- a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksTaskListUpdaterTest.java +++ b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksTaskListUpdaterTest.java @@ -167,7 +167,7 @@ public class GtasksTaskListUpdaterTest extends InjectingTestCase { } private void createParentSiblingMaps() { - for (GoogleTaskList list : googleTaskListDao.getActiveLists("account")) { + for (GoogleTaskList list : googleTaskListDao.getLists("account")) { gtasksTaskListUpdater.updateParentSiblingMapsFor(list); } } diff --git a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksTaskMovingTest.java b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksTaskMovingTest.java index 0fff940e6..509a6dbe3 100644 --- a/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksTaskMovingTest.java +++ b/app/src/androidTestGoogleplay/java/com/todoroo/astrid/gtasks/GtasksTaskMovingTest.java @@ -272,7 +272,7 @@ public class GtasksTaskMovingTest extends InjectingTestCase { googleTaskListDao.insert(account); gtasksListService.updateLists(account, items); - list = googleTaskListDao.getActiveLists("account").get(0); + list = googleTaskListDao.getLists("account").get(0); } @Override diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java b/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java index 5aa218854..96a51ad21 100755 --- a/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java +++ b/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.java @@ -292,7 +292,6 @@ public final class TaskEditFragment extends InjectingFragment .setPositiveButton( android.R.string.ok, (dialog, which) -> { - timerPlugin.stopTimer(model); taskDeleter.markDeleted(model); callback.taskEditFinished(); }) diff --git a/app/src/main/java/com/todoroo/astrid/alarms/AlarmService.java b/app/src/main/java/com/todoroo/astrid/alarms/AlarmService.java index 482d99c3d..874b70f1c 100644 --- a/app/src/main/java/com/todoroo/astrid/alarms/AlarmService.java +++ b/app/src/main/java/com/todoroo/astrid/alarms/AlarmService.java @@ -97,6 +97,12 @@ public class AlarmService { } } + public void cancelAlarms(long taskId) { + for (Alarm alarm : getActiveAlarmsForTask(taskId)) { + jobs.cancelAlarm(alarm.getId()); + } + } + /** Schedules alarms for a single task */ private void scheduleAlarms(long taskId) { for (Alarm alarm : getActiveAlarmsForTask(taskId)) { diff --git a/app/src/main/java/com/todoroo/astrid/dao/Database.java b/app/src/main/java/com/todoroo/astrid/dao/Database.java index 7594aa2b0..dc733ffa1 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/Database.java +++ b/app/src/main/java/com/todoroo/astrid/dao/Database.java @@ -18,6 +18,7 @@ import org.tasks.data.CaldavAccount; import org.tasks.data.CaldavCalendar; import org.tasks.data.CaldavDao; import org.tasks.data.CaldavTask; +import org.tasks.data.DeletionDao; import org.tasks.data.Filter; import org.tasks.data.FilterDao; import org.tasks.data.GoogleTask; @@ -95,6 +96,8 @@ public abstract class Database extends RoomDatabase { public abstract CaldavDao getCaldavDao(); + public abstract DeletionDao getDeletionDao(); + // --- implementation public String getName() { 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 31a38bfbf..33b1f2a3d 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java +++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDao.java @@ -8,7 +8,9 @@ package com.todoroo.astrid.dao; import static com.todoroo.andlib.utility.DateUtilities.now; import android.arch.persistence.room.Dao; +import android.arch.persistence.room.Delete; import android.arch.persistence.room.Insert; +import android.arch.persistence.room.Transaction; import android.arch.persistence.room.Update; import android.content.Context; import android.database.Cursor; @@ -23,6 +25,8 @@ import com.todoroo.astrid.helper.UUIDHelper; import java.util.ArrayList; import java.util.List; import org.tasks.BuildConfig; +import org.tasks.data.GoogleTaskAccount; +import org.tasks.data.GoogleTaskList; import org.tasks.data.LimitOffsetDataSource; import org.tasks.jobs.AfterSaveIntentService; import timber.log.Timber; @@ -58,7 +62,7 @@ public abstract class TaskDao { @android.arch.persistence.room.Query("SELECT * FROM tasks WHERE _id IN (:taskIds)") public abstract List fetch(List taskIds); - @android.arch.persistence.room.Query("SELECT COUNT(1) FROM tasks WHERE timerStart > 0") + @android.arch.persistence.room.Query("SELECT COUNT(1) FROM tasks WHERE timerStart > 0 AND deleted = 0") public abstract int activeTimers(); @android.arch.persistence.room.Query( @@ -130,16 +134,6 @@ public abstract class TaskDao { + "WHERE completed > 0 AND calendarUri NOT NULL AND calendarUri != ''") public abstract int clearCompletedCalendarEvents(); - @android.arch.persistence.room.Query("SELECT * FROM tasks WHERE deleted > 0") - public abstract List getDeleted(); - - @android.arch.persistence.room.Query("DELETE FROM tasks WHERE _id = :id") - public abstract int deleteById(long id); - - @android.arch.persistence.room.Query( - "SELECT tasks.* FROM tasks INNER JOIN google_tasks ON google_tasks.task = tasks._id WHERE google_tasks.deleted = 0 AND google_tasks.list_id = :googleTaskList") - public abstract List getGoogleTasks(String googleTaskList); - /** * Saves the given task to the database.getDatabase(). Task must already exist. Returns true on * success. diff --git a/app/src/main/java/com/todoroo/astrid/gtasks/GtasksFilterExposer.java b/app/src/main/java/com/todoroo/astrid/gtasks/GtasksFilterExposer.java index 39b09deb0..360a8d318 100644 --- a/app/src/main/java/com/todoroo/astrid/gtasks/GtasksFilterExposer.java +++ b/app/src/main/java/com/todoroo/astrid/gtasks/GtasksFilterExposer.java @@ -7,12 +7,10 @@ package com.todoroo.astrid.gtasks; import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.transform; -import static java.util.Collections.emptyList; import android.support.v4.util.Pair; import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.api.GtasksFilter; -import java.util.ArrayList; import java.util.List; import javax.inject.Inject; import org.tasks.data.GoogleTaskAccount; @@ -41,7 +39,7 @@ public class GtasksFilterExposer { public List>> getFilters() { List>> listFilters = newArrayList(); for (GoogleTaskAccount account : googleTaskListDao.getAccounts()) { - List lists = googleTaskListDao.getActiveLists(account.getAccount()); + List lists = googleTaskListDao.getLists(account.getAccount()); listFilters.add(new Pair<>(account, transform(lists, GtasksFilter::new))); } return listFilters; diff --git a/app/src/main/java/com/todoroo/astrid/gtasks/GtasksListService.java b/app/src/main/java/com/todoroo/astrid/gtasks/GtasksListService.java index f9a8b5297..8631d5980 100644 --- a/app/src/main/java/com/todoroo/astrid/gtasks/GtasksListService.java +++ b/app/src/main/java/com/todoroo/astrid/gtasks/GtasksListService.java @@ -10,7 +10,6 @@ import static org.tasks.time.DateTimeUtils.printTimestamp; import com.google.api.services.tasks.model.TaskList; import com.todoroo.astrid.dao.TaskDao; -import com.todoroo.astrid.data.Task; import com.todoroo.astrid.service.TaskDeleter; import java.util.HashSet; import java.util.List; @@ -55,7 +54,7 @@ public class GtasksListService { * @param remoteLists remote information about your lists */ public synchronized void updateLists(GoogleTaskAccount account, List remoteLists) { - List lists = googleTaskListDao.getActiveLists(account.getAccount()); + List lists = googleTaskListDao.getLists(account.getAccount()); Set previousLists = new HashSet<>(); for (GoogleTaskList list : lists) { @@ -96,20 +95,12 @@ public class GtasksListService { // check for lists that aren't on remote server for (Long listId : previousLists) { - deleteList(googleTaskListDao.getById(listId)); + taskDeleter.delete(googleTaskListDao.getById(listId)); } localBroadcastManager.broadcastRefreshList(); } - public void deleteList(GoogleTaskList gtasksList) { - for (Task task : taskDao.getGoogleTasks(gtasksList.getRemoteId())) { - taskDeleter.markDeleted(task); - } - googleTaskDao.deleteList(gtasksList.getRemoteId()); - googleTaskListDao.deleteById(gtasksList.getId()); - } - public List getListsToUpdate(List remoteLists) { List listsToUpdate = newArrayList(); for (TaskList remoteList : remoteLists) { diff --git a/app/src/main/java/com/todoroo/astrid/gtasks/sync/GtasksTaskContainer.java b/app/src/main/java/com/todoroo/astrid/gtasks/sync/GtasksTaskContainer.java index 86cbcf922..1a3a2cd23 100644 --- a/app/src/main/java/com/todoroo/astrid/gtasks/sync/GtasksTaskContainer.java +++ b/app/src/main/java/com/todoroo/astrid/gtasks/sync/GtasksTaskContainer.java @@ -34,14 +34,6 @@ public class GtasksTaskContainer { task.setCreationDate(DateUtilities.now()); task.setCompletionDate( GtasksApiUtilities.gtasksCompletedTimeToUnixTime(remoteTask.getCompleted())); - if (remoteTask.getDeleted() == null || !remoteTask.getDeleted()) { - task.setDeletionDate(0L); - } else { - task.setDeletionDate(DateUtilities.now()); - } - if (remoteTask.getHidden() != null && remoteTask.getHidden()) { - task.setDeletionDate(DateUtilities.now()); - } long dueDate = GtasksApiUtilities.gtasksDueTimeToUnixTime(remoteTask.getDue()); mergeDates(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate), task); diff --git a/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.java b/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.java index b183b3a8e..0b546b953 100644 --- a/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.java +++ b/app/src/main/java/com/todoroo/astrid/reminders/ReminderService.java @@ -62,6 +62,10 @@ public final class ReminderService { } } + public void cancelReminder(long taskId) { + jobs.cancelReminder(taskId); + } + public void scheduleAlarm(Task task) { if (task == null || !task.isSaved()) { return; @@ -71,7 +75,7 @@ public final class ReminderService { // Make sure no alarms are scheduled other than the next one. When that one is shown, it // will schedule the next one after it, and so on and so forth. - jobs.cancelReminder(taskId); + cancelReminder(taskId); if (task.isCompleted() || task.isDeleted()) { return; diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.java b/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.java index 6351cc573..3cb1f4ea1 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.java +++ b/app/src/main/java/com/todoroo/astrid/service/TaskDeleter.java @@ -5,81 +5,67 @@ import static com.todoroo.andlib.utility.DateUtilities.now; import static com.todoroo.astrid.dao.TaskDao.TaskCriteria.isVisible; import static com.todoroo.astrid.dao.TaskDao.TaskCriteria.notCompleted; +import com.google.common.collect.ImmutableList; import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.dao.TaskDao; import com.todoroo.astrid.data.Task; import java.util.ArrayList; import java.util.List; import javax.inject.Inject; -import org.tasks.calendars.CalendarEventProvider; -import org.tasks.data.AlarmDao; -import org.tasks.data.CaldavDao; -import org.tasks.data.GoogleTaskDao; -import org.tasks.data.LocationDao; -import org.tasks.data.TagDao; +import org.tasks.LocalBroadcastManager; +import org.tasks.data.CaldavAccount; +import org.tasks.data.CaldavCalendar; +import org.tasks.data.DeletionDao; +import org.tasks.data.GoogleTaskAccount; +import org.tasks.data.GoogleTaskList; +import org.tasks.jobs.JobManager; public class TaskDeleter { + private final JobManager jobManager; private final TaskDao taskDao; - private final CalendarEventProvider calendarEventProvider; - private final AlarmDao alarmDao; - private final LocationDao locationDao; - private final TagDao tagDao; - private final GoogleTaskDao googleTaskDao; - private final CaldavDao caldavDao; + private final LocalBroadcastManager localBroadcastManager; + private final DeletionDao deletionDao; @Inject - public TaskDeleter( - TaskDao taskDao, - CalendarEventProvider calendarEventProvider, - AlarmDao alarmDao, - LocationDao locationDao, - TagDao tagDao, - GoogleTaskDao googleTaskDao, - CaldavDao caldavDao) { + public TaskDeleter(DeletionDao deletionDao, JobManager jobManager, TaskDao taskDao, LocalBroadcastManager localBroadcastManager) { + this.deletionDao = deletionDao; + this.jobManager = jobManager; this.taskDao = taskDao; - this.calendarEventProvider = calendarEventProvider; - this.alarmDao = alarmDao; - this.locationDao = locationDao; - this.tagDao = tagDao; - this.googleTaskDao = googleTaskDao; - this.caldavDao = caldavDao; + this.localBroadcastManager = localBroadcastManager; } public int purgeDeleted() { - List deleted = taskDao.getDeleted(); - for (Task task : deleted) { - calendarEventProvider.deleteEvent(task); - long id = task.getId(); - taskDao.deleteById(id); - alarmDao.deleteByTaskId(id); - locationDao.deleteByTaskId(id); - tagDao.deleteByTaskId(id); - googleTaskDao.deleteByTaskId(id); - caldavDao.deleteById(id); - } + List deleted = deletionDao.getDeleted(); + deletionDao.delete(deleted); return deleted.size(); } public void markDeleted(Task item) { - if (!item.isSaved()) { - return; - } - - item.setDeletionDate(now()); - taskDao.save(item); + markDeleted(ImmutableList.of(item.getId())); } public List markDeleted(List taskIds) { List tasks = taskDao.fetch(taskIds); - for (Task task : tasks) { - markDeleted(task); - } + deletionDao.markDeleted(now(), taskIds); + jobManager.cleanup(taskIds); + jobManager.syncNow(); + localBroadcastManager.broadcastRefresh(); return tasks; } + public void delete(Task task) { + delete(ImmutableList.of(task.getId())); + } + + public void delete(List tasks) { + deletionDao.delete(tasks); + jobManager.cleanup(tasks); + localBroadcastManager.broadcastRefresh(); + } + public int clearCompleted(Filter filter) { - List completed = new ArrayList<>(); + List completed = new ArrayList<>(); String query = filter .getSqlQuery() @@ -87,12 +73,38 @@ public class TaskDeleter { .replace(notCompleted().toString(), all.toString()); for (Task task : taskDao.fetchFiltered(query)) { if (task.isCompleted()) { - completed.add(task); + completed.add(task.getId()); } } - for (Task task : completed) { - markDeleted(task); - } + markDeleted(completed); return completed.size(); } + + public void delete(GoogleTaskList googleTaskList) { + List ids = deletionDao.delete(googleTaskList); + jobManager.cleanup(ids); + localBroadcastManager.broadcastRefresh(); + localBroadcastManager.broadcastRefreshList(); + } + + public void delete(GoogleTaskAccount googleTaskAccount) { + List ids = deletionDao.delete(googleTaskAccount); + jobManager.cleanup(ids); + localBroadcastManager.broadcastRefresh(); + localBroadcastManager.broadcastRefreshList(); + } + + public void delete(CaldavCalendar caldavCalendar) { + List ids = deletionDao.delete(caldavCalendar); + jobManager.cleanup(ids); + localBroadcastManager.broadcastRefresh(); + localBroadcastManager.broadcastRefreshList(); + } + + public void delete(CaldavAccount caldavAccount) { + List ids = deletionDao.delete(caldavAccount); + jobManager.cleanup(ids); + localBroadcastManager.broadcastRefresh(); + localBroadcastManager.broadcastRefreshList(); + } } diff --git a/app/src/main/java/com/todoroo/astrid/service/TaskDuplicator.java b/app/src/main/java/com/todoroo/astrid/service/TaskDuplicator.java index fbcfc3dcf..114063873 100644 --- a/app/src/main/java/com/todoroo/astrid/service/TaskDuplicator.java +++ b/app/src/main/java/com/todoroo/astrid/service/TaskDuplicator.java @@ -52,7 +52,6 @@ public class TaskDuplicator { clone.setCreationDate(now()); clone.setModificationDate(now()); clone.setCompletionDate(0L); - clone.setDeletionDate(0L); clone.setCalendarUri(""); clone.setUuid(UUIDHelper.newUUID()); diff --git a/app/src/main/java/com/todoroo/astrid/timers/TimerFilterExposer.java b/app/src/main/java/com/todoroo/astrid/timers/TimerFilterExposer.java index 6ba6b0097..8cc43b1ae 100644 --- a/app/src/main/java/com/todoroo/astrid/timers/TimerFilterExposer.java +++ b/app/src/main/java/com/todoroo/astrid/timers/TimerFilterExposer.java @@ -10,6 +10,7 @@ import static java.util.Collections.emptyList; import android.content.Context; import android.content.res.Resources; +import com.todoroo.andlib.sql.Criterion; import com.todoroo.andlib.sql.QueryTemplate; import com.todoroo.astrid.api.Filter; import com.todoroo.astrid.dao.TaskDao; @@ -39,7 +40,9 @@ public final class TimerFilterExposer { Resources r = context.getResources(); Filter filter = new Filter( - r.getString(R.string.TFE_workingOn), new QueryTemplate().where(Task.TIMER_START.gt(0))); + r.getString(R.string.TFE_workingOn), + new QueryTemplate() + .where(Criterion.and(Task.TIMER_START.gt(0), Task.DELETION_DATE.eq(0)))); filter.icon = R.drawable.ic_timer_24dp; return filter; } diff --git a/app/src/main/java/com/todoroo/astrid/timers/TimerPlugin.java b/app/src/main/java/com/todoroo/astrid/timers/TimerPlugin.java index 63a1fa525..a27d00d05 100644 --- a/app/src/main/java/com/todoroo/astrid/timers/TimerPlugin.java +++ b/app/src/main/java/com/todoroo/astrid/timers/TimerPlugin.java @@ -80,7 +80,7 @@ public class TimerPlugin { updateNotifications(); } - private void updateNotifications() { + public void updateNotifications() { int count = taskDao.activeTimers(); if (count == 0) { notificationManager.cancel(Constants.NOTIFICATION_TIMER); diff --git a/app/src/main/java/org/tasks/activities/GoogleTaskListSettingsActivity.java b/app/src/main/java/org/tasks/activities/GoogleTaskListSettingsActivity.java index 2ba45b062..12a7cbb4c 100644 --- a/app/src/main/java/org/tasks/activities/GoogleTaskListSettingsActivity.java +++ b/app/src/main/java/org/tasks/activities/GoogleTaskListSettingsActivity.java @@ -23,6 +23,7 @@ import com.google.api.services.tasks.model.TaskList; import com.todoroo.astrid.activity.TaskListActivity; import com.todoroo.astrid.api.GtasksFilter; import com.todoroo.astrid.gtasks.GtasksListService; +import com.todoroo.astrid.service.TaskDeleter; import javax.inject.Inject; import org.tasks.R; import org.tasks.analytics.Tracker; @@ -63,6 +64,7 @@ public class GoogleTaskListSettingsActivity extends ThemedInjectingAppCompatActi @Inject Tracker tracker; @Inject ThemeCache themeCache; @Inject ThemeColor themeColor; + @Inject TaskDeleter taskDeleter; @BindView(R.id.name) TextInputEditText name; @@ -273,7 +275,7 @@ public class GoogleTaskListSettingsActivity extends ThemedInjectingAppCompatActi @Override public void onListDeleted() { tracker.reportEvent(Tracking.Events.GTASK_DELETE_LIST); - gtasksListService.deleteList(gtasksList); + taskDeleter.delete(gtasksList); setResult(RESULT_OK, new Intent(ACTION_DELETED)); finish(); } diff --git a/app/src/main/java/org/tasks/backup/BackupContainer.java b/app/src/main/java/org/tasks/backup/BackupContainer.java index 90f498383..c2055c392 100644 --- a/app/src/main/java/org/tasks/backup/BackupContainer.java +++ b/app/src/main/java/org/tasks/backup/BackupContainer.java @@ -10,6 +10,7 @@ import org.tasks.data.CaldavCalendar; import org.tasks.data.CaldavTask; import org.tasks.data.Filter; import org.tasks.data.GoogleTask; +import org.tasks.data.GoogleTaskAccount; import org.tasks.data.GoogleTaskList; import org.tasks.data.Location; import org.tasks.data.Tag; @@ -23,6 +24,7 @@ class BackupContainer { final List tags; final List filters; final List googleTaskLists; + private final List googleTaskAccounts; private final List caldavAccounts; private final List caldavCalendars; @@ -30,12 +32,14 @@ class BackupContainer { List tasks, List tags, List filters, + List googleTaskAccounts, List googleTaskLists, List caldavAccounts, List caldavCalendars) { this.tasks = tasks; this.tags = tags; this.filters = filters; + this.googleTaskAccounts = googleTaskAccounts; this.googleTaskLists = googleTaskLists; this.caldavAccounts = caldavAccounts; this.caldavCalendars = caldavCalendars; @@ -49,6 +53,10 @@ class BackupContainer { return caldavCalendars == null ? emptyList() : caldavCalendars; } + public List getGoogleTaskAccounts() { + return googleTaskAccounts == null ? emptyList() : googleTaskAccounts; + } + static class TaskBackup { final Task task; diff --git a/app/src/main/java/org/tasks/backup/TasksJsonExporter.java b/app/src/main/java/org/tasks/backup/TasksJsonExporter.java index dbd943bb6..60435ee9a 100755 --- a/app/src/main/java/org/tasks/backup/TasksJsonExporter.java +++ b/app/src/main/java/org/tasks/backup/TasksJsonExporter.java @@ -178,7 +178,8 @@ public class TasksJsonExporter { taskBackups, tagDataDao.getAll(), filterDao.getAll(), - googleTaskListDao.getAll(), + googleTaskListDao.getAccounts(), + googleTaskListDao.getAllLists(), caldavDao.getAccounts(), caldavDao.getCalendars())); diff --git a/app/src/main/java/org/tasks/backup/TasksJsonImporter.java b/app/src/main/java/org/tasks/backup/TasksJsonImporter.java index 4af8fa371..30bc4c9c1 100644 --- a/app/src/main/java/org/tasks/backup/TasksJsonImporter.java +++ b/app/src/main/java/org/tasks/backup/TasksJsonImporter.java @@ -25,6 +25,7 @@ import org.tasks.data.CaldavTask; import org.tasks.data.Filter; import org.tasks.data.FilterDao; import org.tasks.data.GoogleTask; +import org.tasks.data.GoogleTaskAccount; import org.tasks.data.GoogleTaskDao; import org.tasks.data.GoogleTaskList; import org.tasks.data.GoogleTaskListDao; @@ -132,6 +133,11 @@ public class TasksJsonImporter { tagDataDao.createNew(tagData); } } + for (GoogleTaskAccount googleTaskAccount : backupContainer.getGoogleTaskAccounts()) { + if (googleTaskListDao.getAccount(googleTaskAccount.getAccount()) == null) { + googleTaskListDao.insert(googleTaskAccount); + } + } for (GoogleTaskList googleTaskList : backupContainer.googleTaskLists) { if (googleTaskListDao.getByRemoteId(googleTaskList.getRemoteId()) == null) { googleTaskListDao.insert(googleTaskList); diff --git a/app/src/main/java/org/tasks/caldav/CaldavAccountSettingsActivity.java b/app/src/main/java/org/tasks/caldav/CaldavAccountSettingsActivity.java index c1d230078..485faf1c1 100644 --- a/app/src/main/java/org/tasks/caldav/CaldavAccountSettingsActivity.java +++ b/app/src/main/java/org/tasks/caldav/CaldavAccountSettingsActivity.java @@ -384,13 +384,7 @@ public class CaldavAccountSettingsActivity extends ThemedInjectingAppCompatActiv .setPositiveButton( R.string.remove, (dialog, which) -> { - for (CaldavCalendar calendar : - caldavDao.getCalendarsByAccount(caldavAccount.getUuid())) { - taskDeleter.markDeleted(caldavDao.getTasksByCalendar(calendar.getUuid())); - caldavDao.deleteTasksForCalendar(calendar.getUuid()); - } - caldavDao.deleteCalendarsForAccount(caldavAccount.getUuid()); - caldavDao.delete(caldavAccount); + taskDeleter.delete(caldavAccount); tracker.reportEvent(Events.CALDAV_ACCOUNT_REMOVED); setResult(RESULT_OK); finish(); diff --git a/app/src/main/java/org/tasks/caldav/CaldavCalendarSettingsActivity.java b/app/src/main/java/org/tasks/caldav/CaldavCalendarSettingsActivity.java index 2736037b8..bb08c7a0c 100644 --- a/app/src/main/java/org/tasks/caldav/CaldavCalendarSettingsActivity.java +++ b/app/src/main/java/org/tasks/caldav/CaldavCalendarSettingsActivity.java @@ -371,9 +371,7 @@ public class CaldavCalendarSettingsActivity extends ThemedInjectingAppCompatActi } private void onDeleted() { - taskDeleter.markDeleted(caldavDao.getTasksByCalendar(caldavCalendar.getUuid())); - caldavDao.deleteTasksForCalendar(caldavCalendar.getUuid()); - caldavDao.delete(caldavCalendar); + taskDeleter.delete(caldavCalendar); tracker.reportEvent(Events.CALDAV_LIST_DELETED); setResult(RESULT_OK, new Intent(ACTION_DELETED)); finish(); diff --git a/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.java b/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.java index e19ba3eb5..1ed42759b 100644 --- a/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.java +++ b/app/src/main/java/org/tasks/caldav/CaldavSynchronizer.java @@ -49,6 +49,7 @@ import okhttp3.ResponseBody; import org.tasks.BuildConfig; import org.tasks.LocalBroadcastManager; import org.tasks.R; +import org.tasks.billing.Inventory; import org.tasks.data.CaldavAccount; import org.tasks.data.CaldavCalendar; import org.tasks.data.CaldavDao; @@ -70,6 +71,7 @@ public class CaldavSynchronizer { private final TaskCreator taskCreator; private final TaskDeleter taskDeleter; private final Encryption encryption; + private final Inventory inventory; private final Context context; @Inject @@ -80,7 +82,8 @@ public class CaldavSynchronizer { LocalBroadcastManager localBroadcastManager, TaskCreator taskCreator, TaskDeleter taskDeleter, - Encryption encryption) { + Encryption encryption, + Inventory inventory) { this.context = context; this.caldavDao = caldavDao; this.taskDao = taskDao; @@ -88,12 +91,19 @@ public class CaldavSynchronizer { this.taskCreator = taskCreator; this.taskDeleter = taskDeleter; this.encryption = encryption; + this.inventory = inventory; } public void sync() { // required for dav4android (ServiceLoader) Thread.currentThread().setContextClassLoader(context.getClassLoader()); for (CaldavAccount account : caldavDao.getAccounts()) { + if (!inventory.hasPro()) { + account.setError(context.getString(R.string.requires_pro_subscription)); + caldavDao.update(account); + localBroadcastManager.broadcastRefreshList(); + continue; + } if (isNullOrEmpty(account.getPassword())) { account.setError(context.getString(R.string.password_required)); caldavDao.update(account); @@ -114,11 +124,9 @@ public class CaldavSynchronizer { } Set urls = newHashSet(transform(resources, c -> c.getLocation().toString())); Timber.d("Found calendars: %s", urls); - for (CaldavCalendar deleted : + for (CaldavCalendar calendar : caldavDao.findDeletedCalendars(account.getUuid(), newArrayList(urls))) { - taskDeleter.markDeleted(caldavDao.getTasksByCalendar(deleted.getUuid())); - caldavDao.deleteTasksForCalendar(deleted.getUuid()); - caldavDao.delete(deleted); + taskDeleter.delete(calendar); } for (DavResource resource : resources) { String url = resource.getLocation().toString(); @@ -239,8 +247,7 @@ public class CaldavSynchronizer { newHashSet(remoteObjects))); if (deleted.size() > 0) { Timber.d("DELETED %s", deleted); - taskDeleter.markDeleted(caldavDao.getTasks(caldavCalendar.getUuid(), deleted)); - caldavDao.deleteObjects(caldavCalendar.getUuid(), deleted); + taskDeleter.delete(caldavDao.getTasks(caldavCalendar.getUuid(), deleted)); } caldavCalendar.setCtag(remoteCtag); diff --git a/app/src/main/java/org/tasks/data/AlarmDao.java b/app/src/main/java/org/tasks/data/AlarmDao.java index 568d8600b..558528a1a 100644 --- a/app/src/main/java/org/tasks/data/AlarmDao.java +++ b/app/src/main/java/org/tasks/data/AlarmDao.java @@ -29,7 +29,4 @@ public interface AlarmDao { @Insert long insert(Alarm alarm); - - @Query("DELETE FROM alarms WHERE task = :taskId") - void deleteByTaskId(long taskId); } diff --git a/app/src/main/java/org/tasks/data/CaldavDao.java b/app/src/main/java/org/tasks/data/CaldavDao.java index 10de9f530..a3bdf438b 100644 --- a/app/src/main/java/org/tasks/data/CaldavDao.java +++ b/app/src/main/java/org/tasks/data/CaldavDao.java @@ -25,18 +25,12 @@ public interface CaldavDao { @Update void update(CaldavAccount caldavAccount); - @Delete - void delete(CaldavAccount caldavAccount); - @Insert long insert(CaldavCalendar caldavCalendar); @Update void update(CaldavCalendar caldavCalendar); - @Delete - void delete(CaldavCalendar caldavCalendar); - @Insert long insert(CaldavTask caldavTask); @@ -55,19 +49,13 @@ public interface CaldavDao { @Query("SELECT * FROM caldav_tasks WHERE calendar = :calendar AND object = :object LIMIT 1") CaldavTask getTask(String calendar, String object); - @Query("DELETE FROM caldav_tasks WHERE task = :taskId") - void deleteById(long taskId); - @Query("SELECT * FROM caldav_tasks WHERE task = :taskId") List getTasks(long taskId); - @Query("SELECT task FROM caldav_tasks WHERE calendar = :calendar AND deleted = 0") - List getTasksByCalendar(String calendar); - @Query("SELECT * FROM caldav_calendar") List getCalendars(); - @Query("SELECT * FROM caldav_calendar WHERE account = :account") + @Query("SELECT * FROM caldav_calendar WHERE account = :account ORDER BY name") List getCalendarsByAccount(String account); @Query("SELECT * FROM caldav_calendar WHERE uuid = :uuid LIMIT 1") @@ -77,21 +65,12 @@ public interface CaldavDao { "SELECT * FROM caldav_calendar WHERE account = :account AND name = :name COLLATE NOCASE LIMIT 1") CaldavCalendar getCalendar(String account, String name); - @Query("DELETE FROM caldav_calendar WHERE account = :account") - void deleteCalendarsForAccount(String account); - - @Query("DELETE FROM caldav_tasks WHERE calendar = :calendar") - void deleteTasksForCalendar(String calendar); - @Query("SELECT object FROM caldav_tasks WHERE calendar = :calendar") List getObjects(String calendar); @Query("SELECT task FROM caldav_tasks WHERE calendar = :calendar AND object IN (:objects)") List getTasks(String calendar, List objects); - @Query("DELETE FROM caldav_tasks WHERE calendar = :calendar AND object IN (:objects)") - void deleteObjects(String calendar, List objects); - @Query("SELECT * FROM caldav_calendar WHERE account = :account AND url NOT IN (:urls)") List findDeletedCalendars(String account, List urls); diff --git a/app/src/main/java/org/tasks/data/DeletionDao.java b/app/src/main/java/org/tasks/data/DeletionDao.java new file mode 100644 index 000000000..7c03c4c8f --- /dev/null +++ b/app/src/main/java/org/tasks/data/DeletionDao.java @@ -0,0 +1,105 @@ +package org.tasks.data; + +import android.arch.persistence.room.Dao; +import android.arch.persistence.room.Delete; +import android.arch.persistence.room.Query; +import android.arch.persistence.room.Transaction; +import java.util.ArrayList; +import java.util.List; + +@Dao +public abstract class DeletionDao { + @Query("SELECT _id FROM tasks WHERE deleted > 0") + public abstract List getDeleted(); + + @Query("DELETE FROM caldav_tasks WHERE task IN(:ids)") + abstract void deleteCaldavTasks(List ids); + + @Query("DELETE FROM google_tasks WHERE task IN(:ids)") + abstract void deleteGoogleTasks(List ids); + + @Query("DELETE FROM tags WHERE task IN(:ids)") + abstract void deleteTags(List ids); + + @Query("DELETE FROM locations WHERE task IN(:ids)") + abstract void deleteGeofences(List ids); + + @Query("DELETE FROM alarms WHERE task IN(:ids)") + abstract void deleteAlarms(List ids); + + @Query("DELETE FROM tasks WHERE _id IN(:ids)") + abstract void deleteTasks(List ids); + + @Transaction + public void delete(List ids) { + deleteAlarms(ids); + deleteGeofences(ids); + deleteTags(ids); + deleteGoogleTasks(ids); + deleteCaldavTasks(ids); + deleteTasks(ids); + } + + @Query("SELECT task FROM google_tasks WHERE deleted = 0 AND list_id = :listId") + abstract List getActiveGoogleTasks(String listId); + + @Delete + abstract void deleteGoogleTaskList(GoogleTaskList googleTaskList); + + @Transaction + public List delete(GoogleTaskList googleTaskList) { + List tasks = getActiveGoogleTasks(googleTaskList.getRemoteId()); + delete(tasks); + deleteGoogleTaskList(googleTaskList); + return tasks; + } + + @Delete + abstract void deleteGoogleTaskAccount(GoogleTaskAccount googleTaskAccount); + + @Query("SELECT * FROM google_task_lists WHERE account = :account ORDER BY title ASC") + abstract List getLists(String account); + + @Transaction + public List delete(GoogleTaskAccount googleTaskAccount) { + List deleted = new ArrayList<>(); + for (GoogleTaskList list : getLists(googleTaskAccount.getAccount())) { + deleted.addAll(delete(list)); + } + deleteGoogleTaskAccount(googleTaskAccount); + return deleted; + } + + @Query("UPDATE tasks SET deleted = :timestamp WHERE _id IN(:ids)") + public abstract void markDeleted(long timestamp, List ids); + + @Query("SELECT task FROM caldav_tasks WHERE calendar = :calendar AND deleted = 0") + abstract List getActiveCaldavTasks(String calendar); + + @Delete + abstract void deleteCaldavCalendar(CaldavCalendar caldavCalendar); + + @Transaction + public List delete(CaldavCalendar caldavCalendar) { + List tasks = getActiveCaldavTasks(caldavCalendar.getUuid()); + delete(tasks); + deleteCaldavCalendar(caldavCalendar); + return tasks; + } + + @Query("SELECT * FROM caldav_calendar WHERE account = :account") + abstract List getCalendars(String account); + + @Delete + abstract void deleteCaldavAccount(CaldavAccount caldavAccount); + + @Transaction + public List delete(CaldavAccount caldavAccount) { + List deleted = new ArrayList<>(); + for (CaldavCalendar calendar : getCalendars(caldavAccount.getUuid())) { + deleted.addAll(delete(calendar)); + } + deleteCaldavAccount(caldavAccount); + return deleted; + } +} diff --git a/app/src/main/java/org/tasks/data/GoogleTaskDao.java b/app/src/main/java/org/tasks/data/GoogleTaskDao.java index 920fa154e..3dad109ef 100644 --- a/app/src/main/java/org/tasks/data/GoogleTaskDao.java +++ b/app/src/main/java/org/tasks/data/GoogleTaskDao.java @@ -10,9 +10,6 @@ import java.util.List; @Dao public interface GoogleTaskDao { - @Query("DELETE FROM google_tasks WHERE list_id = :remoteId") - void deleteList(String remoteId); - @Insert void insert(GoogleTask task); @@ -34,9 +31,6 @@ public interface GoogleTaskDao { "SELECT * FROM google_tasks WHERE list_id = :listId AND `order` < :startAtOrder ORDER BY `order` DESC") List getTasksFromReverse(String listId, long startAtOrder); - @Query("DELETE FROM google_tasks WHERE task = :taskId") - void deleteByTaskId(long taskId); - @Delete void delete(GoogleTask deleted); diff --git a/app/src/main/java/org/tasks/data/GoogleTaskList.java b/app/src/main/java/org/tasks/data/GoogleTaskList.java index 2ac0b6960..ad5503a7c 100644 --- a/app/src/main/java/org/tasks/data/GoogleTaskList.java +++ b/app/src/main/java/org/tasks/data/GoogleTaskList.java @@ -43,7 +43,8 @@ public class GoogleTaskList implements Parcelable { private long lastSync; @ColumnInfo(name = "deleted") - private long deleted; + @Deprecated + private long deleted = 0; @ColumnInfo(name = "color") private Integer color; diff --git a/app/src/main/java/org/tasks/data/GoogleTaskListDao.java b/app/src/main/java/org/tasks/data/GoogleTaskListDao.java index 3578b4d60..6436b9756 100644 --- a/app/src/main/java/org/tasks/data/GoogleTaskListDao.java +++ b/app/src/main/java/org/tasks/data/GoogleTaskListDao.java @@ -5,57 +5,46 @@ import android.arch.persistence.room.Delete; import android.arch.persistence.room.Insert; import android.arch.persistence.room.OnConflictStrategy; import android.arch.persistence.room.Query; +import android.arch.persistence.room.Transaction; import android.arch.persistence.room.Update; import java.util.List; @Dao -public interface GoogleTaskListDao { +public abstract class GoogleTaskListDao { @Query("SELECT * FROM google_task_accounts") - List getAccounts(); + public abstract List getAccounts(); @Query("SELECT * FROM google_task_accounts WHERE account = :account COLLATE NOCASE LIMIT 1") - GoogleTaskAccount getAccount(String account); + public abstract GoogleTaskAccount getAccount(String account); @Query("SELECT * FROM google_task_lists WHERE _id = :id") - GoogleTaskList getById(long id); + public abstract GoogleTaskList getById(long id); - @Query("SELECT * FROM google_task_lists WHERE account = :account AND deleted = 0 ORDER BY title ASC") - List getActiveLists(String account); + @Query("SELECT * FROM google_task_lists WHERE account = :account ORDER BY title ASC") + public abstract List getLists(String account); @Query("SELECT * FROM google_task_lists WHERE remote_id = :remoteId LIMIT 1") - GoogleTaskList getByRemoteId(String remoteId); + public abstract GoogleTaskList getByRemoteId(String remoteId); @Query("SELECT * FROM google_task_lists WHERE remote_id = :remoteId AND IFNULL(account, '') = '' LIMIT 1") - GoogleTaskList findExistingList(String remoteId); + public abstract GoogleTaskList findExistingList(String remoteId); @Query("SELECT * FROM google_task_lists") - List getAll(); - - @Query("SELECT * FROM google_task_lists WHERE deleted = 0") - List getAllActiveLists(); - - @Query("DELETE FROM google_task_lists WHERE _id = :id") - void deleteById(long id); + public abstract List getAllLists(); @Insert(onConflict = OnConflictStrategy.REPLACE) - long insertOrReplace(GoogleTaskList googleTaskList); + public abstract long insertOrReplace(GoogleTaskList googleTaskList); @Insert - void insert(GoogleTaskList googleTaskList); + public abstract void insert(GoogleTaskList googleTaskList); @Insert - void insert(GoogleTaskAccount googleTaskAccount); + public abstract void insert(GoogleTaskAccount googleTaskAccount); @Update - void update(GoogleTaskList googleTaskList); + public abstract void update(GoogleTaskList googleTaskList); @Update - void update(GoogleTaskAccount account); - - @Delete - void delete(GoogleTaskList list); - - @Delete - void delete(GoogleTaskAccount account); + public abstract void update(GoogleTaskAccount account); } diff --git a/app/src/main/java/org/tasks/data/LocationDao.java b/app/src/main/java/org/tasks/data/LocationDao.java index 83dd81ad6..0755bf2f3 100644 --- a/app/src/main/java/org/tasks/data/LocationDao.java +++ b/app/src/main/java/org/tasks/data/LocationDao.java @@ -28,7 +28,4 @@ public interface LocationDao { @Insert void insert(Location location); - - @Query("DELETE FROM locations WHERE task = :taskId") - void deleteByTaskId(long taskId); } diff --git a/app/src/main/java/org/tasks/data/TagDao.java b/app/src/main/java/org/tasks/data/TagDao.java index c5cf3e5dd..fea8a5342 100644 --- a/app/src/main/java/org/tasks/data/TagDao.java +++ b/app/src/main/java/org/tasks/data/TagDao.java @@ -41,9 +41,6 @@ public interface TagDao { @Query("SELECT * FROM tags WHERE task = :taskId AND tag_uid = :tagUid") Tag getTagByTaskAndTagUid(long taskId, String tagUid); - @Query("DELETE FROM tags WHERE task = :taskId") - void deleteByTaskId(long taskId); - @Query("DELETE FROM tags WHERE _id = :id") void deleteById(long id); } diff --git a/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.java b/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.java index 48333b743..bde27ffa6 100644 --- a/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.java +++ b/app/src/main/java/org/tasks/filters/FilterCriteriaProvider.java @@ -188,7 +188,7 @@ public class FilterCriteriaProvider { } private CustomFilterCriterion getGtasksFilterCriteria() { - List lists = googleTaskListDao.getAllActiveLists(); + List lists = googleTaskListDao.getAllLists(); String[] listNames = new String[lists.size()]; String[] listIds = new String[lists.size()]; diff --git a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java index 9c764592b..61b42c906 100644 --- a/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java +++ b/app/src/main/java/org/tasks/gtasks/GoogleTaskSynchronizer.java @@ -26,6 +26,7 @@ import com.todoroo.astrid.gtasks.api.HttpNotFoundException; import com.todoroo.astrid.gtasks.sync.GtasksSyncService; import com.todoroo.astrid.gtasks.sync.GtasksTaskContainer; import com.todoroo.astrid.service.TaskCreator; +import com.todoroo.astrid.service.TaskDeleter; import com.todoroo.astrid.utility.Constants; import java.io.IOException; import java.util.ArrayList; @@ -34,6 +35,7 @@ import javax.inject.Inject; import org.tasks.LocalBroadcastManager; import org.tasks.R; import org.tasks.analytics.Tracker; +import org.tasks.billing.Inventory; import org.tasks.data.GoogleTask; import org.tasks.data.GoogleTaskAccount; import org.tasks.data.GoogleTaskDao; @@ -67,6 +69,8 @@ public class GoogleTaskSynchronizer { private final PermissionChecker permissionChecker; private final GoogleAccountManager googleAccountManager; private final LocalBroadcastManager localBroadcastManager; + private final Inventory inventory; + private final TaskDeleter taskDeleter; @Inject public GoogleTaskSynchronizer( @@ -85,7 +89,9 @@ public class GoogleTaskSynchronizer { PlayServices playServices, PermissionChecker permissionChecker, GoogleAccountManager googleAccountManager, - LocalBroadcastManager localBroadcastManager) { + LocalBroadcastManager localBroadcastManager, + Inventory inventory, + TaskDeleter taskDeleter) { this.context = context; this.googleTaskListDao = googleTaskListDao; this.gtasksSyncService = gtasksSyncService; @@ -102,6 +108,8 @@ public class GoogleTaskSynchronizer { this.permissionChecker = permissionChecker; this.googleAccountManager = googleAccountManager; this.localBroadcastManager = localBroadcastManager; + this.inventory = inventory; + this.taskDeleter = taskDeleter; } public static void mergeDates(long remoteDueDate, Task local) { @@ -120,11 +128,16 @@ public class GoogleTaskSynchronizer { } public void sync() { - for (GoogleTaskAccount account : googleTaskListDao.getAccounts()) { + List accounts = googleTaskListDao.getAccounts(); + for (int i = 0 ; i < accounts.size() ; i++) { + GoogleTaskAccount account = accounts.get(i); Timber.d("%s: start sync", account); try { - synchronize(account); - account.setError(""); + if (i == 0 || inventory.hasPro()) { + synchronize(account); + } else { + account.setError(context.getString(R.string.requires_pro_subscription)); + } } catch (UserRecoverableAuthIOException e) { Timber.e(e); sendNotification(context, e.getIntent()); @@ -196,6 +209,7 @@ public class GoogleTaskSynchronizer { for (final GoogleTaskList list : gtasksListService.getListsToUpdate(gtaskLists)) { fetchAndApplyRemoteChanges(gtasksInvoker, list); } + account.setError(""); } private void pushLocalChanges(GtasksInvoker gtasksInvoker) throws UserRecoverableAuthIOException { @@ -345,6 +359,14 @@ public class GoogleTaskSynchronizer { } else if (googleTask.getTask() > 0) { task = taskDao.fetch(googleTask.getTask()); } + Boolean isDeleted = gtask.getDeleted(); + Boolean isHidden = gtask.getHidden(); + if ((isDeleted != null && isDeleted) || (isHidden != null && isHidden)) { + if (task != null) { + taskDeleter.delete(task); + } + continue; + } if (task == null) { task = taskCreator.createWithValues(null, ""); } diff --git a/app/src/main/java/org/tasks/injection/ApplicationModule.java b/app/src/main/java/org/tasks/injection/ApplicationModule.java index a167ebb95..528753859 100644 --- a/app/src/main/java/org/tasks/injection/ApplicationModule.java +++ b/app/src/main/java/org/tasks/injection/ApplicationModule.java @@ -16,6 +16,7 @@ import org.tasks.ErrorReportingSingleThreadExecutor; import org.tasks.analytics.Tracker; import org.tasks.data.AlarmDao; import org.tasks.data.CaldavDao; +import org.tasks.data.DeletionDao; import org.tasks.data.FilterDao; import org.tasks.data.GoogleTaskDao; import org.tasks.data.GoogleTaskListDao; @@ -149,6 +150,12 @@ public class ApplicationModule { return taskDao; } + @Provides + @ApplicationScope + public DeletionDao getDeletionDao(Database database) { + return database.getDeletionDao(); + } + @Provides @ApplicationScope public JobManager getJobManager() { diff --git a/app/src/main/java/org/tasks/injection/JobComponent.java b/app/src/main/java/org/tasks/injection/JobComponent.java index 2fe98d858..b425cf538 100644 --- a/app/src/main/java/org/tasks/injection/JobComponent.java +++ b/app/src/main/java/org/tasks/injection/JobComponent.java @@ -3,6 +3,7 @@ package org.tasks.injection; import dagger.Subcomponent; import org.tasks.jobs.AfterSaveIntentService; import org.tasks.jobs.BackupJob; +import org.tasks.jobs.CleanupJob; import org.tasks.jobs.NotificationJob; import org.tasks.jobs.RefreshJob; import org.tasks.jobs.SyncJob; @@ -23,4 +24,6 @@ public interface JobComponent { void inject(BackupJob backupJob); void inject(RefreshJob refreshJob); + + void inject(CleanupJob cleanupJob); } diff --git a/app/src/main/java/org/tasks/jobs/CleanupJob.java b/app/src/main/java/org/tasks/jobs/CleanupJob.java new file mode 100644 index 000000000..5d6822fe5 --- /dev/null +++ b/app/src/main/java/org/tasks/jobs/CleanupJob.java @@ -0,0 +1,50 @@ +package org.tasks.jobs; + +import android.support.annotation.NonNull; +import com.evernote.android.job.util.support.PersistableBundleCompat; +import com.todoroo.astrid.alarms.AlarmService; +import com.todoroo.astrid.reminders.ReminderService; +import com.todoroo.astrid.timers.TimerPlugin; +import javax.inject.Inject; +import org.tasks.injection.InjectingJob; +import org.tasks.injection.JobComponent; +import org.tasks.location.GeofenceService; +import org.tasks.notifications.NotificationManager; +import timber.log.Timber; + +public class CleanupJob extends InjectingJob { + + static final String EXTRA_TASK_IDS = "extra_task_ids"; + + @Inject NotificationManager notificationManager; + @Inject GeofenceService geofenceService; + @Inject TimerPlugin timerPlugin; + @Inject ReminderService reminderService; + @Inject AlarmService alarmService; + + @NonNull + @Override + protected Result onRunJob(@NonNull Params params) { + super.onRunJob(params); + + PersistableBundleCompat extras = params.getExtras(); + long[] tasks = extras.getLongArray(EXTRA_TASK_IDS); + if (tasks == null) { + Timber.e("No task ids provided"); + return Result.FAILURE; + } + for (long task : tasks) { + alarmService.cancelAlarms(task); + reminderService.cancelReminder(task); + notificationManager.cancel(task); + geofenceService.cancelGeofences(task); + } + timerPlugin.updateNotifications(); + return Result.SUCCESS; + } + + @Override + protected void inject(JobComponent component) { + component.inject(this); + } +} diff --git a/app/src/main/java/org/tasks/jobs/JobCreator.java b/app/src/main/java/org/tasks/jobs/JobCreator.java index 29eb0f8f7..7e852bf26 100644 --- a/app/src/main/java/org/tasks/jobs/JobCreator.java +++ b/app/src/main/java/org/tasks/jobs/JobCreator.java @@ -16,6 +16,7 @@ public class JobCreator implements com.evernote.android.job.JobCreator { static final String TAG_NOTIFICATION = "tag_notification"; static final String TAG_BACKGROUND_SYNC = "tag_background_sync"; static final String TAG_SYNC = "tag_sync"; + static final String TAG_CLEANUP = "tag_cleanup"; @Inject public JobCreator() {} @@ -34,6 +35,8 @@ public class JobCreator implements com.evernote.android.job.JobCreator { case TAG_MIDNIGHT_REFRESH: case TAG_REFRESH: return new RefreshJob(); + case TAG_CLEANUP: + return new CleanupJob(); default: Timber.e("Unhandled tag: %s", tag); return null; diff --git a/app/src/main/java/org/tasks/jobs/JobManager.java b/app/src/main/java/org/tasks/jobs/JobManager.java index 267d92eeb..aff422880 100644 --- a/app/src/main/java/org/tasks/jobs/JobManager.java +++ b/app/src/main/java/org/tasks/jobs/JobManager.java @@ -1,5 +1,6 @@ package org.tasks.jobs; +import static org.tasks.jobs.CleanupJob.EXTRA_TASK_IDS; import static org.tasks.time.DateTimeUtils.currentTimeMillis; import static org.tasks.time.DateTimeUtils.printTimestamp; @@ -7,6 +8,9 @@ import com.evernote.android.job.DailyJob; import com.evernote.android.job.JobRequest; import com.evernote.android.job.JobRequest.Builder; import com.evernote.android.job.JobRequest.NetworkType; +import com.evernote.android.job.util.support.PersistableBundleCompat; +import com.google.common.primitives.Longs; +import java.util.List; import java.util.concurrent.TimeUnit; import javax.annotation.Nullable; import javax.inject.Inject; @@ -45,6 +49,12 @@ public class JobManager { this.googleTaskListDao = googleTaskListDao; } + public void cleanup(List ids) { + PersistableBundleCompat extras = new PersistableBundleCompat(); + extras.putLongArray(EXTRA_TASK_IDS, Longs.toArray(ids)); + new JobRequest.Builder(JobCreator.TAG_CLEANUP).setExtras(extras).startNow().build().schedule(); + } + public void scheduleNotification(long time) { Timber.d("schedule notification: %s", printTimestamp(time)); new JobRequest.Builder(JobCreator.TAG_NOTIFICATION) diff --git a/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java b/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java index baea0fb39..eac708e49 100644 --- a/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java +++ b/app/src/main/java/org/tasks/sync/SynchronizationPreferences.java @@ -16,7 +16,6 @@ import android.support.annotation.NonNull; import android.support.v7.app.AlertDialog; import com.todoroo.astrid.gtasks.auth.GtasksLoginActivity; import com.todoroo.astrid.service.TaskDeleter; -import java.util.List; import javax.inject.Inject; import org.tasks.R; import org.tasks.analytics.Tracker; @@ -28,7 +27,6 @@ import org.tasks.data.CaldavAccount; import org.tasks.data.CaldavDao; import org.tasks.data.GoogleTaskAccount; import org.tasks.data.GoogleTaskDao; -import org.tasks.data.GoogleTaskList; import org.tasks.data.GoogleTaskListDao; import org.tasks.dialogs.DialogBuilder; import org.tasks.gtasks.GoogleAccountManager; @@ -146,11 +144,7 @@ public class SynchronizationPreferences extends InjectingPreferenceActivity { .setPositiveButton( R.string.logout, (dialog, which) -> { - for (GoogleTaskList list : googleTaskListDao.getActiveLists(name)) { - taskDeleter.markDeleted(googleTaskDao.getActiveTasks(list.getRemoteId())); - googleTaskListDao.delete(list); - } - googleTaskListDao.delete(account); + taskDeleter.delete(account); restart(); }) .setNegativeButton(android.R.string.cancel, null) @@ -273,6 +267,11 @@ public class SynchronizationPreferences extends InjectingPreferenceActivity { } } + @Override + protected String getHelpUrl() { + return "http://tasks.org/subscribe"; + } + @Override public void inject(ActivityComponent component) { component.inject(this);