Merge branch 'develop' into feature/fga/pin_create_ui

This commit is contained in:
ganfra 2023-10-19 22:26:21 +02:00
commit 20c2ee9e3a
132 changed files with 2562 additions and 219 deletions

View file

@ -27,9 +27,9 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import com.airbnb.android.showkase.annotation.ShowkaseComposable
import io.element.android.libraries.designsystem.components.list.TextFieldListItem
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.theme.components.DialogPreview
import io.element.android.libraries.designsystem.theme.components.ListSupportingText
import io.element.android.libraries.designsystem.theme.components.SimpleAlertDialogContent
@ -45,6 +45,7 @@ fun ListDialog(
subtitle: String? = null,
cancelText: String = stringResource(CommonStrings.action_cancel),
submitText: String = stringResource(CommonStrings.action_ok),
enabled: Boolean = true,
listItems: LazyListScope.() -> Unit,
) {
val decoratedSubtitle: @Composable (() -> Unit)? = subtitle?.let {
@ -66,6 +67,7 @@ fun ListDialog(
submitText = submitText,
onDismissRequest = onDismissRequest,
onSubmitClicked = onSubmit,
enabled = enabled,
listItems = listItems,
)
}
@ -80,6 +82,7 @@ private fun ListDialogContent(
submitText: String,
modifier: Modifier = Modifier,
title: String? = null,
enabled: Boolean = true,
subtitle: @Composable (() -> Unit)? = null,
) {
SimpleAlertDialogContent(
@ -90,6 +93,7 @@ private fun ListDialogContent(
submitText = submitText,
onCancelClicked = onDismissRequest,
onSubmitClicked = onSubmitClicked,
enabled = enabled,
applyPaddingToContents = false,
) {
LazyColumn(

View file

@ -16,10 +16,13 @@
package io.element.android.libraries.designsystem.components.list
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
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.libraries.designsystem.preview.ElementThemedPreview
import io.element.android.libraries.designsystem.preview.PreviewGroup
@ -29,24 +32,68 @@ import io.element.android.libraries.theme.ElementTheme
@Composable
fun TextFieldListItem(
placeholder: String,
placeholder: String?,
text: String,
onTextChanged: (String) -> Unit,
modifier: Modifier = Modifier,
error: String? = null,
maxLines: Int = 1,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
) {
val textFieldStyle = ElementTheme.materialTypography.bodyLarge
OutlinedTextField(
value = text,
onValueChange = onTextChanged,
placeholder = { Text(placeholder) },
onValueChange = { onTextChanged(it) },
placeholder = placeholder?.let { @Composable { Text(it) } },
colors = OutlinedTextFieldDefaults.colors(
disabledBorderColor = Color.Transparent,
errorBorderColor = Color.Transparent,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
),
isError = error != null,
supportingText = error?.let { @Composable { Text(it) } },
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
textStyle = textFieldStyle,
maxLines = maxLines,
singleLine = maxLines == 1,
modifier = modifier,
)
}
@Composable
fun TextFieldListItem(
placeholder: String?,
text: TextFieldValue,
onTextChanged: (TextFieldValue) -> Unit,
modifier: Modifier = Modifier,
error: String? = null,
maxLines: Int = 1,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
keyboardActions: KeyboardActions = KeyboardActions.Default,
) {
val textFieldStyle = ElementTheme.materialTypography.bodyLarge
OutlinedTextField(
value = text,
onValueChange = { onTextChanged(it) },
placeholder = placeholder?.let { @Composable { Text(it) } },
colors = OutlinedTextFieldDefaults.colors(
disabledBorderColor = Color.Transparent,
errorBorderColor = Color.Transparent,
focusedBorderColor = Color.Transparent,
unfocusedBorderColor = Color.Transparent,
),
isError = error != null,
supportingText = error?.let { @Composable { Text(it) } },
keyboardOptions = keyboardOptions,
keyboardActions = keyboardActions,
textStyle = textFieldStyle,
maxLines = maxLines,
singleLine = maxLines == 1,
modifier = modifier,
)
}
@ -74,3 +121,15 @@ internal fun TextFieldListItemPreview() {
)
}
}
@Preview("Text field List item - textfieldvalue", group = PreviewGroup.ListItems)
@Composable
internal fun TextFieldListItemTextFieldValuePreview() {
ElementThemedPreview {
TextFieldListItem(
placeholder = "Placeholder",
text = TextFieldValue("Text field value"),
onTextChanged = {},
)
}
}

View file

@ -0,0 +1,141 @@
/*
* Copyright (c) 2023 New Vector Ltd
*
* 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 io.element.android.libraries.designsystem.components.preferences
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.input.TextFieldValue
import io.element.android.libraries.designsystem.components.dialogs.ListDialog
import io.element.android.libraries.designsystem.components.list.ListItemContent
import io.element.android.libraries.designsystem.components.list.TextFieldListItem
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.Text
@Composable
fun PreferenceTextField(
headline: String,
onChange: (String?) -> Unit,
modifier: Modifier = Modifier,
placeholder: String? = null,
value: String? = null,
supportingText: String? = null,
displayValue: (String?) -> Boolean = { !it.isNullOrBlank() },
trailingContent: ListItemContent? = null,
validation: (String?) -> Boolean = { true },
onValidationErrorMessage: String? = null,
enabled: Boolean = true,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
style: ListItemStyle = ListItemStyle.Default,
) {
var displayTextFieldDialog by rememberSaveable { mutableStateOf(false) }
val valueToDisplay = if (displayValue(value)) { value } else supportingText
ListItem(
modifier = modifier,
headlineContent = { Text(headline) },
supportingContent = valueToDisplay?.let { @Composable { Text(it) } },
trailingContent = trailingContent,
style = style,
enabled = enabled,
onClick = { displayTextFieldDialog = true }
)
if (displayTextFieldDialog) {
TextFieldDialog(
title = headline,
onSubmit = {
onChange(it.takeIf { it.isNotBlank() })
displayTextFieldDialog = false
},
onDismissRequest = { displayTextFieldDialog = false },
placeholder = placeholder.orEmpty(),
value = value.orEmpty(),
validation = validation,
onValidationErrorMessage = onValidationErrorMessage,
keyboardOptions = keyboardOptions,
)
}
}
@Composable
private fun TextFieldDialog(
title: String,
onSubmit: (String) -> Unit,
onDismissRequest: () -> Unit,
value: String?,
placeholder: String?,
modifier: Modifier = Modifier,
validation: (String?) -> Boolean = { true },
onValidationErrorMessage: String? = null,
autoSelectOnDisplay: Boolean = true,
maxLines: Int = 1,
keyboardOptions: KeyboardOptions = KeyboardOptions.Default,
) {
val focusRequester = remember { FocusRequester() }
var textFieldContents by rememberSaveable(stateSaver = TextFieldValue.Saver) {
mutableStateOf(TextFieldValue(value.orEmpty(), selection = TextRange(value.orEmpty().length)))
}
var error by rememberSaveable { mutableStateOf<String?>(null) }
val canSubmit by remember { derivedStateOf { validation(textFieldContents.text) } }
ListDialog(
title = title,
onSubmit = { onSubmit(textFieldContents.text) },
onDismissRequest = onDismissRequest,
enabled = canSubmit,
modifier = modifier,
) {
item {
TextFieldListItem(
placeholder = placeholder.orEmpty(),
text = textFieldContents,
onTextChanged = {
error = if (!validation(it.text)) onValidationErrorMessage else null
textFieldContents = it
},
error = error,
keyboardOptions = keyboardOptions,
keyboardActions = KeyboardActions(onAny = {
if (validation(textFieldContents.text)) {
onSubmit(textFieldContents.text)
}
}),
maxLines = maxLines,
modifier = Modifier.focusRequester(focusRequester),
)
}
}
if (autoSelectOnDisplay) {
LaunchedEffect(Unit) {
focusRequester.requestFocus()
}
}
}

View file

@ -96,6 +96,7 @@ internal fun SimpleAlertDialogContent(
thirdButtonText: String? = null,
onThirdButtonClicked: () -> Unit = {},
applyPaddingToContents: Boolean = true,
enabled: Boolean = true,
icon: @Composable (() -> Unit)? = null,
content: @Composable () -> Unit,
) {
@ -122,6 +123,7 @@ internal fun SimpleAlertDialogContent(
if (submitText != null) {
Button(
text = submitText,
enabled = enabled,
size = ButtonSize.Medium,
onClick = onSubmitClicked,
)