Replace OutlinedTextField by our TextField (#4521)
* Let TextFieldListItem take the entire width. * Add unit test to detect usage of OutlinedTextField. * Use TextField instead of OutlinedTextField * Remove unnecessary opt in to ExperimentalFoundationApi * Use TextField instead of OutlinedTextField * Fix compilation issue. * Update screenshots * ListDialog: add space between items. * Update screenshots * Set applyPaddingToContents to true by default. * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
@@ -7,7 +7,6 @@
|
||||
|
||||
package io.element.android.features.licenses.impl.list
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
@@ -15,7 +14,6 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
@@ -33,10 +31,11 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.ListItem
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TextField
|
||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun DependencyLicensesListView(
|
||||
state: DependencyLicensesListState,
|
||||
@@ -60,7 +59,7 @@ fun DependencyLicensesListView(
|
||||
) {
|
||||
if (state.licenses.isSuccess()) {
|
||||
// Search field
|
||||
OutlinedTextField(
|
||||
TextField(
|
||||
value = state.filter,
|
||||
onValueChange = { state.eventSink(DependencyLicensesListEvent.SetFilter(it)) },
|
||||
leadingIcon = {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.customreaction
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
@@ -41,7 +40,7 @@ import kotlinx.collections.immutable.ImmutableSet
|
||||
import kotlinx.collections.immutable.persistentSetOf
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun EmojiPicker(
|
||||
onSelectEmoji: (Emoji) -> Unit,
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
package io.element.android.features.messages.impl.timeline.components.reactionsummary
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -94,7 +93,6 @@ fun ReactionSummaryView(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun ReactionSummaryViewContent(
|
||||
summary: ReactionSummaryState.Summary,
|
||||
|
||||
@@ -98,7 +98,6 @@ fun RoomMembersModerationView(
|
||||
onDismissRequest = { state.eventSink(RoomMembersModerationEvents.Reset) },
|
||||
placeholder = stringResource(id = CommonStrings.common_reason),
|
||||
label = stringResource(id = CommonStrings.common_reason),
|
||||
withBorder = true,
|
||||
content = stringResource(R.string.screen_room_member_list_kick_member_confirmation_description),
|
||||
value = "",
|
||||
)
|
||||
@@ -138,7 +137,6 @@ fun RoomMembersModerationView(
|
||||
onDismissRequest = { state.eventSink(RoomMembersModerationEvents.Reset) },
|
||||
placeholder = stringResource(id = CommonStrings.common_reason),
|
||||
label = stringResource(id = CommonStrings.common_reason),
|
||||
withBorder = true,
|
||||
content = stringResource(R.string.screen_room_member_list_ban_member_confirmation_description),
|
||||
value = "",
|
||||
)
|
||||
|
||||
@@ -10,7 +10,6 @@ package io.element.android.features.roomlist.impl.filters
|
||||
import androidx.compose.animation.animateColorAsState
|
||||
import androidx.compose.animation.core.Spring
|
||||
import androidx.compose.animation.core.spring
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.gestures.animateScrollBy
|
||||
@@ -48,7 +47,6 @@ import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.testtags.TestTags
|
||||
import io.element.android.libraries.testtags.testTag
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun RoomListFiltersView(
|
||||
state: RoomListFiltersState,
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package io.element.android.libraries.designsystem.components.dialogs
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
@@ -38,7 +39,7 @@ fun ListDialog(
|
||||
cancelText: String = stringResource(CommonStrings.action_cancel),
|
||||
submitText: String = stringResource(CommonStrings.action_ok),
|
||||
enabled: Boolean = true,
|
||||
applyPaddingToContents: Boolean = false,
|
||||
applyPaddingToContents: Boolean = true,
|
||||
listItems: LazyListScope.() -> Unit,
|
||||
) {
|
||||
val decoratedSubtitle: @Composable (() -> Unit)? = subtitle?.let {
|
||||
@@ -92,7 +93,8 @@ private fun ListDialogContent(
|
||||
// No start padding if padding is already applied to the content
|
||||
val horizontalPadding = if (applyPaddingToContents) 0.dp else 8.dp
|
||||
LazyColumn(
|
||||
modifier = Modifier.padding(horizontal = horizontalPadding)
|
||||
modifier = Modifier.padding(horizontal = horizontalPadding),
|
||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) { listItems() }
|
||||
}
|
||||
}
|
||||
@@ -117,7 +119,7 @@ internal fun ListDialogContentPreview() {
|
||||
cancelText = "Cancel",
|
||||
submitText = "Save",
|
||||
enabled = true,
|
||||
applyPaddingToContents = false,
|
||||
applyPaddingToContents = true,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
package io.element.android.libraries.designsystem.components.dialogs
|
||||
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.runtime.Composable
|
||||
@@ -44,7 +45,6 @@ fun TextFieldDialog(
|
||||
maxLines: Int = 1,
|
||||
content: String? = null,
|
||||
label: String? = null,
|
||||
withBorder: Boolean = false,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
submitText: String = stringResource(CommonStrings.action_ok),
|
||||
) {
|
||||
@@ -65,7 +65,6 @@ fun TextFieldDialog(
|
||||
onSubmit = { onSubmit(textFieldContents.text) },
|
||||
onDismissRequest = onDismissRequest,
|
||||
enabled = canSubmit,
|
||||
applyPaddingToContents = content.isNullOrEmpty().not(),
|
||||
submitText = submitText,
|
||||
modifier = modifier,
|
||||
) {
|
||||
@@ -81,7 +80,6 @@ fun TextFieldDialog(
|
||||
TextFieldListItem(
|
||||
placeholder = placeholder.orEmpty(),
|
||||
label = label,
|
||||
withBorder = withBorder,
|
||||
text = textFieldContents,
|
||||
onTextChange = {
|
||||
error = if (!validation(it.text)) onValidationErrorMessage else null
|
||||
@@ -95,7 +93,9 @@ fun TextFieldDialog(
|
||||
}
|
||||
}),
|
||||
maxLines = maxLines,
|
||||
modifier = Modifier.focusRequester(focusRequester),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.focusRequester(focusRequester),
|
||||
)
|
||||
canRequestFocus = true
|
||||
}
|
||||
@@ -120,22 +120,6 @@ internal fun TextFieldDialogPreview() = ElementPreview {
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextFieldDialogWithBorderPreview() = ElementPreview {
|
||||
TextFieldDialog(
|
||||
title = "Title",
|
||||
content = "Some content",
|
||||
onSubmit = {},
|
||||
onDismissRequest = {},
|
||||
value = "Value",
|
||||
placeholder = "Placeholder",
|
||||
label = "Label",
|
||||
withBorder = true,
|
||||
onValidationErrorMessage = "Error message",
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun TextFieldDialogWithErrorPreview() = ElementPreview {
|
||||
@@ -148,7 +132,6 @@ internal fun TextFieldDialogWithErrorPreview() = ElementPreview {
|
||||
value = "Value",
|
||||
placeholder = "Placeholder",
|
||||
label = "Label",
|
||||
withBorder = true,
|
||||
onValidationErrorMessage = "Error message",
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,17 +9,14 @@ package io.element.android.libraries.designsystem.components.list
|
||||
|
||||
import androidx.compose.foundation.text.KeyboardActions
|
||||
import androidx.compose.foundation.text.KeyboardOptions
|
||||
import androidx.compose.material3.OutlinedTextField
|
||||
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.text.input.TextFieldValue
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.theme.components.TextField
|
||||
import io.element.android.libraries.designsystem.theme.components.TextFieldValidity
|
||||
|
||||
@Composable
|
||||
fun TextFieldListItem(
|
||||
@@ -29,33 +26,19 @@ fun TextFieldListItem(
|
||||
modifier: Modifier = Modifier,
|
||||
error: String? = null,
|
||||
maxLines: Int = 1,
|
||||
withBorder: Boolean = false,
|
||||
label: String? = null,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
) {
|
||||
val textFieldStyle = ElementTheme.materialTypography.bodyLarge
|
||||
|
||||
OutlinedTextField(
|
||||
TextField(
|
||||
value = text,
|
||||
onValueChange = { onTextChange(it) },
|
||||
placeholder = placeholder?.let { @Composable { Text(it) } },
|
||||
label = label?.let { @Composable { Text(it) } },
|
||||
colors = if (withBorder) {
|
||||
OutlinedTextFieldDefaults.colors()
|
||||
} else {
|
||||
OutlinedTextFieldDefaults.colors(
|
||||
disabledBorderColor = Color.Transparent,
|
||||
errorBorderColor = Color.Transparent,
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
)
|
||||
},
|
||||
isError = error != null,
|
||||
supportingText = error?.let { @Composable { Text(it) } },
|
||||
placeholder = placeholder,
|
||||
label = label,
|
||||
validity = if (error != null) TextFieldValidity.Invalid else TextFieldValidity.None,
|
||||
supportingText = error,
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
textStyle = textFieldStyle,
|
||||
maxLines = maxLines,
|
||||
singleLine = maxLines == 1,
|
||||
modifier = modifier,
|
||||
@@ -70,33 +53,19 @@ fun TextFieldListItem(
|
||||
modifier: Modifier = Modifier,
|
||||
error: String? = null,
|
||||
maxLines: Int = 1,
|
||||
withBorder: Boolean = false,
|
||||
label: String? = null,
|
||||
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
|
||||
keyboardActions: KeyboardActions = KeyboardActions.Default,
|
||||
) {
|
||||
val textFieldStyle = ElementTheme.materialTypography.bodyLarge
|
||||
|
||||
OutlinedTextField(
|
||||
TextField(
|
||||
value = text,
|
||||
onValueChange = { onTextChange(it) },
|
||||
placeholder = placeholder?.let { @Composable { Text(it) } },
|
||||
label = label?.let { @Composable { Text(it) } },
|
||||
colors = if (withBorder) {
|
||||
OutlinedTextFieldDefaults.colors()
|
||||
} else {
|
||||
OutlinedTextFieldDefaults.colors(
|
||||
disabledBorderColor = Color.Transparent,
|
||||
errorBorderColor = Color.Transparent,
|
||||
focusedBorderColor = Color.Transparent,
|
||||
unfocusedBorderColor = Color.Transparent,
|
||||
)
|
||||
},
|
||||
isError = error != null,
|
||||
supportingText = error?.let { @Composable { Text(it) } },
|
||||
placeholder = placeholder,
|
||||
label = label,
|
||||
validity = if (error != null) TextFieldValidity.Invalid else TextFieldValidity.None,
|
||||
supportingText = error,
|
||||
keyboardOptions = keyboardOptions,
|
||||
keyboardActions = keyboardActions,
|
||||
textStyle = textFieldStyle,
|
||||
maxLines = maxLines,
|
||||
singleLine = maxLines == 1,
|
||||
modifier = modifier,
|
||||
@@ -138,31 +107,3 @@ internal fun TextFieldListItemTextFieldValuePreview() {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview("Text field List item with border - empty", group = PreviewGroup.ListItems)
|
||||
@Composable
|
||||
internal fun TextFieldListItemWithBorderEmptyPreview() {
|
||||
ElementThemedPreview {
|
||||
TextFieldListItem(
|
||||
placeholder = "Placeholder",
|
||||
label = "Label",
|
||||
text = "",
|
||||
withBorder = true,
|
||||
onTextChange = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview("Text field List item with border - text", group = PreviewGroup.ListItems)
|
||||
@Composable
|
||||
internal fun TextFieldListItemWithBorderPreview() {
|
||||
ElementThemedPreview {
|
||||
TextFieldListItem(
|
||||
placeholder = "Placeholder",
|
||||
label = "Label",
|
||||
text = "Text",
|
||||
withBorder = true,
|
||||
onTextChange = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,4 +24,17 @@ class KonsistImportTest {
|
||||
it.name == "org.jetbrains.annotations.VisibleForTesting"
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `OutlinedTextField should not be used`() {
|
||||
Konsist
|
||||
.scopeFromProject()
|
||||
.imports
|
||||
.assertFalse(
|
||||
additionalMessage = "Please use 'io.element.android.libraries.designsystem.theme.components.TextField' instead of " +
|
||||
"'androidx.compose.material3.OutlinedTextField.",
|
||||
) {
|
||||
it.name == "androidx.compose.material3.OutlinedTextField"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue
Block a user