diff --git a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/TimelineDrag.kt b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/TimelineDrag.kt index 5d31e29..73c5db7 100644 --- a/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/TimelineDrag.kt +++ b/app/src/main/java/de/jeanlucmakiola/calendula/ui/common/TimelineDrag.kt @@ -626,25 +626,8 @@ class TimelineDragController { */ private var originSlot: Triple? = null - /** The edge a resize is dragging, or null for a plain drag (#141). */ - private var resizeEdge: ResizeEdge? = null - - /** The day the resized event starts on; its edges are minutes from that midnight. */ - private var resizeDay: LocalDate? = null - private var resizeStartMin = 0 - private var resizeEndMin = 0 - - /** How far the finger sits past the edge it grabbed, so the edge doesn't jump to it. */ - private var resizeGrabMin = 0f - - /** The column the resized edge is in, held until the finger is well into another. */ - private var resizeColumn: Int? = null - - /** The slot the resized edge sits on, held against a finger trembling between two. */ - private var resizeSlot: Int? = null - - /** The day, counted from the event's start day, the finger is resizing in. */ - private var resizeEdgeDay = 0 + /** The resize in progress, or null for a plain drag (#141). */ + private var resize: ResizeSession? = null fun begin( block: TimedBlock, @@ -691,10 +674,7 @@ class TimelineDragController { } fun cancel() { - resizeEdge = null - resizeDay = null - resizeColumn = null - resizeSlot = null + resize = null source = null clipOffsetMin = 0 dragZone = null @@ -800,11 +780,9 @@ class TimelineDragController { pointerInRoot: Offset, ) { val span = wallClockSpan(block.event, zone) + val session = ResizeSession(edge, span.day, span.startMin, span.endMin) source = block - resizeEdge = edge - resizeDay = span.day - resizeStartMin = span.startMin - resizeEndMin = span.endMin + resize = session clipOffsetMin = 0 this.titleLines = titleLines settling = null @@ -813,12 +791,12 @@ class TimelineDragController { liftedInstanceId = block.event.instanceId pointer = pointerInRoot // Measured from the edge's own column: the handle overhangs into the next. - val edgeDay = if (edge == ResizeEdge.Top) 0 else (resizeEndMin - 1).floorDiv(MINUTES_PER_DAY).coerceAtLeast(0) + val edgeDay = if (edge == ResizeEdge.Top) 0 else (session.endMin - 1).floorDiv(MINUTES_PER_DAY).coerceAtLeast(0) val edgeIndex = geometry.days.indexOf(span.day.plus(edgeDay, DateTimeUnit.DAY)) - resizeColumn = edgeIndex.takeIf { it >= 0 } + session.column = edgeIndex.takeIf { it >= 0 } ?.let { column(it) } - resizeGrabMin = (pointerResizeMinutes() ?: 0f) - - if (edge == ResizeEdge.Top) resizeStartMin else resizeEndMin + session.grabMin = (pointerResizeMinutes(session) ?: 0f) - + if (edge == ResizeEdge.Top) session.startMin else session.endMin originSlot = null recompute() originSlot = drag?.slot @@ -834,7 +812,7 @@ class TimelineDragController { fun preview(zone: TimeZone): EventInstance? { val (date, startMin, spanMin) = landingSlot?.takeIf { it != originSlot } ?: return null val event = source?.event ?: return null - val edge = resizeEdge + val edge = resize?.edge if (edge != null) { val drop = resizedDrop(event, edge, date, startMin, spanMin, zone) return event.copy(start = drop.start, end = drop.end) @@ -850,7 +828,7 @@ class TimelineDragController { fun finishResize(zone: TimeZone): TimelineResizeDrop? { val landed = drag val origin = originSlot - val edge = resizeEdge + val edge = resize?.edge cancel() if (landed == null || landed.slot == origin) return null val drop = resizedDrop(landed.event, edge, landed.date, landed.eventStartMin, landed.eventSpanMin, zone) @@ -862,9 +840,8 @@ class TimelineDragController { * Where the finger is, in minutes from the resized event's start day — * past 1440 in a later column, negative in an earlier one. */ - private fun pointerResizeMinutes(): Float? { + private fun pointerResizeMinutes(session: ResizeSession): Float? { val grid = geometry.grid?.takeIf { it.isAttached } ?: return null - val day = resizeDay ?: return null val hourPx = geometry.hourPx val columnPx = geometry.columnWidthPx val days = geometry.days @@ -872,22 +849,23 @@ class TimelineDragController { val origin = grid.positionInRoot() val held = stickyColumn( position = (pointer.x - origin.x) / columnPx, - held = resizeColumn, + held = session.column, lastIndex = days.lastIndex, ) - resizeColumn = held - val dayOffset = (days[column(held)].toEpochDays() - day.toEpochDays()).toInt() - resizeEdgeDay = dayOffset + session.column = held + val dayOffset = (days[column(held)].toEpochDays() - session.day.toEpochDays()).toInt() + session.edgeDay = dayOffset return dayOffset * MINUTES_PER_DAY + (pointer.y - origin.y) / hourPx * 60f } - private fun recomputeResize(edge: ResizeEdge) { + private fun recomputeResize(session: ResizeSession) { val block = source ?: return - val day = resizeDay ?: return - val raw = pointerResizeMinutes() ?: return - val slot = stickySnap(raw - resizeGrabMin, resizeSlot) - resizeSlot = slot - val (start, end) = resizedSpan(edge, resizeStartMin, resizeEndMin, slot.toFloat(), resizeEdgeDay) + val edge = session.edge + val day = session.day + val raw = pointerResizeMinutes(session) ?: return + val slot = stickySnap(raw - session.grabMin, session.slot) + session.slot = slot + val (start, end) = resizedSpan(edge, session.startMin, session.endMin, slot.toFloat(), session.edgeDay) val days = geometry.days val origin = geometry.grid?.takeIf { it.isAttached }?.positionInRoot() ?: return // Which column the start day sits in, possibly off either end of the view. @@ -946,7 +924,7 @@ class TimelineDragController { * no move events while auto-scroll walks the content underneath it. */ fun recompute() { - resizeEdge?.let { + resize?.let { recomputeResize(it) return } @@ -1049,6 +1027,27 @@ class TimelineDragController { } } +/** One resize gesture (#141): the edge it drags, and the edges as minutes from [day]'s midnight. */ +private class ResizeSession( + val edge: ResizeEdge, + /** The day the resized event starts on. */ + val day: LocalDate, + val startMin: Int, + val endMin: Int, +) { + /** How far the finger sits past the edge it grabbed, so the edge doesn't jump to it. */ + var grabMin = 0f + + /** The column the resized edge is in, held until the finger is well into another. */ + var column: Int? = null + + /** The slot the resized edge sits on, held against a finger trembling between two. */ + var slot: Int? = null + + /** The day, counted from the event's start day, the finger is resizing in. */ + var edgeDay = 0 +} + @Composable fun rememberTimelineDragController(): TimelineDragController { val controller = remember { TimelineDragController() }