[go: nahoru, domu]

blob: abc507bd92305f89ee5c0ec202a49d8aa85cfff1 [file] [log] [blame]
/*
* Copyright 2020 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.demos.text
import androidx.compose.foundation.Interaction
import androidx.compose.foundation.InteractionState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.Text
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.runtime.savedinstancestate.savedInstanceState
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.OffsetMapping
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.text.input.TransformedText
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.intl.LocaleList
import androidx.compose.ui.text.toUpperCase
/**
* The offset translator used for credit card input field.
*
* @see creditCardFilter
*/
private val creditCardOffsetTranslator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
if (offset <= 3) return offset
if (offset <= 7) return offset + 1
if (offset <= 11) return offset + 2
if (offset <= 16) return offset + 3
return 19
}
override fun transformedToOriginal(offset: Int): Int {
if (offset <= 4) return offset
if (offset <= 9) return offset - 1
if (offset <= 14) return offset - 2
if (offset <= 19) return offset - 3
return 16
}
}
/**
* The visual filter for credit card input field.
*
* This filter converts up to 16 digits to hyphen connected 4 digits string.
* For example, "1234567890123456" will be shown as "1234-5678-9012-3456".
*/
private val creditCardFilter = VisualTransformation { text ->
val trimmed = if (text.text.length >= 16) text.text.substring(0..15) else text.text
var out = ""
for (i in 0 until trimmed.length) {
out += trimmed[i]
if (i % 4 == 3 && i != 15) out += "-"
}
TransformedText(AnnotatedString(out), creditCardOffsetTranslator)
}
/**
* The offset translator which works for all offset keep remains the same.
*/
private val identityTranslator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int = offset
override fun transformedToOriginal(offset: Int): Int = offset
}
/**
* The visual filter for capitalization.
*
* This filer converts ASCII characters to capital form.
*/
private class CapitalizeTransformation(
val locale: LocaleList = LocaleList("en-US")
) : VisualTransformation {
override fun filter(text: AnnotatedString): TransformedText {
// Note: identityTranslator doesn't work for some locale, e.g. Turkish
return TransformedText(AnnotatedString(text.text).toUpperCase(locale), identityTranslator)
}
}
/**
* The offset translator for phone number
*
* @see phoneNumberFilter
*/
private val phoneNumberOffsetTranslator = object : OffsetMapping {
override fun originalToTransformed(offset: Int): Int {
return when (offset) {
0 -> 1
1 -> 2
2 -> 3
3 -> 6
4 -> 7
5 -> 8
6 -> 10
7 -> 11
8 -> 12
9 -> 13
else -> 14
}
}
override fun transformedToOriginal(offset: Int): Int {
return when (offset) {
0 -> 0
1 -> 0
2 -> 1
3 -> 2
4 -> 3
5 -> 3
6 -> 3
7 -> 4
8 -> 5
9 -> 6
10 -> 6
11 -> 7
12 -> 8
13 -> 9
else -> 10
}
}
}
/**
* The visual filter for phone number.
*
* This filter converts up to 10 digits to phone number form.
* For example, "1234567890" will be shown as "(123) 456-7890".
*/
private val phoneNumberFilter = VisualTransformation { text ->
val trimmed = if (text.text.length >= 10) text.text.substring(0..9) else text.text
val filled = trimmed + "_".repeat(10 - trimmed.length)
val res = "(" + filled.substring(0..2) + ") " + filled.substring(3..5) + "-" +
filled.substring(6..9)
TransformedText(AnnotatedString(text = res), phoneNumberOffsetTranslator)
}
private val emailFilter = VisualTransformation { text ->
if (text.text.indexOf("@") == -1) {
TransformedText(AnnotatedString(text = text.text + "@gmail.com"), identityTranslator)
} else {
TransformedText(text, identityTranslator)
}
}
@Composable
fun VariousInputFieldDemo() {
LazyColumn {
item {
TagLine(tag = "Capitalization")
VariousEditLine(
keyboardType = KeyboardType.Ascii,
onValueChange = { old, new ->
if (new.any { !it.isLetterOrDigit() }) old else new
},
visualTransformation = CapitalizeTransformation()
)
}
item {
TagLine(tag = "Capitalization (Turkish)")
VariousEditLine(
keyboardType = KeyboardType.Ascii,
onValueChange = { old, new ->
if (new.any { !it.isLetterOrDigit() }) old else new
},
visualTransformation = CapitalizeTransformation(LocaleList("tr"))
)
}
item {
TagLine(tag = "Password")
VariousEditLine(
keyboardType = KeyboardType.Password,
onValueChange = { old, new ->
if (new.any { !it.isLetterOrDigit() }) old else new
},
visualTransformation = PasswordVisualTransformation()
)
}
item {
TagLine(tag = "Phone Number")
VariousEditLine(
keyboardType = KeyboardType.Number,
onValueChange = { old, new ->
if (new.length > 10 || new.any { !it.isDigit() }) old else new
},
visualTransformation = phoneNumberFilter
)
}
item {
TagLine(tag = "Credit Card")
VariousEditLine(
keyboardType = KeyboardType.Number,
onValueChange = { old, new ->
if (new.length > 16 || new.any { !it.isDigit() }) old else new
},
visualTransformation = creditCardFilter
)
}
item {
TagLine(tag = "Email Suggestion")
VariousEditLine(
keyboardType = KeyboardType.Email,
visualTransformation = emailFilter
)
}
item {
TagLine(tag = "Editfield with Hint Text")
HintEditText {
Text(
text = "Hint Text",
color = Color(0xFF888888),
style = TextStyle(fontSize = fontSize8)
)
}
}
item {
TagLine(tag = "TextField InteractionState")
InteractionStateTextField()
}
}
}
@Composable
private fun VariousEditLine(
keyboardType: KeyboardType = KeyboardType.Text,
imeAction: ImeAction = ImeAction.Default,
onValueChange: (String, String) -> String = { _, new -> new },
visualTransformation: VisualTransformation
) {
val state = savedInstanceState { "" }
BasicTextField(
modifier = demoTextFieldModifiers,
value = state.value,
singleLine = true,
keyboardOptions = KeyboardOptions(
keyboardType = keyboardType,
imeAction = imeAction
),
visualTransformation = visualTransformation,
onValueChange = {
val value = onValueChange(state.value, it)
state.value = value
},
textStyle = TextStyle(fontSize = fontSize8)
)
}
@Composable
private fun HintEditText(content: @Composable () -> Unit) {
val state = savedInstanceState { "" }
Box(demoTextFieldModifiers) {
BasicTextField(
modifier = Modifier.fillMaxWidth(),
value = state.value,
onValueChange = { state.value = it },
textStyle = TextStyle(fontSize = fontSize8)
)
if (state.value.isEmpty()) {
content()
}
}
}
@Composable
private fun InteractionStateTextField() {
val state = savedInstanceState(saver = TextFieldValue.Saver) { TextFieldValue() }
val interactionState = remember { InteractionState() }
Column(demoTextFieldModifiers) {
Text("Pressed?: ${interactionState.contains(Interaction.Pressed)}", fontSize = fontSize4)
Text("Focused?: ${interactionState.contains(Interaction.Focused)}", fontSize = fontSize4)
Text("Dragged?: ${interactionState.contains(Interaction.Dragged)}", fontSize = fontSize4)
BasicTextField(
modifier = Modifier.fillMaxWidth(),
value = state.value,
singleLine = true,
interactionState = interactionState,
onValueChange = { state.value = it },
textStyle = TextStyle(fontSize = fontSize8)
)
}
}