Konsist: add test to ensure filename match top level Composable View, and fix existing issue

This commit is contained in:
Benoit Marty 2023-10-10 14:37:01 +02:00
parent 675f77bfa4
commit 308a0c0f57
103 changed files with 1137 additions and 760 deletions

View file

@ -71,7 +71,7 @@ fun BlurHashAsyncImage(
}
@Composable
fun BlurHashImage(
private fun BlurHashImage(
blurHash: String?,
modifier: Modifier = Modifier,
contentDescription: String? = null,

View file

@ -72,7 +72,7 @@ fun ListDialog(
}
@Composable
internal fun ListDialogContent(
private fun ListDialogContent(
listItems: LazyListScope.() -> Unit,
onDismissRequest: () -> Unit,
onSubmitClicked: () -> Unit,

View file

@ -78,7 +78,7 @@ fun MultipleSelectionDialog(
}
@Composable
internal fun MultipleSelectionDialogContent(
private fun MultipleSelectionDialogContent(
options: ImmutableList<ListOption>,
confirmButtonTitle: String,
onConfirmClicked: (List<Int>) -> Unit,

View file

@ -74,7 +74,7 @@ fun SingleSelectionDialog(
}
@Composable
internal fun SingleSelectionDialogContent(
private fun SingleSelectionDialogContent(
options: ImmutableList<ListOption>,
onOptionSelected: (Int) -> Unit,
onDismissRequest: () -> Unit,

View file

@ -52,7 +52,7 @@ fun PreferenceCategory(
}
@Composable
fun PreferenceCategoryTitle(title: String, modifier: Modifier = Modifier) {
private fun PreferenceCategoryTitle(title: String, modifier: Modifier = Modifier) {
Text(
modifier = modifier.padding(
top = 20.dp,

View file

@ -44,7 +44,7 @@ import io.element.android.libraries.theme.ElementTheme
@OptIn(ExperimentalLayoutApi::class)
@Composable
fun PreferenceView(
fun PreferencePage(
title: String,
modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
@ -79,7 +79,7 @@ fun PreferenceView(
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun PreferenceTopAppBar(
private fun PreferenceTopAppBar(
title: String,
modifier: Modifier = Modifier,
onBackPressed: () -> Unit = {},
@ -104,7 +104,7 @@ fun PreferenceTopAppBar(
@PreviewsDayNight
@Composable
internal fun PreferenceViewPreview() = ElementPreview {
PreferenceView(
PreferencePage(
title = "Preference screen"
) {
PreferenceCategory(

View file

@ -16,90 +16,11 @@
package io.element.android.libraries.designsystem.preview
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
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.components.Surface
import io.element.android.libraries.theme.ElementTheme
@Composable
fun ElementPreviewLight(
showBackground: Boolean = true,
content: @Composable () -> Unit
) {
ElementPreview(
darkTheme = false,
showBackground = showBackground,
content = content
)
}
@Composable
fun ElementPreviewDark(
showBackground: Boolean = true,
content: @Composable () -> Unit
) {
ElementPreview(
darkTheme = true,
showBackground = showBackground,
content = content
)
}
@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 {
ElementPreview(
darkTheme = false,
showBackground = showBackground,
content = content,
)
Spacer(modifier = Modifier.height(4.dp))
ElementPreview(
darkTheme = true,
showBackground = showBackground,
content = content
)
}
} else {
Row {
ElementPreview(
darkTheme = false,
showBackground = showBackground,
content = content,
)
Spacer(modifier = Modifier.width(4.dp))
ElementPreview(
darkTheme = true,
showBackground = showBackground,
content = content
)
}
}
}
}
@Composable
@Suppress("ModifierMissing")
fun ElementPreview(

View file

@ -0,0 +1,31 @@
/*
* 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.runtime.Composable
@Composable
fun ElementPreviewDark(
showBackground: Boolean = true,
content: @Composable () -> Unit
) {
ElementPreview(
darkTheme = true,
showBackground = showBackground,
content = content
)
}

View file

@ -0,0 +1,31 @@
/*
* 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.runtime.Composable
@Composable
fun ElementPreviewLight(
showBackground: Boolean = true,
content: @Composable () -> Unit
) {
ElementPreview(
darkTheme = false,
showBackground = showBackground,
content = content
)
}

View file

@ -0,0 +1,74 @@
/*
* 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.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
@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 {
ElementPreview(
darkTheme = false,
showBackground = showBackground,
content = content,
)
Spacer(modifier = Modifier.height(4.dp))
ElementPreview(
darkTheme = true,
showBackground = showBackground,
content = content
)
}
} else {
Row {
ElementPreview(
darkTheme = false,
showBackground = showBackground,
content = content,
)
Spacer(modifier = Modifier.width(4.dp))
ElementPreview(
darkTheme = true,
showBackground = showBackground,
content = content
)
}
}
}
}

View file

@ -52,7 +52,7 @@ fun Dp.applyScaleUp(): Dp = with(LocalDensity.current) {
@Preview
@Composable
internal fun DpScalePreview_0_75f() = WithFontScale(0.75f) {
internal fun DpScale_0_75f_Preview() = WithFontScale(0.75f) {
ElementPreviewLight {
val fontSizeInDp = 16.dp
Column(
@ -77,7 +77,7 @@ internal fun DpScalePreview_0_75f() = WithFontScale(0.75f) {
@Preview
@Composable
internal fun DpScalePreview_1_0f() = WithFontScale(1f) {
internal fun DpScale_1_0f_Preview() = WithFontScale(1f) {
ElementPreviewLight {
val fontSizeInDp = 16.dp
Column(
@ -102,7 +102,7 @@ internal fun DpScalePreview_1_0f() = WithFontScale(1f) {
@Preview
@Composable
internal fun DpScalePreview_1_5f() = WithFontScale(1.5f) {
internal fun DpScale_1_5f_Preview() = WithFontScale(1.5f) {
ElementPreviewLight {
val fontSizeInDp = 16.dp
Column(

View file

@ -117,7 +117,7 @@ fun TextButton(
)
@Composable
internal fun ButtonInternal(
private fun ButtonInternal(
text: String,
onClick: () -> Unit,
style: ButtonStyle,

View file

@ -0,0 +1,127 @@
/*
* 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.theme.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
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.theme.ElementTheme
// Designs: https://www.figma.com/file/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?type=design&node-id=425%3A24208&mode=design&t=G5hCfkLB6GgXDuWe-1
/**
* List section header.
* @param title The title of the section.
* @param modifier The modifier to be applied to the section.
* @param hasDivider Whether to show a divider above the section or not. Default is `true`.
* @param description A description for the section. It's empty by default.
*/
@Composable
fun ListSectionHeader(
title: String,
modifier: Modifier = Modifier,
hasDivider: Boolean = true,
description: @Composable () -> Unit = {},
) {
Column(modifier.fillMaxWidth()) {
if (hasDivider) {
HorizontalDivider(modifier = Modifier.padding(top = 16.dp))
}
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = title,
style = ElementTheme.typography.fontBodyLgMedium,
color = ElementTheme.colors.textPrimary,
)
CompositionLocalProvider(
LocalTextStyle provides ElementTheme.typography.fontBodySmRegular,
LocalContentColor provides ElementTheme.colors.textSecondary,
) {
description()
}
}
}
}
@Preview(group = PreviewGroup.ListSections, name = "List section header")
@Composable
internal fun ListSectionHeaderPreview() {
ElementThemedPreview {
ListSectionHeader(
title = "List section",
hasDivider = false,
)
}
}
@Preview(group = PreviewGroup.ListSections, name = "List section header with divider")
@Composable
internal fun ListSectionHeaderWithDividerPreview() {
ElementThemedPreview {
ListSectionHeader(
title = "List section",
hasDivider = true,
)
}
}
@Preview(group = PreviewGroup.ListSections, name = "List section header with description")
@Composable
internal fun ListSectionHeaderWithDescriptionPreview() {
ElementThemedPreview {
ListSectionHeader(
title = "List section",
description = {
ListSupportingText(
text = "Supporting line text lorem ipsum dolor sit amet, consectetur. Read more",
contentPadding = ListSupportingTextDefaults.Padding.None,
)
},
hasDivider = false,
)
}
}
@Preview(group = PreviewGroup.ListSections, name = "List section header with description and divider")
@Composable
internal fun ListSectionHeaderWithDescriptionAndDividerPreview() {
ElementThemedPreview {
ListSectionHeader(
title = "List section",
description = {
ListSupportingText(
text = "Supporting line text lorem ipsum dolor sit amet, consectetur. Read more",
contentPadding = ListSupportingTextDefaults.Padding.None,
)
},
hasDivider = true,
)
}
}

View file

@ -16,15 +16,10 @@
package io.element.android.libraries.designsystem.theme.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.LocalTextStyle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.ExperimentalTextApi
@ -40,43 +35,6 @@ import io.element.android.libraries.theme.ElementTheme
// Designs: https://www.figma.com/file/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?type=design&node-id=425%3A24208&mode=design&t=G5hCfkLB6GgXDuWe-1
/**
* List section header.
* @param title The title of the section.
* @param modifier The modifier to be applied to the section.
* @param hasDivider Whether to show a divider above the section or not. Default is `true`.
* @param description A description for the section. It's empty by default.
*/
@Composable
fun ListSectionHeader(
title: String,
modifier: Modifier = Modifier,
hasDivider: Boolean = true,
description: @Composable () -> Unit = {},
) {
Column(modifier.fillMaxWidth()) {
if (hasDivider) {
HorizontalDivider(modifier = Modifier.padding(top = 16.dp))
}
Column(
modifier = Modifier.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Text(
text = title,
style = ElementTheme.typography.fontBodyLgMedium,
color = ElementTheme.colors.textPrimary,
)
CompositionLocalProvider(
LocalTextStyle provides ElementTheme.typography.fontBodySmRegular,
LocalContentColor provides ElementTheme.colors.textSecondary,
) {
description()
}
}
}
}
/**
* List supporting text item. Used to display an explanation in the list with a pre-formatted style.
* @param text The text to display.
@ -167,68 +125,6 @@ object ListSupportingTextDefaults {
}
}
// region: List header previews
@Preview(group = PreviewGroup.ListSections, name = "List section header")
@Composable
internal fun ListSectionHeaderPreview() {
ElementThemedPreview {
ListSectionHeader(
title = "List section",
hasDivider = false,
)
}
}
@Preview(group = PreviewGroup.ListSections, name = "List section header with divider")
@Composable
internal fun ListSectionHeaderWithDividerPreview() {
ElementThemedPreview {
ListSectionHeader(
title = "List section",
hasDivider = true,
)
}
}
@Preview(group = PreviewGroup.ListSections, name = "List section header with description")
@Composable
internal fun ListSectionHeaderWithDescriptionPreview() {
ElementThemedPreview {
ListSectionHeader(
title = "List section",
description = {
ListSupportingText(
text = "Supporting line text lorem ipsum dolor sit amet, consectetur. Read more",
contentPadding = ListSupportingTextDefaults.Padding.None,
)
},
hasDivider = false,
)
}
}
@Preview(group = PreviewGroup.ListSections, name = "List section header with description and divider")
@Composable
internal fun ListSectionHeaderWithDescriptionAndDividerPreview() {
ElementThemedPreview {
ListSectionHeader(
title = "List section",
description = {
ListSupportingText(
text = "Supporting line text lorem ipsum dolor sit amet, consectetur. Read more",
contentPadding = ListSupportingTextDefaults.Padding.None,
)
},
hasDivider = true,
)
}
}
// endregion
// region: List supporting text previews
@Preview(group = PreviewGroup.ListSections, name = "List supporting text - no padding")
@Composable
internal fun ListSupportingTextNoPaddingPreview() {
@ -298,5 +194,3 @@ internal fun ListSupportingTextCustomPaddingPreview() {
}
}
}
// endregion

View file

@ -193,11 +193,11 @@ sealed interface SearchBarResultState<in T> {
@Preview(group = PreviewGroup.Search)
@Composable
internal fun SearchBarPreviewInactive() = ElementThemedPreview { ContentToPreview() }
internal fun SearchBarInactivePreview() = ElementThemedPreview { ContentToPreview() }
@Preview(group = PreviewGroup.Search)
@Composable
internal fun SearchBarPreviewActiveEmptyQuery() = ElementThemedPreview {
internal fun SearchBarActiveEmptyQueryPreview() = ElementThemedPreview {
ContentToPreview(
query = "",
active = true,
@ -206,7 +206,7 @@ internal fun SearchBarPreviewActiveEmptyQuery() = ElementThemedPreview {
@Preview(group = PreviewGroup.Search)
@Composable
internal fun SearchBarPreviewActiveWithQuery() = ElementThemedPreview {
internal fun SearchBarActiveWithQueryPreview() = ElementThemedPreview {
ContentToPreview(
query = "search term",
active = true,
@ -215,7 +215,7 @@ internal fun SearchBarPreviewActiveWithQuery() = ElementThemedPreview {
@Preview(group = PreviewGroup.Search)
@Composable
internal fun SearchBarPreviewActiveWithQueryNoBackButton() = ElementThemedPreview {
internal fun SearchBarActiveWithQueryNoBackButtonPreview() = ElementThemedPreview {
ContentToPreview(
query = "search term",
active = true,
@ -225,7 +225,7 @@ internal fun SearchBarPreviewActiveWithQueryNoBackButton() = ElementThemedPrevie
@Preview(group = PreviewGroup.Search)
@Composable
internal fun SearchBarPreviewActiveWithNoResults() = ElementThemedPreview {
internal fun SearchBarActiveWithNoResultsPreview() = ElementThemedPreview {
ContentToPreview(
query = "search term",
active = true,
@ -235,7 +235,7 @@ internal fun SearchBarPreviewActiveWithNoResults() = ElementThemedPreview {
@Preview(group = PreviewGroup.Search)
@Composable
internal fun SearchBarPreviewActiveWithContent() = ElementThemedPreview {
internal fun SearchBarActiveWithContentPreview() = ElementThemedPreview {
ContentToPreview(
query = "search term",
active = true,

View file

@ -30,13 +30,13 @@ import io.element.android.libraries.designsystem.preview.PreviewGroup
@Preview(group = PreviewGroup.DateTimePickers)
@Composable
internal fun DatePickerPreviewLight() {
internal fun DatePickerLightPreview() {
ElementPreviewLight { ContentToPreview() }
}
@Preview(group = PreviewGroup.DateTimePickers)
@Composable
internal fun DatePickerPreviewDark() {
internal fun DatePickerDarkPreview() {
ElementPreviewDark { ContentToPreview() }
}

View file

@ -55,7 +55,7 @@ internal fun TimePickerHorizontalPreview() {
@OptIn(ExperimentalMaterial3Api::class)
@Preview(group = PreviewGroup.DateTimePickers)
@Composable
internal fun TimePickerVerticalPreviewLight() {
internal fun TimePickerVerticalLightPreview() {
ElementPreviewLight {
AlertDialogContent(
buttons = { /*TODO*/ },
@ -77,7 +77,7 @@ internal fun TimePickerVerticalPreviewLight() {
@OptIn(ExperimentalMaterial3Api::class)
@Preview(group = PreviewGroup.DateTimePickers)
@Composable
internal fun TimePickerVerticalPreviewDark() {
internal fun TimePickerVerticalDarkPreview() {
val pickerState = rememberTimePickerState(
initialHour = 12,
initialMinute = 0,

View file

@ -14,11 +14,8 @@
* limitations under the License.
*/
package io.element.android.libraries.designsystem.utils
package io.element.android.libraries.designsystem.utils.snackbar
import androidx.annotation.StringRes
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarDuration
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
@ -26,11 +23,7 @@ import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.compositionLocalOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.components.button.ButtonVisuals
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.Snackbar
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.currentCoroutineContext
@ -38,7 +31,6 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.sync.Mutex
import java.util.concurrent.atomic.AtomicBoolean
/**
* A global dispatcher of [SnackbarMessage] to be displayed in [Snackbar] via a [SnackbarHostState].
@ -78,23 +70,6 @@ fun SnackbarDispatcher.collectSnackbarMessageAsState(): State<SnackbarMessage?>
return snackbarMessage.collectAsState(initial = null)
}
@Composable
fun SnackbarHost(hostState: SnackbarHostState, modifier: Modifier = Modifier) {
androidx.compose.material3.SnackbarHost(hostState, modifier) { data ->
Snackbar(
modifier = Modifier.padding(12.dp), // Add default padding
message = data.visuals.message,
action = data.visuals.actionLabel?.let { ButtonVisuals.Text(it, data::performAction) },
dismissAction = if (data.visuals.withDismissAction) {
ButtonVisuals.Icon(
IconSource.Resource(CommonDrawables.ic_compound_close),
data::dismiss
)
} else null,
)
}
}
/**
* Helper method to display a [SnackbarMessage] in a [SnackbarHostState] handling cancellations.
*/
@ -127,19 +102,3 @@ fun rememberSnackbarHostState(snackbarMessage: SnackbarMessage?): SnackbarHostSt
}
return snackbarHostState
}
/**
* A message to be displayed in a [Snackbar].
* @param messageResId The message to be displayed.
* @param duration The duration of the message. The default value is [SnackbarDuration.Short].
* @param actionResId The action text to be displayed. The default value is `null`.
* @param isDisplayed Used to track if the current message is already displayed or not.
* @param action The action to be performed when the action is clicked.
*/
data class SnackbarMessage(
@StringRes val messageResId: Int,
val duration: SnackbarDuration = SnackbarDuration.Short,
@StringRes val actionResId: Int? = null,
val isDisplayed: AtomicBoolean = AtomicBoolean(false),
val action: () -> Unit = {},
)

View file

@ -0,0 +1,44 @@
/*
* 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.utils.snackbar
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.SnackbarHostState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import io.element.android.libraries.designsystem.components.button.ButtonVisuals
import io.element.android.libraries.designsystem.theme.components.IconSource
import io.element.android.libraries.designsystem.theme.components.Snackbar
import io.element.android.libraries.designsystem.utils.CommonDrawables
@Composable
fun SnackbarHost(hostState: SnackbarHostState, modifier: Modifier = Modifier) {
androidx.compose.material3.SnackbarHost(hostState, modifier) { data ->
Snackbar(
modifier = Modifier.padding(12.dp), // Add default padding
message = data.visuals.message,
action = data.visuals.actionLabel?.let { ButtonVisuals.Text(it, data::performAction) },
dismissAction = if (data.visuals.withDismissAction) {
ButtonVisuals.Icon(
IconSource.Resource(CommonDrawables.ic_compound_close),
data::dismiss
)
} else null,
)
}
}

View file

@ -0,0 +1,37 @@
/*
* 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.utils.snackbar
import androidx.annotation.StringRes
import androidx.compose.material3.SnackbarDuration
import java.util.concurrent.atomic.AtomicBoolean
/**
* A message to be displayed in a [Snackbar].
* @param messageResId The message to be displayed.
* @param duration The duration of the message. The default value is [SnackbarDuration.Short].
* @param actionResId The action text to be displayed. The default value is `null`.
* @param isDisplayed Used to track if the current message is already displayed or not.
* @param action The action to be performed when the action is clicked.
*/
data class SnackbarMessage(
@StringRes val messageResId: Int,
val duration: SnackbarDuration = SnackbarDuration.Short,
@StringRes val actionResId: Int? = null,
val isDisplayed: AtomicBoolean = AtomicBoolean(false),
val action: () -> Unit = {},
)

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
package io.element.android.libraries.designsystem.utils
package io.element.android.libraries.designsystem.utils.snackbar
import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat