diff --git a/app/src/main/java/org/tasks/data/CaldavDao.kt b/app/src/main/java/org/tasks/data/CaldavDao.kt index f1d4ffbf2..ac09797dd 100644 --- a/app/src/main/java/org/tasks/data/CaldavDao.kt +++ b/app/src/main/java/org/tasks/data/CaldavDao.kt @@ -20,6 +20,9 @@ import org.tasks.time.DateTimeUtils.currentTimeMillis @Dao abstract class CaldavDao { + @Query("SELECT COUNT(*) FROM caldav_lists WHERE cdl_account = :account") + abstract fun listCount(account: String): Int + @Query("SELECT * FROM caldav_lists") abstract fun subscribeToCalendars(): LiveData> diff --git a/app/src/main/java/org/tasks/injection/BaseWorker.kt b/app/src/main/java/org/tasks/injection/BaseWorker.kt index 1a06b7ab9..309fa1f53 100644 --- a/app/src/main/java/org/tasks/injection/BaseWorker.kt +++ b/app/src/main/java/org/tasks/injection/BaseWorker.kt @@ -22,8 +22,12 @@ abstract class BaseWorker( } catch (e: Exception) { firebase.reportException(e) Result.failure() + } finally { + destroy() } } protected abstract suspend fun run(): Result + + protected open fun destroy() {} } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/MigrateLocalWork.kt b/app/src/main/java/org/tasks/jobs/MigrateLocalWork.kt new file mode 100644 index 000000000..13a1a39dc --- /dev/null +++ b/app/src/main/java/org/tasks/jobs/MigrateLocalWork.kt @@ -0,0 +1,45 @@ +package org.tasks.jobs + +import android.content.Context +import androidx.hilt.Assisted +import androidx.hilt.work.WorkerInject +import androidx.work.WorkerParameters +import org.tasks.R +import org.tasks.analytics.Firebase +import org.tasks.caldav.CaldavClientProvider +import org.tasks.data.CaldavDao +import org.tasks.injection.BaseWorker +import org.tasks.preferences.Preferences +import org.tasks.sync.SyncAdapters + +class MigrateLocalWork @WorkerInject constructor( + @Assisted context: Context, + @Assisted workerParams: WorkerParameters, + firebase: Firebase, + private val clientProvider: CaldavClientProvider, + private val caldavDao: CaldavDao, + private val preferences: Preferences, + private val syncAdapters: SyncAdapters +) : BaseWorker(context, workerParams, firebase) { + override suspend fun run(): Result { + val uuid = inputData.getString(EXTRA_ACCOUNT) ?: return Result.failure() + val caldavAccount = caldavDao.getAccountByUuid(uuid) ?: return Result.failure() + val caldavClient = clientProvider.forAccount(caldavAccount) + caldavDao.getCalendarsByAccount(CaldavDao.LOCAL).forEach { + it.url = caldavClient.makeCollection(it.name!!, it.color) + it.account = caldavAccount.uuid + caldavDao.update(it) + } + preferences.setBoolean(R.string.p_lists_enabled, false) + syncAdapters.sync() + return Result.success() + } + + override fun destroy() { + clientProvider.dispose() + } + + companion object { + const val EXTRA_ACCOUNT = "extra_account" + } +} \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/WorkManager.kt b/app/src/main/java/org/tasks/jobs/WorkManager.kt index afec321e2..4495777a5 100644 --- a/app/src/main/java/org/tasks/jobs/WorkManager.kt +++ b/app/src/main/java/org/tasks/jobs/WorkManager.kt @@ -3,6 +3,7 @@ package org.tasks.jobs import android.net.Uri import com.todoroo.astrid.data.Task import org.tasks.BuildConfig +import org.tasks.data.CaldavAccount import org.tasks.data.Place interface WorkManager { @@ -13,6 +14,8 @@ interface WorkManager { fun cleanup(ids: Iterable) + fun migrateLocalTasks(caldavAccount: CaldavAccount) + fun googleTaskSync(immediate: Boolean) fun caldavSync(immediate: Boolean) @@ -57,5 +60,6 @@ interface WorkManager { const val TAG_BACKGROUND_SYNC_ETESYNC = "tag_background_sync_etesync" const val TAG_BACKGROUND_SYNC_OPENTASKS = "tag_background_sync_opentasks" const val TAG_REMOTE_CONFIG = "tag_remote_config" + const val TAG_MIGRATE_LOCAL = "tag_migrate_local" } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt b/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt index aada6e6c5..849e0a757 100644 --- a/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt +++ b/app/src/main/java/org/tasks/jobs/WorkManagerImpl.kt @@ -12,16 +12,14 @@ import com.todoroo.andlib.utility.DateUtilities import com.todoroo.astrid.data.Task import org.tasks.BuildConfig import org.tasks.R +import org.tasks.data.* import org.tasks.data.CaldavAccount.Companion.TYPE_CALDAV import org.tasks.data.CaldavAccount.Companion.TYPE_ETESYNC import org.tasks.data.CaldavAccount.Companion.TYPE_OPENTASKS import org.tasks.data.CaldavAccount.Companion.TYPE_TASKS -import org.tasks.data.CaldavDao -import org.tasks.data.GoogleTaskListDao -import org.tasks.data.OpenTaskDao -import org.tasks.data.Place import org.tasks.date.DateTimeUtils.midnight import org.tasks.date.DateTimeUtils.newDateTime +import org.tasks.jobs.MigrateLocalWork.Companion.EXTRA_ACCOUNT import org.tasks.jobs.SyncWork.Companion.EXTRA_IMMEDIATE import org.tasks.jobs.WorkManager.Companion.MAX_CLEANUP_LENGTH import org.tasks.jobs.WorkManager.Companion.REMOTE_CONFIG_INTERVAL_HOURS @@ -31,6 +29,7 @@ import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_GOOGLE_TASKS import org.tasks.jobs.WorkManager.Companion.TAG_BACKGROUND_SYNC_OPENTASKS import org.tasks.jobs.WorkManager.Companion.TAG_BACKUP import org.tasks.jobs.WorkManager.Companion.TAG_MIDNIGHT_REFRESH +import org.tasks.jobs.WorkManager.Companion.TAG_MIGRATE_LOCAL import org.tasks.jobs.WorkManager.Companion.TAG_REFRESH import org.tasks.jobs.WorkManager.Companion.TAG_REMOTE_CONFIG import org.tasks.jobs.WorkManager.Companion.TAG_SYNC_CALDAV @@ -72,6 +71,16 @@ class WorkManagerImpl constructor( .build())) } + @SuppressLint("EnqueueWork") + override fun migrateLocalTasks(caldavAccount: CaldavAccount) { + val builder = OneTimeWorkRequest.Builder(MigrateLocalWork::class.java) + .setInputData(Data.Builder().putString(EXTRA_ACCOUNT, caldavAccount.uuid).build()) + .setConstraints(Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build()) + enqueue(workManager.beginUniqueWork(TAG_MIGRATE_LOCAL, ExistingWorkPolicy.APPEND_OR_REPLACE, builder.build())) + } + override fun cleanup(ids: Iterable) { ids.chunked(MAX_CLEANUP_LENGTH) { enqueue( @@ -250,7 +259,7 @@ class WorkManagerImpl constructor( } @SuppressLint("EnqueueWork") - private fun enqueueUnique(key: String, c: Class, time: Long) { + private fun enqueueUnique(key: String, c: Class, time: Long = 0) { val delay = time - DateUtilities.now() val builder = OneTimeWorkRequest.Builder(c) if (delay > 0) { diff --git a/app/src/main/java/org/tasks/preferences/fragments/TasksAccount.kt b/app/src/main/java/org/tasks/preferences/fragments/TasksAccount.kt index 9556a391f..99fcdc5e8 100644 --- a/app/src/main/java/org/tasks/preferences/fragments/TasksAccount.kt +++ b/app/src/main/java/org/tasks/preferences/fragments/TasksAccount.kt @@ -20,7 +20,9 @@ import org.tasks.billing.PurchaseDialog import org.tasks.data.CaldavAccount import org.tasks.data.CaldavDao import org.tasks.injection.InjectingPreferenceFragment +import org.tasks.jobs.WorkManager import org.tasks.preferences.IconPreference +import org.tasks.ui.Toaster import java.net.HttpURLConnection.HTTP_PAYMENT_REQUIRED import java.net.HttpURLConnection.HTTP_UNAUTHORIZED import javax.inject.Inject @@ -34,6 +36,8 @@ class TasksAccount : InjectingPreferenceFragment() { @Inject lateinit var inventory: Inventory @Inject lateinit var localBroadcastManager: LocalBroadcastManager @Inject lateinit var caldavDao: CaldavDao + @Inject lateinit var workManager: WorkManager + @Inject lateinit var toaster: Toaster lateinit var caldavAccount: CaldavAccount @@ -81,6 +85,12 @@ class TasksAccount : InjectingPreferenceFragment() { false } + findPreference(R.string.offline_lists).setOnPreferenceClickListener { + workManager.migrateLocalTasks(caldavAccount) + toaster.longToast(R.string.migrating_tasks) + false + } + refreshUi() } @@ -111,6 +121,14 @@ class TasksAccount : InjectingPreferenceFragment() { iconVisible = true } + lifecycleScope.launch { + val listCount = caldavDao.listCount(CaldavDao.LOCAL) + val quantityString = resources.getQuantityString(R.plurals.list_count, listCount, listCount) + findPreference(R.string.migrate).isVisible = listCount > 0 + findPreference(R.string.offline_lists).summary = + getString(R.string.migrate_count, quantityString) + } + if (BuildConfig.FLAVOR == "generic") { return } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d94d0e208..e1ed557c6 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -217,6 +217,10 @@ File %1$s contained %2$s.\n\n %d subtask %d subtasks + + %d list + %d lists + time times @@ -669,4 +673,8 @@ File %1$s contained %2$s.\n\n Sign in with Google Authentication required Sponsor + Migrate + Migrating tasks + Offline lists + Move %s to Tasks.org diff --git a/app/src/main/res/xml/preferences_tasks.xml b/app/src/main/res/xml/preferences_tasks.xml index e5d524ced..b0b57ed75 100644 --- a/app/src/main/res/xml/preferences_tasks.xml +++ b/app/src/main/res/xml/preferences_tasks.xml @@ -27,6 +27,16 @@ android:title="@string/refresh_purchases" app:icon="@drawable/ic_cached_24px" /> + + + + + +