Merge pull request #3834 from element-hq/feature/fga/design_system_text_field

Design system : implement new TextField
This commit is contained in:
ganfra 2024-11-12 11:18:07 +01:00 committed by GitHub
commit cffd2da10b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
188 changed files with 817 additions and 901 deletions

View file

@ -23,7 +23,6 @@ import androidx.compose.foundation.selection.selectableGroup
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -36,16 +35,17 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.createroom.impl.R
import io.element.android.libraries.architecture.coverage.ExcludeFromCoverage
import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtom
import io.element.android.libraries.designsystem.atomic.atoms.RoundedIconAtomSize
import io.element.android.libraries.designsystem.components.LabelledTextField
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.modifiers.clearFocusOnTap
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
import io.element.android.libraries.designsystem.preview.PreviewWithLargeHeight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.ListItem
import io.element.android.libraries.designsystem.theme.components.Scaffold
@ -217,7 +217,7 @@ private fun RoomNameWithAvatar(
modifier = Modifier.clickable(onClick = onAvatarClick),
)
LabelledTextField(
TextField(
label = stringResource(R.string.screen_create_room_room_name_label),
value = roomName,
placeholder = stringResource(CommonStrings.common_room_name_placeholder),
@ -233,7 +233,7 @@ private fun RoomTopic(
onTopicChange: (String) -> Unit,
modifier: Modifier = Modifier,
) {
LabelledTextField(
TextField(
modifier = modifier,
label = stringResource(R.string.screen_create_room_topic_label),
value = topic,
@ -322,51 +322,43 @@ private fun RoomAddressField(
onAddressChange: (String) -> Unit,
modifier: Modifier = Modifier,
) {
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(
modifier = Modifier.padding(horizontal = 16.dp),
style = ElementTheme.typography.fontBodyMdRegular,
color = MaterialTheme.colorScheme.primary,
text = stringResource(R.string.screen_create_room_room_address_section_title),
)
TextField(
modifier = Modifier.fillMaxWidth(),
value = address.value,
leadingIcon = {
Text(
text = "#",
style = ElementTheme.typography.fontBodyLgMedium,
color = ElementTheme.colors.textSecondary,
)
},
trailingIcon = {
Text(
text = homeserverName,
style = ElementTheme.typography.fontBodyLgMedium,
color = ElementTheme.colors.textSecondary,
modifier = Modifier.padding(end = 16.dp)
)
},
supportingText = {
Text(
text = stringResource(R.string.screen_create_room_room_address_section_footer),
style = ElementTheme.typography.fontBodySmRegular,
color = ElementTheme.colors.textSecondary,
)
},
onValueChange = onAddressChange,
singleLine = true,
)
}
TextField(
modifier = modifier.fillMaxWidth(),
value = address.value,
label = stringResource(R.string.screen_create_room_room_address_section_title),
leadingIcon = {
Text(
text = "#",
style = ElementTheme.typography.fontBodyLgMedium,
color = ElementTheme.colors.textSecondary,
)
},
trailingIcon = {
Text(
text = homeserverName,
style = ElementTheme.typography.fontBodyLgMedium,
color = ElementTheme.colors.textSecondary,
)
},
supportingText = stringResource(R.string.screen_create_room_room_address_section_footer),
onValueChange = onAddressChange,
singleLine = true,
)
}
@PreviewsDayNight
@PreviewWithLargeHeight
@Composable
internal fun ConfigureRoomViewPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) = ElementPreview {
internal fun ConfigureRoomViewLightPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) =
ElementPreviewLight { ContentToPreview(state) }
@PreviewWithLargeHeight
@Composable
internal fun ConfigureRoomViewDarkPreview(@PreviewParameter(ConfigureRoomStateProvider::class) state: ConfigureRoomState) =
ElementPreviewDark { ContentToPreview(state) }
@ExcludeFromCoverage
@Composable
private fun ContentToPreview(state: ConfigureRoomState) {
ConfigureRoomView(
state = state,
onBackClick = {},

View file

@ -9,7 +9,9 @@
package io.element.android.features.logout.impl
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.Spacer
@ -52,19 +54,18 @@ import io.element.android.libraries.designsystem.atomic.organisms.InfoListOrgani
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.form.textFieldState
import io.element.android.libraries.designsystem.components.list.SwitchListItem
import io.element.android.libraries.designsystem.modifiers.autofill
import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusNext
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.buildAnnotatedStringWithStyledPart
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
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.designsystem.theme.components.autofill
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag
import io.element.android.libraries.ui.strings.CommonStrings
@ -257,26 +258,21 @@ private fun Content(
)
}
Column(
Box(
modifier = Modifier
.fillMaxWidth()
.padding(top = 16.dp),
) {
Text(
text = stringResource(CommonStrings.action_confirm_password),
style = ElementTheme.typography.fontBodySmMedium,
color = ElementTheme.colors.textSecondary,
)
var passwordVisible by remember { mutableStateOf(false) }
if (isLoading) {
// Ensure password is hidden when user submits the form
passwordVisible = false
}
OutlinedTextField(
TextField(
value = passwordFieldState,
label = stringResource(CommonStrings.action_confirm_password),
readOnly = isLoading,
modifier = Modifier
.padding(top = 8.dp)
.fillMaxWidth()
.onTabOrEnterKeyFocusNext(focusManager)
.testTag(TestTags.loginPassword)
@ -293,9 +289,7 @@ private fun Content(
passwordFieldState = sanitized
eventSink(AccountDeactivationEvents.SetPassword(sanitized))
},
placeholder = {
Text(text = stringResource(CommonStrings.common_password))
},
placeholder = stringResource(CommonStrings.common_password),
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
val image =
@ -303,7 +297,7 @@ private fun Content(
val description =
if (passwordVisible) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password)
IconButton(onClick = { passwordVisible = !passwordVisible }) {
Box(modifier = Modifier.clickable { passwordVisible = !passwordVisible }) {
Icon(imageVector = image, description)
}
},

View file

@ -60,8 +60,8 @@ import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.OutlinedButton
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
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.matrix.api.core.RoomIdOrAlias
import io.element.android.libraries.matrix.api.room.RoomType
@ -390,19 +390,13 @@ private fun DefaultLoadedContent(
)
} else if (contentState.joinAuthorisationStatus is JoinAuthorisationStatus.CanKnock) {
Spacer(modifier = Modifier.height(24.dp))
OutlinedTextField(
TextField(
value = knockMessage,
onValueChange = onKnockMessageUpdate,
maxLines = 3,
minLines = 3,
modifier = Modifier.fillMaxWidth()
)
Text(
text = stringResource(R.string.screen_join_room_knock_message_description),
style = ElementTheme.typography.fontBodySmRegular,
color = ElementTheme.colors.textPlaceholder,
textAlign = TextAlign.Start,
modifier = Modifier.fillMaxWidth()
modifier = Modifier.fillMaxWidth(),
supportingText = stringResource(R.string.screen_join_room_knock_message_description)
)
}
}

View file

@ -7,6 +7,7 @@
package io.element.android.features.login.impl.screens.loginpassword
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@ -52,17 +53,15 @@ import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.dialogs.ErrorDialog
import io.element.android.libraries.designsystem.components.form.textFieldState
import io.element.android.libraries.designsystem.modifiers.autofill
import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusNext
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
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.designsystem.theme.components.autofill
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag
import io.element.android.libraries.ui.strings.CommonStrings
@ -101,12 +100,12 @@ fun LoginPasswordView(
Column(
modifier = Modifier
.fillMaxSize()
.imePadding()
.padding(padding)
.consumeWindowInsets(padding)
.verticalScroll(state = scrollState)
.padding(start = 20.dp, end = 20.dp, bottom = 20.dp),
.fillMaxSize()
.imePadding()
.padding(padding)
.consumeWindowInsets(padding)
.verticalScroll(state = scrollState)
.padding(start = 20.dp, end = 20.dp, bottom = 20.dp),
) {
// Title
IconTitleSubtitleMolecule(
@ -140,8 +139,8 @@ fun LoginPasswordView(
onClick = ::submit,
enabled = state.submitEnabled || isLoading,
modifier = Modifier
.fillMaxWidth()
.testTag(TestTags.loginContinue)
.fillMaxWidth()
.testTag(TestTags.loginContinue)
)
Spacer(modifier = Modifier.height(48.dp))
}
@ -170,16 +169,10 @@ private fun LoginForm(
val eventSink = state.eventSink
Column {
Text(
text = stringResource(R.string.screen_login_form_header),
modifier = Modifier.padding(start = 16.dp),
style = ElementTheme.typography.fontBodyMdRegular,
)
Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField(
TextField(
label = stringResource(R.string.screen_login_form_header),
value = loginFieldState,
readOnly = isLoading,
enabled = !isLoading,
modifier = Modifier
.fillMaxWidth()
.onTabOrEnterKeyFocusNext(focusManager)
@ -192,9 +185,7 @@ private fun LoginForm(
eventSink(LoginPasswordEvents.SetLogin(sanitized))
}
),
placeholder = {
Text(text = stringResource(CommonStrings.common_username))
},
placeholder = stringResource(CommonStrings.common_username),
onValueChange = {
val sanitized = it.sanitize()
loginFieldState = sanitized
@ -210,10 +201,14 @@ private fun LoginForm(
singleLine = true,
trailingIcon = if (loginFieldState.isNotEmpty()) {
{
IconButton(onClick = {
Box(Modifier.clickable {
loginFieldState = ""
}) {
Icon(imageVector = CompoundIcons.Close(), contentDescription = stringResource(CommonStrings.action_clear))
Icon(
imageVector = CompoundIcons.Close(),
contentDescription = stringResource(CommonStrings.action_clear),
tint = ElementTheme.colors.iconSecondary
)
}
}
} else {
@ -226,9 +221,9 @@ private fun LoginForm(
passwordVisible = false
}
Spacer(Modifier.height(20.dp))
OutlinedTextField(
TextField(
value = passwordFieldState,
readOnly = isLoading,
enabled = !isLoading,
modifier = Modifier
.fillMaxWidth()
.onTabOrEnterKeyFocusNext(focusManager)
@ -246,18 +241,18 @@ private fun LoginForm(
passwordFieldState = sanitized
eventSink(LoginPasswordEvents.SetPassword(sanitized))
},
placeholder = {
Text(text = stringResource(CommonStrings.common_password))
},
placeholder = stringResource(CommonStrings.common_password),
visualTransformation = if (passwordVisible) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
val image =
if (passwordVisible) CompoundIcons.VisibilityOn() else CompoundIcons.VisibilityOff()
val description =
if (passwordVisible) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password)
IconButton(onClick = { passwordVisible = !passwordVisible }) {
Icon(imageVector = image, description)
Box(Modifier.clickable { passwordVisible = !passwordVisible }) {
Icon(
imageVector = image,
contentDescription = description,
)
}
},
keyboardOptions = KeyboardOptions(

View file

@ -9,6 +9,7 @@
package io.element.android.features.login.impl.screens.searchaccountprovider
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets
@ -23,7 +24,6 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
@ -51,14 +51,12 @@ import io.element.android.libraries.designsystem.atomic.molecules.IconTitleSubti
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.components.form.textFieldState
import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusNext
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag
import io.element.android.libraries.ui.strings.CommonStrings
@ -86,10 +84,10 @@ fun SearchAccountProviderView(
) { padding ->
Box(
modifier = Modifier
.fillMaxSize()
.imePadding()
.padding(padding)
.consumeWindowInsets(padding)
.fillMaxSize()
.imePadding()
.padding(padding)
.consumeWindowInsets(padding)
) {
LazyColumn(modifier = Modifier.fillMaxWidth(), state = rememberLazyListState()) {
item {
@ -104,7 +102,7 @@ fun SearchAccountProviderView(
// TextInput
var userInputState by textFieldState(stateValue = state.userInput)
val focusManager = LocalFocusManager.current
OutlinedTextField(
TextField(
value = userInputState,
// readOnly = isLoading,
modifier = Modifier
@ -126,7 +124,7 @@ fun SearchAccountProviderView(
singleLine = true,
trailingIcon = if (userInputState.isNotEmpty()) {
{
IconButton(onClick = {
Box(Modifier.clickable {
userInputState = ""
eventSink(SearchAccountProviderEvents.UserInput(""))
}) {
@ -139,9 +137,7 @@ fun SearchAccountProviderView(
} else {
null
},
supportingText = {
Text(text = stringResource(id = R.string.screen_account_provider_form_notice), color = MaterialTheme.colorScheme.secondary)
}
supportingText = stringResource(id = R.string.screen_account_provider_form_notice),
)
}

View file

@ -27,7 +27,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
@ -39,9 +38,9 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
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
@ -89,21 +88,16 @@ fun ReportMessageView(
) {
Spacer(modifier = Modifier.height(20.dp))
OutlinedTextField(
TextField(
value = state.reason,
onValueChange = { state.eventSink(ReportMessageEvents.UpdateReason(it)) },
placeholder = { Text(stringResource(R.string.screen_report_content_hint)) },
placeholder = stringResource(R.string.screen_report_content_hint),
minLines = 3,
enabled = !isSending,
modifier = Modifier
.fillMaxWidth()
.heightIn(min = 90.dp)
)
Text(
text = stringResource(R.string.screen_report_content_explanation),
style = ElementTheme.typography.fontBodySmRegular,
color = MaterialTheme.colorScheme.secondary,
textAlign = TextAlign.Start,
modifier = Modifier.padding(top = 4.dp, bottom = 24.dp, start = 16.dp, end = 16.dp)
.heightIn(min = 90.dp),
supportingText = stringResource(R.string.screen_report_content_explanation),
)
Row(

View file

@ -33,7 +33,6 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.poll.impl.R
@ -48,10 +47,10 @@ import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.ListItem
import io.element.android.libraries.designsystem.theme.components.ListItemStyle
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
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.TextButton
import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.matrix.api.poll.PollKind
import io.element.android.libraries.ui.strings.CommonStrings
@ -109,14 +108,10 @@ fun CreatePollView(
) {
item {
Column {
Text(
text = stringResource(id = R.string.screen_create_poll_question_desc),
modifier = Modifier.padding(start = 32.dp),
style = ElementTheme.typography.fontBodyMdRegular,
)
ListItem(
headlineContent = {
OutlinedTextField(
TextField(
label = stringResource(id = R.string.screen_create_poll_question_desc),
value = state.question,
onValueChange = {
state.eventSink(CreatePollEvents.SetQuestion(it))
@ -124,9 +119,7 @@ fun CreatePollView(
modifier = Modifier
.focusRequester(questionFocusRequester)
.fillMaxWidth(),
placeholder = {
Text(text = stringResource(id = R.string.screen_create_poll_question_hint))
},
placeholder = stringResource(id = R.string.screen_create_poll_question_hint),
keyboardOptions = keyboardOptions,
)
}
@ -137,7 +130,7 @@ fun CreatePollView(
val isLastItem = index == state.answers.size - 1
ListItem(
headlineContent = {
OutlinedTextField(
TextField(
value = answer.text,
onValueChange = {
state.eventSink(CreatePollEvents.SetAnswer(index, it))
@ -145,9 +138,7 @@ fun CreatePollView(
modifier = Modifier
.then(if (isLastItem) Modifier.focusRequester(answerFocusRequester) else Modifier)
.fillMaxWidth(),
placeholder = {
Text(text = stringResource(id = R.string.screen_create_poll_answer_hint, index + 1))
},
placeholder = stringResource(id = R.string.screen_create_poll_answer_hint, index + 1),
keyboardOptions = keyboardOptions,
)
},

View file

@ -29,7 +29,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.preferences.impl.R
import io.element.android.libraries.designsystem.components.LabelledOutlinedTextField
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
@ -41,6 +40,7 @@ import io.element.android.libraries.designsystem.theme.aliasScreenTitle
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.TextButton
import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet
import io.element.android.libraries.matrix.ui.components.EditableAvatarView
@ -112,7 +112,7 @@ fun EditUserProfileView(
textAlign = TextAlign.Center,
)
Spacer(modifier = Modifier.height(40.dp))
LabelledOutlinedTextField(
TextField(
label = stringResource(R.string.screen_edit_profile_display_name),
value = state.displayName,
placeholder = stringResource(CommonStrings.common_room_name_placeholder),

View file

@ -39,13 +39,12 @@ import io.element.android.libraries.designsystem.components.preferences.Preferen
import io.element.android.libraries.designsystem.components.preferences.PreferenceRow
import io.element.android.libraries.designsystem.components.preferences.PreferenceSwitch
import io.element.android.libraries.designsystem.components.preferences.PreferenceText
import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusNext
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.debugPlaceholderBackground
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
@ -70,17 +69,14 @@ fun BugReportView(
)
Spacer(modifier = Modifier.height(16.dp))
PreferenceRow {
OutlinedTextField(
TextField(
value = descriptionFieldState,
modifier = Modifier.fillMaxWidth()
.onTabOrEnterKeyFocusNext(LocalFocusManager.current),
modifier = Modifier
.fillMaxWidth()
.onTabOrEnterKeyFocusNext(LocalFocusManager.current),
enabled = isFormEnabled,
label = {
Text(text = stringResource(id = R.string.screen_bug_report_editor_placeholder))
},
supportingText = {
Text(text = stringResource(id = R.string.screen_bug_report_editor_description))
},
placeholder = stringResource(id = R.string.screen_bug_report_editor_placeholder),
supportingText = stringResource(id = R.string.screen_bug_report_editor_description),
onValueChange = {
descriptionFieldState = it
eventSink(BugReportEvents.SetDescription(it))
@ -152,8 +148,8 @@ fun BugReportView(
enabled = state.submitEnabled,
showProgress = state.sending.isLoading(),
modifier = Modifier
.fillMaxWidth()
.padding(top = 24.dp, bottom = 16.dp)
.fillMaxWidth()
.padding(top = 24.dp, bottom = 16.dp)
)
}
}

View file

@ -9,7 +9,6 @@
package io.element.android.features.roomdetails.impl.edit
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
@ -21,7 +20,6 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
@ -33,7 +31,6 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.roomdetails.impl.R
import io.element.android.libraries.designsystem.components.LabelledTextField
import io.element.android.libraries.designsystem.components.async.AsyncActionView
import io.element.android.libraries.designsystem.components.async.AsyncActionViewDefaults
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
@ -45,6 +42,7 @@ import io.element.android.libraries.designsystem.theme.aliasScreenTitle
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.TextButton
import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.designsystem.theme.components.TopAppBar
import io.element.android.libraries.matrix.ui.components.AvatarActionBottomSheet
import io.element.android.libraries.matrix.ui.components.EditableAvatarView
@ -110,40 +108,28 @@ fun RoomDetailsEditView(
)
Spacer(modifier = Modifier.height(60.dp))
if (state.canChangeName) {
LabelledTextField(
label = stringResource(id = R.string.screen_room_details_room_name_label),
value = state.roomRawName,
placeholder = stringResource(CommonStrings.common_room_name_placeholder),
singleLine = true,
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomName(it)) },
)
} else {
LabelledReadOnlyField(
title = stringResource(R.string.screen_room_details_room_name_label),
value = state.roomRawName
)
}
TextField(
label = stringResource(id = R.string.screen_room_details_room_name_label),
value = state.roomRawName,
placeholder = stringResource(CommonStrings.common_room_name_placeholder),
singleLine = true,
readOnly = !state.canChangeName,
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomName(it)) },
)
Spacer(modifier = Modifier.height(28.dp))
if (state.canChangeTopic) {
LabelledTextField(
label = stringResource(CommonStrings.common_topic),
value = state.roomTopic,
placeholder = stringResource(CommonStrings.common_topic_placeholder),
maxLines = 10,
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomTopic(it)) },
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Sentences,
),
)
} else {
LabelledReadOnlyField(
title = stringResource(R.string.screen_room_details_topic_title),
value = state.roomTopic
)
}
TextField(
label = stringResource(CommonStrings.common_topic),
value = state.roomTopic,
placeholder = stringResource(CommonStrings.common_topic_placeholder),
maxLines = 10,
readOnly = !state.canChangeTopic,
onValueChange = { state.eventSink(RoomDetailsEditEvents.UpdateRoomTopic(it)) },
keyboardOptions = KeyboardOptions(
capitalization = KeyboardCapitalization.Sentences,
),
)
}
}
@ -171,30 +157,6 @@ fun RoomDetailsEditView(
)
}
@Composable
private fun LabelledReadOnlyField(
title: String,
value: String,
) {
Column(
verticalArrangement = Arrangement.spacedBy(8.dp),
) {
Text(
modifier = Modifier.padding(horizontal = 16.dp),
style = ElementTheme.typography.fontBodyMdRegular,
color = MaterialTheme.colorScheme.primary,
text = title,
)
Text(
modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 12.dp),
style = MaterialTheme.typography.bodyLarge,
color = MaterialTheme.colorScheme.primary,
text = value,
)
}
}
@PreviewsDayNight
@Composable
internal fun RoomDetailsEditViewPreview(@PreviewParameter(RoomDetailsEditStateProvider::class) state: RoomDetailsEditState) = ElementPreview {

View file

@ -9,9 +9,9 @@ package io.element.android.features.roomdetails.edit
import androidx.activity.ComponentActivity
import androidx.annotation.StringRes
import androidx.compose.ui.test.assertHasClickAction
import androidx.compose.ui.test.assertHasNoClickAction
import androidx.compose.ui.test.assert
import androidx.compose.ui.test.hasTestTag
import androidx.compose.ui.test.isEditable
import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithText
@ -78,7 +78,6 @@ class RoomDetailsEditViewTest {
roomRawName = "Marketing",
),
)
rule.onNodeWithText("Marketing").assertHasClickAction()
rule.onNodeWithText("Marketing").performTextInput("A")
eventsRecorder.assertSingle(RoomDetailsEditEvents.UpdateRoomName("AMarketing"))
}
@ -93,7 +92,7 @@ class RoomDetailsEditViewTest {
canChangeName = false,
),
)
rule.onNodeWithText("Marketing").assertHasNoClickAction()
rule.onNodeWithText("Marketing").assert(!isEditable())
}
@Test
@ -105,7 +104,6 @@ class RoomDetailsEditViewTest {
roomTopic = "My Topic",
),
)
rule.onNodeWithText("My Topic").assertHasClickAction()
rule.onNodeWithText("My Topic").performTextInput("A")
eventsRecorder.assertSingle(RoomDetailsEditEvents.UpdateRoomTopic("AMy Topic"))
}
@ -120,7 +118,7 @@ class RoomDetailsEditViewTest {
canChangeTopic = false,
),
)
rule.onNodeWithText("My Topic").assertHasNoClickAction()
rule.onNodeWithText("My Topic").assert(!isEditable())
}
@Ignore("This test is failing because the bottom sheet does not open")

View file

@ -45,11 +45,11 @@ import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.FilledTextField
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
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.testtags.TestTags
import io.element.android.libraries.ui.strings.CommonStrings
@ -194,7 +194,7 @@ private fun SearchTextField(
),
) {
val focusManager = LocalFocusManager.current
TextField(
FilledTextField(
modifier = modifier.testTag(TestTags.searchTextField.value),
textStyle = ElementTheme.typography.fontBodyLgRegular,
singleLine = true,

View file

@ -49,11 +49,11 @@ import io.element.android.libraries.designsystem.modifiers.applyIf
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.ButtonSize
import io.element.android.libraries.designsystem.theme.components.FilledTextField
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
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.designsystem.utils.copy
import io.element.android.libraries.matrix.api.core.RoomId
@ -130,7 +130,7 @@ private fun RoomListSearchContent(
title = {
val filter = state.query
val focusRequester = FocusRequester()
TextField(
FilledTextField(
modifier = Modifier
.fillMaxWidth()
.focusRequester(focusRequester),

View file

@ -7,6 +7,8 @@
package io.element.android.features.securebackup.impl.reset.password
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
@ -25,14 +27,12 @@ import io.element.android.libraries.designsystem.atomic.pages.FlowStepPage
import io.element.android.libraries.designsystem.components.BigIcon
import io.element.android.libraries.designsystem.components.ProgressDialog
import io.element.android.libraries.designsystem.components.form.textFieldState
import io.element.android.libraries.designsystem.modifiers.onTabOrEnterKeyFocusNext
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.IconButton
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.onTabOrEnterKeyFocusNext
import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.ui.strings.CommonStrings
@Composable
@ -80,14 +80,13 @@ fun ResetIdentityPasswordView(
@Composable
private fun Content(text: String, onTextChange: (String) -> Unit, hasError: Boolean) {
var showPassword by remember { mutableStateOf(false) }
OutlinedTextField(
TextField(
modifier = Modifier
.fillMaxWidth()
.onTabOrEnterKeyFocusNext(LocalFocusManager.current),
value = text,
onValueChange = onTextChange,
label = { Text(stringResource(CommonStrings.common_password)) },
placeholder = { Text(stringResource(R.string.screen_reset_encryption_password_placeholder)) },
placeholder = stringResource(CommonStrings.common_password),
singleLine = true,
visualTransformation = if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
trailingIcon = {
@ -96,13 +95,13 @@ private fun Content(text: String, onTextChange: (String) -> Unit, hasError: Bool
val description =
if (showPassword) stringResource(CommonStrings.a11y_hide_password) else stringResource(CommonStrings.a11y_show_password)
IconButton(onClick = { showPassword = !showPassword }) {
Box(Modifier.clickable { showPassword = !showPassword }) {
Icon(imageVector = image, description)
}
},
isError = hasError,
supportingText = if (hasError) {
{ Text(stringResource(R.string.screen_reset_encryption_password_error)) }
stringResource(R.string.screen_reset_encryption_password_error)
} else {
null
}

View file

@ -36,14 +36,14 @@ import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.securebackup.impl.R
import io.element.android.features.securebackup.impl.tools.RecoveryKeyVisualTransformation
import io.element.android.libraries.designsystem.modifiers.autofill
import io.element.android.libraries.designsystem.modifiers.clickableIfNotNull
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
import io.element.android.libraries.designsystem.theme.components.Icon
import io.element.android.libraries.designsystem.theme.components.OutlinedTextField
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.theme.components.autofill
import io.element.android.libraries.designsystem.theme.components.TextField
import io.element.android.libraries.testtags.TestTags
import io.element.android.libraries.testtags.testTag
import io.element.android.libraries.ui.strings.CommonStrings
@ -62,7 +62,6 @@ internal fun RecoveryKeyView(
) {
Text(
text = stringResource(id = CommonStrings.common_recovery_key),
modifier = Modifier.padding(start = 16.dp),
style = ElementTheme.typography.fontBodyMdRegular,
)
RecoveryKeyContent(state, onClick, onChange, onSubmit)
@ -159,7 +158,7 @@ private fun RecoveryKeyFormContent(
// Do not apply a visual transformation if the key has spaces, to let user enter passphrase
if (keyHasSpace) VisualTransformation.None else RecoveryKeyVisualTransformation()
}
OutlinedTextField(
TextField(
modifier = Modifier
.fillMaxWidth()
.testTag(TestTags.recoveryKey)
@ -179,7 +178,7 @@ private fun RecoveryKeyFormContent(
keyboardActions = KeyboardActions(
onDone = { onSubmit() }
),
label = { Text(text = stringResource(id = R.string.screen_recovery_key_confirm_key_placeholder)) }
placeholder = stringResource(id = R.string.screen_recovery_key_confirm_key_placeholder),
)
}
@ -198,14 +197,12 @@ private fun RecoveryKeyFooter(state: RecoveryKeyViewState) {
}
),
color = ElementTheme.colors.textSecondary,
modifier = Modifier.padding(start = 16.dp),
style = ElementTheme.typography.fontBodySmRegular,
)
} else {
Text(
text = stringResource(id = R.string.screen_recovery_key_save_key_description),
color = ElementTheme.colors.textSecondary,
modifier = Modifier.padding(start = 16.dp),
style = ElementTheme.typography.fontBodySmRegular,
)
}
@ -214,7 +211,6 @@ private fun RecoveryKeyFooter(state: RecoveryKeyViewState) {
Text(
text = stringResource(id = R.string.screen_recovery_key_confirm_key_description),
color = ElementTheme.colors.textSecondary,
modifier = Modifier.padding(start = 16.dp),
style = ElementTheme.typography.fontBodySmRegular,
)
}