[Compound] Implement Snackbars based on designs (#1054)
* Make `InternalButton` internal instead of private so it can be customised. Also, change the `ButtonColors.contentColor` for text buttons to `LocalContentColor.current` by default. * Add temporary color for Snackbar action label * Implement `Snackbar` component based on Compound * Propagate changes to all other components * Use right Preview annotation config * Move `ButtonVisuals` to their own file * Update screenshots * Make previews internal * Update screenshots * Set a custom token for contentColor in AppBars * Change 'Label' to 'Action' in the previews * Add changelog * Update screenshots --------- Co-authored-by: ElementBot <benoitm+elementbot@element.io>
This commit is contained in:
parent
acf29036a6
commit
9e1ff513e4
49 changed files with 441 additions and 147 deletions
1
changelog.d/1054.misc
Normal file
1
changelog.d/1054.misc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Compound: implement Snackbar component.
|
||||||
|
|
@ -195,7 +195,7 @@ private fun AnalyticsOptInFooter(
|
||||||
)
|
)
|
||||||
TextButton(
|
TextButton(
|
||||||
text = stringResource(id = CommonStrings.action_not_now),
|
text = stringResource(id = CommonStrings.action_not_now),
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
onClick = onTermsDeclined,
|
onClick = onTermsDeclined,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -135,7 +135,7 @@ internal fun DefaultInviteSummaryRow(
|
||||||
text = stringResource(CommonStrings.action_decline),
|
text = stringResource(CommonStrings.action_decline),
|
||||||
onClick = onDeclineClicked,
|
onClick = onDeclineClicked,
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(12.dp))
|
Spacer(modifier = Modifier.width(12.dp))
|
||||||
|
|
@ -144,7 +144,7 @@ internal fun DefaultInviteSummaryRow(
|
||||||
text = stringResource(CommonStrings.action_accept),
|
text = stringResource(CommonStrings.action_accept),
|
||||||
onClick = onAcceptClicked,
|
onClick = onAcceptClicked,
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@ import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.layout.wrapContentHeight
|
import androidx.compose.foundation.layout.wrapContentHeight
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.SnackbarHost
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -78,6 +77,7 @@ import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
|
import io.element.android.libraries.designsystem.utils.SnackbarHost
|
||||||
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.core.UserId
|
import io.element.android.libraries.matrix.api.core.UserId
|
||||||
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
import io.element.android.libraries.matrix.api.timeline.item.event.LocalEventSendState
|
||||||
|
|
|
||||||
|
|
@ -34,9 +34,6 @@ import androidx.compose.material.icons.filled.OpenInNew
|
||||||
import androidx.compose.material.icons.filled.Share
|
import androidx.compose.material.icons.filled.Share
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Snackbar
|
|
||||||
import androidx.compose.material3.SnackbarHost
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -64,6 +61,7 @@ import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.IconButton
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
import io.element.android.libraries.designsystem.theme.components.TopAppBar
|
||||||
|
import io.element.android.libraries.designsystem.utils.SnackbarHost
|
||||||
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.media.MediaSource
|
import io.element.android.libraries.matrix.api.media.MediaSource
|
||||||
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
import io.element.android.libraries.matrix.ui.media.MediaRequestData
|
||||||
|
|
@ -99,15 +97,7 @@ fun MediaViewerView(
|
||||||
eventSink = state.eventSink
|
eventSink = state.eventSink
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
snackbarHost = {
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
SnackbarHost(snackbarHostState) { data ->
|
|
||||||
Snackbar(
|
|
||||||
snackbarData = data,
|
|
||||||
containerColor = MaterialTheme.colorScheme.surfaceVariant,
|
|
||||||
contentColor = MaterialTheme.colorScheme.primary
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,6 @@ import androidx.compose.material.icons.outlined.DeveloperMode
|
||||||
import androidx.compose.material.icons.outlined.Help
|
import androidx.compose.material.icons.outlined.Help
|
||||||
import androidx.compose.material.icons.outlined.InsertChart
|
import androidx.compose.material.icons.outlined.InsertChart
|
||||||
import androidx.compose.material.icons.outlined.VerifiedUser
|
import androidx.compose.material.icons.outlined.VerifiedUser
|
||||||
import androidx.compose.material3.Snackbar
|
|
||||||
import androidx.compose.material3.SnackbarHost
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -41,6 +39,7 @@ import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.preview.LargeHeightPreview
|
import io.element.android.libraries.designsystem.preview.LargeHeightPreview
|
||||||
import io.element.android.libraries.designsystem.theme.components.Divider
|
import io.element.android.libraries.designsystem.theme.components.Divider
|
||||||
import io.element.android.libraries.designsystem.theme.components.Text
|
import io.element.android.libraries.designsystem.theme.components.Text
|
||||||
|
import io.element.android.libraries.designsystem.utils.SnackbarHost
|
||||||
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||||
import io.element.android.libraries.matrix.ui.components.MatrixUserProvider
|
import io.element.android.libraries.matrix.ui.components.MatrixUserProvider
|
||||||
|
|
@ -65,13 +64,7 @@ fun PreferencesRootView(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
onBackPressed = onBackPressed,
|
onBackPressed = onBackPressed,
|
||||||
title = stringResource(id = CommonStrings.common_settings),
|
title = stringResource(id = CommonStrings.common_settings),
|
||||||
snackbarHost = {
|
snackbarHost = { SnackbarHost(snackbarHostState) }
|
||||||
SnackbarHost(snackbarHostState) { data ->
|
|
||||||
Snackbar(
|
|
||||||
snackbarData = data,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
UserPreferences(state.myUser)
|
UserPreferences(state.myUser)
|
||||||
if (state.showCompleteVerification) {
|
if (state.showCompleteVerification) {
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,6 @@ import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Snackbar
|
|
||||||
import androidx.compose.material3.SnackbarHost
|
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberTopAppBarState
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -59,6 +57,7 @@ import io.element.android.libraries.designsystem.theme.components.FloatingAction
|
||||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
import io.element.android.libraries.designsystem.utils.LogCompositions
|
import io.element.android.libraries.designsystem.utils.LogCompositions
|
||||||
|
import io.element.android.libraries.designsystem.utils.SnackbarHost
|
||||||
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
import io.element.android.libraries.designsystem.utils.rememberSnackbarHostState
|
||||||
import io.element.android.libraries.matrix.api.core.RoomId
|
import io.element.android.libraries.matrix.api.core.RoomId
|
||||||
import io.element.android.libraries.designsystem.R as DrawableR
|
import io.element.android.libraries.designsystem.R as DrawableR
|
||||||
|
|
@ -227,13 +226,7 @@ fun RoomListContent(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
snackbarHost = {
|
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||||
SnackbarHost(snackbarHostState) { data ->
|
|
||||||
Snackbar(
|
|
||||||
snackbarData = data,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ internal fun RequestVerificationHeader(
|
||||||
Spacer(modifier = Modifier.height(12.dp))
|
Spacer(modifier = Modifier.height(12.dp))
|
||||||
Button(
|
Button(
|
||||||
text = stringResource(CommonStrings.action_continue),
|
text = stringResource(CommonStrings.action_continue),
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
modifier = Modifier.fillMaxWidth(),
|
modifier = Modifier.fillMaxWidth(),
|
||||||
onClick = onVerifyClicked,
|
onClick = onVerifyClicked,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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.material3.Icon
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.Button
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.IconButton
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.IconSource
|
||||||
|
import io.element.android.libraries.designsystem.theme.components.TextButton
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A sealed class that represents the different visual styles that a button can have.
|
||||||
|
*/
|
||||||
|
sealed interface ButtonVisuals {
|
||||||
|
|
||||||
|
val action: () -> Unit
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a [Button] composable based on the visual state.
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun Composable()
|
||||||
|
|
||||||
|
data class Text(val text: String, override val action: () -> Unit) : ButtonVisuals {
|
||||||
|
@Composable
|
||||||
|
override fun Composable() {
|
||||||
|
TextButton(text = text, onClick = action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data class Icon(val iconSource: IconSource, override val action: () -> Unit) : ButtonVisuals {
|
||||||
|
@Composable
|
||||||
|
override fun Composable() {
|
||||||
|
IconButton(onClick = action) {
|
||||||
|
Icon(iconSource.getPainter(), iconSource.contentDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ object PreviewGroup {
|
||||||
const val Preferences = "Preferences"
|
const val Preferences = "Preferences"
|
||||||
const val Progress = "Progress Indicators"
|
const val Progress = "Progress Indicators"
|
||||||
const val Search = "Search views"
|
const val Search = "Search views"
|
||||||
|
const val Snackbars = "Snackbars"
|
||||||
const val Sliders = "Sliders"
|
const val Sliders = "Sliders"
|
||||||
const val Text = "Text"
|
const val Text = "Text"
|
||||||
const val TextFields = "TextFields"
|
const val TextFields = "TextFields"
|
||||||
|
|
|
||||||
|
|
@ -78,7 +78,7 @@ private fun ContentToPreview() {
|
||||||
WithRulers(xRulersOffset = 20.dp, yRulersOffset = 15.dp) {
|
WithRulers(xRulersOffset = 20.dp, yRulersOffset = 15.dp) {
|
||||||
OutlinedButton(
|
OutlinedButton(
|
||||||
text = "A Button with rulers on it!",
|
text = "A Button with rulers on it!",
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
onClick = {},
|
onClick = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,19 +72,19 @@ internal fun SimpleAlertDialogContent(
|
||||||
// Having this 3rd action is discouraged, see https://m3.material.io/components/dialogs/guidelines#e13b68f5-e367-4275-ad6f-c552ee8e358f
|
// Having this 3rd action is discouraged, see https://m3.material.io/components/dialogs/guidelines#e13b68f5-e367-4275-ad6f-c552ee8e358f
|
||||||
TextButton(
|
TextButton(
|
||||||
text = thirdButtonText,
|
text = thirdButtonText,
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
onClick = onThirdButtonClicked,
|
onClick = onThirdButtonClicked,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TextButton(
|
TextButton(
|
||||||
text = cancelText,
|
text = cancelText,
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
onClick = onCancelClicked,
|
onClick = onCancelClicked,
|
||||||
)
|
)
|
||||||
if (submitText != null) {
|
if (submitText != null) {
|
||||||
Button(
|
Button(
|
||||||
text = submitText,
|
text = submitText,
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
onClick = onSubmitClicked,
|
onClick = onSubmitClicked,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ import androidx.compose.foundation.progressSemantics
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Share
|
import androidx.compose.material.icons.outlined.Share
|
||||||
|
import androidx.compose.material3.ButtonColors
|
||||||
import androidx.compose.material3.ButtonDefaults
|
import androidx.compose.material3.ButtonDefaults
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
|
@ -41,6 +42,7 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.RectangleShape
|
import androidx.compose.ui.graphics.RectangleShape
|
||||||
|
import androidx.compose.ui.graphics.isSpecified
|
||||||
import androidx.compose.ui.graphics.painter.Painter
|
import androidx.compose.ui.graphics.painter.Painter
|
||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
import androidx.compose.ui.graphics.vector.rememberVectorPainter
|
||||||
|
|
@ -60,10 +62,19 @@ fun Button(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
buttonSize: ButtonSize = ButtonSize.Large,
|
size: ButtonSize = ButtonSize.Large,
|
||||||
showProgress: Boolean = false,
|
showProgress: Boolean = false,
|
||||||
leadingIcon: IconSource? = null,
|
leadingIcon: IconSource? = null,
|
||||||
) = ButtonInternal(text, onClick, ButtonStyle.Filled, modifier, enabled, buttonSize, showProgress, leadingIcon)
|
) = ButtonInternal(
|
||||||
|
text = text,
|
||||||
|
onClick = onClick,
|
||||||
|
style = ButtonStyle.Filled,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
size = size,
|
||||||
|
showProgress = showProgress,
|
||||||
|
leadingIcon = leadingIcon
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun OutlinedButton(
|
fun OutlinedButton(
|
||||||
|
|
@ -71,10 +82,19 @@ fun OutlinedButton(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
buttonSize: ButtonSize = ButtonSize.Large,
|
size: ButtonSize = ButtonSize.Large,
|
||||||
showProgress: Boolean = false,
|
showProgress: Boolean = false,
|
||||||
leadingIcon: IconSource? = null,
|
leadingIcon: IconSource? = null,
|
||||||
) = ButtonInternal(text, onClick, ButtonStyle.Outlined, modifier, enabled, buttonSize, showProgress, leadingIcon)
|
) = ButtonInternal(
|
||||||
|
text = text,
|
||||||
|
onClick = onClick,
|
||||||
|
style = ButtonStyle.Outlined,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
size = size,
|
||||||
|
showProgress = showProgress,
|
||||||
|
leadingIcon = leadingIcon
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun TextButton(
|
fun TextButton(
|
||||||
|
|
@ -82,17 +102,27 @@ fun TextButton(
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
buttonSize: ButtonSize = ButtonSize.Large,
|
size: ButtonSize = ButtonSize.Large,
|
||||||
showProgress: Boolean = false,
|
showProgress: Boolean = false,
|
||||||
leadingIcon: IconSource? = null,
|
leadingIcon: IconSource? = null,
|
||||||
) = ButtonInternal(text, onClick, ButtonStyle.Text, modifier, enabled, buttonSize, showProgress, leadingIcon)
|
) = ButtonInternal(
|
||||||
|
text = text,
|
||||||
|
onClick = onClick,
|
||||||
|
style = ButtonStyle.Text,
|
||||||
|
modifier = modifier,
|
||||||
|
enabled = enabled,
|
||||||
|
size = size,
|
||||||
|
showProgress = showProgress,
|
||||||
|
leadingIcon = leadingIcon
|
||||||
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ButtonInternal(
|
internal fun ButtonInternal(
|
||||||
text: String,
|
text: String,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
style: ButtonStyle,
|
style: ButtonStyle,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
colors: ButtonColors = style.getColors(),
|
||||||
enabled: Boolean = true,
|
enabled: Boolean = true,
|
||||||
size: ButtonSize = ButtonSize.Large,
|
size: ButtonSize = ButtonSize.Large,
|
||||||
showProgress: Boolean = false,
|
showProgress: Boolean = false,
|
||||||
|
|
@ -123,21 +153,6 @@ private fun ButtonInternal(
|
||||||
ButtonStyle.Text -> RectangleShape
|
ButtonStyle.Text -> RectangleShape
|
||||||
}
|
}
|
||||||
|
|
||||||
val colors = when (style) {
|
|
||||||
ButtonStyle.Filled -> ButtonDefaults.buttonColors(
|
|
||||||
containerColor = ElementTheme.materialColors.primary,
|
|
||||||
contentColor = ElementTheme.materialColors.onPrimary,
|
|
||||||
disabledContainerColor = ElementTheme.colors.bgActionPrimaryDisabled,
|
|
||||||
disabledContentColor = ElementTheme.colors.textOnSolidPrimary
|
|
||||||
)
|
|
||||||
ButtonStyle.Outlined, ButtonStyle.Text -> ButtonDefaults.buttonColors(
|
|
||||||
containerColor = Color.Transparent,
|
|
||||||
contentColor = ElementTheme.materialColors.primary,
|
|
||||||
disabledContainerColor = Color.Transparent,
|
|
||||||
disabledContentColor = ElementTheme.colors.textDisabled,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val border = when (style) {
|
val border = when (style) {
|
||||||
ButtonStyle.Filled, ButtonStyle.Text -> null
|
ButtonStyle.Filled, ButtonStyle.Text -> null
|
||||||
ButtonStyle.Outlined -> BorderStroke(
|
ButtonStyle.Outlined -> BorderStroke(
|
||||||
|
|
@ -202,8 +217,10 @@ private fun ButtonInternal(
|
||||||
}
|
}
|
||||||
|
|
||||||
sealed interface IconSource {
|
sealed interface IconSource {
|
||||||
data class Resource(val id: Int) : IconSource
|
val contentDescription: String?
|
||||||
data class Vector(val vector: ImageVector) : IconSource
|
|
||||||
|
data class Resource(val id: Int, override val contentDescription: String? = null) : IconSource
|
||||||
|
data class Vector(val vector: ImageVector, override val contentDescription: String? = null) : IconSource
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun getPainter(): Painter = when (this) {
|
fun getPainter(): Painter = when (this) {
|
||||||
|
|
@ -216,16 +233,38 @@ enum class ButtonSize {
|
||||||
Medium, Large
|
Medium, Large
|
||||||
}
|
}
|
||||||
|
|
||||||
private enum class ButtonStyle {
|
internal enum class ButtonStyle {
|
||||||
Filled, Outlined, Text
|
Filled, Outlined, Text;
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun getColors(): ButtonColors = when (this) {
|
||||||
|
Filled -> ButtonDefaults.buttonColors(
|
||||||
|
containerColor = ElementTheme.materialColors.primary,
|
||||||
|
contentColor = ElementTheme.materialColors.onPrimary,
|
||||||
|
disabledContainerColor = ElementTheme.colors.bgActionPrimaryDisabled,
|
||||||
|
disabledContentColor = ElementTheme.colors.textOnSolidPrimary
|
||||||
|
)
|
||||||
|
Outlined -> ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color.Transparent,
|
||||||
|
contentColor = ElementTheme.materialColors.primary,
|
||||||
|
disabledContainerColor = Color.Transparent,
|
||||||
|
disabledContentColor = ElementTheme.colors.textDisabled,
|
||||||
|
)
|
||||||
|
Text -> ButtonDefaults.buttonColors(
|
||||||
|
containerColor = Color.Transparent,
|
||||||
|
contentColor = if (LocalContentColor.current.isSpecified) LocalContentColor.current else ElementTheme.materialColors.primary,
|
||||||
|
disabledContainerColor = Color.Transparent,
|
||||||
|
disabledContentColor = ElementTheme.colors.textDisabled,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Preview(group = PreviewGroup.Buttons)
|
@Preview(group = PreviewGroup.Buttons)
|
||||||
@Composable
|
@Composable
|
||||||
internal fun FilledButtonMediumPreview() {
|
internal fun FilledButtonMediumPreview() {
|
||||||
ButtonCombinationPreview(
|
ButtonCombinationPreview(
|
||||||
buttonStyle = ButtonStyle.Filled,
|
style = ButtonStyle.Filled,
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -233,8 +272,8 @@ internal fun FilledButtonMediumPreview() {
|
||||||
@Composable
|
@Composable
|
||||||
internal fun FilledButtonLargePreview() {
|
internal fun FilledButtonLargePreview() {
|
||||||
ButtonCombinationPreview(
|
ButtonCombinationPreview(
|
||||||
buttonStyle = ButtonStyle.Filled,
|
style = ButtonStyle.Filled,
|
||||||
buttonSize = ButtonSize.Large,
|
size = ButtonSize.Large,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -242,8 +281,8 @@ internal fun FilledButtonLargePreview() {
|
||||||
@Composable
|
@Composable
|
||||||
internal fun OutlinedButtonMediumPreview() {
|
internal fun OutlinedButtonMediumPreview() {
|
||||||
ButtonCombinationPreview(
|
ButtonCombinationPreview(
|
||||||
buttonStyle = ButtonStyle.Outlined,
|
style = ButtonStyle.Outlined,
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,8 +290,8 @@ internal fun OutlinedButtonMediumPreview() {
|
||||||
@Composable
|
@Composable
|
||||||
internal fun OutlinedButtonLargePreview() {
|
internal fun OutlinedButtonLargePreview() {
|
||||||
ButtonCombinationPreview(
|
ButtonCombinationPreview(
|
||||||
buttonStyle = ButtonStyle.Outlined,
|
style = ButtonStyle.Outlined,
|
||||||
buttonSize = ButtonSize.Large,
|
size = ButtonSize.Large,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -260,8 +299,8 @@ internal fun OutlinedButtonLargePreview() {
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TextButtonMediumPreview() {
|
internal fun TextButtonMediumPreview() {
|
||||||
ButtonCombinationPreview(
|
ButtonCombinationPreview(
|
||||||
buttonStyle = ButtonStyle.Text,
|
style = ButtonStyle.Text,
|
||||||
buttonSize = ButtonSize.Medium,
|
size = ButtonSize.Medium,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -269,15 +308,15 @@ internal fun TextButtonMediumPreview() {
|
||||||
@Composable
|
@Composable
|
||||||
internal fun TextButtonLargePreview() {
|
internal fun TextButtonLargePreview() {
|
||||||
ButtonCombinationPreview(
|
ButtonCombinationPreview(
|
||||||
buttonStyle = ButtonStyle.Text,
|
style = ButtonStyle.Text,
|
||||||
buttonSize = ButtonSize.Large,
|
size = ButtonSize.Large,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ButtonCombinationPreview(
|
private fun ButtonCombinationPreview(
|
||||||
buttonStyle: ButtonStyle,
|
style: ButtonStyle,
|
||||||
buttonSize: ButtonSize,
|
size: ButtonSize,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
ElementThemedPreview {
|
ElementThemedPreview {
|
||||||
|
|
@ -290,24 +329,24 @@ private fun ButtonCombinationPreview(
|
||||||
// Normal
|
// Normal
|
||||||
ButtonRowPreview(
|
ButtonRowPreview(
|
||||||
modifier = Modifier.then(modifier),
|
modifier = Modifier.then(modifier),
|
||||||
buttonStyle = buttonStyle,
|
style = style,
|
||||||
buttonSize = buttonSize,
|
size = size,
|
||||||
)
|
)
|
||||||
|
|
||||||
// With icon
|
// With icon
|
||||||
ButtonRowPreview(
|
ButtonRowPreview(
|
||||||
modifier = Modifier.then(modifier),
|
modifier = Modifier.then(modifier),
|
||||||
leadingIcon = IconSource.Vector(Icons.Outlined.Share),
|
leadingIcon = IconSource.Vector(Icons.Outlined.Share),
|
||||||
buttonStyle = buttonStyle,
|
style = style,
|
||||||
buttonSize = buttonSize,
|
size = size,
|
||||||
)
|
)
|
||||||
|
|
||||||
// With progress
|
// With progress
|
||||||
ButtonRowPreview(
|
ButtonRowPreview(
|
||||||
modifier = Modifier.then(modifier),
|
modifier = Modifier.then(modifier),
|
||||||
showProgress = true,
|
showProgress = true,
|
||||||
buttonStyle = buttonStyle,
|
style = style,
|
||||||
buttonSize = buttonSize,
|
size = size,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -315,8 +354,8 @@ private fun ButtonCombinationPreview(
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun ButtonRowPreview(
|
private fun ButtonRowPreview(
|
||||||
buttonStyle: ButtonStyle,
|
style: ButtonStyle,
|
||||||
buttonSize: ButtonSize,
|
size: ButtonSize,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
leadingIcon: IconSource? = null,
|
leadingIcon: IconSource? = null,
|
||||||
showProgress: Boolean = false,
|
showProgress: Boolean = false,
|
||||||
|
|
@ -326,8 +365,8 @@ private fun ButtonRowPreview(
|
||||||
text = "A button",
|
text = "A button",
|
||||||
showProgress = showProgress,
|
showProgress = showProgress,
|
||||||
onClick = {},
|
onClick = {},
|
||||||
style = buttonStyle,
|
style = style,
|
||||||
size = buttonSize,
|
size = size,
|
||||||
leadingIcon = leadingIcon,
|
leadingIcon = leadingIcon,
|
||||||
modifier = Modifier.then(modifier),
|
modifier = Modifier.then(modifier),
|
||||||
)
|
)
|
||||||
|
|
@ -336,8 +375,8 @@ private fun ButtonRowPreview(
|
||||||
showProgress = showProgress,
|
showProgress = showProgress,
|
||||||
enabled = false,
|
enabled = false,
|
||||||
onClick = {},
|
onClick = {},
|
||||||
style = buttonStyle,
|
style = style,
|
||||||
size = buttonSize,
|
size = size,
|
||||||
leadingIcon = leadingIcon,
|
leadingIcon = leadingIcon,
|
||||||
modifier = Modifier.then(modifier),
|
modifier = Modifier.then(modifier),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,15 +18,21 @@ package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Share
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.TopAppBarColors
|
import androidx.compose.material3.TopAppBarColors
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
|
import io.element.android.libraries.theme.ElementTheme
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -43,7 +49,11 @@ fun MediumTopAppBar(
|
||||||
title = title,
|
title = title,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
navigationIcon = navigationIcon,
|
navigationIcon = navigationIcon,
|
||||||
actions = actions,
|
actions = {
|
||||||
|
CompositionLocalProvider(LocalContentColor provides ElementTheme.colors.textActionPrimary) {
|
||||||
|
actions()
|
||||||
|
}
|
||||||
|
},
|
||||||
windowInsets = windowInsets,
|
windowInsets = windowInsets,
|
||||||
colors = colors,
|
colors = colors,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
|
|
@ -58,5 +68,14 @@ internal fun MediumTopAppBarPreview() =
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun ContentToPreview() {
|
private fun ContentToPreview() {
|
||||||
MediumTopAppBar(title = { Text(text = "Title") })
|
MediumTopAppBar(
|
||||||
|
title = { Text(text = "Title") },
|
||||||
|
navigationIcon = { BackButton(onClick = {}) },
|
||||||
|
actions = {
|
||||||
|
TextButton(text = "Action", onClick = {})
|
||||||
|
IconButton(onClick = {}) {
|
||||||
|
Icon(imageVector = Icons.Default.Share, contentDescription = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* 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.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
|
import androidx.compose.material3.SnackbarDefaults
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
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 io.element.android.libraries.designsystem.components.button.ButtonVisuals
|
||||||
|
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
|
import io.element.android.libraries.theme.ElementTheme
|
||||||
|
import io.element.android.libraries.theme.SnackBarLabelColorDark
|
||||||
|
import io.element.android.libraries.theme.SnackBarLabelColorLight
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Snackbar(
|
||||||
|
message: String,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
action: ButtonVisuals? = null,
|
||||||
|
dismissAction: ButtonVisuals? = null,
|
||||||
|
actionOnNewLine: Boolean = false,
|
||||||
|
shape: Shape = RoundedCornerShape(8.dp),
|
||||||
|
containerColor: Color = SnackbarDefaults.color,
|
||||||
|
contentColor: Color = ElementTheme.materialColors.inverseOnSurface,
|
||||||
|
actionContentColor: Color = actionContentColor(),
|
||||||
|
dismissActionContentColor: Color = SnackbarDefaults.dismissActionContentColor,
|
||||||
|
) {
|
||||||
|
Snackbar(
|
||||||
|
modifier = modifier,
|
||||||
|
action = action?.let { @Composable { it.Composable() } },
|
||||||
|
dismissAction = dismissAction?.let { @Composable { it.Composable() } },
|
||||||
|
actionOnNewLine = actionOnNewLine,
|
||||||
|
shape = shape,
|
||||||
|
containerColor = containerColor,
|
||||||
|
contentColor = contentColor,
|
||||||
|
actionContentColor = actionContentColor,
|
||||||
|
dismissActionContentColor = dismissActionContentColor,
|
||||||
|
content = { Text(text = message) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Snackbar(
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
action: @Composable (() -> Unit)? = null,
|
||||||
|
dismissAction: @Composable (() -> Unit)? = null,
|
||||||
|
actionOnNewLine: Boolean = false,
|
||||||
|
shape: Shape = RoundedCornerShape(8.dp),
|
||||||
|
containerColor: Color = SnackbarDefaults.color,
|
||||||
|
contentColor: Color = ElementTheme.materialColors.inverseOnSurface,
|
||||||
|
actionContentColor: Color = actionContentColor(),
|
||||||
|
dismissActionContentColor: Color = SnackbarDefaults.dismissActionContentColor,
|
||||||
|
content: @Composable () -> Unit
|
||||||
|
) {
|
||||||
|
androidx.compose.material3.Snackbar(
|
||||||
|
modifier = modifier,
|
||||||
|
action = action,
|
||||||
|
dismissAction = dismissAction,
|
||||||
|
actionOnNewLine = actionOnNewLine,
|
||||||
|
shape = shape,
|
||||||
|
containerColor = containerColor,
|
||||||
|
contentColor = contentColor,
|
||||||
|
actionContentColor = actionContentColor,
|
||||||
|
dismissActionContentColor = dismissActionContentColor,
|
||||||
|
content = content,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO this color is temporary, an `inverse` version should be added to the semantic colors instead
|
||||||
|
@Composable
|
||||||
|
private fun actionContentColor(): Color {
|
||||||
|
return if (ElementTheme.isLightTheme) {
|
||||||
|
SnackBarLabelColorLight
|
||||||
|
} else {
|
||||||
|
SnackBarLabelColorDark
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(name = "Snackbar", group = PreviewGroup.Snackbars)
|
||||||
|
@Composable
|
||||||
|
internal fun SnackbarPreview() {
|
||||||
|
ElementThemedPreview {
|
||||||
|
Snackbar(message = "Snackbar supporting text")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(name = "Snackbar with action", group = PreviewGroup.Snackbars)
|
||||||
|
@Composable
|
||||||
|
internal fun SnackbarWithActionPreview() {
|
||||||
|
ElementThemedPreview {
|
||||||
|
Snackbar(message = "Snackbar supporting text", action = ButtonVisuals.Text("Action", {}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(name = "Snackbar with action and close button", group = PreviewGroup.Snackbars)
|
||||||
|
@Composable
|
||||||
|
internal fun SnackbarWithActionAndCloseButtonPreview() {
|
||||||
|
ElementThemedPreview {
|
||||||
|
Snackbar(
|
||||||
|
message = "Snackbar supporting text",
|
||||||
|
action = ButtonVisuals.Text("Action", {}),
|
||||||
|
dismissAction = ButtonVisuals.Icon(IconSource.Vector(Icons.Default.Close), {})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(name = "Snackbar with action on new line", group = PreviewGroup.Snackbars)
|
||||||
|
@Composable
|
||||||
|
internal fun SnackbarWithActionOnNewLinePreview() {
|
||||||
|
ElementThemedPreview {
|
||||||
|
Snackbar(message = "Snackbar supporting text", action = ButtonVisuals.Text("Action", {}), actionOnNewLine = true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Preview(name = "Snackbar with action and close button on new line", group = PreviewGroup.Snackbars)
|
||||||
|
@Composable
|
||||||
|
internal fun SnackbarWithActionOnNewLineAndCloseButtonPreview() {
|
||||||
|
ElementThemedPreview {
|
||||||
|
Snackbar(
|
||||||
|
message = "Snackbar supporting text",
|
||||||
|
action = ButtonVisuals.Text("Action", {}),
|
||||||
|
dismissAction = ButtonVisuals.Icon(IconSource.Vector(Icons.Default.Close), {}),
|
||||||
|
actionOnNewLine = true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -18,15 +18,21 @@ package io.element.android.libraries.designsystem.theme.components
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.RowScope
|
import androidx.compose.foundation.layout.RowScope
|
||||||
import androidx.compose.foundation.layout.WindowInsets
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Share
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.TopAppBarColors
|
import androidx.compose.material3.TopAppBarColors
|
||||||
import androidx.compose.material3.TopAppBarDefaults
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
|
import io.element.android.libraries.designsystem.components.button.BackButton
|
||||||
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
import io.element.android.libraries.designsystem.preview.ElementThemedPreview
|
||||||
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
import io.element.android.libraries.designsystem.preview.PreviewGroup
|
||||||
|
import io.element.android.libraries.theme.ElementTheme
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -43,7 +49,11 @@ fun TopAppBar(
|
||||||
title = title,
|
title = title,
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
navigationIcon = navigationIcon,
|
navigationIcon = navigationIcon,
|
||||||
actions = actions,
|
actions = {
|
||||||
|
CompositionLocalProvider(LocalContentColor provides ElementTheme.colors.textActionPrimary) {
|
||||||
|
actions()
|
||||||
|
}
|
||||||
|
},
|
||||||
windowInsets = windowInsets,
|
windowInsets = windowInsets,
|
||||||
colors = colors,
|
colors = colors,
|
||||||
scrollBehavior = scrollBehavior,
|
scrollBehavior = scrollBehavior,
|
||||||
|
|
@ -58,5 +68,14 @@ internal fun TopAppBarPreview() =
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
private fun ContentToPreview() {
|
private fun ContentToPreview() {
|
||||||
TopAppBar(title = { Text(text = "Title") })
|
TopAppBar(
|
||||||
|
title = { Text(text = "Title") },
|
||||||
|
navigationIcon = { BackButton(onClick = {}) },
|
||||||
|
actions = {
|
||||||
|
TextButton(text = "Action", onClick = {})
|
||||||
|
IconButton(onClick = {}) {
|
||||||
|
Icon(imageVector = Icons.Default.Share, contentDescription = null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
package io.element.android.libraries.designsystem.utils
|
package io.element.android.libraries.designsystem.utils
|
||||||
|
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material3.SnackbarDuration
|
import androidx.compose.material3.SnackbarDuration
|
||||||
import androidx.compose.material3.SnackbarHostState
|
import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -25,7 +27,11 @@ import androidx.compose.runtime.State
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.runtime.compositionLocalOf
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
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.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
|
@ -65,6 +71,19 @@ fun SnackbarDispatcher.collectSnackbarMessageAsState(): State<SnackbarMessage?>
|
||||||
return snackbarMessage.collectAsState(initial = null)
|
return snackbarMessage.collectAsState(initial = null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun SnackbarHost(hostState: SnackbarHostState, modifier: Modifier = Modifier) {
|
||||||
|
androidx.compose.material3.SnackbarHost(hostState, modifier) { data ->
|
||||||
|
Snackbar(
|
||||||
|
message = data.visuals.message,
|
||||||
|
action = data.visuals.actionLabel?.let { ButtonVisuals.Text(it, data::performAction) },
|
||||||
|
dismissAction = if (data.visuals.withDismissAction) {
|
||||||
|
ButtonVisuals.Icon(IconSource.Vector(Icons.Default.Close), data::dismiss)
|
||||||
|
} else null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun rememberSnackbarHostState(snackbarMessage: SnackbarMessage?): SnackbarHostState {
|
fun rememberSnackbarHostState(snackbarMessage: SnackbarMessage?): SnackbarHostState {
|
||||||
val snackbarHostState = remember { SnackbarHostState() }
|
val snackbarHostState = remember { SnackbarHostState() }
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,8 @@
|
||||||
package io.element.android.libraries.theme
|
package io.element.android.libraries.theme
|
||||||
|
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import io.element.android.libraries.theme.compound.generated.internal.DarkDesignTokens
|
||||||
|
import io.element.android.libraries.theme.compound.generated.internal.LightDesignTokens
|
||||||
|
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
// IMPORTANT!
|
// IMPORTANT!
|
||||||
|
|
@ -26,3 +28,6 @@ import androidx.compose.ui.graphics.Color
|
||||||
// =================================================================================================
|
// =================================================================================================
|
||||||
|
|
||||||
val LinkColor = Color(0xFF0086E6)
|
val LinkColor = Color(0xFF0086E6)
|
||||||
|
|
||||||
|
val SnackBarLabelColorLight = LightDesignTokens.colorGray700
|
||||||
|
val SnackBarLabelColorDark = DarkDesignTokens.colorGray700
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:364f107ffaa4844d0141361642ce3a494a187588f27be50b5fd27d44be21fa64
|
oid sha256:016ca2c634b467ba6d98ed221506d5bbb250b58a5ea631a0076a572f745cfa84
|
||||||
size 8887
|
size 8710
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8d0a5de3c4e09d76b6453ccc6ace5c690d540d945a62e630474932734209058a
|
oid sha256:c129a4d13320fb3fec6039e37c802de33d7dd607faa3890f9f1b34f663eecc46
|
||||||
size 11716
|
size 11552
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:9218d1d514342c400051bebb10ef458c99103fda618bba45e61a524c5a58eb63
|
oid sha256:abe3498282504f7b0bfa3a2713ea556b7d4d361d5173ea56bcdadb37766d0b93
|
||||||
size 11903
|
size 11742
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:f19878925f3b5b377a91885540fb15d29a5b78d8be2282d64e8809af0bbf5ff4
|
oid sha256:d52d7c6d6271577c80ad1ca170aeb9686d8bb572459212d6ef1fe97c490b382d
|
||||||
size 12195
|
size 12035
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:6d98aabf3bd99793367632e18d5cf678e75fb5ad872a1cb300a7e939ad0c2683
|
oid sha256:3e6442ca746462345d0573abfb72028a613b08d53f6a5e3f0ef3c5f09beab423
|
||||||
size 19725
|
size 19491
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:c936d2d804bc9e98fcc49430f11ddaa572b05fc8d3a0df93ad6521ee8e78f708
|
oid sha256:906b39149036cccadd5232c0373a6a94e039b374988ace3d732a5b63b7d81829
|
||||||
size 21806
|
size 21590
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:ac01bc1992e3fa27950c7071cd3e8a06b94a608238d55972816fa2a1a3175e7c
|
oid sha256:545fcfe023789a167a5ee2fe11e7f65426890d794fa08ed32ea4e9fe0fe5f59a
|
||||||
size 9448
|
size 9387
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e39c5ba30983b034886a6adc330d1510b3a48c40511697edcaf6530716c7ba2e
|
oid sha256:b7ebe27e257108881e4869213ea754926fceb8a047ccb81120fc1a1df19279f4
|
||||||
size 12500
|
size 12444
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:e4ff75e74c19280308878e3001a8791aaa735439cc667946fefd21070611630e
|
oid sha256:ecb0ec0f6b9bffc5cd0ab19f85beb962610d5624652b8e6f21d8aedda69a0fb4
|
||||||
size 12698
|
size 12645
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:065d2a09680e35540b870862ec0ba5c54182e016017938ef64e510b6132333c9
|
oid sha256:989b630c0925f0a822b2b7460648e874357e1ecf0ab75caea56c78189d936349
|
||||||
size 13389
|
size 13329
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:94be795b626868e8afbcc26c3f0161ddcb946a122c02eeed7e823825c9aeba19
|
oid sha256:caa94ed925e37306cc9453a5ade0266a897dc010cdde86b92a9e1d4710039edc
|
||||||
size 22263
|
size 22184
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0bb88c64bc68b10b1fb709135f445de5a5e4d78623448d0fef97504e025d5f6d
|
oid sha256:6d9458392de2e0f291f752a8cd9558c9eb891d4140e07c5c61a42a16a3c77838
|
||||||
size 24551
|
size 24507
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:d40dd7970069fb798b738a1775b5843522cc28a581d904f44974d7ceefdbf3c9
|
oid sha256:cafa0bf978a59ff5903429bcb605afd2cb347bb64c3d58e749b0dd7ddfca6199
|
||||||
size 148087
|
size 148827
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:47f20f3dc4e4bdbb6641f26b6e03d0dba0f2c7e0fe22fce927870d14f1472066
|
oid sha256:a19c6af3352ad430c6502ccc9dac1ae8b4b8d690c810ab424c61208fa31e52b0
|
||||||
size 148796
|
size 149411
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:1016b14f6d975828470aa8d6786177d6dde909cc727f39b2c66742a101735e8f
|
oid sha256:852b7b5515cad1bb129273ba95fc528f9cc67bf4dde0995276a96521c4399cbe
|
||||||
size 66240
|
size 66851
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:d40dd7970069fb798b738a1775b5843522cc28a581d904f44974d7ceefdbf3c9
|
oid sha256:cafa0bf978a59ff5903429bcb605afd2cb347bb64c3d58e749b0dd7ddfca6199
|
||||||
size 148087
|
size 148827
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:77983bf8dfa0683d472683cdb7ad545beb6b05fdfb8b82ecf90db49d387db72e
|
oid sha256:e4e9e0b3c5be9a07af8cd9a4f4ae725505148805327455350d9504a5974032c2
|
||||||
size 395299
|
size 395377
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:9a28b7439185193fca0f389d36f287fa38d29d18bfc046a125f936026ffd1918
|
oid sha256:9225a19843eb5c9e1a78a7bd307958c2cad544c58ca2637224455326dfcfffb6
|
||||||
size 6318
|
size 6315
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:459ff294007ea6238f87954e04e8e13614b7c5fa7ade01f44670014013ebfead
|
oid sha256:628072ca45ae0d215ba9bbe965b68442153d81ad98f330ab1178a0f8fcff3e24
|
||||||
size 15382
|
size 15339
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:b2824676afbff473eff8c8cfbcf8b3e58b2851e37324c6a8d9ba47d626b0f8bc
|
oid sha256:93ca4c1155010d01315b00bb79d9807cf0e6f80a609be668cb5600c16e82ef4d
|
||||||
size 14234
|
size 14190
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8850f5c0e52e9441f92010bebe8828cdf5e3715250aadb68f31d996ec1fb7520
|
oid sha256:b7a8ca9eb62e3988fd6adc3d3992bb6a8577b91b44d05a6c45a4af48b3bdbb4f
|
||||||
size 38042
|
size 38282
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:8338dfb26935d63918749a3dd0c3d06d752172aba69bc67969b4928667fa8da1
|
oid sha256:29c635e2bfb59cea20c8ee2c4c008a2edc74127313c437d63f7e4ef4f0851921
|
||||||
size 39183
|
size 39425
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:c90d81b34d6876b7d4406adce0a775dc67b48da91eac6b4a814eaae9a7b028c2
|
oid sha256:8242b5826755b17c8a1bd919bc87358b701fc8431ba107c7624c69d2d6a61085
|
||||||
size 54262
|
size 54268
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:0e1999174751655dd87b042f1ea22f281cbf9b5deecc494f05307f125d6e9dac
|
oid sha256:05588cb33208fb210e7953509edc739cf9401f713132a7b44a9883615a4423c0
|
||||||
size 56358
|
size 56365
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:c7f0987b11f1ecc5e8359b668ac8cf29f0d5b6ef6f5c74d3660e68696be699ae
|
oid sha256:c591956dbbc4265381b6bff537efe21bdb70f3ab14862b63976ff2038b193dc6
|
||||||
size 7219
|
size 12176
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
version https://git-lfs.github.com/spec/v1
|
version https://git-lfs.github.com/spec/v1
|
||||||
oid sha256:5f470f47f972d0c948a308622e49855bb88365675d8b251cd1cce9972f5569c9
|
oid sha256:b47ed55d8919fd15da1e3877df6fa32a58bd51ebd676a7ff303e09ddb1d2d7fd
|
||||||
size 6878
|
size 11604
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:313860648fc6bf47ec98182ff018c54df61703fd8c1e302811a1e3a79a35b72a
|
||||||
|
size 15933
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:92ffb912aeeea5d161bd8c94ce7ac865eee13de50a7bc15217bfd0955e5a9b32
|
||||||
|
size 18516
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:55e08f85f71dc07addee6079425158831ed50209f4a43fad9a8d0252d55d0f4a
|
||||||
|
size 19486
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:de21230c271bc78f767f130e07403d778ac65d347cbb4ba564d883c679a283ad
|
||||||
|
size 20084
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
version https://git-lfs.github.com/spec/v1
|
||||||
|
oid sha256:62b5669a3f1a1138f5b982d27a1d4b2f0a2f79e862a4e50eb238c1d09de3d390
|
||||||
|
size 18833
|
||||||
Loading…
Add table
Add a link
Reference in a new issue