Skip to content

Commit 8622e9e

Browse files
authored
Migrate Modifier.selectionGestureInput from Modifier.composed to Modifier.Node (JetBrains#2857)
Migrate Modifier.selectionGestureInput from Modifier.composed to Modifier.Node Fixes [CMP-9913](https://youtrack.jetbrains.com/issue/CMP-9913) Move Modifier.selectionGestureInput from composed API to Modifier.Node ## Release Notes N/A
1 parent a81869b commit 8622e9e

1 file changed

Lines changed: 80 additions & 23 deletions

File tree

compose/foundation/foundation/src/iosMain/kotlin/androidx/compose/foundation/text/modifiers/SelectionController.ios.kt

Lines changed: 80 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,24 @@ import androidx.compose.foundation.text.selection.SelectionAdjustment
2525
import androidx.compose.foundation.text.selection.SelectionRegistrar
2626
import androidx.compose.foundation.text.selection.hasSelection
2727
import androidx.compose.foundation.text.selection.isMouseOrTouchPad
28-
import androidx.compose.runtime.getValue
29-
import androidx.compose.runtime.rememberUpdatedState
3028
import androidx.compose.ui.Modifier
31-
import androidx.compose.ui.composed
3229
import androidx.compose.ui.geometry.Offset
3330
import androidx.compose.ui.hapticfeedback.HapticFeedback
3431
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
3532
import androidx.compose.ui.input.pointer.AwaitPointerEventScope
3633
import androidx.compose.ui.input.pointer.PointerEvent
3734
import androidx.compose.ui.input.pointer.PointerEventPass
35+
import androidx.compose.ui.input.pointer.SuspendingPointerInputModifierNode
3836
import androidx.compose.ui.input.pointer.changedToDownIgnoreConsumed
3937
import androidx.compose.ui.input.pointer.changedToUp
4038
import androidx.compose.ui.input.pointer.isPrimaryPressed
4139
import androidx.compose.ui.input.pointer.isShiftPressed
42-
import androidx.compose.ui.input.pointer.pointerInput
4340
import androidx.compose.ui.layout.LayoutCoordinates
41+
import androidx.compose.ui.node.CompositionLocalConsumerModifierNode
42+
import androidx.compose.ui.node.DelegatingNode
43+
import androidx.compose.ui.node.ModifierNodeElement
44+
import androidx.compose.ui.node.currentValueOf
45+
import androidx.compose.ui.platform.InspectorInfo
4446
import androidx.compose.ui.platform.LocalHapticFeedback
4547
import androidx.compose.ui.util.fastAll
4648
import androidx.compose.ui.util.fastForEach
@@ -228,29 +230,84 @@ internal actual fun SelectionRegistrar.makeSelectionModifier(
228230
return Modifier.selectionGestureInput(mouseSelectionObserver, longPressDragObserver)
229231
}
230232

231-
// Copied from SelectionController.kt, except CupertinoTextDragObserver parameter
232233
private fun Modifier.selectionGestureInput(
233234
mouseSelectionObserver: MouseSelectionObserver,
234235
textDragObserver: CupertinoTextDragObserver,
235-
): Modifier = composed {
236-
// TODO(https://youtrack.jetbrains.com/issue/COMPOSE-79) how we can rewrite this without `composed`?
237-
val currentMouseSelectionObserver by rememberUpdatedState(mouseSelectionObserver)
238-
val currentTextDragObserver by rememberUpdatedState(textDragObserver)
239-
val hapticFeedback = LocalHapticFeedback.current
240-
this.pointerInput(Unit) {
241-
val clicksCounter = ClicksCounter(viewConfiguration)
242-
awaitEachGesture {
243-
val down = awaitDown()
244-
if (
245-
down.isMouseOrTouchPad() &&
246-
down.buttons.isPrimaryPressed &&
247-
down.changes.fastAll { !it.isConsumed }
248-
) {
249-
mouseSelection(currentMouseSelectionObserver, clicksCounter, down)
250-
} else if (!down.isMouseOrTouchPad()) {
251-
touchSelection(currentTextDragObserver, clicksCounter, down, hapticFeedback)
236+
): Modifier = this.then(
237+
SelectionGestureInputElement(
238+
mouseSelectionObserver = mouseSelectionObserver,
239+
textDragObserver = textDragObserver,
240+
)
241+
)
242+
243+
private class SelectionGestureInputElement(
244+
private val mouseSelectionObserver: MouseSelectionObserver,
245+
private val textDragObserver: CupertinoTextDragObserver,
246+
) : ModifierNodeElement<SelectionGestureInputNode>() {
247+
248+
override fun create(): SelectionGestureInputNode = SelectionGestureInputNode(
249+
mouseSelectionObserver = mouseSelectionObserver,
250+
textDragObserver = textDragObserver,
251+
)
252+
253+
override fun update(node: SelectionGestureInputNode) = node.update(
254+
mouseSelectionObserver = mouseSelectionObserver,
255+
textDragObserver = textDragObserver,
256+
)
257+
258+
override fun InspectorInfo.inspectableProperties() {
259+
name = "selectionGestureInput"
260+
properties["mouseSelectionObserver"] = mouseSelectionObserver
261+
properties["textDragObserver"] = textDragObserver
262+
}
263+
264+
override fun equals(other: Any?): Boolean =
265+
other is SelectionGestureInputElement &&
266+
other !== this &&
267+
mouseSelectionObserver == other.mouseSelectionObserver &&
268+
textDragObserver == other.textDragObserver
269+
270+
override fun hashCode(): Int {
271+
var result = mouseSelectionObserver.hashCode()
272+
result = 31 * result + textDragObserver.hashCode()
273+
return result
274+
}
275+
}
276+
277+
private class SelectionGestureInputNode(
278+
private var mouseSelectionObserver: MouseSelectionObserver,
279+
private var textDragObserver: CupertinoTextDragObserver,
280+
): DelegatingNode(), CompositionLocalConsumerModifierNode {
281+
282+
private val pointerInputNode = delegate(
283+
SuspendingPointerInputModifierNode(
284+
pointerInputEventHandler = {
285+
val hapticFeedback = currentValueOf(LocalHapticFeedback)
286+
val clicksCounter = ClicksCounter(viewConfiguration)
287+
288+
awaitEachGesture {
289+
val down = awaitDown()
290+
291+
if (
292+
down.isMouseOrTouchPad() &&
293+
down.buttons.isPrimaryPressed &&
294+
down.changes.fastAll { !it.isConsumed }
295+
) {
296+
mouseSelection(mouseSelectionObserver, clicksCounter, down)
297+
} else if (!down.isMouseOrTouchPad()) {
298+
touchSelection(textDragObserver, clicksCounter, down, hapticFeedback)
299+
}
300+
}
252301
}
253-
}
302+
)
303+
)
304+
305+
fun update(
306+
mouseSelectionObserver: MouseSelectionObserver,
307+
textDragObserver: CupertinoTextDragObserver,
308+
) {
309+
this.mouseSelectionObserver = mouseSelectionObserver
310+
this.textDragObserver = textDragObserver
254311
}
255312
}
256313

0 commit comments

Comments
 (0)