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.material
18
19 import androidx.compose.foundation.interaction.Interaction
20 import androidx.compose.foundation.interaction.MutableInteractionSource
21 import androidx.compose.foundation.layout.defaultMinSize
22 import androidx.compose.foundation.layout.padding
23 import androidx.compose.foundation.text.BasicSecureTextField
24 import androidx.compose.foundation.text.KeyboardOptions
25 import androidx.compose.foundation.text.input.InputTransformation
26 import androidx.compose.foundation.text.input.KeyboardActionHandler
27 import androidx.compose.foundation.text.input.TextFieldState
28 import androidx.compose.foundation.text.input.TextObfuscationMode
29 import androidx.compose.material.TextFieldDefaults.indicatorLine
30 import androidx.compose.runtime.Composable
31 import androidx.compose.runtime.remember
32 import androidx.compose.ui.Modifier
33 import androidx.compose.ui.graphics.Shape
34 import androidx.compose.ui.graphics.SolidColor
35 import androidx.compose.ui.graphics.takeOrElse
36 import androidx.compose.ui.platform.LocalDensity
37 import androidx.compose.ui.semantics.semantics
38 import androidx.compose.ui.text.TextStyle
39 import androidx.compose.ui.text.input.ImeAction
40 import androidx.compose.ui.text.input.KeyboardType
41 import androidx.compose.ui.text.input.VisualTransformation
42
43 /**
44 * [Material Design filled text field for secure
45 * content](https://m2.material.io/components/text-fields#filled-text-field)
46 *
47 * Text fields allow users to enter text into a UI. [SecureTextField] is specifically designed for
48 * password entry fields. It only supports a single line of content and comes with default settings
49 * that are appropriate for entering secure content. Additionally, some context menu actions like
50 * cut, copy, and drag are disabled for added security.
51 *
52 * Filled text fields have more visual emphasis than outlined text fields, making them stand out
53 * when surrounded by other content and components. For an outlined version, see
54 * [OutlinedSecureTextField].
55 *
56 * Example of a password text field:
57 *
58 * @sample androidx.compose.material.samples.PasswordTextField
59 * @param state [TextFieldState] object that holds the internal editing state of this text field.
60 * @param modifier a [Modifier] for this text field.
61 * @param enabled controls the enabled state of the [TextField]. When `false`, the text field will
62 * be neither editable nor focusable, the input of the text field will not be selectable, visually
63 * text field will appear in the disabled UI state.
64 * @param textStyle the style to be applied to the input text. The default [textStyle] uses the
65 * [LocalTextStyle] defined by the theme.
66 * @param label the optional label to be displayed inside the text field container. The default text
67 * style for internal [Text] is [Typography.caption] when the text field is in focus and
68 * [Typography.subtitle1] when the text field is not in focus.
69 * @param placeholder the optional placeholder to be displayed when the text field is in focus and
70 * the input text is empty. The default text style for internal [Text] is [Typography.subtitle1].
71 * @param leadingIcon the optional leading icon to be displayed at the beginning of the text field
72 * container.
73 * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
74 * container.
75 * @param isError indicates if the text field's current value is in error. If set to true, the
76 * label, bottom indicator and trailing icon by default will be displayed in error color.
77 * @param inputTransformation Optional [InputTransformation] that will be used to transform changes
78 * to the [TextFieldState] made by the user. The transformation will be applied to changes made by
79 * hardware and software keyboard events, pasting or dropping text, accessibility services, and
80 * tests. The transformation will _not_ be applied when changing the [state] programmatically, or
81 * when the transformation is changed. If the transformation is changed on an existing text field,
82 * it will be applied to the next user edit. the transformation will not immediately affect the
83 * current [state].
84 * @param textObfuscationMode the method used to obscure the input text.
85 * @param textObfuscationCharacter the character to use while obfuscating the text. It doesn't have
86 * an effect when [textObfuscationMode] is set to [TextObfuscationMode.Visible].
87 * @param keyboardOptions software keyboard options that contains configuration such as
88 * [KeyboardType] and [ImeAction].
89 * @param onKeyboardAction Called when the user presses the action button in the input method editor
90 * (IME), or by pressing the enter key on a hardware keyboard. By default this parameter is null,
91 * and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would
92 * close the keyboard, [ImeAction.Next] would switch the focus to the next focusable item on the
93 * screen.
94 * @param shape the shape of the text field's container
95 * @param colors [TextFieldColors] that will be used to resolve color of the text, content
96 * (including label, placeholder, leading and trailing icons, indicator line) and background for
97 * this text field in different states. See [TextFieldDefaults.textFieldColors]
98 * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
99 * emitting [Interaction]s for this text field. You can use this to change the text field's
100 * appearance or preview the text field in different states. Note that if `null` is provided,
101 * interactions will still happen internally.
102 */
103 @Composable
104 fun SecureTextField(
105 state: TextFieldState,
106 modifier: Modifier = Modifier,
107 enabled: Boolean = true,
108 textStyle: TextStyle = LocalTextStyle.current,
109 label: @Composable (() -> Unit)? = null,
110 placeholder: @Composable (() -> Unit)? = null,
111 leadingIcon: @Composable (() -> Unit)? = null,
112 trailingIcon: @Composable (() -> Unit)? = null,
113 isError: Boolean = false,
114 inputTransformation: InputTransformation? = null,
115 textObfuscationMode: TextObfuscationMode = TextObfuscationMode.RevealLastTyped,
116 textObfuscationCharacter: Char = DefaultObfuscationCharacter,
117 keyboardOptions: KeyboardOptions = SecureTextFieldKeyboardOptions,
118 onKeyboardAction: KeyboardActionHandler? = null,
119 shape: Shape = TextFieldDefaults.TextFieldShape,
120 colors: TextFieldColors = TextFieldDefaults.textFieldColors(),
121 interactionSource: MutableInteractionSource? = null,
122 ) {
123 @Suppress("NAME_SHADOWING")
124 val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
125 // If color is not provided via the text style, use content color as a default
126 val textColor = textStyle.color.takeOrElse { colors.textColor(enabled).value }
127 val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
128
129 BasicSecureTextField(
130 state = state,
131 modifier =
132 modifier
133 .indicatorLine(enabled, isError, interactionSource, colors)
134 .defaultErrorSemantics(isError, getString(Strings.DefaultErrorMessage))
135 .defaultMinSize(
136 minWidth = TextFieldDefaults.MinWidth,
137 minHeight = TextFieldDefaults.MinHeight
138 ),
139 enabled = enabled,
140 textStyle = mergedTextStyle,
141 cursorBrush = SolidColor(colors.cursorColor(isError).value),
142 inputTransformation = inputTransformation,
143 textObfuscationMode = textObfuscationMode,
144 textObfuscationCharacter = textObfuscationCharacter,
145 keyboardOptions = keyboardOptions,
146 onKeyboardAction = onKeyboardAction,
147 interactionSource = interactionSource,
148 decorator = { innerTextField ->
149 TextFieldDefaults.TextFieldDecorationBox(
150 value = state.text.toString(),
151 visualTransformation = VisualTransformation.None,
152 innerTextField = innerTextField,
153 placeholder = placeholder,
154 label = label,
155 leadingIcon = leadingIcon,
156 trailingIcon = trailingIcon,
157 singleLine = true,
158 enabled = enabled,
159 isError = isError,
160 interactionSource = interactionSource,
161 shape = shape,
162 colors = colors,
163 )
164 }
165 )
166 }
167
168 /**
169 * [Material Design outlined text field for secure
170 * content](https://m2.material.io/components/text-fields#outlined-text-field)
171 *
172 * Text fields allow users to enter text into a UI. [OutlinedSecureTextField] is specifically
173 * designed for password entry fields. It only supports a single line of content and comes with
174 * default settings that are appropriate for entering secure content. Additionally, some context
175 * menu actions like cut, copy, and drag are disabled for added security.
176 *
177 * Outlined text fields have less visual emphasis than filled text fields. When they appear in
178 * places like forms, where many text fields are placed together, their reduced emphasis helps
179 * simplify the layout. For a filled version, see [SecureTextField].
180 *
181 * @param state [TextFieldState] object that holds the internal editing state of this text field.
182 * @param modifier a [Modifier] for this text field
183 * @param enabled controls the enabled state of the [OutlinedTextField]. When `false`, the text
184 * field will be neither editable nor focusable, the input of the text field will not be
185 * selectable, visually text field will appear in the disabled UI state
186 * @param textStyle the style to be applied to the input text. The default [textStyle] uses the
187 * [LocalTextStyle] defined by the theme
188 * @param label the optional label to be displayed inside the text field container. The default text
189 * style for internal [Text] is [Typography.caption] when the text field is in focus and
190 * [Typography.subtitle1] when the text field is not in focus
191 * @param placeholder the optional placeholder to be displayed when the text field is in focus and
192 * the input text is empty. The default text style for internal [Text] is [Typography.subtitle1]
193 * @param leadingIcon the optional leading icon to be displayed at the beginning of the text field
194 * container
195 * @param trailingIcon the optional trailing icon to be displayed at the end of the text field
196 * container
197 * @param isError indicates if the text field's current value is in error. If set to true, the
198 * label, bottom indicator and trailing icon by default will be displayed in error color
199 * @param inputTransformation Optional [InputTransformation] that will be used to transform changes
200 * to the [TextFieldState] made by the user. The transformation will be applied to changes made by
201 * hardware and software keyboard events, pasting or dropping text, accessibility services, and
202 * tests. The transformation will _not_ be applied when changing the [state] programmatically, or
203 * when the transformation is changed. If the transformation is changed on an existing text field,
204 * it will be applied to the next user edit. the transformation will not immediately affect the
205 * current [state].
206 * @param textObfuscationMode the method used to obscure the input text.
207 * @param textObfuscationCharacter the character to use while obfuscating the text. It doesn't have
208 * an effect when [textObfuscationMode] is set to [TextObfuscationMode.Visible].
209 * @param keyboardOptions software keyboard options that contains configuration such as
210 * [KeyboardType] and [ImeAction]
211 * @param onKeyboardAction Called when the user presses the action button in the input method editor
212 * (IME), or by pressing the enter key on a hardware keyboard. By default this parameter is null,
213 * and would execute the default behavior for a received IME Action e.g., [ImeAction.Done] would
214 * close the keyboard, [ImeAction.Next] would switch the focus to the next focusable item on the
215 * screen.
216 * @param shape the shape of the text field's border
217 * @param colors [TextFieldColors] that will be used to resolve color of the text and content
218 * (including label, placeholder, leading and trailing icons, border) for this text field in
219 * different states. See [TextFieldDefaults.outlinedTextFieldColors]
220 * @param interactionSource an optional hoisted [MutableInteractionSource] for observing and
221 * emitting [Interaction]s for this text field. You can use this to change the text field's
222 * appearance or preview the text field in different states. Note that if `null` is provided,
223 * interactions will still happen internally.
224 */
225 @Composable
OutlinedSecureTextFieldnull226 fun OutlinedSecureTextField(
227 state: TextFieldState,
228 modifier: Modifier = Modifier,
229 enabled: Boolean = true,
230 textStyle: TextStyle = LocalTextStyle.current,
231 label: @Composable (() -> Unit)? = null,
232 placeholder: @Composable (() -> Unit)? = null,
233 leadingIcon: @Composable (() -> Unit)? = null,
234 trailingIcon: @Composable (() -> Unit)? = null,
235 isError: Boolean = false,
236 inputTransformation: InputTransformation? = null,
237 textObfuscationMode: TextObfuscationMode = TextObfuscationMode.RevealLastTyped,
238 textObfuscationCharacter: Char = DefaultObfuscationCharacter,
239 keyboardOptions: KeyboardOptions = SecureTextFieldKeyboardOptions,
240 onKeyboardAction: KeyboardActionHandler? = null,
241 shape: Shape = TextFieldDefaults.OutlinedTextFieldShape,
242 colors: TextFieldColors = TextFieldDefaults.outlinedTextFieldColors(),
243 interactionSource: MutableInteractionSource? = null,
244 ) {
245 @Suppress("NAME_SHADOWING")
246 val interactionSource = interactionSource ?: remember { MutableInteractionSource() }
247 // If color is not provided via the text style, use content color as a default
248 val textColor = textStyle.color.takeOrElse { colors.textColor(enabled).value }
249 val mergedTextStyle = textStyle.merge(TextStyle(color = textColor))
250
251 val density = LocalDensity.current
252
253 BasicSecureTextField(
254 state = state,
255 modifier =
256 modifier
257 .then(
258 if (label != null) {
259 Modifier
260 // Merge semantics at the beginning of the modifier chain to ensure
261 // padding is considered part of the text field.
262 .semantics(mergeDescendants = true) {}
263 .padding(top = with(density) { OutlinedTextFieldTopPadding.toDp() })
264 } else {
265 Modifier
266 }
267 )
268 .defaultErrorSemantics(isError, getString(Strings.DefaultErrorMessage))
269 .defaultMinSize(
270 minWidth = TextFieldDefaults.MinWidth,
271 minHeight = TextFieldDefaults.MinHeight
272 ),
273 enabled = enabled,
274 textStyle = mergedTextStyle,
275 cursorBrush = SolidColor(colors.cursorColor(isError).value),
276 inputTransformation = inputTransformation,
277 textObfuscationMode = textObfuscationMode,
278 textObfuscationCharacter = textObfuscationCharacter,
279 keyboardOptions = keyboardOptions,
280 onKeyboardAction = onKeyboardAction,
281 interactionSource = interactionSource,
282 decorator = { innerTextField ->
283 TextFieldDefaults.OutlinedTextFieldDecorationBox(
284 value = state.text.toString(),
285 visualTransformation = VisualTransformation.None,
286 innerTextField = innerTextField,
287 placeholder = placeholder,
288 label = label,
289 leadingIcon = leadingIcon,
290 trailingIcon = trailingIcon,
291 singleLine = true,
292 enabled = enabled,
293 isError = isError,
294 interactionSource = interactionSource,
295 shape = shape,
296 colors = colors,
297 border = {
298 TextFieldDefaults.BorderBox(enabled, isError, interactionSource, colors, shape)
299 }
300 )
301 }
302 )
303 }
304
305 private val SecureTextFieldKeyboardOptions =
306 KeyboardOptions(autoCorrectEnabled = false, keyboardType = KeyboardType.Password)
307
308 private const val DefaultObfuscationCharacter: Char = '\u2022'
309