diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt index 12a27d099..0f00519ce 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/EventActivity.kt @@ -1307,7 +1307,7 @@ class EventActivity : SimpleActivity() { // recreate the event if it was moved in a different CalDAV calendar if (mEvent.id != null && oldSource != newSource && oldSource != SOURCE_IMPORTED_ICS) { if (mRepeatInterval > 0 && wasRepeatable) { - applyOriginalStartEndTimes() + eventsHelper.applyOriginalStartEndTimes(mEvent, mOriginalStartTS, mOriginalEndTS) } eventsHelper.deleteEvent(mEvent.id!!, true) mEvent.id = null @@ -1358,68 +1358,29 @@ class EventActivity : SimpleActivity() { private fun showEditRepeatingEventDialog() { EditRepeatingEventDialog(this) { hideKeyboard() + if (it == null) { + return@EditRepeatingEventDialog + } when (it) { EDIT_SELECTED_OCCURRENCE -> { - ensureBackgroundThread { - mEvent.apply { - parentId = id!!.toLong() - id = null - repeatRule = 0 - repeatInterval = 0 - repeatLimit = 0 - } - - eventsHelper.insertEvent(mEvent, addToCalDAV = true, showToasts = true) { - finish() - } + eventsHelper.editSelectedOccurrence(mEvent, true) { + finish() } } EDIT_FUTURE_OCCURRENCES -> { - ensureBackgroundThread { - val eventId = mEvent.id!! - 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() - } - } + eventsHelper.editFutureOccurrences(mEvent, mEventOccurrenceTS, true) { + finish() } } EDIT_ALL_OCCURRENCES -> { - ensureBackgroundThread { - applyOriginalStartEndTimes() - eventsHelper.updateEvent(mEvent, updateAtCalDAV = true, showToasts = true) { - finish() - } + eventsHelper.editAllOccurrences(mEvent, mOriginalStartTS, mOriginalEndTS, 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() { updateStartDateText() updateStartTimeText() diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt index 99b2a1edf..0caf1805b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/activities/TaskActivity.kt @@ -471,55 +471,23 @@ class TaskActivity : SimpleActivity() { private fun showEditRepeatingTaskDialog() { EditRepeatingEventDialog(this, isTask = true) { hideKeyboard() + if (it == null) { + return@EditRepeatingEventDialog + } when (it) { EDIT_SELECTED_OCCURRENCE -> { - ensureBackgroundThread { - mTask.apply { - parentId = id!!.toLong() - id = null - repeatRule = 0 - repeatInterval = 0 - repeatLimit = 0 - } - - eventsHelper.insertTask(mTask, showToasts = true) { - finish() - } + eventsHelper.editSelectedOccurrence(mTask, true) { + finish() } } EDIT_FUTURE_OCCURRENCES -> { - ensureBackgroundThread { - val taskId = mTask.id!! - 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() - } - } + eventsHelper.editFutureOccurrences(mTask, mTaskOccurrenceTS, true) { + finish() } } EDIT_ALL_OCCURRENCES -> { - ensureBackgroundThread { - // Shift the start and end times of the first (original) event based on the changes made - 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() - } + eventsHelper.editAllOccurrences(mTask, mOriginalStartTS, showToasts = true) { + finish() } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/EditRepeatingEventDialog.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/EditRepeatingEventDialog.kt index 5627e539e..e0cd0223d 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/EditRepeatingEventDialog.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/dialogs/EditRepeatingEventDialog.kt @@ -12,7 +12,7 @@ import com.simplemobiletools.commons.extensions.hideKeyboard import com.simplemobiletools.commons.extensions.setupDialogStuff 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 init { @@ -33,12 +33,15 @@ class EditRepeatingEventDialog(val activity: SimpleActivity, val isTask: Boolean activity.setupDialogStuff(view, this) { alertDialog -> dialog = alertDialog alertDialog.hideKeyboard() + alertDialog.setOnDismissListener { sendResult(null) } } } } - private fun sendResult(allOccurrences: Int) { + private fun sendResult(allOccurrences: Int?) { callback(allOccurrences) - dialog?.dismiss() + if (allOccurrences != null) { + dialog?.dismiss() + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/fragments/WeekFragment.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/fragments/WeekFragment.kt index d3e9525a6..681971e15 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/fragments/WeekFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/fragments/WeekFragment.kt @@ -16,6 +16,9 @@ import androidx.collection.LongSparseArray import androidx.constraintlayout.widget.ConstraintLayout import androidx.fragment.app.Fragment 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.helpers.* import com.simplemobiletools.calendar.pro.helpers.Formatter @@ -188,6 +191,7 @@ class WeekFragment : Fragment(), WeeklyCalendar { fun updateCalendar() { if (context != null) { + currentlyDraggedView = null WeeklyCalendarImpl(this, requireContext()).updateWeeklyCalendar(weekTimestamp) } } @@ -269,12 +273,12 @@ class WeekFragment : Fragment(), WeeklyCalendar { DragEvent.ACTION_DRAG_ENDED -> true DragEvent.ACTION_DROP -> { 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() ensureBackgroundThread { val event = context?.eventsDB?.getEventOrTaskWithId(eventId) - event?.let { - val currentStartTime = Formatter.getDateTimeFromTS(it.startTS) + event?.let { event -> + val currentStartTime = Formatter.getDateTimeFromTS(event.startTS) val startTime = Formatter.getDateTimeFromTS(weekTimestamp + index * DAY_SECONDS) .withTime( startHour, @@ -284,14 +288,47 @@ class WeekFragment : Fragment(), WeeklyCalendar { ).seconds() val currentEventDuration = event.endTS - event.startTS val endTime = startTime + currentEventDuration - context?.eventsHelper?.updateEvent( - it.copy( - startTS = startTime, - endTS = endTime, - flags = it.flags.removeBit(FLAG_ALL_DAY) - ), updateAtCalDAV = true, showToasts = false - ) { - updateCalendar() + val newEvent = event.copy( + startTS = startTime, + endTS = endTime, + flags = event.flags.removeBit(FLAG_ALL_DAY) + ) + if (event.repeatInterval > 0) { + val activity = this.activity as SimpleActivity + 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 { return GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() { override fun onSingleTapUp(event: MotionEvent): Boolean { @@ -634,7 +678,7 @@ class WeekFragment : Fragment(), WeeklyCalendar { setOnLongClickListener { view -> currentlyDraggedView = 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()) { view.startDragAndDrop(clipData, shadowBuilder, null, 0) } else { @@ -898,7 +942,6 @@ class WeekFragment : Fragment(), WeeklyCalendar { if (!dragEvent.result) { view.beVisible() } - currentlyDraggedView = null true } else -> false diff --git a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt index cb9927108..fb3a1e1c9 100644 --- a/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt +++ b/app/src/main/kotlin/com/simplemobiletools/calendar/pro/helpers/EventsHelper.kt @@ -180,6 +180,66 @@ class EventsHelper(val context: Context) { 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) { if (enableEventType) { val eventType = event.eventType.toString()