Merge develop into feature/fga/image_loading
This commit is contained in:
commit
affb928801
602 changed files with 3434 additions and 1627 deletions
|
|
@ -33,6 +33,8 @@ android {
|
|||
implementation(libs.accompanist.systemui)
|
||||
implementation(projects.libraries.elementresources)
|
||||
implementation(projects.libraries.uiStrings)
|
||||
|
||||
ksp(libs.showkase.processor)
|
||||
kspTest(libs.showkase.processor)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ import androidx.compose.ui.text.ParagraphStyle
|
|||
import androidx.compose.ui.text.TextLayoutResult
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
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 kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
|
|
@ -97,15 +97,10 @@ fun ClickableLinkText(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Text)
|
||||
@Composable
|
||||
internal fun ClickableLinkTextLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun ClickableLinkTextDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
internal fun ClickableLinkTextPreview() =
|
||||
ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
@ -117,3 +112,4 @@ private fun ContentToPreview() {
|
|||
interactionSource = MutableInteractionSource(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
|
|
@ -52,13 +52,9 @@ fun LabelledCheckbox(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Toggles)
|
||||
@Composable
|
||||
internal fun LabelledCheckboxLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun LabelledCheckboxDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun LabelledCheckboxPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
import androidx.compose.ui.window.DialogProperties
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.components.dialogs.DialogPreview
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
|
|
@ -71,15 +72,43 @@ fun ProgressDialog(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun ProgressDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
private fun ProgressDialogContent(
|
||||
modifier: Modifier = Modifier,
|
||||
text: String? = null,
|
||||
) {
|
||||
Box(
|
||||
contentAlignment = Alignment.Center,
|
||||
modifier = modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.surfaceVariant,
|
||||
shape = RoundedCornerShape(8.dp)
|
||||
)
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
CircularProgressIndicator(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant
|
||||
)
|
||||
if (!text.isNullOrBlank()) {
|
||||
Text(
|
||||
text = text,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.padding(16.dp)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Dialogs)
|
||||
@Composable
|
||||
internal fun ProgressDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun ProgressDialogPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
ProgressDialog(text = "test dialog content")
|
||||
DialogPreview {
|
||||
ProgressDialogContent(text = "test dialog content")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ import androidx.compose.ui.unit.sp
|
|||
import coil.compose.AsyncImage
|
||||
import io.element.android.libraries.designsystem.AvatarGradientEnd
|
||||
import io.element.android.libraries.designsystem.AvatarGradientStart
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.preview.debugPlaceholderAvatar
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import timber.log.Timber
|
||||
|
|
@ -106,17 +106,7 @@ private fun InitialsAvatar(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Avatars)
|
||||
@Composable
|
||||
fun AvatarLightPreview(@PreviewParameter(AvatarDataProvider::class) avatarData: AvatarData) =
|
||||
ElementPreviewLight { ContentToPreview(avatarData) }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
fun AvatarDarkPreview(@PreviewParameter(AvatarDataProvider::class) avatarData: AvatarData) =
|
||||
ElementPreviewDark { ContentToPreview(avatarData) }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview(avatarData: AvatarData) {
|
||||
Avatar(avatarData)
|
||||
}
|
||||
fun AvatarPreview(@PreviewParameter(AvatarDataProvider::class) avatarData: AvatarData) =
|
||||
ElementThemedPreview { Avatar(avatarData) }
|
||||
|
|
|
|||
|
|
@ -16,22 +16,16 @@
|
|||
|
||||
package io.element.android.libraries.designsystem.components.avatar
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import kotlinx.parcelize.IgnoredOnParcel
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Immutable
|
||||
@Parcelize
|
||||
data class AvatarData(
|
||||
val id: String,
|
||||
val name: String?,
|
||||
val url: String? = null,
|
||||
@IgnoredOnParcel
|
||||
val size: AvatarSize = AvatarSize.MEDIUM
|
||||
) : Parcelable {
|
||||
) {
|
||||
|
||||
@IgnoredOnParcel
|
||||
val initial by lazy {
|
||||
(name?.takeIf { it.isNotBlank() } ?: id)
|
||||
.let { dn ->
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
|
@ -47,16 +47,9 @@ fun BackButton(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Buttons)
|
||||
@Composable
|
||||
internal fun BackButtonPreviewLight() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun BackButtonPreviewDark() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
internal fun BackButtonPreview() = ElementThemedPreview {
|
||||
Column {
|
||||
BackButton(onClick = { }, enabled = true, contentDescription = "Back")
|
||||
BackButton(onClick = { }, enabled = false, contentDescription = "Back")
|
||||
|
|
|
|||
|
|
@ -33,8 +33,8 @@ import androidx.compose.ui.graphics.Shape
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.ElementTextStyles
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Button
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.ElementButtonDefaults
|
||||
|
|
@ -93,16 +93,9 @@ fun ButtonWithProgress(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Buttons)
|
||||
@Composable
|
||||
internal fun ButtonWithProgressLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun ButtonWithProgressDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
internal fun ButtonWithProgressPreview() = ElementThemedPreview {
|
||||
ButtonWithProgress(
|
||||
text = "Button with progress",
|
||||
onClick = {},
|
||||
|
|
|
|||
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.button
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Share
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.ElementTextStyles
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
@Composable
|
||||
fun MainActionButton(
|
||||
title: String,
|
||||
icon: ImageVector,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true,
|
||||
contentDescription: String = title,
|
||||
) {
|
||||
val ripple = rememberRipple(bounded = false)
|
||||
val interactionSource = MutableInteractionSource()
|
||||
Column(
|
||||
modifier.clickable(
|
||||
enabled = enabled,
|
||||
interactionSource = interactionSource,
|
||||
onClick = onClick,
|
||||
indication = ripple
|
||||
),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
val tintColor = if (enabled) LocalContentColor.current else MaterialTheme.colorScheme.secondary
|
||||
Icon(
|
||||
icon,
|
||||
contentDescription = contentDescription,
|
||||
tint = tintColor,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
Text(
|
||||
title,
|
||||
style = ElementTextStyles.Regular.bodyMD.copy(fontWeight = FontWeight.Medium),
|
||||
color = tintColor,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(group = PreviewGroup.Buttons)
|
||||
@Composable
|
||||
internal fun MainActionButtonPreview() {
|
||||
ElementThemedPreview {
|
||||
ContentsToPreview()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentsToPreview() {
|
||||
Row(Modifier.padding(10.dp)) {
|
||||
MainActionButton(title = "Share", icon = Icons.Outlined.Share, onClick = { })
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
MainActionButton(title = "Share", icon = Icons.Outlined.Share, onClick = { }, enabled = false)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* 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.dialogs
|
||||
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.sizeIn
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.LocalContentColor
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.ProvideTextStyle
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.CompositionLocalProvider
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.layout.Layout
|
||||
import androidx.compose.ui.layout.Placeable
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.ElementTextStyles
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import kotlin.math.max
|
||||
|
||||
@Composable
|
||||
internal fun SimpleAlertDialogContent(
|
||||
content: String,
|
||||
cancelText: String,
|
||||
onCancelClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
title: String? = null,
|
||||
submitText: String? = null,
|
||||
onSubmitClicked: () -> Unit = {},
|
||||
thirdButtonText: String? = null,
|
||||
onThirdButtonClicked: () -> Unit = {},
|
||||
emphasizeSubmitButton: Boolean = false,
|
||||
shape: Shape = AlertDialogDefaults.shape,
|
||||
containerColor: Color = AlertDialogDefaults.containerColor,
|
||||
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
|
||||
titleContentColor: Color = AlertDialogDefaults.titleContentColor,
|
||||
textContentColor: Color = AlertDialogDefaults.textContentColor,
|
||||
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||
icon: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
AlertDialogContent(
|
||||
buttons = {
|
||||
AlertDialogFlowRow(
|
||||
mainAxisSpacing = ButtonsMainAxisSpacing,
|
||||
crossAxisSpacing = ButtonsCrossAxisSpacing
|
||||
) {
|
||||
if (thirdButtonText != null) {
|
||||
// If there is a 3rd item it should be at the end of the dialog
|
||||
// Having this 3rd action is discouraged, see https://m3.material.io/components/dialogs/guidelines#e13b68f5-e367-4275-ad6f-c552ee8e358f
|
||||
TextButton(onClick = onThirdButtonClicked) {
|
||||
Text(thirdButtonText)
|
||||
}
|
||||
}
|
||||
TextButton(onClick = onCancelClicked) {
|
||||
Text(cancelText)
|
||||
}
|
||||
if (submitText != null) {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onSubmitClicked()
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
submitText,
|
||||
style = if (emphasizeSubmitButton) {
|
||||
ElementTextStyles.Bold.subheadline
|
||||
} else {
|
||||
MaterialTheme.typography.labelLarge
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
modifier = modifier,
|
||||
title = {
|
||||
if (title != null) { Text(text = title) }
|
||||
},
|
||||
text = {
|
||||
Text(content)
|
||||
},
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
iconContentColor = iconContentColor,
|
||||
titleContentColor = titleContentColor,
|
||||
textContentColor = textContentColor,
|
||||
tonalElevation = tonalElevation,
|
||||
icon = icon,
|
||||
// Note that a button content color is provided here from the dialog's token, but in
|
||||
// most cases, TextButtons should be used for dismiss and confirm buttons.
|
||||
// TextButtons will not consume this provided content color value, and will used their
|
||||
// own defined or default colors.
|
||||
buttonContentColor = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun AlertDialogContent(
|
||||
buttons: @Composable () -> Unit,
|
||||
icon: (@Composable () -> Unit)?,
|
||||
title: (@Composable () -> Unit)?,
|
||||
text: @Composable (() -> Unit)?,
|
||||
shape: Shape,
|
||||
containerColor: Color,
|
||||
tonalElevation: Dp,
|
||||
buttonContentColor: Color,
|
||||
iconContentColor: Color,
|
||||
titleContentColor: Color,
|
||||
textContentColor: Color,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Surface(
|
||||
modifier = modifier,
|
||||
shape = shape,
|
||||
color = containerColor,
|
||||
tonalElevation = tonalElevation,
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.padding(DialogPadding)
|
||||
) {
|
||||
icon?.let {
|
||||
CompositionLocalProvider(LocalContentColor provides iconContentColor) {
|
||||
Box(
|
||||
Modifier
|
||||
.padding(IconPadding)
|
||||
.align(Alignment.CenterHorizontally)
|
||||
) {
|
||||
icon()
|
||||
}
|
||||
}
|
||||
}
|
||||
title?.let {
|
||||
CompositionLocalProvider(LocalContentColor provides titleContentColor) {
|
||||
val textStyle = MaterialTheme.typography.headlineSmall
|
||||
ProvideTextStyle(textStyle) {
|
||||
Box(
|
||||
// Align the title to the center when an icon is present.
|
||||
Modifier
|
||||
.padding(TitlePadding)
|
||||
.align(
|
||||
if (icon == null) {
|
||||
Alignment.Start
|
||||
} else {
|
||||
Alignment.CenterHorizontally
|
||||
}
|
||||
)
|
||||
) {
|
||||
title()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
text?.let {
|
||||
CompositionLocalProvider(LocalContentColor provides textContentColor) {
|
||||
val textStyle =
|
||||
MaterialTheme.typography.bodyMedium
|
||||
ProvideTextStyle(textStyle) {
|
||||
Box(
|
||||
Modifier
|
||||
.weight(weight = 1f, fill = false)
|
||||
.padding(TextPadding)
|
||||
.align(Alignment.Start)
|
||||
) {
|
||||
text()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Box(modifier = Modifier.align(Alignment.End)) {
|
||||
CompositionLocalProvider(LocalContentColor provides buttonContentColor) {
|
||||
val textStyle =
|
||||
MaterialTheme.typography.labelLarge
|
||||
ProvideTextStyle(value = textStyle, content = buttons)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple clone of FlowRow that arranges its children in a horizontal flow with limited
|
||||
* customization.
|
||||
*/
|
||||
@Composable
|
||||
internal fun AlertDialogFlowRow(
|
||||
mainAxisSpacing: Dp,
|
||||
crossAxisSpacing: Dp,
|
||||
content: @Composable () -> Unit
|
||||
) {
|
||||
Layout(content) { measurables, constraints ->
|
||||
val sequences = mutableListOf<List<Placeable>>()
|
||||
val crossAxisSizes = mutableListOf<Int>()
|
||||
val crossAxisPositions = mutableListOf<Int>()
|
||||
|
||||
var mainAxisSpace = 0
|
||||
var crossAxisSpace = 0
|
||||
|
||||
val currentSequence = mutableListOf<Placeable>()
|
||||
var currentMainAxisSize = 0
|
||||
var currentCrossAxisSize = 0
|
||||
|
||||
// Return whether the placeable can be added to the current sequence.
|
||||
fun canAddToCurrentSequence(placeable: Placeable) =
|
||||
currentSequence.isEmpty() || currentMainAxisSize + mainAxisSpacing.roundToPx() +
|
||||
placeable.width <= constraints.maxWidth
|
||||
|
||||
// Store current sequence information and start a new sequence.
|
||||
fun startNewSequence() {
|
||||
if (sequences.isNotEmpty()) {
|
||||
crossAxisSpace += crossAxisSpacing.roundToPx()
|
||||
}
|
||||
sequences += currentSequence.toList()
|
||||
crossAxisSizes += currentCrossAxisSize
|
||||
crossAxisPositions += crossAxisSpace
|
||||
|
||||
crossAxisSpace += currentCrossAxisSize
|
||||
mainAxisSpace = max(mainAxisSpace, currentMainAxisSize)
|
||||
|
||||
currentSequence.clear()
|
||||
currentMainAxisSize = 0
|
||||
currentCrossAxisSize = 0
|
||||
}
|
||||
|
||||
for (measurable in measurables) {
|
||||
// Ask the child for its preferred size.
|
||||
val placeable = measurable.measure(constraints)
|
||||
|
||||
// Start a new sequence if there is not enough space.
|
||||
if (!canAddToCurrentSequence(placeable)) startNewSequence()
|
||||
|
||||
// Add the child to the current sequence.
|
||||
if (currentSequence.isNotEmpty()) {
|
||||
currentMainAxisSize += mainAxisSpacing.roundToPx()
|
||||
}
|
||||
currentSequence.add(placeable)
|
||||
currentMainAxisSize += placeable.width
|
||||
currentCrossAxisSize = max(currentCrossAxisSize, placeable.height)
|
||||
}
|
||||
|
||||
if (currentSequence.isNotEmpty()) startNewSequence()
|
||||
|
||||
val mainAxisLayoutSize = max(mainAxisSpace, constraints.minWidth)
|
||||
|
||||
val crossAxisLayoutSize = max(crossAxisSpace, constraints.minHeight)
|
||||
|
||||
val layoutWidth = mainAxisLayoutSize
|
||||
|
||||
val layoutHeight = crossAxisLayoutSize
|
||||
|
||||
layout(layoutWidth, layoutHeight) {
|
||||
sequences.forEachIndexed { i, placeables ->
|
||||
val childrenMainAxisSizes = IntArray(placeables.size) { j ->
|
||||
placeables[j].width +
|
||||
if (j < placeables.lastIndex) mainAxisSpacing.roundToPx() else 0
|
||||
}
|
||||
val arrangement = Arrangement.Bottom
|
||||
// TODO(soboleva): rtl support
|
||||
// Handle vertical direction
|
||||
val mainAxisPositions = IntArray(childrenMainAxisSizes.size) { 0 }
|
||||
with(arrangement) {
|
||||
arrange(mainAxisLayoutSize, childrenMainAxisSizes, mainAxisPositions)
|
||||
}
|
||||
placeables.forEachIndexed { j, placeable ->
|
||||
placeable.place(
|
||||
x = mainAxisPositions[j],
|
||||
y = crossAxisPositions[i]
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
internal fun DialogPreview(content: @Composable () -> Unit) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.sizeIn(minWidth = DialogMinWidth, maxWidth = DialogMaxWidth)
|
||||
.padding(20.dp),
|
||||
propagateMinConstraints = true
|
||||
) {
|
||||
content()
|
||||
}
|
||||
}
|
||||
|
||||
// Paddings for each of the dialog's parts.
|
||||
private val DialogPadding = PaddingValues(all = 24.dp)
|
||||
private val IconPadding = PaddingValues(bottom = 16.dp)
|
||||
private val TitlePadding = PaddingValues(bottom = 16.dp)
|
||||
private val TextPadding = PaddingValues(bottom = 24.dp)
|
||||
|
||||
internal val ButtonsMainAxisSpacing = 8.dp
|
||||
internal val ButtonsCrossAxisSpacing = 12.dp
|
||||
|
||||
internal val DialogMinWidth = 280.dp
|
||||
internal val DialogMaxWidth = 560.dp
|
||||
|
|
@ -18,8 +18,8 @@ package io.element.android.libraries.designsystem.components.dialogs
|
|||
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -28,13 +28,12 @@ import androidx.compose.ui.res.stringResource
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import io.element.android.libraries.designsystem.ElementTextStyles
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.utils.BooleanProvider
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ConfirmationDialog(
|
||||
content: String,
|
||||
|
|
@ -56,70 +55,82 @@ fun ConfirmationDialog(
|
|||
textContentColor: Color = AlertDialogDefaults.textContentColor,
|
||||
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||
) {
|
||||
AlertDialog(
|
||||
AlertDialog(modifier = modifier, onDismissRequest = onDismiss) {
|
||||
ConfirmationDialogContent(
|
||||
title = title,
|
||||
content = content,
|
||||
submitText = submitText,
|
||||
cancelText = cancelText,
|
||||
thirdButtonText = thirdButtonText,
|
||||
onSubmitClicked = onSubmitClicked,
|
||||
onCancelClicked = onCancelClicked,
|
||||
onThirdButtonClicked = onThirdButtonClicked,
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
iconContentColor = iconContentColor,
|
||||
titleContentColor = titleContentColor,
|
||||
textContentColor = textContentColor,
|
||||
tonalElevation = tonalElevation,
|
||||
emphasizeSubmitButton = emphasizeSubmitButton,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ConfirmationDialogContent(
|
||||
content: String,
|
||||
submitText: String,
|
||||
cancelText: String,
|
||||
onSubmitClicked: () -> Unit,
|
||||
onCancelClicked: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
title: String? = null,
|
||||
thirdButtonText: String? = null,
|
||||
onThirdButtonClicked: () -> Unit = {},
|
||||
emphasizeSubmitButton: Boolean = false,
|
||||
shape: Shape = AlertDialogDefaults.shape,
|
||||
containerColor: Color = AlertDialogDefaults.containerColor,
|
||||
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
|
||||
titleContentColor: Color = AlertDialogDefaults.titleContentColor,
|
||||
textContentColor: Color = AlertDialogDefaults.textContentColor,
|
||||
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||
icon: @Composable (() -> Unit)? = null,
|
||||
) {
|
||||
SimpleAlertDialogContent(
|
||||
modifier = modifier,
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
if (title != null) { Text(text = title) }
|
||||
},
|
||||
text = {
|
||||
Text(content)
|
||||
},
|
||||
dismissButton = {
|
||||
if (thirdButtonText != null) {
|
||||
// If there is a 3rd item it should be at the end of the dialog
|
||||
// Having this 3rd action is discouraged, see https://m3.material.io/components/dialogs/guidelines#e13b68f5-e367-4275-ad6f-c552ee8e358f
|
||||
TextButton(onClick = onThirdButtonClicked) {
|
||||
Text(thirdButtonText)
|
||||
}
|
||||
}
|
||||
TextButton(onClick = onCancelClicked) {
|
||||
Text(cancelText)
|
||||
}
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(
|
||||
onClick = {
|
||||
onSubmitClicked()
|
||||
},
|
||||
) {
|
||||
Text(
|
||||
submitText,
|
||||
style = if (emphasizeSubmitButton) {
|
||||
ElementTextStyles.Bold.subheadline
|
||||
} else {
|
||||
MaterialTheme.typography.labelLarge
|
||||
}
|
||||
)
|
||||
}
|
||||
},
|
||||
title = title,
|
||||
content = content,
|
||||
submitText = submitText,
|
||||
onSubmitClicked = onSubmitClicked,
|
||||
cancelText = cancelText,
|
||||
onCancelClicked = onCancelClicked,
|
||||
thirdButtonText = thirdButtonText,
|
||||
onThirdButtonClicked = onThirdButtonClicked,
|
||||
emphasizeSubmitButton = emphasizeSubmitButton,
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
iconContentColor = iconContentColor,
|
||||
titleContentColor = titleContentColor,
|
||||
textContentColor = textContentColor,
|
||||
tonalElevation = tonalElevation,
|
||||
icon = icon,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Dialogs)
|
||||
@Composable
|
||||
internal fun ConfirmationDialogLightPreview(@PreviewParameter(BooleanProvider::class) emphasizeSubmitButton: Boolean) =
|
||||
ElementPreviewLight { ContentToPreview(emphasizeSubmitButton) }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun ConfirmationDialogDarkPreview(@PreviewParameter(BooleanProvider::class) emphasizeSubmitButton: Boolean) =
|
||||
ElementPreviewDark { ContentToPreview(emphasizeSubmitButton) }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview(emphasizeSubmitButton: Boolean) {
|
||||
ConfirmationDialog(
|
||||
title = "Title",
|
||||
content = "Content",
|
||||
thirdButtonText = "Disable",
|
||||
onSubmitClicked = {},
|
||||
onDismiss = {},
|
||||
emphasizeSubmitButton = emphasizeSubmitButton,
|
||||
)
|
||||
}
|
||||
internal fun ConfirmationDialogPreview(@PreviewParameter(BooleanProvider::class) emphasizeSubmitButton: Boolean) =
|
||||
ElementThemedPreview {
|
||||
DialogPreview {
|
||||
ConfirmationDialogContent(
|
||||
content = "Content",
|
||||
title = "Title",
|
||||
submitText = "OK",
|
||||
cancelText = "Cancel",
|
||||
thirdButtonText = "Disable",
|
||||
onSubmitClicked = {},
|
||||
onCancelClicked = {},
|
||||
emphasizeSubmitButton = emphasizeSubmitButton,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package io.element.android.libraries.designsystem.components.dialogs
|
|||
|
||||
import androidx.compose.material3.AlertDialog
|
||||
import androidx.compose.material3.AlertDialogDefaults
|
||||
import androidx.compose.material3.TextButton
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
|
@ -26,11 +26,11 @@ import androidx.compose.ui.graphics.Shape
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun ErrorDialog(
|
||||
content: String,
|
||||
|
|
@ -45,20 +45,42 @@ fun ErrorDialog(
|
|||
textContentColor: Color = AlertDialogDefaults.textContentColor,
|
||||
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||
) {
|
||||
AlertDialog(
|
||||
AlertDialog(modifier = modifier, onDismissRequest = onDismiss) {
|
||||
ErrorDialogContent(
|
||||
title = title,
|
||||
content = content,
|
||||
submitText = submitText,
|
||||
onSubmitText = onDismiss,
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
iconContentColor = iconContentColor,
|
||||
titleContentColor = titleContentColor,
|
||||
textContentColor = textContentColor,
|
||||
tonalElevation = tonalElevation,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ErrorDialogContent(
|
||||
content: String,
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = ErrorDialogDefaults.title,
|
||||
submitText: String = ErrorDialogDefaults.submitText,
|
||||
onSubmitText: () -> Unit = {},
|
||||
shape: Shape = AlertDialogDefaults.shape,
|
||||
containerColor: Color = AlertDialogDefaults.containerColor,
|
||||
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
|
||||
titleContentColor: Color = AlertDialogDefaults.titleContentColor,
|
||||
textContentColor: Color = AlertDialogDefaults.textContentColor,
|
||||
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||
) {
|
||||
SimpleAlertDialogContent(
|
||||
modifier = modifier,
|
||||
onDismissRequest = onDismiss,
|
||||
title = {
|
||||
Text(title)
|
||||
},
|
||||
text = {
|
||||
Text(content)
|
||||
},
|
||||
confirmButton = {
|
||||
TextButton(onClick = onDismiss) {
|
||||
Text(submitText)
|
||||
}
|
||||
},
|
||||
title = title,
|
||||
content = content,
|
||||
cancelText = submitText,
|
||||
onCancelClicked = onSubmitText,
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
iconContentColor = iconContentColor,
|
||||
|
|
@ -73,17 +95,14 @@ object ErrorDialogDefaults {
|
|||
val submitText: String @Composable get() = stringResource(id = StringR.string.action_ok)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Dialogs)
|
||||
@Composable
|
||||
internal fun ErrorDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun ErrorDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
ErrorDialog(
|
||||
content = "Content",
|
||||
)
|
||||
internal fun ErrorDialogPreview() {
|
||||
ElementThemedPreview {
|
||||
DialogPreview {
|
||||
ErrorDialogContent(
|
||||
content = "Content",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ import androidx.compose.ui.graphics.Shape
|
|||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
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.ui.strings.R as StringR
|
||||
|
||||
|
|
@ -75,23 +75,54 @@ fun RetryDialog(
|
|||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun RetryDialogContent(
|
||||
content: String,
|
||||
modifier: Modifier = Modifier,
|
||||
title: String = RetryDialogDefaults.title,
|
||||
retryText: String = RetryDialogDefaults.retryText,
|
||||
dismissText: String = RetryDialogDefaults.dismissText,
|
||||
onRetry: () -> Unit = {},
|
||||
onDismiss: () -> Unit = {},
|
||||
shape: Shape = AlertDialogDefaults.shape,
|
||||
containerColor: Color = AlertDialogDefaults.containerColor,
|
||||
iconContentColor: Color = AlertDialogDefaults.iconContentColor,
|
||||
titleContentColor: Color = AlertDialogDefaults.titleContentColor,
|
||||
textContentColor: Color = AlertDialogDefaults.textContentColor,
|
||||
tonalElevation: Dp = AlertDialogDefaults.TonalElevation,
|
||||
) {
|
||||
SimpleAlertDialogContent(
|
||||
modifier = modifier,
|
||||
title = title,
|
||||
content = content,
|
||||
submitText = retryText,
|
||||
onSubmitClicked = onRetry,
|
||||
cancelText = dismissText,
|
||||
onCancelClicked = onDismiss,
|
||||
shape = shape,
|
||||
containerColor = containerColor,
|
||||
iconContentColor = iconContentColor,
|
||||
titleContentColor = titleContentColor,
|
||||
textContentColor = textContentColor,
|
||||
tonalElevation = tonalElevation,
|
||||
)
|
||||
}
|
||||
|
||||
object RetryDialogDefaults {
|
||||
val title: String @Composable get() = stringResource(id = StringR.string.dialog_title_error)
|
||||
val retryText: String @Composable get() = stringResource(id = StringR.string.action_retry)
|
||||
val dismissText: String @Composable get() = stringResource(id = StringR.string.action_cancel)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Dialogs)
|
||||
@Composable
|
||||
internal fun RetryDialogLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun RetryDialogDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun RetryDialogPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
RetryDialog(
|
||||
content = "Content",
|
||||
)
|
||||
DialogPreview {
|
||||
RetryDialogContent(
|
||||
content = "Content",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Divider
|
||||
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
|
||||
|
||||
@Composable
|
||||
|
|
@ -64,13 +63,9 @@ fun PreferenceCategoryTitle(title: String, modifier: Modifier = Modifier) {
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Preferences)
|
||||
@Composable
|
||||
internal fun PreferenceCategoryLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun PreferenceCategoryDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun PreferenceCategoryPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -16,12 +16,31 @@
|
|||
|
||||
package io.element.android.libraries.designsystem.components.preferences
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Divider
|
||||
|
||||
@Composable
|
||||
fun PreferenceDivider(modifier: Modifier = Modifier) {
|
||||
Divider(modifier, thickness = 0.5.dp)
|
||||
}
|
||||
|
||||
@Preview(group = PreviewGroup.Dividers)
|
||||
@Composable
|
||||
internal fun PreferenceDividerPreview() {
|
||||
ElementThemedPreview {
|
||||
Box(Modifier.padding(vertical = 10.dp), contentAlignment = Alignment.Center) {
|
||||
PreferenceDivider()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Slider
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.toEnabledColor
|
||||
|
|
@ -87,13 +87,9 @@ fun PreferenceSlide(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Preferences)
|
||||
@Composable
|
||||
internal fun PreferenceSlideLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun PreferenceSlideDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun PreferenceSlidePreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.designsystem.toEnabledColor
|
||||
|
|
@ -60,13 +60,17 @@ fun PreferenceSwitch(
|
|||
enabled = enabled
|
||||
)
|
||||
Text(
|
||||
modifier = Modifier.weight(1f).padding(vertical = preferencePaddingVertical),
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(vertical = preferencePaddingVertical),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = enabled.toEnabledColor(),
|
||||
text = title
|
||||
)
|
||||
Checkbox(
|
||||
modifier = Modifier.padding(end = preferencePaddingHorizontal).align(Alignment.CenterVertically),
|
||||
modifier = Modifier
|
||||
.padding(end = preferencePaddingHorizontal)
|
||||
.align(Alignment.CenterVertically),
|
||||
checked = isChecked,
|
||||
enabled = enabled,
|
||||
onCheckedChange = onCheckedChange
|
||||
|
|
@ -75,13 +79,9 @@ fun PreferenceSwitch(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Preferences)
|
||||
@Composable
|
||||
internal fun PreferenceSwitchLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun PreferenceSwitchDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun PreferenceSwitchPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.components.preferences.components.PreferenceIcon
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
|
||||
|
|
@ -95,7 +95,9 @@ fun PreferenceText(
|
|||
Text(currentValue, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.secondary)
|
||||
Spacer(Modifier.width(16.dp))
|
||||
} else if (loadingCurrentValue) {
|
||||
CircularProgressIndicator(modifier = Modifier.progressSemantics().size(20.dp), strokeWidth = 2.dp)
|
||||
CircularProgressIndicator(modifier = Modifier
|
||||
.progressSemantics()
|
||||
.size(20.dp), strokeWidth = 2.dp)
|
||||
Spacer(Modifier.width(16.dp))
|
||||
}
|
||||
|
||||
|
|
@ -103,13 +105,9 @@ fun PreferenceText(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Preferences)
|
||||
@Composable
|
||||
internal fun PreferenceTextLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun PreferenceTextDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun PreferenceTextPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
open class ImageVectorProvider : PreviewParameterProvider<ImageVector?> {
|
||||
override val values: Sequence<ImageVector?>
|
||||
get() = sequenceOf(
|
||||
null,
|
||||
Icons.Default.BugReport,
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ import androidx.compose.ui.graphics.vector.ImageVector
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.toSecondaryEnabledColor
|
||||
|
||||
|
|
@ -57,15 +57,10 @@ fun PreferenceIcon(
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Preferences)
|
||||
@Composable
|
||||
internal fun PreferenceIconLightPreview(@PreviewParameter(ImageVectorProvider::class) content: ImageVector?) =
|
||||
ElementPreviewLight { ContentToPreview(content) }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun PreferenceIconDarkPreview(@PreviewParameter(ImageVectorProvider::class) content: ImageVector?) =
|
||||
ElementPreviewDark { ContentToPreview(content) }
|
||||
internal fun PreferenceIconPreview(@PreviewParameter(ImageVectorProvider::class) content: ImageVector?) =
|
||||
ElementThemedPreview { ContentToPreview(content) }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview(content: ImageVector?) {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,18 @@
|
|||
|
||||
package io.element.android.libraries.designsystem.preview
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||
import io.element.android.libraries.designsystem.theme.components.Surface
|
||||
|
||||
|
|
@ -45,6 +56,45 @@ fun ElementPreviewDark(
|
|||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("ModifierMissing")
|
||||
fun ElementThemedPreview(
|
||||
showBackground: Boolean = true,
|
||||
vertical: Boolean = true,
|
||||
content: @Composable () -> Unit,
|
||||
) {
|
||||
Box(modifier = Modifier
|
||||
.background(Color.Gray)
|
||||
.padding(4.dp)) {
|
||||
if (vertical) {
|
||||
Column {
|
||||
ElementPreviewLight(
|
||||
showBackground = showBackground,
|
||||
content = content,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
ElementPreviewDark(
|
||||
showBackground = showBackground,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Row {
|
||||
ElementPreviewLight(
|
||||
showBackground = showBackground,
|
||||
content = content,
|
||||
)
|
||||
Spacer(modifier = Modifier.width(4.dp))
|
||||
ElementPreviewDark(
|
||||
showBackground = showBackground,
|
||||
content = content
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
@Suppress("ModifierMissing")
|
||||
private fun ElementPreview(
|
||||
darkTheme: Boolean,
|
||||
showBackground: Boolean,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* 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.preview
|
||||
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
||||
/**
|
||||
* Our Paparazzi tests will check components with non-null `heightDp` and use a custom rendering for them,
|
||||
* adding extra vertical space so long scrolling components can be displayed. This is a helper for that functionality.
|
||||
*/
|
||||
@Preview(heightDp = 1000)
|
||||
annotation class LargeHeightPreview
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* 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.preview
|
||||
|
||||
object PreviewGroup {
|
||||
const val AppBars = "App Bars"
|
||||
const val Avatars = "Avatars"
|
||||
const val BottomSheets = "Bottom Sheets"
|
||||
const val Buttons = "Buttons"
|
||||
const val Dialogs = "Dialogs"
|
||||
const val Dividers = "Dividers"
|
||||
const val FABs = "Floating Action Buttons"
|
||||
const val Icons = "Icons"
|
||||
const val Preferences = "Preferences"
|
||||
const val Progress = "Progress Indicators"
|
||||
const val Search = "Search views"
|
||||
const val Sliders = "Sliders"
|
||||
const val Text = "Text"
|
||||
const val TextFields = "TextFields"
|
||||
const val Toggles = "Toggles"
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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.showkase
|
||||
|
||||
import com.airbnb.android.showkase.annotation.ShowkaseRoot
|
||||
import com.airbnb.android.showkase.annotation.ShowkaseRootModule
|
||||
|
||||
@ShowkaseRoot
|
||||
class DesignSystemShowkaseRootModule : ShowkaseRootModule
|
||||
|
|
@ -30,8 +30,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun Button(
|
||||
|
|
@ -71,16 +71,9 @@ object ElementButtonDefaults {
|
|||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Buttons)
|
||||
@Composable
|
||||
internal fun ButtonsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun ButtonsDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
internal fun ButtonPreview() = ElementThemedPreview {
|
||||
Column {
|
||||
Button(onClick = {}, enabled = true) {
|
||||
Text(text = "Click me! - Enabled")
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ import androidx.compose.material3.TopAppBarScrollBehavior
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -52,16 +52,12 @@ fun CenterAlignedTopAppBar(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.AppBars)
|
||||
@Composable
|
||||
internal fun CenterAlignedTopAppBarLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun CenterAlignedTopAppBarDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
internal fun CenterAlignedTopAppBarPreview() =
|
||||
ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
CenterAlignedTopAppBar(title = { Text(text = "Title") })
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun Checkbox(
|
||||
|
|
@ -46,13 +46,9 @@ fun Checkbox(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Toggles)
|
||||
@Composable
|
||||
internal fun CheckboxesLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun CheckboxesDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun CheckboxesPreview() = ElementThemedPreview(vertical = false) { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun CircularProgressIndicator(
|
||||
|
|
@ -56,13 +56,9 @@ fun CircularProgressIndicator(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Progress)
|
||||
@Composable
|
||||
internal fun CircularProgressIndicatorLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun CircularProgressIndicatorDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun CircularProgressIndicatorPreview() = ElementThemedPreview(vertical = false) { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -16,14 +16,19 @@
|
|||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.material3.DividerDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun Divider(
|
||||
|
|
@ -38,13 +43,13 @@ fun Divider(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Dividers)
|
||||
@Composable
|
||||
internal fun DividerLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun DividerDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun DividerPreview() = ElementThemedPreview {
|
||||
Box(Modifier.padding(vertical = 10.dp), contentAlignment = Alignment.Center) {
|
||||
ContentToPreview()
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ import androidx.compose.ui.graphics.Color
|
|||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun FloatingActionButton(
|
||||
|
|
@ -57,15 +57,10 @@ fun FloatingActionButton(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.FABs)
|
||||
@Composable
|
||||
internal fun FloatingActionButtonLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun FloatingActionButtonDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
internal fun FloatingActionButtonPreview() =
|
||||
ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ import androidx.compose.ui.graphics.ImageBitmap
|
|||
import androidx.compose.ui.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun Icon(
|
||||
|
|
@ -75,15 +75,10 @@ fun Icon(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Icons)
|
||||
@Composable
|
||||
internal fun IconImageVectorLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun IconImageVectorDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
internal fun IconImageVectorPreview() =
|
||||
ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun IconButton(
|
||||
|
|
@ -45,15 +45,10 @@ fun IconButton(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Buttons)
|
||||
@Composable
|
||||
internal fun IconButtonLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun IconButtonDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
internal fun IconButtonPreview() =
|
||||
ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ import androidx.compose.material3.TopAppBarScrollBehavior
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -52,15 +52,10 @@ fun MediumTopAppBar(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.AppBars)
|
||||
@Composable
|
||||
internal fun MediumTopAppBarLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun MediumTopAppBarDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
internal fun MediumTopAppBarPreview() =
|
||||
ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,17 @@
|
|||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.ColumnScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.shape.CornerSize
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
import androidx.compose.material.ModalBottomSheetDefaults
|
||||
import androidx.compose.material.ModalBottomSheetState
|
||||
|
|
@ -28,13 +38,17 @@ import androidx.compose.material.rememberModalBottomSheetState
|
|||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.contentColorFor
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.modifiers.applyIf
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@OptIn(ExperimentalMaterialApi::class)
|
||||
@Composable
|
||||
|
|
@ -42,15 +56,36 @@ fun ModalBottomSheetLayout(
|
|||
sheetContent: @Composable ColumnScope.() -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
sheetState: ModalBottomSheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden),
|
||||
sheetShape: Shape = MaterialTheme.shapes.large,
|
||||
sheetShape: Shape = MaterialTheme.shapes.large.copy(bottomStart = CornerSize(0.dp), bottomEnd = CornerSize(0.dp)),
|
||||
sheetElevation: Dp = ModalBottomSheetDefaults.Elevation,
|
||||
sheetBackgroundColor: Color = MaterialTheme.colorScheme.surface,
|
||||
sheetContentColor: Color = contentColorFor(sheetBackgroundColor),
|
||||
scrimColor: Color = ModalBottomSheetDefaults.scrimColor,
|
||||
displayHandle: Boolean = false,
|
||||
useSystemPadding: Boolean = true,
|
||||
content: @Composable () -> Unit = {}
|
||||
) {
|
||||
androidx.compose.material.ModalBottomSheetLayout(
|
||||
sheetContent = sheetContent,
|
||||
sheetContent = {
|
||||
Column(
|
||||
Modifier.fillMaxWidth()
|
||||
.applyIf(useSystemPadding, ifTrue = {
|
||||
navigationBarsPadding()
|
||||
})
|
||||
) {
|
||||
if (displayHandle) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.onSurfaceVariant, RoundedCornerShape(2.dp))
|
||||
.size(width = 32.dp, height = 4.dp)
|
||||
.align(Alignment.CenterHorizontally),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(24.dp))
|
||||
}
|
||||
sheetContent()
|
||||
}
|
||||
},
|
||||
modifier = modifier,
|
||||
sheetState = sheetState,
|
||||
sheetShape = sheetShape,
|
||||
|
|
@ -62,12 +97,12 @@ fun ModalBottomSheetLayout(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.BottomSheets)
|
||||
@Composable
|
||||
internal fun ModalBottomSheetLayoutLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.BottomSheets)
|
||||
@Composable
|
||||
internal fun ModalBottomSheetLayoutDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
|
|
@ -75,9 +110,13 @@ internal fun ModalBottomSheetLayoutDarkPreview() =
|
|||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
ModalBottomSheetLayout(
|
||||
modifier = Modifier.height(140.dp),
|
||||
displayHandle = true,
|
||||
sheetState = ModalBottomSheetState(ModalBottomSheetValue.Expanded),
|
||||
sheetContent = {
|
||||
Text(text = "Sheet Content", modifier = Modifier.background(color = Color.Green))
|
||||
Text(text = "Sheet Content", modifier = Modifier
|
||||
.padding(start = 16.dp, end = 16.dp, bottom = 20.dp)
|
||||
.background(color = Color.Green))
|
||||
}
|
||||
) {
|
||||
Text(text = "Content", modifier = Modifier.background(color = Color.Red))
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun OutlinedButton(
|
||||
|
|
@ -73,13 +73,9 @@ object ElementOutlinedButtonDefaults {
|
|||
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Buttons)
|
||||
@Composable
|
||||
internal fun OutlinedButtonsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun OutlinedButtonsDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun OutlinedButtonsPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -39,13 +39,13 @@ import androidx.compose.ui.input.key.KeyEventType
|
|||
import androidx.compose.ui.input.key.key
|
||||
import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||
import androidx.compose.ui.input.key.type
|
||||
import androidx.compose.ui.platform.LocalFocusManager
|
||||
import androidx.compose.ui.text.TextStyle
|
||||
import androidx.compose.ui.text.input.VisualTransformation
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.utils.allBooleans
|
||||
import io.element.android.libraries.designsystem.utils.asInt
|
||||
|
||||
|
|
@ -109,11 +109,11 @@ fun Modifier.onTabOrEnterKeyFocusNext(focusManager: FocusManager): Modifier = on
|
|||
}
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.TextFields)
|
||||
@Composable
|
||||
internal fun OutlinedTextFieldsLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
internal fun OutlinedTextFieldsPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.TextFields)
|
||||
@Composable
|
||||
internal fun OutlinedTextFieldsDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun RadioButton(
|
||||
|
|
@ -46,13 +46,9 @@ fun RadioButton(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Toggles)
|
||||
@Composable
|
||||
internal fun RadioButtonLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun RadioButtonDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun RadioButtonPreview() = ElementThemedPreview(vertical = false) { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -73,13 +73,9 @@ fun SearchBar(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Search)
|
||||
@Composable
|
||||
internal fun DockedSearchBarLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun DockedSearchBarDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun DockedSearchBarPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -24,8 +24,8 @@ import androidx.compose.runtime.Composable
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun Slider(
|
||||
|
|
@ -53,13 +53,9 @@ fun Slider(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Sliders)
|
||||
@Composable
|
||||
internal fun SlidersLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun SlidersDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun SlidersPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import androidx.compose.ui.unit.Dp
|
|||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
|
||||
@Composable
|
||||
fun Surface(
|
||||
|
|
@ -57,13 +58,8 @@ fun Surface(
|
|||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun SurfaceLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun SurfaceDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
internal fun SurfacePreview() =
|
||||
ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import androidx.compose.ui.unit.TextUnit
|
|||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.utils.toHrf
|
||||
import kotlinx.collections.immutable.ImmutableMap
|
||||
import kotlinx.collections.immutable.persistentMapOf
|
||||
|
|
@ -130,11 +131,11 @@ fun Text(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Text)
|
||||
@Composable
|
||||
internal fun TextLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Text)
|
||||
@Composable
|
||||
internal fun TextDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
|
||||
|
|
|
|||
|
|
@ -29,8 +29,8 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Shape
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@Composable
|
||||
fun TextButton(
|
||||
|
|
@ -59,13 +59,9 @@ fun TextButton(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.Buttons)
|
||||
@Composable
|
||||
internal fun TextButtonLightPreview() = ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun TextButtonDarkPreview() = ElementPreviewDark { ContentToPreview() }
|
||||
internal fun TextButtonPreview() = ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import androidx.compose.ui.tooling.preview.Preview
|
|||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
import io.element.android.libraries.designsystem.utils.allBooleans
|
||||
import io.element.android.libraries.designsystem.utils.asInt
|
||||
|
||||
|
|
@ -97,12 +98,12 @@ fun TextField(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.TextFields)
|
||||
@Composable
|
||||
internal fun TextFieldLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.TextFields)
|
||||
@Composable
|
||||
internal fun TextFieldDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ import androidx.compose.material3.TopAppBarScrollBehavior
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
|
|
@ -52,16 +52,12 @@ fun TopAppBar(
|
|||
)
|
||||
}
|
||||
|
||||
@Preview
|
||||
@Preview(group = PreviewGroup.AppBars)
|
||||
@Composable
|
||||
internal fun TopAppBarLightPreview() =
|
||||
ElementPreviewLight { ContentToPreview() }
|
||||
|
||||
@Preview
|
||||
@Composable
|
||||
internal fun TopAppBarDarkPreview() =
|
||||
ElementPreviewDark { ContentToPreview() }
|
||||
internal fun TopAppBarPreview() =
|
||||
ElementThemedPreview { ContentToPreview() }
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ContentToPreview() {
|
||||
TopAppBar(title = { Text(text = "Title") })
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ plugins {
|
|||
id("io.element.android-library")
|
||||
id("kotlin-parcelize")
|
||||
alias(libs.plugins.anvil)
|
||||
kotlin("plugin.serialization") version "1.8.20"
|
||||
kotlin("plugin.serialization") version "1.8.21"
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
|
|||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import java.io.Closeable
|
||||
|
||||
|
|
@ -40,6 +42,7 @@ interface MatrixClient : Closeable {
|
|||
suspend fun unignoreUser(userId: UserId): Result<Unit>
|
||||
suspend fun createRoom(createRoomParams: CreateRoomParameters): Result<RoomId>
|
||||
suspend fun createDM(userId: UserId): Result<RoomId>
|
||||
suspend fun getProfile(userId: UserId): Result<MatrixUser>
|
||||
fun startSync()
|
||||
fun stopSync()
|
||||
fun sessionVerificationService(): SessionVerificationService
|
||||
|
|
@ -52,4 +55,6 @@ interface MatrixClient : Closeable {
|
|||
fun onSlidingSyncUpdate()
|
||||
|
||||
fun roomMembershipObserver(): RoomMembershipObserver
|
||||
|
||||
suspend fun searchUsers(searchTerm: String, limit: Long): Result<MatrixSearchUserResults>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package io.element.android.libraries.matrix.api.room
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
data class RoomMember(
|
||||
val userId: UserId,
|
||||
|
|
@ -29,6 +30,12 @@ data class RoomMember(
|
|||
val isIgnored: Boolean,
|
||||
)
|
||||
|
||||
fun RoomMember.toMatrixUser() = MatrixUser(
|
||||
userId = userId,
|
||||
displayName = displayName,
|
||||
avatarUrl = avatarUrl,
|
||||
)
|
||||
|
||||
enum class RoomMembershipState {
|
||||
BAN, INVITE, JOIN, KNOCK, LEAVE
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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.matrix.api.user
|
||||
|
||||
data class MatrixSearchUserResults(
|
||||
val results: List<MatrixUser>,
|
||||
val limited: Boolean,
|
||||
)
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* 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.matrix.api.user
|
||||
|
||||
import android.os.Parcelable
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class MatrixUser(
|
||||
val userId: UserId,
|
||||
val displayName: String? = null,
|
||||
val avatarUrl: String? = null
|
||||
) : Parcelable
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
plugins {
|
||||
id("io.element.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
kotlin("plugin.serialization") version "1.8.20"
|
||||
kotlin("plugin.serialization") version "1.8.21"
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
|
|||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.impl.media.RustMediaLoader
|
||||
import io.element.android.libraries.matrix.impl.notification.RustNotificationService
|
||||
|
|
@ -36,9 +38,12 @@ import io.element.android.libraries.matrix.impl.pushers.RustPushersService
|
|||
import io.element.android.libraries.matrix.impl.room.RustMatrixRoom
|
||||
import io.element.android.libraries.matrix.impl.room.RustRoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.impl.sync.SlidingSyncObserverProxy
|
||||
import io.element.android.libraries.matrix.impl.usersearch.UserProfileMapper
|
||||
import io.element.android.libraries.matrix.impl.usersearch.UserSearchResultMapper
|
||||
import io.element.android.libraries.matrix.impl.verification.RustSessionVerificationService
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.flow.filter
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
|
@ -268,6 +273,12 @@ class RustMatrixClient constructor(
|
|||
return createRoom(createRoomParams)
|
||||
}
|
||||
|
||||
override suspend fun getProfile(userId: UserId): Result<MatrixUser> = withContext(Dispatchers.IO) {
|
||||
runCatching {
|
||||
client.getProfile(userId.value).let(UserProfileMapper::map)
|
||||
}
|
||||
}
|
||||
|
||||
override fun sessionVerificationService(): SessionVerificationService = verificationService
|
||||
|
||||
override fun pushersService(): PushersService = pushersService
|
||||
|
|
@ -334,6 +345,13 @@ class RustMatrixClient constructor(
|
|||
|
||||
override fun roomMembershipObserver(): RoomMembershipObserver = roomMembershipObserver
|
||||
|
||||
override suspend fun searchUsers(searchTerm: String, limit: Long): Result<MatrixSearchUserResults> =
|
||||
withContext(dispatchers.io) {
|
||||
runCatching {
|
||||
client.searchUsers(searchTerm, limit.toULong()).let(UserSearchResultMapper::map)
|
||||
}
|
||||
}
|
||||
|
||||
private fun File.deleteSessionDirectory(userID: String): Boolean {
|
||||
// Rust sanitises the user ID replacing invalid characters with an _
|
||||
val sanitisedUserID = userID.replace(":", "_")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.matrix.impl.usersearch
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import org.matrix.rustcomponents.sdk.UserProfile
|
||||
|
||||
object UserProfileMapper {
|
||||
fun map(userProfile: UserProfile): MatrixUser =
|
||||
MatrixUser(
|
||||
userId = UserId(userProfile.userId),
|
||||
displayName = userProfile.displayName,
|
||||
avatarUrl = userProfile.avatarUrl,
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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.matrix.impl.usersearch
|
||||
|
||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||
import org.matrix.rustcomponents.sdk.SearchUsersResults
|
||||
|
||||
object UserSearchResultMapper {
|
||||
|
||||
fun map(result: SearchUsersResults): MatrixSearchUserResults {
|
||||
return MatrixSearchUserResults(
|
||||
results = result.results.map(UserProfileMapper::map),
|
||||
limited = result.limited,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -27,6 +27,8 @@ import io.element.android.libraries.matrix.api.pusher.PushersService
|
|||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
|
||||
import io.element.android.libraries.matrix.api.room.RoomSummaryDataSource
|
||||
import io.element.android.libraries.matrix.api.user.MatrixSearchUserResults
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
|
||||
import io.element.android.libraries.matrix.test.media.FakeMediaLoader
|
||||
import io.element.android.libraries.matrix.test.notification.FakeNotificationService
|
||||
|
|
@ -56,6 +58,8 @@ class FakeMatrixClient(
|
|||
private var findDmResult: MatrixRoom? = FakeMatrixRoom()
|
||||
private var logoutFailure: Throwable? = null
|
||||
private val getRoomResults = mutableMapOf<RoomId, MatrixRoom>()
|
||||
private val searchUserResults = mutableMapOf<String, Result<MatrixSearchUserResults>>()
|
||||
private val getProfileResults = mutableMapOf<UserId, Result<MatrixUser>>()
|
||||
|
||||
override fun getRoom(roomId: RoomId): MatrixRoom? {
|
||||
return getRoomResults[roomId]
|
||||
|
|
@ -84,6 +88,10 @@ class FakeMatrixClient(
|
|||
return createDmResult
|
||||
}
|
||||
|
||||
override suspend fun getProfile(userId: UserId): Result<MatrixUser> {
|
||||
return getProfileResults[userId] ?: Result.failure(IllegalStateException("No profile found for $userId"))
|
||||
}
|
||||
|
||||
override fun startSync() = Unit
|
||||
|
||||
override fun stopSync() = Unit
|
||||
|
|
@ -115,6 +123,10 @@ class FakeMatrixClient(
|
|||
return RoomMembershipObserver()
|
||||
}
|
||||
|
||||
override suspend fun searchUsers(searchTerm: String, limit: Long): Result<MatrixSearchUserResults> {
|
||||
return searchUserResults[searchTerm] ?: Result.failure(IllegalStateException("No response defined for $searchTerm"))
|
||||
}
|
||||
|
||||
// Mocks
|
||||
|
||||
fun givenLogoutError(failure: Throwable?) {
|
||||
|
|
@ -148,4 +160,12 @@ class FakeMatrixClient(
|
|||
fun givenGetRoomResult(roomId: RoomId, result: MatrixRoom) {
|
||||
getRoomResults[roomId] = result
|
||||
}
|
||||
|
||||
fun givenSearchUsersResult(searchTerm: String, result: Result<MatrixSearchUserResults>) {
|
||||
searchUserResults[searchTerm] = result
|
||||
}
|
||||
|
||||
fun givenGetProfileResult(userId: UserId, result: Result<MatrixUser>) {
|
||||
getProfileResults[userId] = result
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2022 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.matrix.ui
|
||||
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
import kotlinx.coroutines.FlowPreview
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.asFlow
|
||||
import javax.inject.Inject
|
||||
|
||||
class MatrixItemHelper @Inject constructor(
|
||||
private val client: MatrixClient
|
||||
) {
|
||||
/**
|
||||
* TODO Make username and avatar live...
|
||||
*/
|
||||
@OptIn(FlowPreview::class)
|
||||
fun getCurrentUserData(avatarSize: AvatarSize): Flow<MatrixUser> {
|
||||
return suspend {
|
||||
val userAvatarUrl = client.loadUserAvatarURLString().getOrNull()
|
||||
val userDisplayName = client.loadUserDisplayName().getOrNull()
|
||||
val avatarData =
|
||||
AvatarData(
|
||||
client.sessionId.value,
|
||||
userDisplayName,
|
||||
userAvatarUrl,
|
||||
avatarSize
|
||||
)
|
||||
MatrixUser(
|
||||
id = client.sessionId,
|
||||
username = userDisplayName,
|
||||
avatarData = avatarData,
|
||||
)
|
||||
}.asFlow()
|
||||
}
|
||||
}
|
||||
|
|
@ -30,14 +30,14 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
|||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Checkbox
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
@Composable
|
||||
fun CheckableMatrixUserRow(
|
||||
checked: Boolean,
|
||||
matrixUser: MatrixUser,
|
||||
modifier: Modifier = Modifier,
|
||||
avatarSize: AvatarSize = matrixUser.avatarData.size,
|
||||
avatarSize: AvatarSize = AvatarSize.MEDIUM,
|
||||
onCheckedChange: (Boolean) -> Unit = {},
|
||||
enabled: Boolean = true,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
|||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
|
||||
@Composable
|
||||
|
|
@ -56,7 +57,7 @@ fun MatrixUserHeader(
|
|||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Avatar(
|
||||
matrixUser.avatarData.copy(size = AvatarSize.HUGE),
|
||||
matrixUser.getAvatarData(size = AvatarSize.HUGE),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
// Name
|
||||
|
|
@ -69,10 +70,10 @@ fun MatrixUserHeader(
|
|||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
// Id
|
||||
if (matrixUser.username.isNullOrEmpty().not()) {
|
||||
if (matrixUser.displayName.isNullOrEmpty().not()) {
|
||||
Spacer(modifier = Modifier.height(4.dp))
|
||||
Text(
|
||||
text = matrixUser.id.value,
|
||||
text = matrixUser.userId.value,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
fontSize = 14.sp,
|
||||
maxLines = 1,
|
||||
|
|
|
|||
|
|
@ -17,25 +17,20 @@
|
|||
package io.element.android.libraries.matrix.ui.components
|
||||
|
||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||
import io.element.android.libraries.designsystem.components.avatar.anAvatarData
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
open class MatrixUserProvider : PreviewParameterProvider<MatrixUser> {
|
||||
override val values: Sequence<MatrixUser>
|
||||
get() = sequenceOf(
|
||||
aMatrixUser(),
|
||||
aMatrixUser().copy(
|
||||
username = null,
|
||||
avatarData = anAvatarData().copy(name = null)
|
||||
),
|
||||
aMatrixUser().copy(displayName = null),
|
||||
)
|
||||
}
|
||||
|
||||
fun aMatrixUser(id: String = "@id_of_alice:server.org", userName: String = "Alice") = MatrixUser(
|
||||
id = UserId(id),
|
||||
username = userName,
|
||||
avatarData = anAvatarData(id, userName)
|
||||
fun aMatrixUser(id: String = "@id_of_alice:server.org", displayName: String = "Alice") = MatrixUser(
|
||||
userId = UserId(id),
|
||||
displayName = displayName,
|
||||
)
|
||||
|
||||
fun aMatrixUserList() = listOf(
|
||||
|
|
@ -55,10 +50,7 @@ open class MatrixUserWithNullProvider : PreviewParameterProvider<MatrixUser?> {
|
|||
override val values: Sequence<MatrixUser?>
|
||||
get() = sequenceOf(
|
||||
aMatrixUser(),
|
||||
aMatrixUser().copy(
|
||||
username = null,
|
||||
avatarData = anAvatarData().copy(name = null)
|
||||
),
|
||||
aMatrixUser().copy(displayName = null),
|
||||
null,
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,14 +37,15 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
|||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.model.getAvatarData
|
||||
import io.element.android.libraries.matrix.ui.model.getBestName
|
||||
|
||||
@Composable
|
||||
fun MatrixUserRow(
|
||||
matrixUser: MatrixUser,
|
||||
modifier: Modifier = Modifier,
|
||||
avatarSize: AvatarSize = matrixUser.avatarData.size,
|
||||
avatarSize: AvatarSize = AvatarSize.MEDIUM,
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier
|
||||
|
|
@ -54,7 +55,7 @@ fun MatrixUserRow(
|
|||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
Avatar(
|
||||
matrixUser.avatarData.copy(size = avatarSize),
|
||||
matrixUser.getAvatarData(size = avatarSize),
|
||||
)
|
||||
Column(
|
||||
modifier = Modifier
|
||||
|
|
@ -70,9 +71,9 @@ fun MatrixUserRow(
|
|||
color = MaterialTheme.colorScheme.primary,
|
||||
)
|
||||
// Id
|
||||
if (matrixUser.username.isNullOrEmpty().not()) {
|
||||
if (matrixUser.displayName.isNullOrEmpty().not()) {
|
||||
Text(
|
||||
text = matrixUser.id.value,
|
||||
text = matrixUser.userId.value,
|
||||
color = MaterialTheme.colorScheme.secondary,
|
||||
fontSize = 14.sp,
|
||||
maxLines = 1,
|
||||
|
|
|
|||
|
|
@ -16,20 +16,17 @@
|
|||
|
||||
package io.element.android.libraries.matrix.ui.model
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.runtime.Immutable
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import io.element.android.libraries.designsystem.components.avatar.AvatarSize
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
|
||||
@Parcelize
|
||||
@Immutable
|
||||
data class MatrixUser(
|
||||
val id: UserId,
|
||||
val username: String? = null,
|
||||
val avatarData: AvatarData = AvatarData(id.value, username),
|
||||
) : Parcelable
|
||||
fun MatrixUser.getAvatarData(size: AvatarSize = AvatarSize.MEDIUM) = AvatarData(
|
||||
id = userId.value,
|
||||
name = displayName,
|
||||
url = avatarUrl,
|
||||
size = size,
|
||||
)
|
||||
|
||||
fun MatrixUser.getBestName(): String {
|
||||
return username?.takeIf { it.isNotEmpty() } ?: id.value
|
||||
return displayName?.takeIf { it.isNotEmpty() } ?: userId.value
|
||||
}
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
plugins {
|
||||
id("io.element.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
kotlin("plugin.serialization") version "1.8.20"
|
||||
kotlin("plugin.serialization") version "1.8.21"
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
<string name="notification_room_action_mark_as_read">"Als gelesen markieren"</string>
|
||||
<string name="notification_ticker_text_dm">"%1$s: %2$s"</string>
|
||||
<string name="notification_ticker_text_group">"%1$s: %2$s %3$s"</string>
|
||||
<string name="notification_unread_notified_messages_and_invitation">"%1$s und %2$s"</string>
|
||||
<string name="notification_unread_notified_messages_in_room_and_invitation">"%1$s in %2$s und %3$s"</string>
|
||||
<plurals name="notification_compat_summary_line_for_room">
|
||||
<item quantity="one">"%1$s: %2$d Nachricht"</item>
|
||||
|
|
|
|||
|
|
@ -18,32 +18,26 @@
|
|||
<string name="notification_unread_notified_messages_in_room_and_invitation">"%1$s în %2$s și %3$s"</string>
|
||||
<plurals name="notification_compat_summary_line_for_room">
|
||||
<item quantity="one">"%1$s: %2$d mesaj"</item>
|
||||
<item quantity="few"></item>
|
||||
<item quantity="other">"%1$s: %2$d mesaje"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_compat_summary_title">
|
||||
<item quantity="one">"%d notificare"</item>
|
||||
<item quantity="few"></item>
|
||||
<item quantity="other">"%d notificări"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_invitations">
|
||||
<item quantity="one">"%d invitație"</item>
|
||||
<item quantity="few"></item>
|
||||
<item quantity="other">"%d invitații"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_new_messages_for_room">
|
||||
<item quantity="one">"%d mesaj nou"</item>
|
||||
<item quantity="few"></item>
|
||||
<item quantity="other">"%d mesaje noi"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_unread_notified_messages">
|
||||
<item quantity="one">"%d mesaj notificat necitit"</item>
|
||||
<item quantity="few"></item>
|
||||
<item quantity="other">"%d mesaje notificate necitite"</item>
|
||||
</plurals>
|
||||
<plurals name="notification_unread_notified_messages_in_room_rooms">
|
||||
<item quantity="one">"%d cameră"</item>
|
||||
<item quantity="few"></item>
|
||||
<item quantity="other">"%d camere"</item>
|
||||
</plurals>
|
||||
<string name="push_choose_distributor_dialog_title_android">"Alegeți modul de primire a notificărilor"</string>
|
||||
|
|
@ -51,4 +45,4 @@
|
|||
<string name="push_distributor_firebase_android">"Servicii Google"</string>
|
||||
<string name="push_no_valid_google_play_services_apk_android">"Nu au fost găsite servicii Google Play valide. Este posibil ca notificările să nu funcționeze corect."</string>
|
||||
<string name="notification_room_action_quick_reply">"Raspuns rapid"</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
@ -16,7 +16,7 @@
|
|||
plugins {
|
||||
id("io.element.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
kotlin("plugin.serialization") version "1.8.20"
|
||||
kotlin("plugin.serialization") version "1.8.21"
|
||||
}
|
||||
|
||||
android {
|
||||
|
|
|
|||
|
|
@ -31,17 +31,19 @@ class UnifiedPushGatewayResolver @Inject constructor(
|
|||
suspend fun getGateway(endpoint: String): String? {
|
||||
val gateway = UnifiedPushConfig.default_push_gateway_http_url
|
||||
val url = URL(endpoint)
|
||||
val custom = "${url.protocol}://${url.host}/_matrix/push/v1/notify"
|
||||
Timber.i("Testing $custom")
|
||||
val port = if (url.port != -1) { ":${url.port}" } else { "" }
|
||||
val customBase = "${url.protocol}://${url.host}${port}"
|
||||
val customUrl = "$customBase/_matrix/push/v1/notify"
|
||||
Timber.i("Testing $customUrl")
|
||||
try {
|
||||
return withContext(coroutineDispatchers.io) {
|
||||
val api = retrofitFactory.create("${url.protocol}://${url.host}")
|
||||
val api = retrofitFactory.create(customBase)
|
||||
.create(UnifiedPushApi::class.java)
|
||||
try {
|
||||
val discoveryResponse = api.discover()
|
||||
if (discoveryResponse.unifiedpush.gateway == "matrix") {
|
||||
Timber.d("Using custom gateway")
|
||||
return@withContext custom
|
||||
return@withContext customUrl
|
||||
}
|
||||
} catch (throwable: Throwable) {
|
||||
Timber.tag("UnifiedPushHelper").e(throwable)
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ import androidx.compose.material3.MaterialTheme
|
|||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.platform.LocalInspectionMode
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
|
|
@ -55,8 +57,9 @@ fun TextComposer(
|
|||
if (LocalInspectionMode.current) {
|
||||
FakeComposer(modifier)
|
||||
} else {
|
||||
val focusRequester = FocusRequester()
|
||||
AndroidView(
|
||||
modifier = modifier,
|
||||
modifier = modifier.focusRequester(focusRequester),
|
||||
factory = { context ->
|
||||
RichTextComposerLayout(context).apply {
|
||||
// Sets up listeners for View -> Compose communication
|
||||
|
|
|
|||
|
|
@ -93,14 +93,12 @@
|
|||
<string name="report_content_hint">"Grund für die Meldung dieses Inhalts"</string>
|
||||
<string name="room_timeline_beginning_of_room">"Dies ist der Anfang von %1$s."</string>
|
||||
<string name="room_timeline_read_marker_title">"Neu"</string>
|
||||
<string name="screen_room_member_details_block_alert_action">"Blockieren"</string>
|
||||
<string name="screen_room_member_details_block_user">"Nutzer blockieren"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_action">"Blockierung aufheben"</string>
|
||||
<string name="screen_room_member_details_unblock_user">"Nutzer entblockieren"</string>
|
||||
<string name="screen_analytics_settings_share_data">"Teile Analyse-Daten"</string>
|
||||
<string name="screen_media_picker_error_failed_selection">"Medienauswahl fehlgeschlagen, bitte versuche es erneut."</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Erkennungsschwelle"</string>
|
||||
<string name="settings_version_number">"Version: %1$s (%2$s)"</string>
|
||||
<string name="test_language_identifier">"de"</string>
|
||||
<string name="dialog_title_error">"Fehler"</string>
|
||||
<string name="dialog_title_success">"Erfolg"</string>
|
||||
<string name="screen_report_content_block_user">"Nutzer blockieren"</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -128,12 +128,6 @@
|
|||
<string name="room_timeline_beginning_of_room_no_name">"Este es el principio de esta conversación."</string>
|
||||
<string name="room_timeline_read_marker_title">"Nuevos"</string>
|
||||
<string name="screen_report_content_block_user_hint">"Marque si quieres ocultar todos los mensajes actuales y futuros de este usuario"</string>
|
||||
<string name="screen_room_member_details_block_alert_action">"Bloquear"</string>
|
||||
<string name="screen_room_member_details_block_alert_description">"Los usuarios bloqueados no podrán enviarte mensajes y se ocultarán todos sus mensajes. Puede revertir esta acción en cualquier momento."</string>
|
||||
<string name="screen_room_member_details_block_user">"Bloquear usuario"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_action">"Desbloquear"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_description">"Al desbloquear al usuario, podrás volver a ver todos sus mensajes."</string>
|
||||
<string name="screen_room_member_details_unblock_user">"Desbloquear usuario"</string>
|
||||
<string name="settings_rageshake">"Agitar con fuerza"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Umbral de detección"</string>
|
||||
<string name="settings_title_general">"General"</string>
|
||||
|
|
@ -142,4 +136,4 @@
|
|||
<string name="dialog_title_error">"Error"</string>
|
||||
<string name="dialog_title_success">"Terminado"</string>
|
||||
<string name="screen_report_content_block_user">"Bloquear usuario"</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -128,12 +128,6 @@
|
|||
<string name="room_timeline_beginning_of_room_no_name">"Questo è l\'inizio della conversazione."</string>
|
||||
<string name="room_timeline_read_marker_title">"Nuovo"</string>
|
||||
<string name="screen_report_content_block_user_hint">"Seleziona se vuoi nascondere tutti i messaggi attuali e futuri di questo utente"</string>
|
||||
<string name="screen_room_member_details_block_alert_action">"Blocca"</string>
|
||||
<string name="screen_room_member_details_block_alert_description">"Gli utenti bloccati non saranno in grado di inviarti nuovi messaggi e tutti quelli già esistenti saranno nascosti. Potrai annullare questa azione in qualsiasi momento."</string>
|
||||
<string name="screen_room_member_details_block_user">"Blocca utente"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_action">"Sblocca"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_description">"Dopo aver sbloccato l\'utente, potrai vedere nuovamente tutti i suoi messaggi."</string>
|
||||
<string name="screen_room_member_details_unblock_user">"Sblocca utente"</string>
|
||||
<string name="settings_rageshake">"Rageshake"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Soglia di rilevamento"</string>
|
||||
<string name="settings_title_general">"Generali"</string>
|
||||
|
|
@ -142,4 +136,4 @@
|
|||
<string name="dialog_title_error">"Errore"</string>
|
||||
<string name="dialog_title_success">"Operazione riuscita"</string>
|
||||
<string name="screen_report_content_block_user">"Blocca utente"</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -122,12 +122,10 @@
|
|||
<string name="login_initial_device_name_android">"%1$s Android"</string>
|
||||
<plurals name="common_member_count">
|
||||
<item quantity="one">"%1$d membru"</item>
|
||||
<item quantity="few"></item>
|
||||
<item quantity="other">"%1$d membri"</item>
|
||||
</plurals>
|
||||
<plurals name="room_timeline_state_changes">
|
||||
<item quantity="one">"%1$d schimbare a camerii"</item>
|
||||
<item quantity="few"></item>
|
||||
<item quantity="other">"%1$d schimbări ale camerei"</item>
|
||||
</plurals>
|
||||
<string name="preference_rageshake">"Rageshake pentru a raporta erori"</string>
|
||||
|
|
@ -137,7 +135,6 @@
|
|||
<string name="room_timeline_beginning_of_room">"Acesta este începutul conversației %1$s."</string>
|
||||
<string name="room_timeline_beginning_of_room_no_name">"Acesta este începutul acestei conversații."</string>
|
||||
<string name="room_timeline_read_marker_title">"Nou"</string>
|
||||
<string name="screen_analytics_help_us_improve">"Ajutați-ne să identificăm problemele și să îmbunătățim %1$s prin partajarea datelor de utilizare anonime."</string>
|
||||
<string name="screen_analytics_prompt_data_usage"><b>"Nu"</b>" înregistrăm sau profilăm datele contului"</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Ajutați-ne să identificăm problemele și să îmbunătățim %1$s prin partajarea datelor de utilizare anonime."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"Puteți citi toate condițiile noastre %1$s."</string>
|
||||
|
|
@ -145,16 +142,7 @@
|
|||
<string name="screen_analytics_prompt_settings">"Puteți dezactiva această opțiune oricând din setări"</string>
|
||||
<string name="screen_analytics_prompt_third_party_sharing"><b>"Nu"</b>" împărtășim informații cu terți"</string>
|
||||
<string name="screen_analytics_prompt_title">"Ajutați la îmbunătățirea %1$s"</string>
|
||||
<string name="screen_analytics_read_terms">"Puteți citi toate condițiile noastre %1$s."</string>
|
||||
<string name="screen_analytics_read_terms_content_link">"aici"</string>
|
||||
<string name="screen_analytics_share_data">"Partajați datele analitice"</string>
|
||||
<string name="screen_report_content_block_user_hint">"Confirmați că doriți să ascundeți toate mesajele curente și viitoare de la acest utilizator"</string>
|
||||
<string name="screen_room_member_details_block_alert_action">"Blocați"</string>
|
||||
<string name="screen_room_member_details_block_alert_description">"Utilizatorii blocați nu vă vor putea trimite mesaje și toate mesajele lor vor fi ascunse. Puteți anula această acțiune oricând."</string>
|
||||
<string name="screen_room_member_details_block_user">"Blocați utilizatorul"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_action">"Deblocați"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_description">"La deblocarea utilizatorului, veți putea vedea din nou toate mesajele de la acesta."</string>
|
||||
<string name="screen_room_member_details_unblock_user">"Deblocați utilizatorul"</string>
|
||||
<string name="settings_rageshake">"Rageshake"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Prag de detecție"</string>
|
||||
<string name="settings_title_general">"General"</string>
|
||||
|
|
@ -162,5 +150,8 @@
|
|||
<string name="test_language_identifier">"ro"</string>
|
||||
<string name="dialog_title_error">"Eroare"</string>
|
||||
<string name="dialog_title_success">"Succes"</string>
|
||||
<string name="screen_analytics_settings_help_us_improve">"Ajutați-ne să identificăm problemele și să îmbunătățim %1$s prin partajarea datelor de utilizare anonime."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"Puteți citi toate condițiile noastre %1$s."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"aici"</string>
|
||||
<string name="screen_report_content_block_user">"Blocați utilizatorul"</string>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -135,7 +135,6 @@
|
|||
<string name="room_timeline_beginning_of_room">"This is the beginning of %1$s."</string>
|
||||
<string name="room_timeline_beginning_of_room_no_name">"This is the beginning of this conversation."</string>
|
||||
<string name="room_timeline_read_marker_title">"New"</string>
|
||||
<string name="screen_analytics_help_us_improve">"Help us identify issues and improve %1$s by sharing anonymous usage data."</string>
|
||||
<string name="screen_analytics_prompt_data_usage">"We "<b>"don\'t"</b>" record or profile any account data"</string>
|
||||
<string name="screen_analytics_prompt_help_us_improve">"Help us identify issues and improve %1$s by sharing anonymous usage data."</string>
|
||||
<string name="screen_analytics_prompt_read_terms">"You can read all our terms %1$s."</string>
|
||||
|
|
@ -143,16 +142,11 @@
|
|||
<string name="screen_analytics_prompt_settings">"You can turn this off anytime in settings"</string>
|
||||
<string name="screen_analytics_prompt_third_party_sharing">"We "<b>"don\'t"</b>" share information with third parties"</string>
|
||||
<string name="screen_analytics_prompt_title">"Help improve %1$s"</string>
|
||||
<string name="screen_analytics_read_terms">"You can read all our terms %1$s."</string>
|
||||
<string name="screen_analytics_read_terms_content_link">"here"</string>
|
||||
<string name="screen_analytics_share_data">"Share analytics data"</string>
|
||||
<string name="screen_analytics_settings_share_data">"Share analytics data"</string>
|
||||
<string name="screen_media_picker_error_failed_selection">"Failed selecting media, please try again."</string>
|
||||
<string name="screen_media_upload_preview_error_failed_processing">"Failed processing media to upload, please try again."</string>
|
||||
<string name="screen_media_upload_preview_error_failed_sending">"Failed uploading media, please try again."</string>
|
||||
<string name="screen_report_content_block_user_hint">"Check if you want to hide all current and future messages from this user"</string>
|
||||
<string name="screen_room_member_details_block_alert_action">"Block"</string>
|
||||
<string name="screen_room_member_details_block_alert_description">"Blocked users will not be able to send you messages and all message by them will be hidden. You can reverse this action anytime."</string>
|
||||
<string name="screen_room_member_details_block_user">"Block user"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_action">"Unblock"</string>
|
||||
<string name="screen_room_member_details_unblock_alert_description">"On unblocking the user, you will be able to see all messages by them again."</string>
|
||||
<string name="screen_room_member_details_unblock_user">"Unblock user"</string>
|
||||
<string name="settings_rageshake">"Rageshake"</string>
|
||||
<string name="settings_rageshake_detection_threshold">"Detection threshold"</string>
|
||||
<string name="settings_title_general">"General"</string>
|
||||
|
|
@ -161,5 +155,8 @@
|
|||
<string name="test_untranslated_default_language_identifier">"en"</string>
|
||||
<string name="dialog_title_error">"Error"</string>
|
||||
<string name="dialog_title_success">"Success"</string>
|
||||
<string name="screen_analytics_settings_help_us_improve">"Help us identify issues and improve %1$s by sharing anonymous usage data."</string>
|
||||
<string name="screen_analytics_settings_read_terms">"You can read all our terms %1$s."</string>
|
||||
<string name="screen_analytics_settings_read_terms_content_link">"here"</string>
|
||||
<string name="screen_report_content_block_user">"Block user"</string>
|
||||
</resources>
|
||||
Loading…
Add table
Add a link
Reference in a new issue