![JAR search and dependency download from the Maven repository](/logo.png)
net.peanuuutz.fork.ui.foundation.input.Focusable.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of fork-ui Show documentation
Show all versions of fork-ui Show documentation
Comprehensive API designed for Minecraft modders
The newest version!
/*
* Copyright 2020 The Android Open Source Project
* Modifications Copyright 2022 Peanuuutz
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.peanuuutz.fork.ui.foundation.input
import androidx.compose.runtime.Stable
import kotlinx.coroutines.launch
import net.peanuuutz.fork.ui.foundation.input.interaction.FocusInteraction
import net.peanuuutz.fork.ui.foundation.input.interaction.MutableInteractionSource
import net.peanuuutz.fork.ui.foundation.input.interaction.emitFocus
import net.peanuuutz.fork.ui.foundation.input.interaction.emitUnFocus
import net.peanuuutz.fork.ui.foundation.input.interaction.tryEmitUnFocus
import net.peanuuutz.fork.ui.inspection.InspectInfo
import net.peanuuutz.fork.ui.ui.context.focus.FocusMoveDirection
import net.peanuuutz.fork.ui.ui.modifier.Modifier
import net.peanuuutz.fork.ui.ui.modifier.ModifierNodeElement
import net.peanuuutz.fork.ui.ui.modifier.input.FocusChangedModifierNode
import net.peanuuutz.fork.ui.ui.modifier.input.focusTarget
import net.peanuuutz.fork.ui.ui.node.BranchingModifierNode
import net.peanuuutz.fork.ui.ui.node.FocusEventModifierNode
@Stable
fun Modifier.focusable(
interactionSource: MutableInteractionSource,
label: Any? = null,
isEnabled: Boolean = true
): Modifier {
if (!isEnabled) {
return this
}
val element = FocusableModifier(
interactionSource = interactionSource,
label = label
)
return this
.then(element)
.focusTarget()
}
// ======== Internal ========
private data class FocusableModifier(
val interactionSource: MutableInteractionSource,
val label: Any?
) : ModifierNodeElement() {
override fun create(): FocusableModifierNode {
return FocusableModifierNode(
interactionSource = interactionSource,
label = label
)
}
override fun update(node: FocusableModifierNode) {
node.interactionSource = interactionSource
node.label = label
}
override fun InspectInfo.inspect() {
set("label", label)
}
}
private class FocusableModifierNode(
interactionSource: MutableInteractionSource,
label: Any?
) : BranchingModifierNode(), FocusEventModifierNode {
var interactionSource: MutableInteractionSource = interactionSource
set(value) {
if (field == value) {
return
}
field.tryEmitUnFocus(
stateProvider = this::focusState,
stateUpdater = this::focusState::set
)
field = value
}
var label: Any? = label
set(value) {
if (field == value) {
return
}
interactionSource.tryEmitUnFocus(
stateProvider = this::focusState,
stateUpdater = this::focusState::set
)
field = value
}
private val focusChangedDetector: FocusChangedModifierNode = branch {
FocusChangedModifierNode { isFocused, _ ->
if (isFocused) {
nodeScope.launch {
val effectInteractionSource = [email protected]
effectInteractionSource.emitUnFocus(
stateProvider = this@FocusableModifierNode::focusState,
stateUpdater = this@FocusableModifierNode::focusState::set
)
effectInteractionSource.emitFocus(
stateProvider = this@FocusableModifierNode::focusState,
stateUpdater = this@FocusableModifierNode::focusState::set,
labelProvider = this@FocusableModifierNode::label
)
}
} else {
nodeScope.launch {
[email protected](
stateProvider = this@FocusableModifierNode::focusState,
stateUpdater = this@FocusableModifierNode::focusState::set
)
}
}
}
}
private var focusState: FocusInteraction.Focus? = null
override fun onDetach() {
interactionSource.tryEmitUnFocus(
stateProvider = this::focusState,
stateUpdater = this::focusState::set
)
}
override fun onFocusEvent(isFocused: Boolean, direction: FocusMoveDirection?) {
focusChangedDetector.onFocusEvent(isFocused, direction)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy