Convert Task to data class

pull/2283/head
Alex Baker 1 year ago
parent f72860cef1
commit 114ec3f03b

@ -1,15 +1,14 @@
package com.todoroo.astrid.data package com.todoroo.astrid.data
import android.content.ContentValues
import android.os.Parcel
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.IntDef import androidx.annotation.IntDef
import androidx.core.os.ParcelCompat
import androidx.room.* import androidx.room.*
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import com.todoroo.andlib.data.Table import com.todoroo.andlib.data.Table
import com.todoroo.andlib.sql.Field import com.todoroo.andlib.sql.Field
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import kotlinx.parcelize.Parcelize
import kotlinx.parcelize.RawValue
import net.fortuna.ical4j.model.Recur import net.fortuna.ical4j.model.Recur
import org.tasks.Strings import org.tasks.Strings
import org.tasks.data.Tag import org.tasks.data.Tag
@ -18,130 +17,67 @@ import org.tasks.date.DateTimeUtils.toDateTime
import org.tasks.time.DateTimeUtils.startOfDay import org.tasks.time.DateTimeUtils.startOfDay
import timber.log.Timber import timber.log.Timber
@Parcelize
@Entity( @Entity(
tableName = Task.TABLE_NAME, tableName = Task.TABLE_NAME,
indices = [ indices = [
Index(name = "t_rid", value = ["remoteId"], unique = true), Index(name = "t_rid", value = ["remoteId"], unique = true),
Index(name = "active_and_visible", value = ["completed", "deleted", "hideUntil"])]) Index(name = "active_and_visible", value = ["completed", "deleted", "hideUntil"])])
class Task : Parcelable { data class Task(
/** ID */
@PrimaryKey(autoGenerate = true) @PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "_id") @ColumnInfo(name = "_id")
@Transient @Transient
var id = NO_ID var id: Long = NO_ID,
/** Name of Task */
@ColumnInfo(name = "title") @ColumnInfo(name = "title")
var title: String? = null var title: String? = null,
@ColumnInfo(name = "importance") @ColumnInfo(name = "importance")
var priority = Priority.NONE var priority: Int = Priority.NONE,
/** Unixtime Task is due, 0 if not set */
@ColumnInfo(name = "dueDate") @ColumnInfo(name = "dueDate")
var dueDate = 0L var dueDate: Long = 0L,
/** Unixtime Task should be hidden until, 0 if not set */
@ColumnInfo(name = "hideUntil") @ColumnInfo(name = "hideUntil")
var hideUntil = 0L var hideUntil: Long = 0L,
/** Unixtime Task was created */
@ColumnInfo(name = "created") @ColumnInfo(name = "created")
var creationDate = 0L var creationDate: Long = 0L,
/** Unixtime Task was last touched */
@ColumnInfo(name = "modified") @ColumnInfo(name = "modified")
var modificationDate = 0L var modificationDate: Long = 0L,
/** Unixtime Task was completed. 0 means active */
@ColumnInfo(name = "completed") @ColumnInfo(name = "completed")
var completionDate = 0L var completionDate: Long = 0L,
/** Unixtime Task was deleted. 0 means not deleted */
@ColumnInfo(name = "deleted") @ColumnInfo(name = "deleted")
var deletionDate = 0L var deletionDate: Long = 0L,
// --- data access boilerplate
@ColumnInfo(name = "notes") @ColumnInfo(name = "notes")
var notes: String? = null var notes: String? = null,
@ColumnInfo(name = "estimatedSeconds") @ColumnInfo(name = "estimatedSeconds")
var estimatedSeconds = 0 var estimatedSeconds: Int = 0,
@ColumnInfo(name = "elapsedSeconds") @ColumnInfo(name = "elapsedSeconds")
var elapsedSeconds = 0 var elapsedSeconds: Int = 0,
@ColumnInfo(name = "timerStart") @ColumnInfo(name = "timerStart")
var timerStart = 0L var timerStart: Long = 0L,
/** Flags for when to send reminders */
@ColumnInfo(name = "notificationFlags") @ColumnInfo(name = "notificationFlags")
@SerializedName("ringFlags", alternate = ["reminderFlags"]) @SerializedName("ringFlags", alternate = ["reminderFlags"])
var ringFlags = 0 var ringFlags: Int = 0,
/** Unixtime the last reminder was triggered */
@ColumnInfo(name = "lastNotified") @ColumnInfo(name = "lastNotified")
var reminderLast = 0L var reminderLast: Long = 0L,
@ColumnInfo(name = "recurrence") @ColumnInfo(name = "recurrence")
var recurrence: String? = null var recurrence: String? = null,
@ColumnInfo(name = "repeat_from", defaultValue = RepeatFrom.DUE_DATE.toString()) @ColumnInfo(name = "repeat_from", defaultValue = RepeatFrom.DUE_DATE.toString())
var repeatFrom: Int = RepeatFrom.DUE_DATE var repeatFrom: Int = RepeatFrom.DUE_DATE,
@ColumnInfo(name = "calendarUri") @ColumnInfo(name = "calendarUri")
var calendarURI: String? = null var calendarURI: String? = null,
/** Remote id */
@ColumnInfo(name = "remoteId") @ColumnInfo(name = "remoteId")
var remoteId: String? = NO_UUID var remoteId: String? = NO_UUID,
@ColumnInfo(name = "collapsed") @ColumnInfo(name = "collapsed")
var isCollapsed = false var isCollapsed: Boolean = false,
@ColumnInfo(name = "parent") @ColumnInfo(name = "parent")
@Transient @Transient
var parent = 0L var parent: Long = 0L,
@ColumnInfo(name = "order") @ColumnInfo(name = "order")
var order: Long? = null var order: Long? = null,
@ColumnInfo(name = "read_only", defaultValue = "0") @ColumnInfo(name = "read_only", defaultValue = "0")
var readOnly: Boolean = false var readOnly: Boolean = false,
@Ignore @Ignore
@Transient @Transient
private var transitoryData: HashMap<String, Any>? = null private var transitoryData: @RawValue HashMap<String, Any>? = null,
) : Parcelable {
constructor()
@Ignore
constructor(parcel: Parcel) {
calendarURI = parcel.readString()
completionDate = parcel.readLong()
creationDate = parcel.readLong()
deletionDate = parcel.readLong()
dueDate = parcel.readLong()
elapsedSeconds = parcel.readInt()
estimatedSeconds = parcel.readInt()
hideUntil = parcel.readLong()
id = parcel.readLong()
priority = parcel.readInt()
modificationDate = parcel.readLong()
notes = parcel.readString()
recurrence = parcel.readString()
ringFlags = parcel.readInt()
reminderLast = parcel.readLong()
timerStart = parcel.readLong()
title = parcel.readString()
remoteId = parcel.readString() ?: NO_UUID
transitoryData = parcel.readHashMap(ContentValues::class.java.classLoader) as HashMap<String, Any>?
isCollapsed = ParcelCompat.readBoolean(parcel)
parent = parcel.readLong()
readOnly = ParcelCompat.readBoolean(parcel)
order = parcel.readLong()
}
var uuid: String var uuid: String
get() = if (Strings.isNullOrEmpty(remoteId)) NO_UUID else remoteId!! get() = if (Strings.isNullOrEmpty(remoteId)) NO_UUID else remoteId!!
set(uuid) { set(uuid) {
@ -247,36 +183,6 @@ class Task : Parcelable {
val isNew: Boolean val isNew: Boolean
get() = id == NO_ID get() = id == NO_ID
/** {@inheritDoc} */
override fun describeContents() = 0
/** {@inheritDoc} */
override fun writeToParcel(dest: Parcel, flags: Int) {
dest.writeString(calendarURI)
dest.writeLong(completionDate)
dest.writeLong(creationDate)
dest.writeLong(deletionDate)
dest.writeLong(dueDate)
dest.writeInt(elapsedSeconds)
dest.writeInt(estimatedSeconds)
dest.writeLong(hideUntil)
dest.writeLong(id)
dest.writeInt(priority)
dest.writeLong(modificationDate)
dest.writeString(notes)
dest.writeString(recurrence)
dest.writeInt(ringFlags)
dest.writeLong(reminderLast)
dest.writeLong(timerStart)
dest.writeString(title)
dest.writeString(remoteId)
dest.writeMap(transitoryData as Map<*, *>?)
ParcelCompat.writeBoolean(dest, isCollapsed)
dest.writeLong(parent)
ParcelCompat.writeBoolean(dest, readOnly)
dest.writeLong(order ?: 0)
}
fun insignificantChange(task: Task?): Boolean { fun insignificantChange(task: Task?): Boolean {
if (this === task) { if (this === task) {
return true return true
@ -384,11 +290,7 @@ class Task : Parcelable {
return transitoryData != null && transitoryData!!.containsKey(key) return transitoryData != null && transitoryData!!.containsKey(key)
} }
fun <T> getTransitory(key: String?): T? { fun <T> getTransitory(key: String?): T? = transitoryData?.get(key) as T?
return if (transitoryData == null) {
null
} else transitoryData!![key] as T?
}
// --- Convenience wrappers for using transitories as flags // --- Convenience wrappers for using transitories as flags
fun checkTransitory(flag: String?): Boolean { fun checkTransitory(flag: String?): Boolean {
@ -396,68 +298,6 @@ class Task : Parcelable {
return trans != null return trans != null
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Task) return false
if (id != other.id) return false
if (title != other.title) return false
if (priority != other.priority) return false
if (dueDate != other.dueDate) return false
if (hideUntil != other.hideUntil) return false
if (creationDate != other.creationDate) return false
if (modificationDate != other.modificationDate) return false
if (completionDate != other.completionDate) return false
if (deletionDate != other.deletionDate) return false
if (notes != other.notes) return false
if (estimatedSeconds != other.estimatedSeconds) return false
if (elapsedSeconds != other.elapsedSeconds) return false
if (timerStart != other.timerStart) return false
if (ringFlags != other.ringFlags) return false
if (reminderLast != other.reminderLast) return false
if (recurrence != other.recurrence) return false
if (calendarURI != other.calendarURI) return false
if (remoteId != other.remoteId) return false
if (isCollapsed != other.isCollapsed) return false
if (parent != other.parent) return false
if (transitoryData != other.transitoryData) return false
if (readOnly != other.readOnly) return false
if (order != other.order) return false
return true
}
override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + (title?.hashCode() ?: 0)
result = 31 * result + priority
result = 31 * result + dueDate.hashCode()
result = 31 * result + hideUntil.hashCode()
result = 31 * result + creationDate.hashCode()
result = 31 * result + modificationDate.hashCode()
result = 31 * result + completionDate.hashCode()
result = 31 * result + deletionDate.hashCode()
result = 31 * result + (notes?.hashCode() ?: 0)
result = 31 * result + estimatedSeconds
result = 31 * result + elapsedSeconds
result = 31 * result + timerStart.hashCode()
result = 31 * result + ringFlags
result = 31 * result + reminderLast.hashCode()
result = 31 * result + (recurrence?.hashCode() ?: 0)
result = 31 * result + (calendarURI?.hashCode() ?: 0)
result = 31 * result + remoteId.hashCode()
result = 31 * result + isCollapsed.hashCode()
result = 31 * result + parent.hashCode()
result = 31 * result + (transitoryData?.hashCode() ?: 0)
result = 31 * result + readOnly.hashCode()
result = 31 * result + order.hashCode()
return result
}
override fun toString(): String {
return "Task(id=$id, title=$title, priority=$priority, dueDate=$dueDate, hideUntil=$hideUntil, creationDate=$creationDate, modificationDate=$modificationDate, completionDate=$completionDate, deletionDate=$deletionDate, notes=$notes, estimatedSeconds=$estimatedSeconds, elapsedSeconds=$elapsedSeconds, timerStart=$timerStart, ringFlags=$ringFlags, reminderLast=$reminderLast, recurrence=$recurrence, calendarURI=$calendarURI, remoteId='$remoteId', isCollapsed=$isCollapsed, parent=$parent, transitoryData=$transitoryData, readOnly=$readOnly, order=$order)"
}
@Retention(AnnotationRetention.SOURCE) @Retention(AnnotationRetention.SOURCE)
@IntDef(Priority.HIGH, Priority.MEDIUM, Priority.LOW, Priority.NONE) @IntDef(Priority.HIGH, Priority.MEDIUM, Priority.LOW, Priority.NONE)
annotation class Priority { annotation class Priority {
@ -478,41 +318,32 @@ class Task : Parcelable {
} }
} }
fun clone(): Task {
val parcel = Parcel.obtain()
writeToParcel(parcel, 0)
parcel.setDataPosition(0)
val task = Task(parcel)
parcel.recycle()
return task
}
companion object { companion object {
const val TABLE_NAME = "tasks" const val TABLE_NAME = "tasks"
// --- table and uri // --- table and uri
/** table for this model */ /** table for this model */
@JvmField val TABLE = Table(TABLE_NAME) val TABLE = Table(TABLE_NAME)
@JvmField val FIELDS = Field.field("$TABLE_NAME.*") val FIELDS = Field.field("$TABLE_NAME.*")
const val NO_ID: Long = 0 const val NO_ID: Long = 0
// --- properties // --- properties
@JvmField val ID = TABLE.column("_id") @JvmField val ID = TABLE.column("_id")
@JvmField val TITLE = TABLE.column("title") @JvmField val TITLE = TABLE.column("title")
@JvmField val IMPORTANCE = TABLE.column("importance") val IMPORTANCE = TABLE.column("importance")
@JvmField val DUE_DATE = TABLE.column("dueDate") val DUE_DATE = TABLE.column("dueDate")
@JvmField val HIDE_UNTIL = TABLE.column("hideUntil") val HIDE_UNTIL = TABLE.column("hideUntil")
@JvmField val MODIFICATION_DATE = TABLE.column("modified") @JvmField val MODIFICATION_DATE = TABLE.column("modified")
@JvmField val CREATION_DATE = TABLE.column("created") @JvmField val CREATION_DATE = TABLE.column("created")
@JvmField val COMPLETION_DATE = TABLE.column("completed") val COMPLETION_DATE = TABLE.column("completed")
@JvmField val DELETION_DATE = TABLE.column("deleted") @JvmField val DELETION_DATE = TABLE.column("deleted")
@JvmField val NOTES = TABLE.column("notes") val NOTES = TABLE.column("notes")
@JvmField val TIMER_START = TABLE.column("timerStart") val TIMER_START = TABLE.column("timerStart")
@JvmField val PARENT = TABLE.column("parent") val PARENT = TABLE.column("parent")
@JvmField val RECURRENCE = TABLE.column("recurrence") val RECURRENCE = TABLE.column("recurrence")
/** constant value for no uuid */ /** constant value for no uuid */
const val NO_UUID = "0" // $NON-NLS-1$ const val NO_UUID = "0" // $NON-NLS-1$
@JvmField val UUID = TABLE.column("remoteId") val UUID = TABLE.column("remoteId")
/** whether to send a reminder at deadline */ /** whether to send a reminder at deadline */
const val NOTIFY_AT_DEADLINE = 1 shl 1 const val NOTIFY_AT_DEADLINE = 1 shl 1
@ -528,16 +359,6 @@ class Task : Parcelable {
const val NOTIFY_AT_START = 1 shl 5 const val NOTIFY_AT_START = 1 shl 5
@JvmField val CREATOR: Parcelable.Creator<Task> = object : Parcelable.Creator<Task> {
override fun createFromParcel(source: Parcel): Task? {
return Task(source)
}
override fun newArray(size: Int): Array<Task?> {
return arrayOfNulls(size)
}
}
/** urgency array index -> significance */ /** urgency array index -> significance */
const val URGENCY_NONE = 0 const val URGENCY_NONE = 0
const val URGENCY_SPECIFIC_DAY = 7 const val URGENCY_SPECIFIC_DAY = 7
@ -574,7 +395,7 @@ class Task : Parcelable {
* @param setting one of the URGENCY_* constants * @param setting one of the URGENCY_* constants
* @param customDate if specific day or day & time is set, this value * @param customDate if specific day or day & time is set, this value
*/ */
@JvmStatic fun createDueDate(setting: Int, customDate: Long): Long { fun createDueDate(setting: Int, customDate: Long): Long {
val date: Long = when (setting) { val date: Long = when (setting) {
URGENCY_NONE -> 0 URGENCY_NONE -> 0
URGENCY_TODAY -> DateUtilities.now() URGENCY_TODAY -> DateUtilities.now()
@ -605,7 +426,7 @@ class Task : Parcelable {
return dueDate > 0 && dueDate % 60000 > 0 return dueDate > 0 && dueDate % 60000 > 0
} }
@JvmStatic fun isValidUuid(uuid: String): Boolean { fun isValidUuid(uuid: String): Boolean {
return try { return try {
val value = uuid.toLong() val value = uuid.toLong()
value > 0 value > 0
@ -615,14 +436,12 @@ class Task : Parcelable {
} }
} }
@JvmStatic
fun String?.sanitizeRecur(): String? = this fun String?.sanitizeRecur(): String? = this
?.replace("BYDAY=;", "") ?.replace("BYDAY=;", "")
?.replace(INVALID_COUNT, "") // ical4j adds COUNT=-1 if there is an UNTIL value ?.replace(INVALID_COUNT, "") // ical4j adds COUNT=-1 if there is an UNTIL value
@JvmStatic fun isUuidEmpty(uuid: String?): Boolean { fun isUuidEmpty(uuid: String?): Boolean {
return NO_UUID == uuid || Strings.isNullOrEmpty(uuid) return NO_UUID == uuid || Strings.isNullOrEmpty(uuid)
} }
} }
} }

@ -68,10 +68,9 @@ class SubtaskControlSet : TaskEditControlFragment() {
completeNewSubtask = { completeNewSubtask = {
viewModel.newSubtasks.value = viewModel.newSubtasks.value =
ArrayList(viewModel.newSubtasks.value).apply { ArrayList(viewModel.newSubtasks.value).apply {
val modified = it.clone().apply { val modified = it.copy(
completionDate = completionDate = if (it.isCompleted) 0 else now()
if (isCompleted) 0 else now() )
}
set(indexOf(it), modified) set(indexOf(it), modified)
} }
}, },

Loading…
Cancel
Save