Skip to content

Commit ddedfe4

Browse files
committed
Refactor DmfsTask to use Entity for task data
1 parent a2eada8 commit ddedfe4

2 files changed

Lines changed: 69 additions & 30 deletions

File tree

lib/src/main/kotlin/at/bitfire/ical4android/DmfsTask.kt

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ package at.bitfire.ical4android
88

99
import android.content.ContentUris
1010
import android.content.ContentValues
11+
import android.content.Entity
1112
import android.net.Uri
1213
import android.os.RemoteException
1314
import at.bitfire.synctools.mapping.tasks.DmfsTaskBuilder
@@ -20,47 +21,44 @@ import at.bitfire.synctools.storage.toContentValues
2021
import net.fortuna.ical4j.model.Parameter
2122
import net.fortuna.ical4j.model.parameter.RelType
2223
import net.fortuna.ical4j.model.property.RelatedTo
24+
import org.dmfs.tasks.contract.TaskContract
2325
import org.dmfs.tasks.contract.TaskContract.Properties
2426
import org.dmfs.tasks.contract.TaskContract.Tasks
2527
import java.io.FileNotFoundException
2628
import java.util.logging.Level
2729
import java.util.logging.Logger
2830

2931
/**
30-
* Stores and retrieves VTODO iCalendar objects (represented as [Task]s) to/from the
31-
* tasks.org-content provider (currently tasks.org and OpenTasks).
32+
* Stores and retrieves tasks to/from the tasks.org-content provider (currently tasks.org and
33+
* OpenTasks).
3234
*
33-
* Extend this class to process specific fields of the task.
35+
* A task in the context of this class is one row in the [TaskContract.Tasks] table,
36+
* plus associated data rows (like alarms and reminders).
37+
*
38+
* Exceptions (of recurring tasks) have their own entries in the [TaskContract.Tasks] table and thus
39+
* are separate.
3440
*
3541
* The SEQUENCE field is stored in [Tasks.SYNC_VERSION], so don't use [Tasks.SYNC_VERSION]
3642
* for anything else.
43+
*
44+
* @param taskList task list where the task is stored
45+
* @param values entity with all columns, as returned by the calendar provider; [TaskContract.Tasks._ID] must be set to a non-null value
3746
*/
47+
3848
class DmfsTask(
39-
val taskList: DmfsTaskList
49+
val taskList: DmfsTaskList,
50+
val values: Entity
4051
) {
4152

4253
private val logger = Logger.getLogger(javaClass.name)
4354

44-
var id: Long? = null
45-
var syncId: String? = null
46-
var eTag: String? = null
47-
var flags: Int = 0
48-
49-
50-
constructor(taskList: DmfsTaskList, values: ContentValues): this(taskList) {
51-
id = values.getAsLong(Tasks._ID)
52-
syncId = values.getAsString(Tasks._SYNC_ID)
53-
eTag = values.getAsString(COLUMN_ETAG)
54-
flags = values.getAsInteger(COLUMN_FLAGS) ?: 0
55-
}
56-
57-
constructor(taskList: DmfsTaskList, task: Task, syncId: String?, eTag: String?, flags: Int): this(taskList) {
58-
this.task = task
59-
this.syncId = syncId
60-
this.eTag = eTag
61-
this.flags = flags
62-
}
55+
private val mainValues
56+
get() = values.entityValues
6357

58+
var id: Long = mainValues.getAsLong(Tasks._ID)
59+
var syncId: String? = mainValues.getAsString(Tasks._SYNC_ID)
60+
var eTag: String? = mainValues.getAsString(COLUMN_ETAG)
61+
var flags: Int = mainValues.getAsInteger(COLUMN_FLAGS) ?: 0
6462

6563
var task: Task? = null
6664
/**

lib/src/main/kotlin/at/bitfire/synctools/storage/tasks/DmfsTaskList.kt

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ package at.bitfire.synctools.storage.tasks
88

99
import android.content.ContentUris
1010
import android.content.ContentValues
11+
import android.content.Entity
12+
import android.database.Cursor
1113
import android.net.Uri
1214
import android.os.RemoteException
1315
import at.bitfire.ical4android.DmfsTask
@@ -21,7 +23,7 @@ import java.util.LinkedList
2123
import java.util.logging.Logger
2224

2325
/**
24-
* Represents a locally stored task list, containing [at.bitfire.ical4android.DmfsTask]s (tasks).
26+
* Represents a locally stored task list, containing [DmfsTask]s (tasks).
2527
* Communicates with tasks.org-compatible content providers (currently tasks.org and OpenTasks) to store the tasks.
2628
*/
2729
class DmfsTaskList(
@@ -65,19 +67,55 @@ class DmfsTaskList(
6567
val tasks = LinkedList<DmfsTask>()
6668
try {
6769
val (protectedWhere, protectedWhereArgs) = whereWithTaskListId(where, whereArgs)
68-
client.query(tasksUri(), null, protectedWhere, protectedWhereArgs, null)?.use { cursor ->
69-
while (cursor.moveToNext())
70-
tasks += DmfsTask(this, cursor.toContentValues())
70+
client.query(tasksUri(), arrayOf(TaskContract.Tasks._ID), protectedWhere, protectedWhereArgs, null)?.use { cursor ->
71+
while (cursor.moveToNext()) {
72+
val taskId = cursor.getLong(0)
73+
val entity = getTaskEntity(taskId)
74+
if (entity != null)
75+
tasks += DmfsTask(this, entity)
76+
}
7177
}
7278
} catch (e: RemoteException) {
7379
throw LocalStorageException("Couldn't query ${providerName.authority} tasks", e)
7480
}
7581
return tasks
7682
}
7783

78-
fun getTask(id: Long) = findTasks("${TaskContract.Tasks._ID}=?", arrayOf(id.toString())).firstOrNull()
79-
?: throw LocalStorageException("Couldn't query ${providerName.authority} tasks")
80-
84+
fun getTask(id: Long): DmfsTask? {
85+
val values = getTaskEntity(id) ?: return null
86+
return DmfsTask(this, values)
87+
}
88+
89+
fun getTaskEntity(id: Long, where: String? = null, whereArgs: Array<String>? = null): Entity? {
90+
try {
91+
client.query(taskUri(id, true), null, where, whereArgs, null)?.use { cursor ->
92+
if (cursor.moveToFirst()) {
93+
// first row holds main values, we expect cursor is already at row we need to read from
94+
val entity = Entity(cursor.toContentValues())
95+
addSubValuesToEntity(cursor, entity)
96+
return entity
97+
}
98+
}
99+
} catch (e: RemoteException) {
100+
throw LocalStorageException("Couldn't query event entity", e)
101+
}
102+
return null
103+
}
104+
105+
106+
/**
107+
* Adds subvalues (extended properties like attendee, attachment, etc) to given entity.
108+
*/
109+
private fun addSubValuesToEntity(cursor: Cursor, entity: Entity) {
110+
// we expect the cursor already is at position to start reading
111+
// all rows hold subvalues (extended properties)
112+
while (cursor.moveToNext()) {
113+
val cv = cursor.toContentValues()
114+
val mimetype = cv.getAsString(TaskContract.PropertyColumns.MIMETYPE) // CONTENT_ITEM_TYPE of extended property
115+
entity.addSubValue(tasksPropertyUri(mimetype), cv)
116+
}
117+
}
118+
81119
/**
82120
* Updates tasks in this task list.
83121
*
@@ -155,6 +193,9 @@ class DmfsTaskList(
155193
fun tasksPropertiesUri() =
156194
TaskContract.Properties.getContentUri(providerName.authority).asSyncAdapter(account)
157195

196+
fun tasksPropertyUri(mimetype: String): Uri =
197+
tasksPropertiesUri().buildUpon().appendPath(mimetype).build()!!
198+
158199
/**
159200
* Restricts a given selection/where clause to this task list ID.
160201
*

0 commit comments

Comments
 (0)