1 /* <lambda>null2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.compose.material3.internal 18 19 import androidx.compose.ui.Modifier 20 import androidx.compose.ui.node.ModifierNodeElement 21 import androidx.compose.ui.node.SemanticsModifierNode 22 import androidx.compose.ui.node.TraversableNode 23 import androidx.compose.ui.node.invalidateSemantics 24 import androidx.compose.ui.node.traverseAncestors 25 import androidx.compose.ui.platform.InspectorInfo 26 import androidx.compose.ui.semantics.SemanticsPropertyReceiver 27 28 internal fun Modifier.childSemantics(properties: SemanticsPropertyReceiver.() -> Unit = {}) = 29 this then ChildSemanticsNodeElement(properties) 30 parentSemanticsnull31internal fun Modifier.parentSemantics(properties: SemanticsPropertyReceiver.() -> Unit) = 32 this then ParentSemanticsNodeElement(properties) 33 34 internal class ChildSemanticsNodeElement(val properties: SemanticsPropertyReceiver.() -> Unit) : 35 ModifierNodeElement<ChildSemanticsNode>() { 36 override fun create(): ChildSemanticsNode = ChildSemanticsNode(properties) 37 38 override fun update(node: ChildSemanticsNode) { 39 node.properties = properties 40 node.invalidateSemantics() 41 } 42 43 override fun InspectorInfo.inspectableProperties() { 44 name = "childSemantics" 45 this@inspectableProperties.properties["properties"] = 46 this@ChildSemanticsNodeElement.properties 47 } 48 49 override fun equals(other: Any?): Boolean { 50 if (this === other) return true 51 if (other !is ChildSemanticsNodeElement) return false 52 53 return properties === other.properties 54 } 55 56 override fun hashCode(): Int { 57 return properties.hashCode() 58 } 59 } 60 61 internal class ParentSemanticsNodeElement(val properties: SemanticsPropertyReceiver.() -> Unit) : 62 ModifierNodeElement<ParentSemanticsNode>() { createnull63 override fun create(): ParentSemanticsNode = ParentSemanticsNode(properties) 64 65 override fun update(node: ParentSemanticsNode) { 66 node.properties = properties 67 node.invalidateSemantics() 68 } 69 inspectablePropertiesnull70 override fun InspectorInfo.inspectableProperties() { 71 name = "parentSemantics" 72 this@inspectableProperties.properties["properties"] = 73 this@ParentSemanticsNodeElement.properties 74 } 75 equalsnull76 override fun equals(other: Any?): Boolean { 77 if (this === other) return true 78 if (other !is ParentSemanticsNodeElement) return false 79 80 return properties === other.properties 81 } 82 hashCodenull83 override fun hashCode(): Int { 84 return properties.hashCode() 85 } 86 } 87 88 internal class ChildSemanticsNode(var properties: SemanticsPropertyReceiver.() -> Unit) : 89 Modifier.Node(), SemanticsModifierNode { 90 applySemanticsnull91 override fun SemanticsPropertyReceiver.applySemantics() { 92 traverseAncestors(ParentSemanticsNodeKey) { node -> 93 with(node as ParentSemanticsNode) { 94 obtainSemantics() 95 false 96 } 97 } 98 properties() 99 } 100 onDetachnull101 override fun onDetach() { 102 super.onDetach() 103 traverseAncestors(ParentSemanticsNodeKey) { node -> 104 (node as ParentSemanticsNode) 105 node.releaseSemantics() 106 false 107 } 108 } 109 } 110 111 internal class ParentSemanticsNode(var properties: SemanticsPropertyReceiver.() -> Unit) : 112 Modifier.Node(), TraversableNode, SemanticsModifierNode { 113 114 private var semanticsConsumed: Boolean = false 115 116 override val shouldMergeDescendantSemantics: Boolean 117 get() = true 118 119 override val traverseKey: Any = ParentSemanticsNodeKey 120 applySemanticsnull121 override fun SemanticsPropertyReceiver.applySemantics() { 122 if (!semanticsConsumed) { 123 properties() 124 } 125 } 126 SemanticsPropertyReceivernull127 fun SemanticsPropertyReceiver.obtainSemantics() { 128 semanticsConsumed = true 129 properties() 130 invalidateSemantics() 131 } 132 releaseSemanticsnull133 fun releaseSemantics() { 134 semanticsConsumed = false 135 invalidateSemantics() 136 } 137 } 138 139 internal object ParentSemanticsNodeKey 140