Compare commits
3 Commits
release/v2
...
fix/267-dr
| Author | SHA1 | Date | |
|---|---|---|---|
| c2fbfb0bef | |||
| 8db99868af | |||
| 3a29e6f676 |
@@ -33,6 +33,9 @@ val BLOCK_OUTER_INSET = 1.dp
|
|||||||
/** Padding between a timed block's edge and its text. */
|
/** Padding between a timed block's edge and its text. */
|
||||||
val BLOCK_TEXT_PADDING = 4.dp
|
val BLOCK_TEXT_PADDING = 4.dp
|
||||||
|
|
||||||
|
/** The same, above and below — what a block's height has to pay before any text. */
|
||||||
|
val BLOCK_TEXT_INSET = 2.dp
|
||||||
|
|
||||||
/** Most lines a time label may wrap over before it is worth more than a title line. */
|
/** Most lines a time label may wrap over before it is worth more than a title line. */
|
||||||
const val MAX_TIME_LINES = 2
|
const val MAX_TIME_LINES = 2
|
||||||
|
|
||||||
@@ -61,6 +64,33 @@ fun blockTextLines(text: String, style: TextStyle, textWidth: Dp, max: Int): Int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lines the time label may take at [textWidth], out of the [spare] height left
|
||||||
|
* once the title and the label's own first line are paid for.
|
||||||
|
*
|
||||||
|
* A week column is narrower than a "09:30–11:00" range, so the label takes a
|
||||||
|
* second line rather than lose its end — but only out of a line the title
|
||||||
|
* measured itself as not needing, never one it would have filled.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun blockTimeLines(label: String, textWidth: Dp, spare: Dp): Int {
|
||||||
|
val timeLineHeight = with(LocalDensity.current) {
|
||||||
|
MaterialTheme.typography.labelSmall.lineHeight.toDp()
|
||||||
|
}
|
||||||
|
return if (spare >= timeLineHeight) {
|
||||||
|
blockTextLines(
|
||||||
|
text = label,
|
||||||
|
// The style it is drawn in, or the budget measures a line the label
|
||||||
|
// never uses (#219).
|
||||||
|
style = MaterialTheme.typography.labelSmall.asEventTime(),
|
||||||
|
textWidth = textWidth,
|
||||||
|
max = MAX_TIME_LINES,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A timed block's title, over at most [maxLines].
|
* A timed block's title, over at most [maxLines].
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -81,6 +81,13 @@ data class TimelineDrag(
|
|||||||
val eventSpanMin: Int,
|
val eventSpanMin: Int,
|
||||||
/** The event as the grid would draw it, one piece per day column it covers. */
|
/** The event as the grid would draw it, one piece per day column it covers. */
|
||||||
val pieces: List<TimelineDragPiece>,
|
val pieces: List<TimelineDragPiece>,
|
||||||
|
/**
|
||||||
|
* Lines the block the finger picked up drew its title over, zero for one too
|
||||||
|
* short to have drawn it at all. The floating copy is that block's size, so
|
||||||
|
* it has to spend its height the same way or the text re-wraps under the
|
||||||
|
* finger and snaps back on drop (#267).
|
||||||
|
*/
|
||||||
|
val titleLines: Int,
|
||||||
/**
|
/**
|
||||||
* True when [pieces] is only [edgeDragSlice]'s stand-in — the event has left
|
* True when [pieces] is only [edgeDragSlice]'s stand-in — the event has left
|
||||||
* every column this timeline shows. A hint under the finger, not where the
|
* every column this timeline shows. A hint under the finger, not where the
|
||||||
@@ -311,6 +318,9 @@ class TimelineDragController {
|
|||||||
*/
|
*/
|
||||||
private var clipOffsetMin = 0
|
private var clipOffsetMin = 0
|
||||||
|
|
||||||
|
/** What the picked-up block drew its title over — see [TimelineDrag.titleLines]. */
|
||||||
|
private var titleLines = 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The slot the block already occupied when it was picked up — not the same
|
* The slot the block already occupied when it was picked up — not the same
|
||||||
* as its start, since the target snaps to the grid (09:07 lifts to 09:00).
|
* as its start, since the target snaps to the grid (09:07 lifts to 09:00).
|
||||||
@@ -320,11 +330,13 @@ class TimelineDragController {
|
|||||||
fun begin(
|
fun begin(
|
||||||
block: TimedBlock,
|
block: TimedBlock,
|
||||||
clipOffsetMin: Int,
|
clipOffsetMin: Int,
|
||||||
|
titleLines: Int,
|
||||||
pointerInRoot: Offset,
|
pointerInRoot: Offset,
|
||||||
blockInRoot: Offset,
|
blockInRoot: Offset,
|
||||||
) {
|
) {
|
||||||
source = block
|
source = block
|
||||||
this.clipOffsetMin = clipOffsetMin
|
this.clipOffsetMin = clipOffsetMin
|
||||||
|
this.titleLines = titleLines
|
||||||
settling = null
|
settling = null
|
||||||
isDragging = true
|
isDragging = true
|
||||||
liftedInstanceId = block.event.instanceId
|
liftedInstanceId = block.event.instanceId
|
||||||
@@ -343,6 +355,7 @@ class TimelineDragController {
|
|||||||
fun cancel() {
|
fun cancel() {
|
||||||
source = null
|
source = null
|
||||||
clipOffsetMin = 0
|
clipOffsetMin = 0
|
||||||
|
titleLines = 0
|
||||||
isDragging = false
|
isDragging = false
|
||||||
liftedInstanceId = null
|
liftedInstanceId = null
|
||||||
originSlot = null
|
originSlot = null
|
||||||
@@ -465,6 +478,7 @@ class TimelineDragController {
|
|||||||
startMin = startMin,
|
startMin = startMin,
|
||||||
eventStartMin = eventStartMin,
|
eventStartMin = eventStartMin,
|
||||||
eventSpanMin = eventSpan,
|
eventSpanMin = eventSpan,
|
||||||
|
titleLines = titleLines,
|
||||||
// Bounded to the columns this timeline actually shows: a day it
|
// Bounded to the columns this timeline actually shows: a day it
|
||||||
// doesn't has no piece to draw. The write is unaffected.
|
// doesn't has no piece to draw. The write is unaffected.
|
||||||
pieces = slices
|
pieces = slices
|
||||||
@@ -677,6 +691,7 @@ fun TimelineDragOverlay(controller: TimelineDragController, modifier: Modifier =
|
|||||||
lift = lift,
|
lift = lift,
|
||||||
alpha = copyAlpha,
|
alpha = copyAlpha,
|
||||||
title = title,
|
title = title,
|
||||||
|
titleLines = drag.titleLines,
|
||||||
// Once for the whole event: repeated, it would name it per day.
|
// Once for the whole event: repeated, it would name it per day.
|
||||||
label = label.takeIf { index == labelled },
|
label = label.takeIf { index == labelled },
|
||||||
)
|
)
|
||||||
@@ -696,9 +711,28 @@ private fun DragCopy(
|
|||||||
lift: Float,
|
lift: Float,
|
||||||
alpha: Float,
|
alpha: Float,
|
||||||
title: String,
|
title: String,
|
||||||
|
titleLines: Int,
|
||||||
label: String?,
|
label: String?,
|
||||||
) {
|
) {
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
|
val width = with(density) { sizePx.width.toDp() }
|
||||||
|
val height = with(density) { sizePx.height.toDp() }
|
||||||
|
val textWidth = width - (BLOCK_OUTER_INSET + BLOCK_TEXT_PADDING) * 2
|
||||||
|
val titleLineHeight = with(density) {
|
||||||
|
MaterialTheme.typography.labelMedium.lineHeight.toDp()
|
||||||
|
}
|
||||||
|
val timeLineHeight = with(density) {
|
||||||
|
MaterialTheme.typography.labelSmall.lineHeight.toDp()
|
||||||
|
}
|
||||||
|
// The block's size, spent the block's way, so nothing reflows under the
|
||||||
|
// finger (#267) — but the range is paid for first, since it may be showing
|
||||||
|
// where a block too short for it will land, and nothing clips the overrun.
|
||||||
|
val available = height - BLOCK_TEXT_INSET * 2
|
||||||
|
val reserved = if (label == null) 0.dp else timeLineHeight
|
||||||
|
val titleBudget = ((available - reserved) / titleLineHeight).toInt().coerceAtLeast(0)
|
||||||
|
val lines = titleLines.coerceAtMost(titleBudget)
|
||||||
|
val spare = available - titleLineHeight * lines - reserved
|
||||||
|
val timeMaxLines = if (label == null) 1 else blockTimeLines(label, textWidth, spare)
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
// Absolute: these are root coordinates, and the direction-aware
|
// Absolute: these are root coordinates, and the direction-aware
|
||||||
@@ -709,10 +743,7 @@ private fun DragCopy(
|
|||||||
(topLeftInRoot.y - overlayOrigin.y).roundToInt(),
|
(topLeftInRoot.y - overlayOrigin.y).roundToInt(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.size(
|
.size(width = width, height = height)
|
||||||
width = with(density) { sizePx.width.toDp() },
|
|
||||||
height = with(density) { sizePx.height.toDp() },
|
|
||||||
)
|
|
||||||
.padding(horizontal = BLOCK_OUTER_INSET)
|
.padding(horizontal = BLOCK_OUTER_INSET)
|
||||||
.graphicsLayer {
|
.graphicsLayer {
|
||||||
scaleX = 1f + 0.02f * lift
|
scaleX = 1f + 0.02f * lift
|
||||||
@@ -723,28 +754,28 @@ private fun DragCopy(
|
|||||||
clip = false
|
clip = false
|
||||||
}
|
}
|
||||||
.eventSurface(paint, shape, cuts)
|
.eventSurface(paint, shape, cuts)
|
||||||
.padding(horizontal = BLOCK_TEXT_PADDING, vertical = 2.dp),
|
.padding(horizontal = BLOCK_TEXT_PADDING, vertical = BLOCK_TEXT_INSET),
|
||||||
) {
|
) {
|
||||||
Column {
|
Column {
|
||||||
val titleOverflow = eventTitleOverflow()
|
if (lines > 0) {
|
||||||
Text(
|
BlockTitle(
|
||||||
text = title,
|
title = title,
|
||||||
style = MaterialTheme.typography.labelMedium,
|
maxLines = lines,
|
||||||
maxLines = 1,
|
textWidth = textWidth,
|
||||||
overflow = titleOverflow.overflow,
|
color = paint.titleInk,
|
||||||
softWrap = titleOverflow.softWrap,
|
textDecoration = paint.decoration,
|
||||||
color = paint.titleInk,
|
fontWeight = paint.titleWeight,
|
||||||
fontWeight = paint.titleWeight,
|
)
|
||||||
textDecoration = paint.decoration,
|
}
|
||||||
)
|
|
||||||
if (label != null) {
|
if (label != null) {
|
||||||
|
val overflow = eventTitleOverflow(singleLine = timeMaxLines == 1)
|
||||||
Text(
|
Text(
|
||||||
text = label,
|
text = label,
|
||||||
// As the block it lifted off sets its own time (#219).
|
// As the block it lifted off sets its own time (#219).
|
||||||
style = MaterialTheme.typography.labelSmall.asEventTime(),
|
style = MaterialTheme.typography.labelSmall.asEventTime(),
|
||||||
maxLines = 1,
|
maxLines = timeMaxLines,
|
||||||
overflow = titleOverflow.overflow,
|
overflow = overflow.overflow,
|
||||||
softWrap = titleOverflow.softWrap,
|
softWrap = overflow.softWrap,
|
||||||
color = paint.secondaryInk,
|
color = paint.secondaryInk,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,10 +83,10 @@ import de.jeanlucmakiola.calendula.ui.common.CalendarView
|
|||||||
import de.jeanlucmakiola.calendula.ui.common.IMPLEMENTED_VIEWS
|
import de.jeanlucmakiola.calendula.ui.common.IMPLEMENTED_VIEWS
|
||||||
import de.jeanlucmakiola.calendula.ui.common.BLOCK_OUTER_INSET
|
import de.jeanlucmakiola.calendula.ui.common.BLOCK_OUTER_INSET
|
||||||
import de.jeanlucmakiola.calendula.ui.common.BLOCK_TEXT_PADDING
|
import de.jeanlucmakiola.calendula.ui.common.BLOCK_TEXT_PADDING
|
||||||
|
import de.jeanlucmakiola.calendula.ui.common.BLOCK_TEXT_INSET
|
||||||
import de.jeanlucmakiola.calendula.ui.common.BlockTimeLabel
|
import de.jeanlucmakiola.calendula.ui.common.BlockTimeLabel
|
||||||
import de.jeanlucmakiola.calendula.ui.common.BlockTitle
|
import de.jeanlucmakiola.calendula.ui.common.BlockTitle
|
||||||
import de.jeanlucmakiola.calendula.ui.common.MAX_TIME_LINES
|
import de.jeanlucmakiola.calendula.ui.common.blockTimeLines
|
||||||
import de.jeanlucmakiola.calendula.ui.common.blockTextLines
|
|
||||||
import de.jeanlucmakiola.calendula.ui.common.animatedBlockPlacement
|
import de.jeanlucmakiola.calendula.ui.common.animatedBlockPlacement
|
||||||
import de.jeanlucmakiola.calendula.ui.common.ghostAlpha
|
import de.jeanlucmakiola.calendula.ui.common.ghostAlpha
|
||||||
import de.jeanlucmakiola.calendula.ui.common.LocalEventMove
|
import de.jeanlucmakiola.calendula.ui.common.LocalEventMove
|
||||||
@@ -120,7 +120,6 @@ import de.jeanlucmakiola.calendula.ui.common.LocalUse24HourFormat
|
|||||||
import de.jeanlucmakiola.calendula.ui.common.LocalShowHourLines
|
import de.jeanlucmakiola.calendula.ui.common.LocalShowHourLines
|
||||||
import de.jeanlucmakiola.calendula.ui.common.LocalTimelineZoom
|
import de.jeanlucmakiola.calendula.ui.common.LocalTimelineZoom
|
||||||
import de.jeanlucmakiola.calendula.ui.common.MIN_EVENT_FRACTION
|
import de.jeanlucmakiola.calendula.ui.common.MIN_EVENT_FRACTION
|
||||||
import de.jeanlucmakiola.calendula.ui.common.asEventTime
|
|
||||||
import de.jeanlucmakiola.calendula.ui.common.hourHeight
|
import de.jeanlucmakiola.calendula.ui.common.hourHeight
|
||||||
import de.jeanlucmakiola.calendula.ui.common.rememberTimelinePinchZoom
|
import de.jeanlucmakiola.calendula.ui.common.rememberTimelinePinchZoom
|
||||||
import de.jeanlucmakiola.calendula.ui.common.formatMinuteOfDay
|
import de.jeanlucmakiola.calendula.ui.common.formatMinuteOfDay
|
||||||
@@ -738,33 +737,20 @@ private fun EventBlock(
|
|||||||
val timeLineHeight = with(density) {
|
val timeLineHeight = with(density) {
|
||||||
MaterialTheme.typography.labelSmall.lineHeight.toDp()
|
MaterialTheme.typography.labelSmall.lineHeight.toDp()
|
||||||
}
|
}
|
||||||
// What's left for text once the 2.dp top/bottom padding is paid for. A block
|
// A block that cannot afford both lines spends its space on the title, and
|
||||||
// that cannot afford both lines spends its space on the title, and one too
|
// one too short even for that drops the title rather than serving a sliced one.
|
||||||
// short even for that drops the title rather than serving a sliced one.
|
|
||||||
// Height alone decides: a duration threshold would keep hiding the time on a
|
// Height alone decides: a duration threshold would keep hiding the time on a
|
||||||
// half-hour block the user has pinched open to three times the room it needs.
|
// half-hour block the user has pinched open to three times the room it needs.
|
||||||
val available = height - 4.dp
|
val available = height - BLOCK_TEXT_INSET * 2
|
||||||
val showTime = available >= titleLineHeight + timeLineHeight
|
val showTime = available >= titleLineHeight + timeLineHeight
|
||||||
val showTitle = available >= titleLineHeight
|
val showTitle = available >= titleLineHeight
|
||||||
val textWidth = width - (BLOCK_OUTER_INSET + BLOCK_TEXT_PADDING) * 2
|
val textWidth = width - (BLOCK_OUTER_INSET + BLOCK_TEXT_PADDING) * 2
|
||||||
val titleMaxLines = if (showTime) 1 else 2
|
val titleMaxLines = if (showTime) 1 else 2
|
||||||
// The range only wraps out of a line the title has not claimed, which on a
|
// On a day column — wide enough for "09:30–11:00" several times over — the
|
||||||
// day column — wide enough for "09:30–11:00" several times over — means it
|
// range never needs the second line, until lanes cut the column down.
|
||||||
// never does, until lanes cut the column down.
|
|
||||||
val spare = available - titleLineHeight * titleMaxLines -
|
val spare = available - titleLineHeight * titleMaxLines -
|
||||||
if (showTime) timeLineHeight else 0.dp
|
if (showTime) timeLineHeight else 0.dp
|
||||||
val timeMaxLines = if (showTime && spare >= timeLineHeight) {
|
val timeMaxLines = if (showTime) blockTimeLines(timeLabel, textWidth, spare) else 1
|
||||||
blockTextLines(
|
|
||||||
text = timeLabel,
|
|
||||||
// The style it is drawn in, or the budget measures a line the label
|
|
||||||
// never uses (#219).
|
|
||||||
style = MaterialTheme.typography.labelSmall.asEventTime(),
|
|
||||||
textWidth = textWidth,
|
|
||||||
max = MAX_TIME_LINES,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
val paint = eventPaint(block.event, dark)
|
val paint = eventPaint(block.event, dark)
|
||||||
val zone = remember { TimeZone.currentSystemDefault() }
|
val zone = remember { TimeZone.currentSystemDefault() }
|
||||||
val moveAction = eventMoveAction(block.event)
|
val moveAction = eventMoveAction(block.event)
|
||||||
@@ -780,7 +766,13 @@ private fun EventBlock(
|
|||||||
enabled = draggable,
|
enabled = draggable,
|
||||||
key = block.event.instanceId,
|
key = block.event.instanceId,
|
||||||
onPickUp = { pointer, blockRoot, _ ->
|
onPickUp = { pointer, blockRoot, _ ->
|
||||||
dragController.begin(block, clipOffset, pointer, blockRoot)
|
dragController.begin(
|
||||||
|
block = block,
|
||||||
|
clipOffsetMin = clipOffset,
|
||||||
|
titleLines = if (showTitle) titleMaxLines else 0,
|
||||||
|
pointerInRoot = pointer,
|
||||||
|
blockInRoot = blockRoot,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onMove = dragController::move,
|
onMove = dragController::move,
|
||||||
onDrop = { dragController.finish()?.let(onDrop) },
|
onDrop = { dragController.finish()?.let(onDrop) },
|
||||||
@@ -797,7 +789,7 @@ private fun EventBlock(
|
|||||||
// After clickable, so it is the inner node and wins the main pass;
|
// After clickable, so it is the inner node and wins the main pass;
|
||||||
// the tap still works, since a drag consumes the up.
|
// the tap still works, since a drag consumes the up.
|
||||||
.then(dragModifier)
|
.then(dragModifier)
|
||||||
.padding(horizontal = BLOCK_TEXT_PADDING, vertical = 2.dp)
|
.padding(horizontal = BLOCK_TEXT_PADDING, vertical = BLOCK_TEXT_INSET)
|
||||||
.semantics {
|
.semantics {
|
||||||
contentDescription = "$title, $timeLabel"
|
contentDescription = "$title, $timeLabel"
|
||||||
if (moveAction != null) customActions = listOf(moveAction)
|
if (moveAction != null) customActions = listOf(moveAction)
|
||||||
|
|||||||
@@ -91,10 +91,11 @@ import de.jeanlucmakiola.calendula.ui.common.IMPLEMENTED_VIEWS
|
|||||||
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
|
import de.jeanlucmakiola.calendula.ui.common.EventDimAlpha
|
||||||
import de.jeanlucmakiola.calendula.ui.common.BLOCK_OUTER_INSET
|
import de.jeanlucmakiola.calendula.ui.common.BLOCK_OUTER_INSET
|
||||||
import de.jeanlucmakiola.calendula.ui.common.BLOCK_TEXT_PADDING
|
import de.jeanlucmakiola.calendula.ui.common.BLOCK_TEXT_PADDING
|
||||||
|
import de.jeanlucmakiola.calendula.ui.common.BLOCK_TEXT_INSET
|
||||||
import de.jeanlucmakiola.calendula.ui.common.BlockTimeLabel
|
import de.jeanlucmakiola.calendula.ui.common.BlockTimeLabel
|
||||||
import de.jeanlucmakiola.calendula.ui.common.BlockTitle
|
import de.jeanlucmakiola.calendula.ui.common.BlockTitle
|
||||||
import de.jeanlucmakiola.calendula.ui.common.MAX_TIME_LINES
|
|
||||||
import de.jeanlucmakiola.calendula.ui.common.blockTextLines
|
import de.jeanlucmakiola.calendula.ui.common.blockTextLines
|
||||||
|
import de.jeanlucmakiola.calendula.ui.common.blockTimeLines
|
||||||
import de.jeanlucmakiola.calendula.ui.common.animatedBlockPlacement
|
import de.jeanlucmakiola.calendula.ui.common.animatedBlockPlacement
|
||||||
import de.jeanlucmakiola.calendula.ui.common.ghostAlpha
|
import de.jeanlucmakiola.calendula.ui.common.ghostAlpha
|
||||||
import de.jeanlucmakiola.calendula.ui.common.LocalEventMove
|
import de.jeanlucmakiola.calendula.ui.common.LocalEventMove
|
||||||
@@ -130,7 +131,6 @@ import de.jeanlucmakiola.calendula.ui.common.LocalShowHourLines
|
|||||||
import de.jeanlucmakiola.calendula.ui.common.LocalTimelineZoom
|
import de.jeanlucmakiola.calendula.ui.common.LocalTimelineZoom
|
||||||
import de.jeanlucmakiola.calendula.ui.common.MIN_EVENT_FRACTION
|
import de.jeanlucmakiola.calendula.ui.common.MIN_EVENT_FRACTION
|
||||||
import de.jeanlucmakiola.calendula.ui.common.MIN_TITLE_WRAP_WIDTH
|
import de.jeanlucmakiola.calendula.ui.common.MIN_TITLE_WRAP_WIDTH
|
||||||
import de.jeanlucmakiola.calendula.ui.common.asEventTime
|
|
||||||
import de.jeanlucmakiola.calendula.ui.common.hourHeight
|
import de.jeanlucmakiola.calendula.ui.common.hourHeight
|
||||||
import de.jeanlucmakiola.calendula.ui.common.rememberTimelinePinchZoom
|
import de.jeanlucmakiola.calendula.ui.common.rememberTimelinePinchZoom
|
||||||
import de.jeanlucmakiola.calendula.ui.common.formatMinuteOfDay
|
import de.jeanlucmakiola.calendula.ui.common.formatMinuteOfDay
|
||||||
@@ -883,8 +883,7 @@ private fun EventBlock(
|
|||||||
val timeLineHeight = with(density) {
|
val timeLineHeight = with(density) {
|
||||||
MaterialTheme.typography.labelSmall.lineHeight.toDp()
|
MaterialTheme.typography.labelSmall.lineHeight.toDp()
|
||||||
}
|
}
|
||||||
// What's left for text once the 2.dp top/bottom padding is paid for.
|
val available = height - BLOCK_TEXT_INSET * 2
|
||||||
val available = height - 4.dp
|
|
||||||
// Only full-width (non-overlapping) blocks that are tall enough show the
|
// Only full-width (non-overlapping) blocks that are tall enough show the
|
||||||
// time. On narrow overlapping columns we drop it so the title can wrap to
|
// time. On narrow overlapping columns we drop it so the title can wrap to
|
||||||
// fill the whole block, mirroring Google Calendar — and a block that cannot
|
// fill the whole block, mirroring Google Calendar — and a block that cannot
|
||||||
@@ -918,23 +917,9 @@ private fun EventBlock(
|
|||||||
max = titleBudget,
|
max = titleBudget,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// A week column is narrower than a "09:30–11:00" range, so the label takes a
|
|
||||||
// second line rather than lose its end — but only out of a line the title
|
|
||||||
// measured itself as not needing, never one it would have filled.
|
|
||||||
val spare = available - titleLineHeight * titleMaxLines -
|
val spare = available - titleLineHeight * titleMaxLines -
|
||||||
if (showTime) timeLineHeight else 0.dp
|
if (showTime) timeLineHeight else 0.dp
|
||||||
val timeMaxLines = if (showTime && spare >= timeLineHeight) {
|
val timeMaxLines = if (showTime) blockTimeLines(timeLabel, textWidth, spare) else 1
|
||||||
blockTextLines(
|
|
||||||
text = timeLabel,
|
|
||||||
// The style it is drawn in, or the budget measures a line the label
|
|
||||||
// never uses (#219).
|
|
||||||
style = MaterialTheme.typography.labelSmall.asEventTime(),
|
|
||||||
textWidth = textWidth,
|
|
||||||
max = MAX_TIME_LINES,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
val dimCutoff = LocalDimCutoff.current
|
val dimCutoff = LocalDimCutoff.current
|
||||||
val dimmed = dimCutoff != null && block.event.hasEnded(dimCutoff)
|
val dimmed = dimCutoff != null && block.event.hasEnded(dimCutoff)
|
||||||
val zone = remember { TimeZone.currentSystemDefault() }
|
val zone = remember { TimeZone.currentSystemDefault() }
|
||||||
@@ -951,7 +936,13 @@ private fun EventBlock(
|
|||||||
enabled = draggable,
|
enabled = draggable,
|
||||||
key = block.event.instanceId,
|
key = block.event.instanceId,
|
||||||
onPickUp = { pointer, blockRoot, _ ->
|
onPickUp = { pointer, blockRoot, _ ->
|
||||||
dragController.begin(block, clipOffset, pointer, blockRoot)
|
dragController.begin(
|
||||||
|
block = block,
|
||||||
|
clipOffsetMin = clipOffset,
|
||||||
|
titleLines = if (showTitle) titleMaxLines else 0,
|
||||||
|
pointerInRoot = pointer,
|
||||||
|
blockInRoot = blockRoot,
|
||||||
|
)
|
||||||
},
|
},
|
||||||
onMove = dragController::move,
|
onMove = dragController::move,
|
||||||
onDrop = { dragController.finish()?.let(onDrop) },
|
onDrop = { dragController.finish()?.let(onDrop) },
|
||||||
@@ -968,7 +959,7 @@ private fun EventBlock(
|
|||||||
// After clickable, so it is the inner node and wins the main pass;
|
// After clickable, so it is the inner node and wins the main pass;
|
||||||
// the tap still works, since a drag consumes the up.
|
// the tap still works, since a drag consumes the up.
|
||||||
.then(dragModifier)
|
.then(dragModifier)
|
||||||
.padding(horizontal = BLOCK_TEXT_PADDING, vertical = 2.dp)
|
.padding(horizontal = BLOCK_TEXT_PADDING, vertical = BLOCK_TEXT_INSET)
|
||||||
.semantics {
|
.semantics {
|
||||||
contentDescription = "$title, $timeLabel"
|
contentDescription = "$title, $timeLabel"
|
||||||
if (moveAction != null) customActions = listOf(moveAction)
|
if (moveAction != null) customActions = listOf(moveAction)
|
||||||
|
|||||||
Reference in New Issue
Block a user