| /* |
| * Copyright 2023 The Android Open Source Project |
| * |
| * 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 androidx.compose.foundation.text2.input |
| |
| import androidx.compose.foundation.ExperimentalFoundationApi |
| import androidx.compose.ui.text.TextRange |
| import androidx.compose.ui.text.constrain |
| |
| /** |
| * An immutable snapshot of the contents of a [TextFieldState]. |
| * |
| * This class is a [CharSequence] and directly represents the text being edited. It also stores |
| * the current [selectionInChars] of the field, which may either represent the cursor (if the |
| * selection is [collapsed][TextRange.collapsed]) or the selection range. |
| * |
| * This class also may contain the range being composed by the IME, if any, although this is not |
| * exposed. |
| * |
| * @see TextFieldBuffer |
| */ |
| @ExperimentalFoundationApi |
| sealed interface TextFieldCharSequence : CharSequence { |
| /** |
| * The selection range. If the selection is collapsed, it represents cursor |
| * location. When selection range is out of bounds, it is constrained with the text length. |
| */ |
| val selectionInChars: TextRange |
| |
| /** |
| * Composition range created by IME. If null, there is no composition range. |
| * |
| * Input service composition is an instance of text produced by IME. An example visual for the |
| * composition is that the currently composed word is visually separated from others with |
| * underline, or text background. For description of composition please check |
| * [W3C IME Composition](https://www.w3.org/TR/ime-api/#ime-composition) |
| * |
| * Composition can only be set by the system. |
| */ |
| val compositionInChars: TextRange? |
| |
| /** |
| * Returns true if the text in this object is equal to the text in [other], disregarding any |
| * other properties of this (such as selection) or [other]. |
| */ |
| fun contentEquals(other: CharSequence): Boolean |
| |
| abstract override fun toString(): String |
| abstract override fun equals(other: Any?): Boolean |
| abstract override fun hashCode(): Int |
| } |
| |
| @ExperimentalFoundationApi |
| fun TextFieldCharSequence( |
| text: String = "", |
| selection: TextRange = TextRange.Zero |
| ): TextFieldCharSequence = TextFieldCharSequenceWrapper(text, selection, composition = null) |
| |
| @OptIn(ExperimentalFoundationApi::class) |
| internal fun TextFieldCharSequence( |
| text: CharSequence, |
| selection: TextRange, |
| composition: TextRange? = null |
| ): TextFieldCharSequence = TextFieldCharSequenceWrapper(text, selection, composition) |
| |
| @OptIn(ExperimentalFoundationApi::class) |
| private class TextFieldCharSequenceWrapper( |
| private val text: CharSequence, |
| selection: TextRange, |
| composition: TextRange? |
| ) : TextFieldCharSequence { |
| |
| override val length: Int |
| get() = text.length |
| |
| override val selectionInChars: TextRange = selection.constrain(0, text.length) |
| |
| override val compositionInChars: TextRange? = composition?.constrain(0, text.length) |
| |
| override operator fun get(index: Int): Char = text[index] |
| |
| override fun subSequence(startIndex: Int, endIndex: Int): CharSequence = |
| text.subSequence(startIndex, endIndex) |
| |
| override fun toString(): String = text.toString() |
| |
| override fun contentEquals(other: CharSequence): Boolean = text.contentEquals(other) |
| |
| /** |
| * Returns true if [other] is a [TextFieldCharSequence] with the same contents, text, and composition. |
| * To compare just the text, call [contentEquals]. |
| */ |
| override fun equals(other: Any?): Boolean { |
| if (this === other) return true |
| if (javaClass != other?.javaClass) return false |
| |
| other as TextFieldCharSequenceWrapper |
| |
| if (selectionInChars != other.selectionInChars) return false |
| if (compositionInChars != other.compositionInChars) return false |
| if (!contentEquals(other.text)) return false |
| |
| return true |
| } |
| |
| override fun hashCode(): Int { |
| var result = text.hashCode() |
| result = 31 * result + selectionInChars.hashCode() |
| result = 31 * result + (compositionInChars?.hashCode() ?: 0) |
| return result |
| } |
| } |