Merge pull request #2152 from Aga-C/weekly-edit-repeating-events

Added editing options for repeating events in weekly view (#2122)
This commit is contained in:
Tibor Kaputa 2023-07-16 18:12:09 +02:00 committed by GitHub
commit 11657e8849
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 141 additions and 106 deletions

View File

@ -1307,7 +1307,7 @@ class EventActivity : SimpleActivity() {
// recreate the event if it was moved in a different CalDAV calendar // recreate the event if it was moved in a different CalDAV calendar
if (mEvent.id != null && oldSource != newSource && oldSource != SOURCE_IMPORTED_ICS) { if (mEvent.id != null && oldSource != newSource && oldSource != SOURCE_IMPORTED_ICS) {
if (mRepeatInterval > 0 && wasRepeatable) { if (mRepeatInterval > 0 && wasRepeatable) {
applyOriginalStartEndTimes() eventsHelper.applyOriginalStartEndTimes(mEvent, mOriginalStartTS, mOriginalEndTS)
} }
eventsHelper.deleteEvent(mEvent.id!!, true) eventsHelper.deleteEvent(mEvent.id!!, true)
mEvent.id = null mEvent.id = null
@ -1358,68 +1358,29 @@ class EventActivity : SimpleActivity() {
private fun showEditRepeatingEventDialog() { private fun showEditRepeatingEventDialog() {
EditRepeatingEventDialog(this) { EditRepeatingEventDialog(this) {
hideKeyboard() hideKeyboard()
if (it == null) {
return@EditRepeatingEventDialog
}
when (it) { when (it) {
EDIT_SELECTED_OCCURRENCE -> { EDIT_SELECTED_OCCURRENCE -> {
ensureBackgroundThread { eventsHelper.editSelectedOccurrence(mEvent, true) {
mEvent.apply { finish()
parentId = id!!.toLong()
id = null
repeatRule = 0
repeatInterval = 0
repeatLimit = 0
}
eventsHelper.insertEvent(mEvent, addToCalDAV = true, showToasts = true) {
finish()
}
} }
} }
EDIT_FUTURE_OCCURRENCES -> { EDIT_FUTURE_OCCURRENCES -> {
ensureBackgroundThread { eventsHelper.editFutureOccurrences(mEvent, mEventOccurrenceTS, true) {
val eventId = mEvent.id!! finish()
val originalEvent = eventsDB.getEventWithId(eventId) ?: return@ensureBackgroundThread
mEvent.maybeAdjustRepeatLimitCount(originalEvent, mEventOccurrenceTS)
mEvent.id = null
eventsHelper.apply {
addEventRepeatLimit(eventId, mEventOccurrenceTS)
if (mEventOccurrenceTS == originalEvent.startTS) {
deleteEvent(eventId, true)
}
insertEvent(mEvent, addToCalDAV = true, showToasts = true) {
finish()
}
}
} }
} }
EDIT_ALL_OCCURRENCES -> { EDIT_ALL_OCCURRENCES -> {
ensureBackgroundThread { eventsHelper.editAllOccurrences(mEvent, mOriginalStartTS, mOriginalEndTS, true) {
applyOriginalStartEndTimes() finish()
eventsHelper.updateEvent(mEvent, updateAtCalDAV = true, showToasts = true) {
finish()
}
} }
} }
} }
} }
} }
private fun applyOriginalStartEndTimes() {
// Shift the start and end times of the first (original) event based on the changes made
val originalEvent = eventsDB.getEventWithId(mEvent.id!!) ?: return
val originalStartTS = originalEvent.startTS
val originalEndTS = originalEvent.endTS
val oldStartTS = mOriginalStartTS
val oldEndTS = mOriginalEndTS
mEvent.apply {
val startTSDelta = oldStartTS - startTS
val endTSDelta = oldEndTS - endTS
startTS = originalStartTS - startTSDelta
endTS = originalEndTS - endTSDelta
}
}
private fun updateStartTexts() { private fun updateStartTexts() {
updateStartDateText() updateStartDateText()
updateStartTimeText() updateStartTimeText()

View File

@ -471,55 +471,23 @@ class TaskActivity : SimpleActivity() {
private fun showEditRepeatingTaskDialog() { private fun showEditRepeatingTaskDialog() {
EditRepeatingEventDialog(this, isTask = true) { EditRepeatingEventDialog(this, isTask = true) {
hideKeyboard() hideKeyboard()
if (it == null) {
return@EditRepeatingEventDialog
}
when (it) { when (it) {
EDIT_SELECTED_OCCURRENCE -> { EDIT_SELECTED_OCCURRENCE -> {
ensureBackgroundThread { eventsHelper.editSelectedOccurrence(mTask, true) {
mTask.apply { finish()
parentId = id!!.toLong()
id = null
repeatRule = 0
repeatInterval = 0
repeatLimit = 0
}
eventsHelper.insertTask(mTask, showToasts = true) {
finish()
}
} }
} }
EDIT_FUTURE_OCCURRENCES -> { EDIT_FUTURE_OCCURRENCES -> {
ensureBackgroundThread { eventsHelper.editFutureOccurrences(mTask, mTaskOccurrenceTS, true) {
val taskId = mTask.id!! finish()
val originalTask = eventsDB.getTaskWithId(taskId) ?: return@ensureBackgroundThread
mTask.maybeAdjustRepeatLimitCount(originalTask, mTaskOccurrenceTS)
mTask.id = null
eventsHelper.apply {
addEventRepeatLimit(taskId, mTaskOccurrenceTS)
if (mTaskOccurrenceTS == originalTask.startTS) {
deleteEvent(taskId, true)
}
insertTask(mTask, showToasts = true) {
finish()
}
}
} }
} }
EDIT_ALL_OCCURRENCES -> { EDIT_ALL_OCCURRENCES -> {
ensureBackgroundThread { eventsHelper.editAllOccurrences(mTask, mOriginalStartTS, showToasts = true) {
// Shift the start and end times of the first (original) event based on the changes made finish()
val originalEvent = eventsDB.getTaskWithId(mTask.id!!) ?: return@ensureBackgroundThread
val originalStartTS = originalEvent.startTS
val oldStartTS = mOriginalStartTS
mTask.apply {
val startTSDelta = oldStartTS - startTS
startTS = originalStartTS - startTSDelta
endTS = startTS
}
eventsHelper.updateEvent(mTask, updateAtCalDAV = false, showToasts = true) {
finish()
}
} }
} }
} }

View File

@ -12,7 +12,7 @@ import com.simplemobiletools.commons.extensions.hideKeyboard
import com.simplemobiletools.commons.extensions.setupDialogStuff import com.simplemobiletools.commons.extensions.setupDialogStuff
import kotlinx.android.synthetic.main.dialog_edit_repeating_event.view.* import kotlinx.android.synthetic.main.dialog_edit_repeating_event.view.*
class EditRepeatingEventDialog(val activity: SimpleActivity, val isTask: Boolean = false, val callback: (allOccurrences: Int) -> Unit) { class EditRepeatingEventDialog(val activity: SimpleActivity, val isTask: Boolean = false, val callback: (allOccurrences: Int?) -> Unit) {
private var dialog: AlertDialog? = null private var dialog: AlertDialog? = null
init { init {
@ -33,12 +33,15 @@ class EditRepeatingEventDialog(val activity: SimpleActivity, val isTask: Boolean
activity.setupDialogStuff(view, this) { alertDialog -> activity.setupDialogStuff(view, this) { alertDialog ->
dialog = alertDialog dialog = alertDialog
alertDialog.hideKeyboard() alertDialog.hideKeyboard()
alertDialog.setOnDismissListener { sendResult(null) }
} }
} }
} }
private fun sendResult(allOccurrences: Int) { private fun sendResult(allOccurrences: Int?) {
callback(allOccurrences) callback(allOccurrences)
dialog?.dismiss() if (allOccurrences != null) {
dialog?.dismiss()
}
} }
} }

View File

@ -16,6 +16,9 @@ import androidx.collection.LongSparseArray
import androidx.constraintlayout.widget.ConstraintLayout import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.simplemobiletools.calendar.pro.R import com.simplemobiletools.calendar.pro.R
import com.simplemobiletools.calendar.pro.activities.MainActivity
import com.simplemobiletools.calendar.pro.activities.SimpleActivity
import com.simplemobiletools.calendar.pro.dialogs.EditRepeatingEventDialog
import com.simplemobiletools.calendar.pro.extensions.* import com.simplemobiletools.calendar.pro.extensions.*
import com.simplemobiletools.calendar.pro.helpers.* import com.simplemobiletools.calendar.pro.helpers.*
import com.simplemobiletools.calendar.pro.helpers.Formatter import com.simplemobiletools.calendar.pro.helpers.Formatter
@ -188,6 +191,7 @@ class WeekFragment : Fragment(), WeeklyCalendar {
fun updateCalendar() { fun updateCalendar() {
if (context != null) { if (context != null) {
currentlyDraggedView = null
WeeklyCalendarImpl(this, requireContext()).updateWeeklyCalendar(weekTimestamp) WeeklyCalendarImpl(this, requireContext()).updateWeeklyCalendar(weekTimestamp)
} }
} }
@ -269,12 +273,12 @@ class WeekFragment : Fragment(), WeeklyCalendar {
DragEvent.ACTION_DRAG_ENDED -> true DragEvent.ACTION_DRAG_ENDED -> true
DragEvent.ACTION_DROP -> { DragEvent.ACTION_DROP -> {
try { try {
val eventId = dragEvent.clipData.getItemAt(0).text.toString().toLong() val (eventId, originalStartTS, originalEndTS) = dragEvent.clipData.getItemAt(0).text.toString().split(";").map { it.toLong() }
val startHour = (dragEvent.y / rowHeight).toInt() val startHour = (dragEvent.y / rowHeight).toInt()
ensureBackgroundThread { ensureBackgroundThread {
val event = context?.eventsDB?.getEventOrTaskWithId(eventId) val event = context?.eventsDB?.getEventOrTaskWithId(eventId)
event?.let { event?.let { event ->
val currentStartTime = Formatter.getDateTimeFromTS(it.startTS) val currentStartTime = Formatter.getDateTimeFromTS(event.startTS)
val startTime = Formatter.getDateTimeFromTS(weekTimestamp + index * DAY_SECONDS) val startTime = Formatter.getDateTimeFromTS(weekTimestamp + index * DAY_SECONDS)
.withTime( .withTime(
startHour, startHour,
@ -284,14 +288,47 @@ class WeekFragment : Fragment(), WeeklyCalendar {
).seconds() ).seconds()
val currentEventDuration = event.endTS - event.startTS val currentEventDuration = event.endTS - event.startTS
val endTime = startTime + currentEventDuration val endTime = startTime + currentEventDuration
context?.eventsHelper?.updateEvent( val newEvent = event.copy(
it.copy( startTS = startTime,
startTS = startTime, endTS = endTime,
endTS = endTime, flags = event.flags.removeBit(FLAG_ALL_DAY)
flags = it.flags.removeBit(FLAG_ALL_DAY) )
), updateAtCalDAV = true, showToasts = false if (event.repeatInterval > 0) {
) { val activity = this.activity as SimpleActivity
updateCalendar() activity.runOnUiThread {
EditRepeatingEventDialog(activity) {
activity.hideKeyboard()
when (it) {
null -> {
revertDraggedEvent()
}
EDIT_SELECTED_OCCURRENCE -> {
context?.eventsHelper?.editSelectedOccurrence(newEvent, false) {
updateCalendar()
}
}
EDIT_FUTURE_OCCURRENCES -> {
context?.eventsHelper?.editFutureOccurrences(newEvent, originalStartTS, false) {
// we need to refresh all fragments because they can contain future occurrences
(activity as MainActivity).refreshItems()
}
}
EDIT_ALL_OCCURRENCES -> {
context?.eventsHelper?.editAllOccurrences(newEvent, originalStartTS, originalEndTS, false) {
(activity as MainActivity).refreshItems()
}
}
}
}
}
} else {
if (event.startTS == newEvent.startTS && event.endTS == newEvent.endTS) {
revertDraggedEvent()
} else {
context?.eventsHelper?.updateEvent(newEvent, updateAtCalDAV = true, showToasts = false) {
updateCalendar()
}
}
} }
} }
} }
@ -306,6 +343,13 @@ class WeekFragment : Fragment(), WeeklyCalendar {
} }
} }
private fun revertDraggedEvent() {
activity?.runOnUiThread {
currentlyDraggedView?.beVisible()
currentlyDraggedView = null
}
}
private fun getViewGestureDetector(view: ViewGroup, index: Int): GestureDetector { private fun getViewGestureDetector(view: ViewGroup, index: Int): GestureDetector {
return GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() { return GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapUp(event: MotionEvent): Boolean { override fun onSingleTapUp(event: MotionEvent): Boolean {
@ -634,7 +678,7 @@ class WeekFragment : Fragment(), WeeklyCalendar {
setOnLongClickListener { view -> setOnLongClickListener { view ->
currentlyDraggedView = view currentlyDraggedView = view
val shadowBuilder = View.DragShadowBuilder(view) val shadowBuilder = View.DragShadowBuilder(view)
val clipData = ClipData.newPlainText(WEEKLY_EVENT_ID_LABEL, event.id.toString()) val clipData = ClipData.newPlainText(WEEKLY_EVENT_ID_LABEL, "${event.id};${event.startTS};${event.endTS}")
if (isNougatPlus()) { if (isNougatPlus()) {
view.startDragAndDrop(clipData, shadowBuilder, null, 0) view.startDragAndDrop(clipData, shadowBuilder, null, 0)
} else { } else {
@ -898,7 +942,6 @@ class WeekFragment : Fragment(), WeeklyCalendar {
if (!dragEvent.result) { if (!dragEvent.result) {
view.beVisible() view.beVisible()
} }
currentlyDraggedView = null
true true
} }
else -> false else -> false

View File

@ -180,6 +180,66 @@ class EventsHelper(val context: Context) {
callback?.invoke() callback?.invoke()
} }
fun applyOriginalStartEndTimes(event: Event, oldStartTS: Long, oldEndTS: Long) {
val originalEvent = eventsDB.getEventOrTaskWithId(event.id!!) ?: return
val originalStartTS = originalEvent.startTS
val originalEndTS = originalEvent.endTS
event.apply {
val startTSDelta = oldStartTS - startTS
val endTSDelta = oldEndTS - endTS
startTS = originalStartTS - startTSDelta
endTS = if (isTask()) startTS else originalEndTS - endTSDelta
}
}
fun editSelectedOccurrence(event: Event, showToasts: Boolean, callback: () -> Unit) {
ensureBackgroundThread {
event.apply {
parentId = id!!.toLong()
id = null
repeatRule = 0
repeatInterval = 0
repeatLimit = 0
}
if (event.isTask()) {
insertTask(event, showToasts = showToasts, callback = callback)
} else {
insertEvent(event, addToCalDAV = true, showToasts = showToasts) {
callback()
}
}
}
}
fun editFutureOccurrences(event: Event, eventOccurrenceTS: Long, showToasts: Boolean, callback: () -> Unit) {
ensureBackgroundThread {
val eventId = event.id!!
val originalEvent = eventsDB.getEventOrTaskWithId(event.id!!) ?: return@ensureBackgroundThread
event.maybeAdjustRepeatLimitCount(originalEvent, eventOccurrenceTS)
event.id = null
addEventRepeatLimit(eventId, eventOccurrenceTS)
if (eventOccurrenceTS == originalEvent.startTS) {
deleteEvent(eventId, true)
}
if (event.isTask()) {
insertTask(event, showToasts = showToasts, callback = callback)
} else {
insertEvent(event, addToCalDAV = true, showToasts = showToasts) {
callback()
}
}
}
}
fun editAllOccurrences(event: Event, originalStartTS: Long, originalEndTS: Long = 0, showToasts: Boolean, callback: () -> Unit) {
ensureBackgroundThread {
applyOriginalStartEndTimes(event, originalStartTS, originalEndTS)
updateEvent(event, updateAtCalDAV = !event.isTask(), showToasts = showToasts, callback = callback)
}
}
private fun ensureEventTypeVisibility(event: Event, enableEventType: Boolean) { private fun ensureEventTypeVisibility(event: Event, enableEventType: Boolean) {
if (enableEventType) { if (enableEventType) {
val eventType = event.eventType.toString() val eventType = event.eventType.toString()