1 /*
2  * Copyright 2023 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.foundation.text.modifiers
18 
19 import androidx.compose.foundation.text.DefaultMinLines
20 import androidx.compose.foundation.text.TextAutoSize
21 import androidx.compose.ui.geometry.Rect
22 import androidx.compose.ui.graphics.ColorProducer
23 import androidx.compose.ui.node.ModifierNodeElement
24 import androidx.compose.ui.platform.InspectorInfo
25 import androidx.compose.ui.text.AnnotatedString
26 import androidx.compose.ui.text.Placeholder
27 import androidx.compose.ui.text.TextLayoutResult
28 import androidx.compose.ui.text.TextStyle
29 import androidx.compose.ui.text.font.FontFamily
30 import androidx.compose.ui.text.style.TextOverflow
31 
32 /** Element for any text that is in a selection container. */
33 internal class SelectableTextAnnotatedStringElement(
34     private val text: AnnotatedString,
35     private val style: TextStyle,
36     private val fontFamilyResolver: FontFamily.Resolver,
37     private val onTextLayout: ((TextLayoutResult) -> Unit)? = null,
38     private val overflow: TextOverflow = TextOverflow.Clip,
39     private val softWrap: Boolean = true,
40     private val maxLines: Int = Int.MAX_VALUE,
41     private val minLines: Int = DefaultMinLines,
42     private val placeholders: List<AnnotatedString.Range<Placeholder>>? = null,
43     private val onPlaceholderLayout: ((List<Rect?>) -> Unit)? = null,
44     private val selectionController: SelectionController? = null,
45     private val color: ColorProducer? = null,
46     private val autoSize: TextAutoSize? = null
47 ) : ModifierNodeElement<SelectableTextAnnotatedStringNode>() {
48 
createnull49     override fun create(): SelectableTextAnnotatedStringNode =
50         SelectableTextAnnotatedStringNode(
51             text,
52             style,
53             fontFamilyResolver,
54             onTextLayout,
55             overflow,
56             softWrap,
57             maxLines,
58             minLines,
59             placeholders,
60             onPlaceholderLayout,
61             selectionController,
62             color,
63             autoSize
64         )
65 
66     override fun update(node: SelectableTextAnnotatedStringNode) {
67         node.update(
68             text = text,
69             style = style,
70             placeholders = placeholders,
71             minLines = minLines,
72             maxLines = maxLines,
73             softWrap = softWrap,
74             fontFamilyResolver = fontFamilyResolver,
75             overflow = overflow,
76             onTextLayout = onTextLayout,
77             onPlaceholderLayout = onPlaceholderLayout,
78             selectionController = selectionController,
79             color = color,
80             autoSize = autoSize
81         )
82     }
83 
equalsnull84     override fun equals(other: Any?): Boolean {
85         if (this === other) return true
86 
87         if (other !is SelectableTextAnnotatedStringElement) return false
88 
89         // these three are most likely to actually change
90         if (color != other.color) return false
91         if (text != other.text) return false
92         if (style != other.style) return false
93         if (placeholders != other.placeholders) return false
94 
95         // these are equally unlikely to change
96         if (fontFamilyResolver != other.fontFamilyResolver) return false
97         if (autoSize != other.autoSize) return false
98         if (onTextLayout !== other.onTextLayout) return false
99         if (overflow != other.overflow) return false
100         if (softWrap != other.softWrap) return false
101         if (maxLines != other.maxLines) return false
102         if (minLines != other.minLines) return false
103 
104         // these never change, but check anyway for correctness
105         if (onPlaceholderLayout !== other.onPlaceholderLayout) return false
106         if (selectionController != other.selectionController) return false
107 
108         return true
109     }
110 
hashCodenull111     override fun hashCode(): Int {
112         var result = text.hashCode()
113         result = 31 * result + style.hashCode()
114         result = 31 * result + fontFamilyResolver.hashCode()
115         result = 31 * result + (onTextLayout?.hashCode() ?: 0)
116         result = 31 * result + overflow.hashCode()
117         result = 31 * result + softWrap.hashCode()
118         result = 31 * result + maxLines
119         result = 31 * result + minLines
120         result = 31 * result + (placeholders?.hashCode() ?: 0)
121         result = 31 * result + (onPlaceholderLayout?.hashCode() ?: 0)
122         result = 31 * result + (selectionController?.hashCode() ?: 0)
123         result = 31 * result + (autoSize?.hashCode() ?: 0)
124         result = 31 * result + (color?.hashCode() ?: 0)
125         return result
126     }
127 
inspectablePropertiesnull128     override fun InspectorInfo.inspectableProperties() {
129         // Show nothing in the inspector.
130     }
131 }
132