From 546ce57e5c47195c1bdbb1d83a39a4f15f1ce293 Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Wed, 3 Dec 2025 13:01:40 +0100 Subject: [PATCH 1/3] LocalTask: Don't subclass DmfsTask Signed-off-by: Sunik Kupfer --- .../at/bitfire/davdroid/resource/LocalTask.kt | 74 ++++++++----------- gradle/libs.versions.toml | 2 +- 2 files changed, 32 insertions(+), 44 deletions(-) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTask.kt b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTask.kt index 9c54f04ca0..ee88ddbb2e 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTask.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTask.kt @@ -10,35 +10,42 @@ import android.content.Context import android.net.Uri import androidx.core.content.contentValuesOf import at.bitfire.ical4android.DmfsTask -import at.bitfire.ical4android.DmfsTaskFactory -import at.bitfire.ical4android.DmfsTaskList -import at.bitfire.ical4android.Task import at.bitfire.ical4android.TaskProvider import com.google.common.base.MoreObjects import org.dmfs.tasks.contract.TaskContract.Tasks import java.util.Optional +import java.util.logging.Logger /** * Represents a Dmfs Task (OpenTasks and Tasks.org) entry */ -class LocalTask: DmfsTask, LocalResource { +class LocalTask( + val dmfsTask: DmfsTask +): LocalResource { - override var fileName: String? = null + val logger: Logger = Logger.getLogger(javaClass.name) - /** - * Note: Schedule-Tag for tasks is not supported - */ - override var scheduleTag: String? = null + // LocalResource implementation + + override val id: Long? + get() = dmfsTask.id - constructor(taskList: DmfsTaskList<*>, task: Task, fileName: String?, eTag: String?, flags: Int) - : super(taskList, task, fileName, eTag, flags) + override var fileName: String? + get() = dmfsTask.syncId + set(value) { dmfsTask.syncId = value } - private constructor(taskList: DmfsTaskList<*>, values: ContentValues) - : super(taskList, values) + override var eTag: String? + get() = dmfsTask.eTag + set(value) { dmfsTask.eTag = value } + /** + * Note: Schedule-Tag for tasks is not supported + */ + override var scheduleTag: String? = null - /* custom queries */ + override val flags: Int + get() = dmfsTask.flags override fun clearDirty(fileName: Optional, eTag: String?, scheduleTag: String?) { if (scheduleTag != null) @@ -47,46 +54,33 @@ class LocalTask: DmfsTask, LocalResource { val values = ContentValues(4) if (fileName.isPresent) values.put(Tasks._SYNC_ID, fileName.get()) - values.put(COLUMN_ETAG, eTag) - values.put(Tasks.SYNC_VERSION, task!!.sequence) + values.put(DmfsTask.COLUMN_ETAG, eTag) + values.put(Tasks.SYNC_VERSION, dmfsTask.task!!.sequence) values.put(Tasks._DIRTY, 0) - taskList.provider.update(taskSyncURI(), values, null, null) + dmfsTask.update(values) if (fileName.isPresent) this.fileName = fileName.get() this.eTag = eTag } - fun update(data: Task, fileName: String?, eTag: String?, scheduleTag: String?, flags: Int) { - if (scheduleTag != null) - logger.fine("Schedule-Tag for tasks not supported, won't save") - - this.fileName = fileName - this.eTag = eTag - this.flags = flags - - // processes this.{fileName, eTag, scheduleTag, flags} and resets DIRTY flag - update(data) - } - override fun updateFlags(flags: Int) { if (id != null) { - val values = contentValuesOf(COLUMN_FLAGS to flags) - taskList.provider.update(taskSyncURI(), values, null, null) + val values = contentValuesOf(DmfsTask.COLUMN_FLAGS to flags) + dmfsTask.update(values) } - - this.flags = flags + dmfsTask.flags = flags } override fun updateSequence(sequence: Int) = throw NotImplementedError() override fun updateUid(uid: String) { val values = contentValuesOf(Tasks._UID to uid) - taskList.provider.update(taskSyncURI(), values, null, null) + dmfsTask.update(values) } override fun deleteLocal() { - delete() + dmfsTask.delete() } override fun resetDeleted() { @@ -110,9 +104,9 @@ class LocalTask: DmfsTask, LocalResource { .toString() override fun getViewUri(context: Context): Uri? = id?.let { id -> - when (taskList.providerName) { + when (dmfsTask.taskList.providerName) { TaskProvider.ProviderName.OpenTasks -> { - val contentUri = Tasks.getContentUri(taskList.providerName.authority) + val contentUri = Tasks.getContentUri(dmfsTask.taskList.providerName.authority) ContentUris.withAppendedId(contentUri, id) } // Tasks.org can't handle view content URIs (missing intent-filter) @@ -121,10 +115,4 @@ class LocalTask: DmfsTask, LocalResource { } } - - object Factory: DmfsTaskFactory { - override fun fromProvider(taskList: DmfsTaskList<*>, values: ContentValues) = - LocalTask(taskList, values) - } - } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9bdae503eb..c65b7bdb27 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,7 @@ androidx-test-junit = "1.3.0" androidx-work = "2.11.0" bitfire-cert4android = "42d883e958" bitfire-dav4jvm = "acd9bca096" -bitfire-synctools = "ad0c68d820" +bitfire-synctools = "91de363117" compose-accompanist = "0.37.3" compose-bom = "2025.11.01" conscrypt = "2.5.3" From d37dcd1437d275c9f8408e86f0b3c9e6f971d17d Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Wed, 3 Dec 2025 13:35:28 +0100 Subject: [PATCH 2/3] Adapt usages Signed-off-by: Sunik Kupfer --- .../at/bitfire/davdroid/resource/LocalTask.kt | 7 +++++++ .../at/bitfire/davdroid/resource/LocalTaskList.kt | 14 +++++++++----- .../migration/AccountSettingsMigration10.kt | 1 - .../at/bitfire/davdroid/sync/TasksSyncManager.kt | 5 +++-- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTask.kt b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTask.kt index ee88ddbb2e..87fb7de657 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTask.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTask.kt @@ -10,6 +10,7 @@ import android.content.Context import android.net.Uri import androidx.core.content.contentValuesOf import at.bitfire.ical4android.DmfsTask +import at.bitfire.ical4android.Task import at.bitfire.ical4android.TaskProvider import com.google.common.base.MoreObjects import org.dmfs.tasks.contract.TaskContract.Tasks @@ -47,6 +48,12 @@ class LocalTask( override val flags: Int get() = dmfsTask.flags + fun add() = dmfsTask.add() + + fun update(data: Task) = dmfsTask.update(data) + + fun delete() = dmfsTask.delete() + override fun clearDirty(fileName: Optional, eTag: String?, scheduleTag: String?) { if (scheduleTag != null) logger.fine("Schedule-Tag for tasks not supported, won't save") diff --git a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTaskList.kt b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTaskList.kt index 4408042809..e739342cc2 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTaskList.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/resource/LocalTaskList.kt @@ -26,7 +26,7 @@ class LocalTaskList private constructor( provider: ContentProviderClient, providerName: TaskProvider.ProviderName, id: Long -): DmfsTaskList(account, provider, providerName, LocalTask.Factory, id), LocalCollection { +): DmfsTaskList(account, provider, providerName, id), LocalCollection { private val logger = Logger.getGlobal() @@ -51,10 +51,11 @@ class LocalTaskList private constructor( } override fun findDeleted() = queryTasks(Tasks._DELETED, null) + .map { LocalTask(it) } override fun findDirty(): List { - val tasks = queryTasks(Tasks._DIRTY, null) - for (localTask in tasks) { + val dmfsTasks = queryTasks(Tasks._DIRTY, null) + for (localTask in dmfsTasks) { try { val task = requireNotNull(localTask.task) val sequence = task.sequence @@ -66,11 +67,14 @@ class LocalTaskList private constructor( logger.log(Level.WARNING, "Couldn't check/increase sequence", e) } } - return tasks + return dmfsTasks.map { LocalTask(it) } } override fun findByName(name: String) = - queryTasks("${Tasks._SYNC_ID}=?", arrayOf(name)).firstOrNull() + queryTasks("${Tasks._SYNC_ID}=?", arrayOf(name)) + .firstOrNull()?.let { + LocalTask(it) + } override fun markNotDirty(flags: Int): Int { diff --git a/app/src/main/kotlin/at/bitfire/davdroid/settings/migration/AccountSettingsMigration10.kt b/app/src/main/kotlin/at/bitfire/davdroid/settings/migration/AccountSettingsMigration10.kt index 21bcd9248c..a934453517 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/settings/migration/AccountSettingsMigration10.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/settings/migration/AccountSettingsMigration10.kt @@ -12,7 +12,6 @@ import android.provider.CalendarContract.Calendars import android.provider.CalendarContract.Reminders import androidx.core.content.ContextCompat import androidx.core.content.contentValuesOf -import at.bitfire.davdroid.resource.LocalTask import at.bitfire.ical4android.DmfsTask import at.bitfire.ical4android.TaskProvider import at.techbee.jtx.JtxContract.asSyncAdapter diff --git a/app/src/main/kotlin/at/bitfire/davdroid/sync/TasksSyncManager.kt b/app/src/main/kotlin/at/bitfire/davdroid/sync/TasksSyncManager.kt index dc14b2ed39..eacb2e5c4c 100644 --- a/app/src/main/kotlin/at/bitfire/davdroid/sync/TasksSyncManager.kt +++ b/app/src/main/kotlin/at/bitfire/davdroid/sync/TasksSyncManager.kt @@ -25,6 +25,7 @@ import at.bitfire.davdroid.resource.LocalTaskList import at.bitfire.davdroid.resource.SyncState import at.bitfire.davdroid.util.DavUtils import at.bitfire.davdroid.util.DavUtils.lastSegment +import at.bitfire.ical4android.DmfsTask import at.bitfire.ical4android.Task import at.bitfire.synctools.exception.InvalidICalendarException import dagger.assisted.Assisted @@ -103,7 +104,7 @@ class TasksSyncManager @AssistedInject constructor( override fun syncAlgorithm() = SyncAlgorithm.PROPFIND_REPORT override fun generateUpload(resource: LocalTask): GeneratedResource { - val task = requireNotNull(resource.task) + val task = requireNotNull(resource.dmfsTask.task) logger.log(Level.FINE, "Preparing upload of task ${resource.id}", task) // get/create UID @@ -191,7 +192,7 @@ class TasksSyncManager @AssistedInject constructor( local.update(newData) } else { logger.log(Level.INFO, "Adding $fileName to local task list", newData) - val newLocal = LocalTask(localCollection, newData, fileName, eTag, LocalResource.FLAG_REMOTELY_PRESENT) + val newLocal = LocalTask(DmfsTask(localCollection, newData, fileName, eTag, LocalResource.FLAG_REMOTELY_PRESENT)) SyncException.wrapWithLocalResource(newLocal) { newLocal.add() } From 833eef66c312715ff6c627a99cedf50d1b7c865b Mon Sep 17 00:00:00 2001 From: Sunik Kupfer Date: Mon, 8 Dec 2025 13:59:49 +0100 Subject: [PATCH 3/3] Update synctools Signed-off-by: Sunik Kupfer --- gradle/libs.versions.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index c65b7bdb27..4f6b915d78 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,7 +20,7 @@ androidx-test-junit = "1.3.0" androidx-work = "2.11.0" bitfire-cert4android = "42d883e958" bitfire-dav4jvm = "acd9bca096" -bitfire-synctools = "91de363117" +bitfire-synctools = "de78892b5c" compose-accompanist = "0.37.3" compose-bom = "2025.11.01" conscrypt = "2.5.3"