[go: nahoru, domu]

blob: 68611b41e6b558187bf0909cb93943c4d2b3dcf8 [file] [log] [blame]
/*
* Copyright 2019 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.ui.text.input
import androidx.compose.Immutable
import androidx.compose.Stable
import androidx.compose.runtime.savedinstancestate.Saver
import androidx.compose.runtime.savedinstancestate.listSaver
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.substring
import kotlin.math.max
import kotlin.math.min
/**
* Stores an input state for IME
*
* IME can request editor state with calling getTextBeforeCursor, getSelectedText, etc.
* This class stores a snapshot of the input state of the edit buffer and provide utility functions
* for answering these information retrieval requests.
*/
@Immutable
@Deprecated(
"Please use androidx.compose.ui.text.input.TextFieldValue instead",
ReplaceWith("TextFieldValue", "androidx.compose.ui.text.input.TextFieldValue")
)
data class EditorValue(
/**
* A text visible to IME
*/
val text: String = "",
/**
* A selection range visible to IME.
* The selection range must be valid range in the given text.
*/
val selection: TextRange = TextRange.Zero,
/**
* A composition range visible to IME.
* If null, there is no composition range.
* If non-null, the composition range must be valid range in the given text.
*/
val composition: TextRange? = null
) {
/**
* Helper function for getting text before selection range.
*/
fun getTextBeforeSelection(maxChars: Int): String =
text.substring(max(0, selection.min - maxChars), selection.min)
/**
* Helper function for getting text after selection range.
*/
fun getTextAfterSelection(maxChars: Int): String =
text.substring(selection.max, min(selection.max + maxChars, text.length))
/**
* Helper function for getting text currently selected.
*/
fun getSelectedText(): String = text.substring(selection)
}
/**
* A class holding information about the editing state.
*
* The input service updates text selection, cursor, text and text composition. This class
* represents those values and it is possible to observe changes to those values in the text
* editing composables.
*
* 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)
*
* This class stores a snapshot of the input state of the edit buffer and provide utility functions
* for answering IME requests such as getTextBeforeCursor, getSelectedText.
*
* @param text the text will be rendered
* @param selection the selection range. If the selection is collapsed, it represents cursor
* location. Selection range must be within the bounds of the [text], otherwise an exception will be
* thrown.
* @param composition A composition range visible to IME. If null, there is no composition range.
* Composition range must be within the bounds of the [text], otherwise an exception will be
* thrown. For description of composition please check [W3C IME Composition](https://www.w3
* .org/TR/ime-api/#ime-composition).
*/
@Immutable
data class TextFieldValue(
@Stable
val text: String = "",
@Stable
val selection: TextRange = TextRange.Zero,
@Stable
val composition: TextRange? = null
) {
init {
// TextRange end is exclusive therefore can be at the end of the text
require(selection.end <= text.length) {
"Selection is out of bounds. [selection: $selection, text.length = ${text.length}]"
}
// TextRange end is exclusive therefore can be at the end of the text
composition?.let {
require(composition.end <= text.length) {
"Composition is out of bounds. " +
"[composition: $selection, text.length = ${text.length}]"
}
}
}
companion object {
/**
* The default [Saver] implementation for [TextFieldValue].
*/
val Saver = listSaver<TextFieldValue, Any>(
save = {
listOf(it.text, it.selection.start, it.selection.end)
},
restore = {
TextFieldValue(it[0] as String, TextRange(it[1] as Int, it[2] as Int))
}
)
}
}
/**
* Helper function for getting text before selection range.
*/
fun TextFieldValue.getTextBeforeSelection(maxChars: Int): String =
text.substring(max(0, selection.min - maxChars), selection.min)
/**
* Helper function for getting text after selection range.
*/
fun TextFieldValue.getTextAfterSelection(maxChars: Int): String =
text.substring(selection.max, min(selection.max + maxChars, text.length))
/**
* Helper function for getting text currently selected.
*/
fun TextFieldValue.getSelectedText(): String = text.substring(selection)