Add task repetition (handle task completion)
This commit is contained in:
parent
afbe184fee
commit
b46514ea52
11 changed files with 98 additions and 17 deletions
|
@ -51,6 +51,7 @@ class TaskActivity : SimpleActivity() {
|
|||
private var mRepeatRule = 0
|
||||
private var mTaskOccurrenceTS = 0L
|
||||
private var mOriginalStartTS = 0L
|
||||
private var mTaskCompleted = false
|
||||
private var mLastSavePromptTS = 0L
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
|
@ -206,6 +207,7 @@ class TaskActivity : SimpleActivity() {
|
|||
if (task != null) {
|
||||
mTask = task
|
||||
mTaskOccurrenceTS = intent.getLongExtra(EVENT_OCCURRENCE_TS, 0L)
|
||||
mTaskCompleted = intent.getBooleanExtra(IS_TASK_COMPLETED, false)
|
||||
if (intent.getBooleanExtra(IS_DUPLICATE_INTENT, false)) {
|
||||
mTask.id = null
|
||||
updateActionBarTitle(getString(R.string.new_task))
|
||||
|
@ -469,7 +471,18 @@ class TaskActivity : SimpleActivity() {
|
|||
private fun setupMarkCompleteButton() {
|
||||
toggle_mark_complete.setOnClickListener { toggleCompletion() }
|
||||
toggle_mark_complete.beVisibleIf(mTask.id != null)
|
||||
if (mTask.isTaskCompleted()) {
|
||||
updateTaskCompleted()
|
||||
ensureBackgroundThread {
|
||||
// the stored value might be incorrect so update it (e.g. user completed the task via notification action before editing)
|
||||
mTaskCompleted = isTaskCompleted(mTask.copy(startTS = mOriginalStartTS, endTS = mOriginalStartTS))
|
||||
runOnUiThread {
|
||||
updateTaskCompleted()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTaskCompleted() {
|
||||
if (mTaskCompleted) {
|
||||
toggle_mark_complete.background = ContextCompat.getDrawable(this, R.drawable.button_background_stroke)
|
||||
toggle_mark_complete.setText(R.string.mark_incomplete)
|
||||
toggle_mark_complete.setTextColor(getProperTextColor())
|
||||
|
@ -484,14 +497,9 @@ class TaskActivity : SimpleActivity() {
|
|||
}
|
||||
|
||||
private fun toggleCompletion() {
|
||||
if (mTask.isTaskCompleted()) {
|
||||
mTask.flags = mTask.flags.removeBit(FLAG_TASK_COMPLETED)
|
||||
} else {
|
||||
mTask.flags = mTask.flags or FLAG_TASK_COMPLETED
|
||||
}
|
||||
|
||||
ensureBackgroundThread {
|
||||
eventsDB.updateTaskCompletion(mTask.id!!, mTask.flags)
|
||||
val task = mTask.copy(startTS = mOriginalStartTS)
|
||||
updateTaskCompletion(task, completed = !mTaskCompleted)
|
||||
hideKeyboard()
|
||||
finish()
|
||||
}
|
||||
|
|
|
@ -13,14 +13,16 @@ import com.simplemobiletools.calendar.pro.helpers.Converters
|
|||
import com.simplemobiletools.calendar.pro.helpers.REGULAR_EVENT_TYPE_ID
|
||||
import com.simplemobiletools.calendar.pro.interfaces.EventTypesDao
|
||||
import com.simplemobiletools.calendar.pro.interfaces.EventsDao
|
||||
import com.simplemobiletools.calendar.pro.interfaces.TasksDao
|
||||
import com.simplemobiletools.calendar.pro.interfaces.WidgetsDao
|
||||
import com.simplemobiletools.calendar.pro.models.Event
|
||||
import com.simplemobiletools.calendar.pro.models.EventType
|
||||
import com.simplemobiletools.calendar.pro.models.Task
|
||||
import com.simplemobiletools.calendar.pro.models.Widget
|
||||
import com.simplemobiletools.commons.extensions.getProperPrimaryColor
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
@Database(entities = [Event::class, EventType::class, Widget::class], version = 6)
|
||||
@Database(entities = [Event::class, EventType::class, Widget::class, Task::class], version = 7)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class EventsDatabase : RoomDatabase() {
|
||||
|
||||
|
@ -30,6 +32,8 @@ abstract class EventsDatabase : RoomDatabase() {
|
|||
|
||||
abstract fun WidgetsDao(): WidgetsDao
|
||||
|
||||
abstract fun TasksDao(): TasksDao
|
||||
|
||||
companion object {
|
||||
private var db: EventsDatabase? = null
|
||||
|
||||
|
@ -49,6 +53,7 @@ abstract class EventsDatabase : RoomDatabase() {
|
|||
.addMigrations(MIGRATION_3_4)
|
||||
.addMigrations(MIGRATION_4_5)
|
||||
.addMigrations(MIGRATION_5_6)
|
||||
.addMigrations(MIGRATION_6_7)
|
||||
.build()
|
||||
db!!.openHelper.setWriteAheadLoggingEnabled(true)
|
||||
}
|
||||
|
@ -113,5 +118,14 @@ abstract class EventsDatabase : RoomDatabase() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val MIGRATION_6_7 = object : Migration(6, 7) {
|
||||
override fun migrate(database: SupportSQLiteDatabase) {
|
||||
database.apply {
|
||||
execSQL("CREATE TABLE IF NOT EXISTS `tasks` (`id` INTEGER PRIMARY KEY AUTOINCREMENT, `task_id` INTEGER NOT NULL, `start_ts` INTEGER NOT NULL, `flags` INTEGER NOT NULL)")
|
||||
execSQL("CREATE UNIQUE INDEX IF NOT EXISTS `index_tasks_id` ON `tasks` (`id`)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ import com.simplemobiletools.calendar.pro.helpers.*
|
|||
import com.simplemobiletools.calendar.pro.helpers.Formatter
|
||||
import com.simplemobiletools.calendar.pro.interfaces.EventTypesDao
|
||||
import com.simplemobiletools.calendar.pro.interfaces.EventsDao
|
||||
import com.simplemobiletools.calendar.pro.interfaces.TasksDao
|
||||
import com.simplemobiletools.calendar.pro.interfaces.WidgetsDao
|
||||
import com.simplemobiletools.calendar.pro.models.*
|
||||
import com.simplemobiletools.calendar.pro.receivers.CalDAVSyncReceiver
|
||||
|
@ -51,6 +52,7 @@ val Context.config: Config get() = Config.newInstance(applicationContext)
|
|||
val Context.eventsDB: EventsDao get() = EventsDatabase.getInstance(applicationContext).EventsDao()
|
||||
val Context.eventTypesDB: EventTypesDao get() = EventsDatabase.getInstance(applicationContext).EventTypesDao()
|
||||
val Context.widgetsDB: WidgetsDao get() = EventsDatabase.getInstance(applicationContext).WidgetsDao()
|
||||
val Context.completedTasksDB: TasksDao get() = EventsDatabase.getInstance(applicationContext).TasksDao()
|
||||
val Context.eventsHelper: EventsHelper get() = EventsHelper(this)
|
||||
val Context.calDAVHelper: CalDAVHelper get() = CalDAVHelper(this)
|
||||
|
||||
|
@ -237,6 +239,7 @@ fun Context.notifyEvent(originalEvent: Event) {
|
|||
val descriptionOrLocation = if (config.replaceDescription) event.location else event.description
|
||||
val content = "$displayedStartDate $timeRange $descriptionOrLocation".trim()
|
||||
ensureBackgroundThread {
|
||||
if (event.isTask()) eventsHelper.updateIsTaskCompleted(event)
|
||||
val notification = getNotification(pendingIntent, event, content)
|
||||
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
try {
|
||||
|
@ -653,3 +656,19 @@ fun Context.getDatesWeekDateTime(date: DateTime): String {
|
|||
date.withZone(DateTimeZone.UTC).toString()
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.isTaskCompleted(event: Event): Boolean {
|
||||
val task = completedTasksDB.getTaskWithIdAndTs(event.id!!, event.startTS) ?: return false
|
||||
return task.flags and FLAG_TASK_COMPLETED != 0
|
||||
}
|
||||
|
||||
fun Context.updateTaskCompletion(event: Event, completed: Boolean) {
|
||||
if (completed) {
|
||||
event.flags = event.flags or FLAG_TASK_COMPLETED
|
||||
val task = Task(null, event.id!!, event.startTS, event.flags)
|
||||
completedTasksDB.insertOrUpdate(task)
|
||||
} else {
|
||||
event.flags = event.flags.removeBit(FLAG_TASK_COMPLETED)
|
||||
completedTasksDB.deleteTaskWithIdAndTs(event.id!!, event.startTS)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,11 @@ import com.simplemobiletools.calendar.pro.extensions.eventsHelper
|
|||
import com.simplemobiletools.calendar.pro.extensions.getViewBitmap
|
||||
import com.simplemobiletools.calendar.pro.extensions.printBitmap
|
||||
import com.simplemobiletools.calendar.pro.helpers.*
|
||||
import com.simplemobiletools.calendar.pro.helpers.Formatter
|
||||
import com.simplemobiletools.calendar.pro.interfaces.NavigationListener
|
||||
import com.simplemobiletools.calendar.pro.models.Event
|
||||
import com.simplemobiletools.commons.extensions.*
|
||||
import kotlinx.android.synthetic.main.fragment_day.view.*
|
||||
import kotlinx.android.synthetic.main.top_navigation.view.*
|
||||
import java.util.*
|
||||
|
||||
class DayFragment : Fragment() {
|
||||
var mListener: NavigationListener? = null
|
||||
|
@ -129,6 +127,7 @@ class DayFragment : Fragment() {
|
|||
Intent(context, getActivityToOpen(event.isTask())).apply {
|
||||
putExtra(EVENT_ID, event.id)
|
||||
putExtra(EVENT_OCCURRENCE_TS, event.startTS)
|
||||
putExtra(IS_TASK_COMPLETED, event.isTaskCompleted())
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -610,6 +610,7 @@ class WeekFragment : Fragment(), WeeklyCalendar {
|
|||
Intent(context, getActivityToOpen(event.isTask())).apply {
|
||||
putExtra(EVENT_ID, event.id!!)
|
||||
putExtra(EVENT_OCCURRENCE_TS, event.startTS)
|
||||
putExtra(IS_TASK_COMPLETED, event.isTaskCompleted())
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
|
@ -813,6 +814,7 @@ class WeekFragment : Fragment(), WeeklyCalendar {
|
|||
Intent(context, getActivityToOpen(event.isTask())).apply {
|
||||
putExtra(EVENT_ID, event.id)
|
||||
putExtra(EVENT_OCCURRENCE_TS, event.startTS)
|
||||
putExtra(IS_TASK_COMPLETED, event.isTaskCompleted())
|
||||
startActivity(this)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ const val YEAR_LABEL = "year"
|
|||
const val EVENT_ID = "event_id"
|
||||
const val IS_DUPLICATE_INTENT = "is_duplicate_intent"
|
||||
const val EVENT_OCCURRENCE_TS = "event_occurrence_ts"
|
||||
const val IS_TASK_COMPLETED = "is_task_completed"
|
||||
const val NEW_EVENT_START_TS = "new_event_start_ts"
|
||||
const val WEEK_START_TIMESTAMP = "week_start_timestamp"
|
||||
const val NEW_EVENT_SET_HOUR_DURATION = "new_event_set_hour_duration"
|
||||
|
|
|
@ -316,6 +316,7 @@ class EventsHelper(val context: Context) {
|
|||
}
|
||||
|
||||
events.forEach {
|
||||
if (it.isTask()) updateIsTaskCompleted(it)
|
||||
it.updateIsPastEvent()
|
||||
val originalEvent = eventsDB.getEventWithId(it.id!!)
|
||||
if (originalEvent != null &&
|
||||
|
@ -481,10 +482,18 @@ class EventsHelper(val context: Context) {
|
|||
return events
|
||||
}
|
||||
|
||||
fun updateIsTaskCompleted(event: Event) {
|
||||
val task = context.completedTasksDB.getTaskWithIdAndTs(event.id!!, startTs = event.startTS)
|
||||
event.flags = task?.flags ?: event.flags
|
||||
}
|
||||
|
||||
fun getRunningEventsOrTasks(): List<Event> {
|
||||
val ts = getNowSeconds()
|
||||
val events = eventsDB.getOneTimeEventsOrTasksFromTo(ts, ts).toMutableList() as ArrayList<Event>
|
||||
events.addAll(getRepeatableEventsFor(ts, ts))
|
||||
events.forEach {
|
||||
if (it.isTask()) updateIsTaskCompleted(it)
|
||||
}
|
||||
return events
|
||||
}
|
||||
|
||||
|
|
|
@ -112,9 +112,6 @@ interface EventsDao {
|
|||
@Query("UPDATE events SET repetition_exceptions = :repetitionExceptions WHERE id = :id AND (type = $TYPE_EVENT OR type = $TYPE_TASK)")
|
||||
fun updateEventRepetitionExceptions(repetitionExceptions: String, id: Long)
|
||||
|
||||
@Query("UPDATE events SET flags = :newFlags WHERE id = :id")
|
||||
fun updateTaskCompletion(id: Long, newFlags: Int)
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertOrUpdate(event: Event): Long
|
||||
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package com.simplemobiletools.calendar.pro.interfaces
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.simplemobiletools.calendar.pro.models.Task
|
||||
|
||||
@Dao
|
||||
interface TasksDao {
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
fun insertOrUpdate(task: Task): Long
|
||||
|
||||
@Query("SELECT * FROM tasks WHERE task_id = :id AND start_ts = :startTs")
|
||||
fun getTaskWithIdAndTs(id: Long, startTs: Long): Task?
|
||||
|
||||
@Query("DELETE FROM tasks WHERE task_id = :id AND start_ts = :startTs")
|
||||
fun deleteTaskWithIdAndTs(id: Long, startTs: Long)
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.simplemobiletools.calendar.pro.models
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Entity
|
||||
import androidx.room.Index
|
||||
import androidx.room.PrimaryKey
|
||||
|
||||
@Entity(tableName = "tasks", indices = [(Index(value = ["id"], unique = true))])
|
||||
data class Task(
|
||||
@PrimaryKey(autoGenerate = true) var id: Long?,
|
||||
@ColumnInfo(name = "task_id") var task_id: Long,
|
||||
@ColumnInfo(name = "start_ts") var startTS: Long = 0L,
|
||||
@ColumnInfo(name = "flags") var flags: Int = 0,
|
||||
)
|
|
@ -5,9 +5,9 @@ import android.content.Intent
|
|||
import com.simplemobiletools.calendar.pro.extensions.cancelNotification
|
||||
import com.simplemobiletools.calendar.pro.extensions.cancelPendingIntent
|
||||
import com.simplemobiletools.calendar.pro.extensions.eventsDB
|
||||
import com.simplemobiletools.calendar.pro.extensions.updateTaskCompletion
|
||||
import com.simplemobiletools.calendar.pro.helpers.ACTION_MARK_COMPLETED
|
||||
import com.simplemobiletools.calendar.pro.helpers.EVENT_ID
|
||||
import com.simplemobiletools.calendar.pro.helpers.FLAG_TASK_COMPLETED
|
||||
|
||||
class MarkCompletedService : IntentService("MarkCompleted") {
|
||||
|
||||
|
@ -17,8 +17,7 @@ class MarkCompletedService : IntentService("MarkCompleted") {
|
|||
val taskId = intent.getLongExtra(EVENT_ID, 0L)
|
||||
val task = eventsDB.getTaskWithId(taskId)
|
||||
if (task != null) {
|
||||
task.flags = task.flags or FLAG_TASK_COMPLETED
|
||||
eventsDB.updateTaskCompletion(task.id!!, task.flags)
|
||||
updateTaskCompletion(task, true)
|
||||
cancelPendingIntent(task.id!!)
|
||||
cancelNotification(task.id!!)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue