Keep the move action and default off while unknown (#173)
Switching drag off gated the whole move scope, which also removed the TalkBack move action — a menu item can't cause an accidental drag, so it stays; only the gesture is gated now, via EventMoveScope.dragEnabled. The host flow also started at true, re-arming the gesture for the first frames of a cold start for exactly the user who turned it off.
This commit is contained in:
@@ -312,12 +312,13 @@ fun CalendarHost(
|
||||
heldEditKey = key
|
||||
editKey = key
|
||||
}
|
||||
// Off by preference (#173) means no scope at all: every block then registers
|
||||
// no drag gesture, and the edit form stays the way to reschedule.
|
||||
// Off by preference (#173) switches off the gesture, not the scope: blocks
|
||||
// register no drag, while the edit form and its TalkBack action stay put.
|
||||
val dragToReschedule = viewModel.dragToReschedule.collectAsStateWithLifecycle().value
|
||||
val moveScope = remember(movableCalendarIds, reschedule) {
|
||||
val moveScope = remember(movableCalendarIds, reschedule, dragToReschedule) {
|
||||
EventMoveScope(
|
||||
movableCalendarIds = movableCalendarIds,
|
||||
dragEnabled = dragToReschedule,
|
||||
move = reschedule::move,
|
||||
inFlight = reschedule.inFlight,
|
||||
undoStarted = reschedule.undoStarted,
|
||||
@@ -342,7 +343,7 @@ fun CalendarHost(
|
||||
// navigation, so it fades through rather than sliding — paging *within* a
|
||||
// view keeps the directional slide. AnimatedContent keyed on the view type.
|
||||
val viewSwitch = fadeThrough()
|
||||
CompositionLocalProvider(LocalEventMove provides moveScope.takeIf { dragToReschedule }) {
|
||||
CompositionLocalProvider(LocalEventMove provides moveScope) {
|
||||
AnimatedContent(
|
||||
targetState = view,
|
||||
transitionSpec = { viewSwitch },
|
||||
|
||||
@@ -54,11 +54,17 @@ class CalendarHostViewModel @Inject constructor(
|
||||
initialValue = false,
|
||||
)
|
||||
|
||||
/** Whether events may be dragged to another slot to reschedule them (#68, #173). */
|
||||
/**
|
||||
* Whether events may be dragged to another slot to reschedule them (#68, #173).
|
||||
* Off until the stored value arrives, even though the preference itself defaults
|
||||
* on: the wrong guess costs an enabled user a gesture for the few frames a cold
|
||||
* start takes to read DataStore, but re-arms the one thing a disabled user
|
||||
* switched off to be rid of.
|
||||
*/
|
||||
val dragToReschedule: StateFlow<Boolean> = prefs.dragToReschedule
|
||||
.stateIn(
|
||||
scope = viewModelScope,
|
||||
started = SharingStarted.WhileSubscribed(5_000L),
|
||||
initialValue = true,
|
||||
initialValue = false,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -29,6 +29,12 @@ class EventMoveScope(
|
||||
* the repository writes whatever it is handed — so this gate is load-bearing.
|
||||
*/
|
||||
val movableCalendarIds: Set<Long>,
|
||||
/**
|
||||
* Whether the *gesture* is on (#173). Off gates the drag alone: [edit] and the
|
||||
* TalkBack action below stay, since invoking a menu item can't cause the
|
||||
* accidental drags the setting exists to stop.
|
||||
*/
|
||||
val dragEnabled: Boolean,
|
||||
/** False when the drop was refused outright, so nothing will be written. */
|
||||
val move: (MoveRequest) -> Boolean,
|
||||
/**
|
||||
@@ -91,6 +97,17 @@ fun ghostAlpha(lifted: Boolean): Float = animateFloatAsState(
|
||||
label = "ghost-alpha",
|
||||
).value
|
||||
|
||||
/**
|
||||
* Whether [event] can be picked up and dragged — its calendar allows moving and
|
||||
* the gesture is switched on. Not the same question as [eventMoveAction], which
|
||||
* survives the setting.
|
||||
*/
|
||||
@Composable
|
||||
fun eventDragAllowed(event: EventInstance): Boolean {
|
||||
val move = LocalEventMove.current ?: return false
|
||||
return move.dragEnabled && move.allows(event)
|
||||
}
|
||||
|
||||
/**
|
||||
* A TalkBack action that opens [event] in the edit form, so rescheduling isn't
|
||||
* pointer-only. Null when this event can't be moved.
|
||||
|
||||
@@ -92,6 +92,7 @@ import de.jeanlucmakiola.calendula.ui.common.TimelineDragController
|
||||
import de.jeanlucmakiola.calendula.ui.common.TimelineDragOverlay
|
||||
import de.jeanlucmakiola.calendula.ui.common.TimelineDrop
|
||||
import de.jeanlucmakiola.calendula.ui.common.beginsOn
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventDragAllowed
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventMoveAction
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberEventDragSource
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberTimelineDragController
|
||||
@@ -737,7 +738,7 @@ private fun EventBlock(
|
||||
val moveAction = eventMoveAction(block.event)
|
||||
// A block clipped at the top continues from the previous day: its top edge
|
||||
// is midnight, not the event's start, so dragging it would invent a time.
|
||||
val draggable = moveAction != null && block.beginsOn(date, zone)
|
||||
val draggable = eventDragAllowed(block.event) && block.beginsOn(date, zone)
|
||||
val dragModifier = rememberEventDragSource(
|
||||
enabled = draggable,
|
||||
key = block.event.instanceId,
|
||||
|
||||
@@ -2172,7 +2172,7 @@ private fun monthChipDragModifier(
|
||||
rowHeightPx: Float,
|
||||
isRtl: Boolean,
|
||||
): Modifier = rememberDragSurface(
|
||||
enabled = moveScope != null && controller != null,
|
||||
enabled = moveScope?.dragEnabled == true && controller != null,
|
||||
key = week.days.first(),
|
||||
onPickUp = { local, pointerInRoot, nodeInRoot, size ->
|
||||
val bandTop = band[0]?.takeIf { it.isAttached }?.positionInRoot()?.y
|
||||
|
||||
@@ -100,6 +100,7 @@ import de.jeanlucmakiola.calendula.ui.common.TimelineDragController
|
||||
import de.jeanlucmakiola.calendula.ui.common.TimelineDragOverlay
|
||||
import de.jeanlucmakiola.calendula.ui.common.TimelineDrop
|
||||
import de.jeanlucmakiola.calendula.ui.common.beginsOn
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventDragAllowed
|
||||
import de.jeanlucmakiola.calendula.ui.common.eventMoveAction
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberEventDragSource
|
||||
import de.jeanlucmakiola.calendula.ui.common.rememberTimelineDragController
|
||||
@@ -905,7 +906,7 @@ private fun EventBlock(
|
||||
val moveAction = eventMoveAction(block.event)
|
||||
// A block clipped at the top continues from the previous day: its top edge
|
||||
// is midnight, not the event's start, so dragging it would invent a time.
|
||||
val draggable = moveAction != null && block.beginsOn(date, zone)
|
||||
val draggable = eventDragAllowed(block.event) && block.beginsOn(date, zone)
|
||||
val dragModifier = rememberEventDragSource(
|
||||
enabled = draggable,
|
||||
key = block.event.instanceId,
|
||||
|
||||
Reference in New Issue
Block a user