Floating toolbar (#6147)
* Use floating toolbar on homepage * Fix deprecation issue * Create HorizontalFloatingToolbar wrapper in our components. * Fix Konsist test. * Fix compilation issue after rebase. * Fix lint issue. `floatingActionButton` must be the last parameter. * Add Preview for the case empty space. * Fix navigation bar overlapping buttons in empty space view. * Increase content padding, and apply it to the space tab too. * Update screenshots --------- Co-authored-by: chelsea <git@cdhildit.ch> Co-authored-by: ElementBot <android@element.io>
This commit is contained in:
commit
e56c7e1227
50 changed files with 395 additions and 165 deletions
|
|
@ -33,7 +33,6 @@ data class HomeState(
|
|||
val eventSink: (HomeEvent) -> Unit,
|
||||
) {
|
||||
val isBackHandlerEnabled = currentHomeNavigationBarItem != HomeNavigationBarItem.Chats || roomListState.spaceFiltersState is SpaceFiltersState.Selected
|
||||
val displayActions = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats
|
||||
val displayRoomListFilters = currentHomeNavigationBarItem == HomeNavigationBarItem.Chats && roomListState.displayFilters
|
||||
val showNavigationBar = homeSpacesState.canCreateSpaces || homeSpacesState.spaceRooms.isNotEmpty()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,12 @@ open class HomeStateProvider : PreviewParameterProvider<HomeState> {
|
|||
),
|
||||
) + RoomListStateProvider().values.map {
|
||||
aHomeState(roomListState = it)
|
||||
}
|
||||
} + aHomeState(
|
||||
currentHomeNavigationBarItem = HomeNavigationBarItem.Spaces,
|
||||
homeSpacesState = aHomeSpacesState(
|
||||
spaceRooms = emptyList(),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
internal fun aHomeState(
|
||||
|
|
|
|||
|
|
@ -21,19 +21,22 @@ import androidx.compose.foundation.layout.fillMaxSize
|
|||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.FabPosition
|
||||
import androidx.compose.material3.FloatingToolbarDefaults.ScreenOffset
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.rememberTopAppBarState
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
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 androidx.compose.ui.zIndex
|
||||
import dev.chrisbanes.haze.hazeEffect
|
||||
import dev.chrisbanes.haze.hazeSource
|
||||
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
|
||||
|
|
@ -58,15 +61,15 @@ import io.element.android.libraries.androidutils.throttler.FirstThrottler
|
|||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
import io.element.android.libraries.designsystem.theme.components.FloatingActionButton
|
||||
import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbar
|
||||
import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbarItem
|
||||
import io.element.android.libraries.designsystem.theme.components.HorizontalFloatingToolbarSeparator
|
||||
import io.element.android.libraries.designsystem.theme.components.Icon
|
||||
import io.element.android.libraries.designsystem.theme.components.NavigationBar
|
||||
import io.element.android.libraries.designsystem.theme.components.NavigationBarIcon
|
||||
import io.element.android.libraries.designsystem.theme.components.NavigationBarItem
|
||||
import io.element.android.libraries.designsystem.theme.components.NavigationBarText
|
||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.SnackbarHost
|
||||
import io.element.android.libraries.designsystem.utils.snackbar.rememberSnackbarHostState
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.ui.strings.CommonStrings
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
@Composable
|
||||
|
|
@ -185,12 +188,10 @@ private fun HomeScaffold(
|
|||
onAccountSwitch = {
|
||||
state.eventSink(HomeEvent.SwitchToAccount(it))
|
||||
},
|
||||
onCreateSpace = onCreateSpaceClick,
|
||||
scrollBehavior = scrollBehavior,
|
||||
displayFilters = state.displayRoomListFilters,
|
||||
filtersState = roomListState.filtersState,
|
||||
spaceFiltersState = roomListState.spaceFiltersState,
|
||||
canCreateSpaces = state.homeSpacesState.canCreateSpaces,
|
||||
canReportBug = state.canReportBug,
|
||||
modifier = Modifier.hazeEffect(
|
||||
state = hazeState,
|
||||
|
|
@ -198,7 +199,7 @@ private fun HomeScaffold(
|
|||
)
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
floatingActionButton = {
|
||||
if (state.showNavigationBar) {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
HomeBottomBar(
|
||||
|
|
@ -222,14 +223,29 @@ private fun HomeScaffold(
|
|||
state.eventSink(HomeEvent.SelectHomeNavigationBarItem(item))
|
||||
}
|
||||
},
|
||||
modifier = Modifier.hazeEffect(
|
||||
state = hazeState,
|
||||
style = HazeMaterials.thick(),
|
||||
)
|
||||
floatingActionButton = when (state.currentHomeNavigationBarItem) {
|
||||
HomeNavigationBarItem.Chats -> {
|
||||
{
|
||||
HomeFloatingActionButton(onStartChatClick, CommonStrings.action_create_room)
|
||||
}
|
||||
}
|
||||
HomeNavigationBarItem.Spaces -> if (state.homeSpacesState.canCreateSpaces) {
|
||||
{
|
||||
HomeFloatingActionButton(onCreateSpaceClick, CommonStrings.action_create_space)
|
||||
}
|
||||
} else {
|
||||
// No FAB for spaces if we cannot create spaces
|
||||
null
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
floatingActionButtonPosition = FabPosition.Center,
|
||||
content = { padding ->
|
||||
val contentPadding = PaddingValues(
|
||||
bottom = 112.dp,
|
||||
)
|
||||
when (state.currentHomeNavigationBarItem) {
|
||||
HomeNavigationBarItem.Chats -> {
|
||||
RoomListContentView(
|
||||
|
|
@ -243,15 +259,7 @@ private fun HomeScaffold(
|
|||
onConfirmRecoveryKeyClick = onConfirmRecoveryKeyClick,
|
||||
onRoomClick = ::onRoomClick,
|
||||
onCreateRoomClick = onStartChatClick,
|
||||
contentPadding = PaddingValues(
|
||||
// FAB height is 56dp, bottom padding is 16dp, we add 8dp as extra margin -> 56+16+8 = 80,
|
||||
// and include provided bottom padding
|
||||
// Disable contentPadding due to navigation issue using the keyboard
|
||||
// See https://issuetracker.google.com/issues/436432313
|
||||
bottom = 80.dp,
|
||||
// bottom = 80.dp + padding.calculateBottomPadding(),
|
||||
// top = padding.calculateTopPadding()
|
||||
),
|
||||
contentPadding = contentPadding,
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
PaddingValues(
|
||||
|
|
@ -274,6 +282,7 @@ private fun HomeScaffold(
|
|||
.padding(padding)
|
||||
.consumeWindowInsets(padding)
|
||||
.hazeSource(state = hazeState),
|
||||
contentPadding = contentPadding,
|
||||
state = state.homeSpacesState,
|
||||
lazyListState = spacesLazyListState,
|
||||
onSpaceClick = { spaceId ->
|
||||
|
|
@ -286,49 +295,48 @@ private fun HomeScaffold(
|
|||
}
|
||||
}
|
||||
},
|
||||
floatingActionButton = {
|
||||
if (state.displayActions) {
|
||||
FloatingActionButton(
|
||||
onClick = onStartChatClick,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.Plus(),
|
||||
contentDescription = stringResource(id = R.string.screen_roomlist_a11y_create_message),
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
snackbarHost = { SnackbarHost(snackbarHostState) },
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun HomeFloatingActionButton(
|
||||
onClick: () -> Unit,
|
||||
contentDescription: Int,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
FloatingActionButton(onClick = onClick, modifier = modifier) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.Plus(),
|
||||
contentDescription = stringResource(id = contentDescription),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
|
||||
@Composable
|
||||
private fun HomeBottomBar(
|
||||
currentHomeNavigationBarItem: HomeNavigationBarItem,
|
||||
onItemClick: (HomeNavigationBarItem) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
floatingActionButton: (@Composable () -> Unit)?,
|
||||
) {
|
||||
NavigationBar(
|
||||
containerColor = Color.Transparent,
|
||||
HorizontalFloatingToolbar(
|
||||
floatingActionButton = floatingActionButton,
|
||||
modifier = modifier
|
||||
.padding(bottom = ScreenOffset)
|
||||
.zIndex(1f),
|
||||
) {
|
||||
HomeNavigationBarItem.entries.forEach { item ->
|
||||
HomeNavigationBarItem.entries.forEachIndexed { index, item ->
|
||||
if (index > 0) {
|
||||
HorizontalFloatingToolbarSeparator()
|
||||
}
|
||||
val isSelected = currentHomeNavigationBarItem == item
|
||||
NavigationBarItem(
|
||||
selected = isSelected,
|
||||
onClick = {
|
||||
onItemClick(item)
|
||||
},
|
||||
icon = {
|
||||
NavigationBarIcon(
|
||||
imageVector = item.icon(isSelected),
|
||||
)
|
||||
},
|
||||
label = {
|
||||
NavigationBarText(
|
||||
text = stringResource(item.labelRes),
|
||||
)
|
||||
}
|
||||
HorizontalFloatingToolbarItem(
|
||||
icon = item.icon(isSelected),
|
||||
tooltipLabel = stringResource(item.labelRes),
|
||||
isSelected = isSelected,
|
||||
onClick = { onItemClick(item) },
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,9 +87,7 @@ fun HomeTopBar(
|
|||
onMenuActionClick: (RoomListMenuAction) -> Unit,
|
||||
onOpenSettings: () -> Unit,
|
||||
onAccountSwitch: (SessionId) -> Unit,
|
||||
onCreateSpace: () -> Unit,
|
||||
scrollBehavior: TopAppBarScrollBehavior,
|
||||
canCreateSpaces: Boolean,
|
||||
canReportBug: Boolean,
|
||||
displayFilters: Boolean,
|
||||
filtersState: RoomListFiltersState,
|
||||
|
|
@ -134,17 +132,13 @@ fun HomeTopBar(
|
|||
)
|
||||
},
|
||||
actions = {
|
||||
when (selectedNavigationItem) {
|
||||
HomeNavigationBarItem.Chats -> RoomListMenuItems(
|
||||
if (selectedNavigationItem == HomeNavigationBarItem.Chats) {
|
||||
RoomListMenuItems(
|
||||
onToggleSearch = onToggleSearch,
|
||||
onMenuActionClick = onMenuActionClick,
|
||||
canReportBug = canReportBug,
|
||||
spaceFiltersState = spaceFiltersState,
|
||||
)
|
||||
HomeNavigationBarItem.Spaces -> SpacesMenuItems(
|
||||
canCreateSpaces = canCreateSpaces,
|
||||
onCreateSpace = onCreateSpace
|
||||
)
|
||||
}
|
||||
},
|
||||
// We want a 16dp left padding for the navigationIcon :
|
||||
|
|
@ -230,21 +224,6 @@ private fun RoomListMenuItems(
|
|||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SpacesMenuItems(
|
||||
canCreateSpaces: Boolean,
|
||||
onCreateSpace: () -> Unit
|
||||
) {
|
||||
if (canCreateSpaces) {
|
||||
IconButton(onClick = onCreateSpace) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.Plus(),
|
||||
contentDescription = stringResource(CommonStrings.action_create_space)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SpaceFilterButton(
|
||||
spaceFiltersState: SpaceFiltersState,
|
||||
|
|
@ -365,8 +344,6 @@ internal fun HomeTopBarPreview() = ElementPreview {
|
|||
onOpenSettings = {},
|
||||
onAccountSwitch = {},
|
||||
onToggleSearch = {},
|
||||
onCreateSpace = {},
|
||||
canCreateSpaces = true,
|
||||
canReportBug = true,
|
||||
displayFilters = true,
|
||||
filtersState = aRoomListFiltersState(),
|
||||
|
|
@ -388,8 +365,6 @@ internal fun HomeTopBarSpaceFiltersSelectedPreview() = ElementPreview {
|
|||
onOpenSettings = {},
|
||||
onAccountSwitch = {},
|
||||
onToggleSearch = {},
|
||||
onCreateSpace = {},
|
||||
canCreateSpaces = true,
|
||||
canReportBug = true,
|
||||
displayFilters = true,
|
||||
filtersState = aRoomListFiltersState(),
|
||||
|
|
@ -411,8 +386,6 @@ internal fun HomeTopBarSpacesPreview() = ElementPreview {
|
|||
onOpenSettings = {},
|
||||
onAccountSwitch = {},
|
||||
onToggleSearch = {},
|
||||
onCreateSpace = {},
|
||||
canCreateSpaces = true,
|
||||
canReportBug = true,
|
||||
displayFilters = false,
|
||||
filtersState = aRoomListFiltersState(),
|
||||
|
|
@ -434,8 +407,6 @@ internal fun HomeTopBarWithIndicatorPreview() = ElementPreview {
|
|||
onOpenSettings = {},
|
||||
onAccountSwitch = {},
|
||||
onToggleSearch = {},
|
||||
onCreateSpace = {},
|
||||
canCreateSpaces = true,
|
||||
canReportBug = true,
|
||||
displayFilters = true,
|
||||
filtersState = aRoomListFiltersState(),
|
||||
|
|
@ -457,8 +428,6 @@ internal fun HomeTopBarMultiAccountPreview() = ElementPreview {
|
|||
onOpenSettings = {},
|
||||
onAccountSwitch = {},
|
||||
onToggleSearch = {},
|
||||
onCreateSpace = {},
|
||||
canCreateSpaces = true,
|
||||
canReportBug = true,
|
||||
displayFilters = true,
|
||||
filtersState = aRoomListFiltersState(),
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ package io.element.android.features.home.impl.spaces
|
|||
|
||||
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.foundation.lazy.LazyColumn
|
||||
|
|
@ -48,6 +49,7 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
fun HomeSpacesView(
|
||||
state: HomeSpacesState,
|
||||
lazyListState: LazyListState,
|
||||
contentPadding: PaddingValues,
|
||||
onSpaceClick: (RoomId) -> Unit,
|
||||
onCreateSpaceClick: () -> Unit,
|
||||
onExploreClick: () -> Unit,
|
||||
|
|
@ -55,7 +57,7 @@ fun HomeSpacesView(
|
|||
) {
|
||||
if (state.canCreateSpaces && state.spaceRooms.isEmpty()) {
|
||||
EmptySpaceHomeView(
|
||||
modifier = modifier,
|
||||
modifier = modifier.padding(contentPadding),
|
||||
onCreateSpaceClick = onCreateSpaceClick,
|
||||
onExploreClick = onExploreClick,
|
||||
canExploreSpaces = state.canExploreSpaces,
|
||||
|
|
@ -63,7 +65,8 @@ fun HomeSpacesView(
|
|||
} else {
|
||||
LazyColumn(
|
||||
modifier = modifier,
|
||||
state = lazyListState
|
||||
state = lazyListState,
|
||||
contentPadding = contentPadding,
|
||||
) {
|
||||
val space = state.space
|
||||
when (space) {
|
||||
|
|
@ -115,6 +118,9 @@ fun HomeSpacesView(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ref: https://www.figma.com/design/pDlJZGBsri47FNTXMnEdXB/Compound-Android-Templates?node-id=1763-74215&t=9IGKMXHDfTGAqzQK-4
|
||||
*/
|
||||
@Composable
|
||||
private fun EmptySpaceHomeView(
|
||||
onCreateSpaceClick: () -> Unit,
|
||||
|
|
@ -159,8 +165,7 @@ private fun EmptySpaceHomeView(
|
|||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
|
|
@ -174,5 +179,6 @@ internal fun HomeSpacesViewPreview(
|
|||
onSpaceClick = {},
|
||||
onCreateSpaceClick = {},
|
||||
onExploreClick = {},
|
||||
contentPadding = PaddingValues(bottom = 112.dp),
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ androidx_preference = "androidx.preference:preference:1.2.1"
|
|||
androidx_webkit = "androidx.webkit:webkit:1.15.0"
|
||||
|
||||
androidx_compose_bom = { module = "androidx.compose:compose-bom", version.ref = "compose_bom" }
|
||||
androidx_compose_material3 = { module = "androidx.compose.material3:material3" }
|
||||
androidx_compose_material3 = { module = "androidx.compose.material3:material3", version = '1.5.0-alpha11' }
|
||||
androidx_compose_material3_windowsizeclass = { module = "androidx.compose.material3:material3-window-size-class" }
|
||||
androidx_compose_material3_adaptive = "androidx.compose.material3:material3-adaptive-android:1.0.0-alpha06"
|
||||
androidx_compose_ui = { module = "androidx.compose.ui:ui" }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright (c) 2026 Element Creations Ltd.
|
||||
*
|
||||
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
|
||||
* Please see LICENSE files in the repository root for full details.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.designsystem.theme.components
|
||||
|
||||
import androidx.compose.animation.core.FiniteAnimationSpec
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.PaddingValues
|
||||
import androidx.compose.foundation.layout.RowScope
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.widthIn
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
|
||||
import androidx.compose.material3.FilledIconButton
|
||||
import androidx.compose.material3.FloatingToolbarColors
|
||||
import androidx.compose.material3.FloatingToolbarDefaults
|
||||
import androidx.compose.material3.FloatingToolbarHorizontalFabPosition
|
||||
import androidx.compose.material3.FloatingToolbarScrollBehavior
|
||||
import androidx.compose.material3.IconButtonDefaults
|
||||
import androidx.compose.material3.TooltipAnchorPosition
|
||||
import androidx.compose.material3.TooltipDefaults
|
||||
import androidx.compose.material3.rememberTooltipState
|
||||
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.graphics.vector.ImageVector
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import io.element.android.compound.theme.ElementTheme
|
||||
import io.element.android.compound.tokens.generated.CompoundIcons
|
||||
import io.element.android.libraries.designsystem.atomic.atoms.CounterAtom
|
||||
import io.element.android.libraries.designsystem.components.tooltip.PlainTooltip
|
||||
import io.element.android.libraries.designsystem.components.tooltip.TooltipBox
|
||||
import io.element.android.libraries.designsystem.preview.ElementPreview
|
||||
import io.element.android.libraries.designsystem.preview.PreviewsDayNight
|
||||
|
||||
/**
|
||||
* Ref: https://www.figma.com/design/G1xy0HDZKJf5TCRFmKb5d5/Compound-Android-Components?node-id=4457-1136
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun HorizontalFloatingToolbar(
|
||||
modifier: Modifier = Modifier,
|
||||
expanded: Boolean = true,
|
||||
floatingActionButton: (@Composable () -> Unit)? = null,
|
||||
colors: FloatingToolbarColors = FloatingToolbarDefaults.standardFloatingToolbarColors().copy(
|
||||
toolbarContainerColor = ElementTheme.colors.bgSubtleSecondary,
|
||||
),
|
||||
contentPadding: PaddingValues = PaddingValues(
|
||||
vertical = 8.dp,
|
||||
horizontal = 12.dp,
|
||||
),
|
||||
scrollBehavior: FloatingToolbarScrollBehavior? = null,
|
||||
shape: Shape = FloatingToolbarDefaults.ContainerShape,
|
||||
leadingContent: @Composable (RowScope.() -> Unit)? = null,
|
||||
trailingContent: @Composable (RowScope.() -> Unit)? = null,
|
||||
floatingActionButtonPosition: FloatingToolbarHorizontalFabPosition =
|
||||
FloatingToolbarHorizontalFabPosition.End,
|
||||
animationSpec: FiniteAnimationSpec<Float> = FloatingToolbarDefaults.animationSpec(),
|
||||
expandedShadowElevation: Dp = 8.dp,
|
||||
collapsedShadowElevation: Dp = if (floatingActionButton == null) {
|
||||
FloatingToolbarDefaults.ContainerCollapsedElevation
|
||||
} else {
|
||||
FloatingToolbarDefaults.ContainerCollapsedElevationWithFab
|
||||
},
|
||||
content: @Composable RowScope.() -> Unit,
|
||||
) {
|
||||
if (floatingActionButton == null) {
|
||||
androidx.compose.material3.HorizontalFloatingToolbar(
|
||||
expanded = expanded,
|
||||
modifier = modifier,
|
||||
colors = colors,
|
||||
contentPadding = contentPadding,
|
||||
scrollBehavior = scrollBehavior,
|
||||
shape = shape,
|
||||
leadingContent = leadingContent,
|
||||
trailingContent = trailingContent,
|
||||
expandedShadowElevation = expandedShadowElevation,
|
||||
collapsedShadowElevation = collapsedShadowElevation,
|
||||
content = content,
|
||||
)
|
||||
} else {
|
||||
androidx.compose.material3.HorizontalFloatingToolbar(
|
||||
expanded = expanded,
|
||||
floatingActionButton = floatingActionButton,
|
||||
modifier = modifier,
|
||||
colors = colors,
|
||||
contentPadding = contentPadding,
|
||||
scrollBehavior = scrollBehavior,
|
||||
shape = shape,
|
||||
floatingActionButtonPosition = floatingActionButtonPosition,
|
||||
animationSpec = animationSpec,
|
||||
expandedShadowElevation = expandedShadowElevation,
|
||||
collapsedShadowElevation = collapsedShadowElevation,
|
||||
content = content,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun HorizontalFloatingToolbarItem(
|
||||
icon: ImageVector,
|
||||
tooltipLabel: String,
|
||||
isSelected: Boolean,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
counter: Int? = null,
|
||||
forceRenderingTooltip: Boolean = false,
|
||||
) {
|
||||
TooltipBox(
|
||||
positionProvider =
|
||||
TooltipDefaults.rememberTooltipPositionProvider(
|
||||
TooltipAnchorPosition.Above
|
||||
),
|
||||
tooltip = { PlainTooltip { Text(tooltipLabel) } },
|
||||
state = rememberTooltipState(
|
||||
initialIsVisible = forceRenderingTooltip,
|
||||
),
|
||||
modifier = modifier,
|
||||
) {
|
||||
val colors = if (isSelected) {
|
||||
IconButtonDefaults.filledIconButtonColors().copy(
|
||||
containerColor = ElementTheme.colors.bgCanvasDefault,
|
||||
contentColor = ElementTheme.colors.iconPrimary,
|
||||
)
|
||||
} else {
|
||||
IconButtonDefaults.filledIconButtonColors().copy(
|
||||
containerColor = Color.Transparent,
|
||||
contentColor = ElementTheme.colors.iconSecondary,
|
||||
)
|
||||
}
|
||||
Box {
|
||||
FilledIconButton(
|
||||
modifier = Modifier.widthIn(min = 56.dp),
|
||||
colors = colors,
|
||||
onClick = onClick,
|
||||
) {
|
||||
Icon(
|
||||
modifier = Modifier.size(24.dp),
|
||||
imageVector = icon,
|
||||
contentDescription = tooltipLabel,
|
||||
)
|
||||
}
|
||||
if (counter != null) {
|
||||
CounterAtom(
|
||||
modifier = Modifier
|
||||
.align(Alignment.TopEnd)
|
||||
.padding(top = 6.dp, end = 3.dp),
|
||||
count = counter,
|
||||
textStyle = ElementTheme.typography.fontBodyXsMedium,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun HorizontalFloatingToolbarSeparator(modifier: Modifier = Modifier) {
|
||||
Spacer(modifier = modifier.width(16.dp))
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun HorizontalFloatingToolbarPreview() = ElementPreview {
|
||||
ContentToPreview(
|
||||
floatingActionButton = {
|
||||
FloatingActionButton(
|
||||
onClick = {},
|
||||
) {
|
||||
Icon(
|
||||
imageVector = CompoundIcons.Plus(),
|
||||
contentDescription = null,
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@PreviewsDayNight
|
||||
@Composable
|
||||
internal fun HorizontalFloatingToolbarNoFabPreview() = ElementPreview {
|
||||
ContentToPreview(
|
||||
floatingActionButton = null,
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3ExpressiveApi::class, ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ContentToPreview(
|
||||
floatingActionButton: (@Composable () -> Unit)?,
|
||||
) {
|
||||
HorizontalFloatingToolbar(
|
||||
modifier = Modifier.padding(28.dp),
|
||||
floatingActionButton = floatingActionButton,
|
||||
) {
|
||||
listOf(
|
||||
CompoundIcons.ChatSolid(),
|
||||
CompoundIcons.Space(),
|
||||
).forEachIndexed { index, icon ->
|
||||
if (index > 0) {
|
||||
HorizontalFloatingToolbarSeparator()
|
||||
}
|
||||
HorizontalFloatingToolbarItem(
|
||||
icon = icon,
|
||||
tooltipLabel = "Label",
|
||||
isSelected = index == 0,
|
||||
counter = if (index == 0) 6 else null,
|
||||
forceRenderingTooltip = true,
|
||||
onClick = { },
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -107,10 +107,10 @@ fun ListItem(
|
|||
onClick: (() -> Unit)? = null,
|
||||
) {
|
||||
// We cannot just pass the disabled colors, they must be set manually: https://issuetracker.google.com/issues/280480132
|
||||
val headlineColor = if (enabled) colors.headlineColor else colors.disabledHeadlineColor
|
||||
val supportingColor = if (enabled) colors.supportingTextColor else colors.disabledHeadlineColor.copy(alpha = 0.80f)
|
||||
val leadingContentColor = if (enabled) colors.leadingIconColor else colors.disabledLeadingIconColor
|
||||
val trailingContentColor = if (enabled) colors.trailingIconColor else colors.disabledTrailingIconColor
|
||||
val headlineColor = if (enabled) colors.contentColor else colors.disabledContentColor
|
||||
val supportingColor = if (enabled) colors.supportingContentColor else colors.disabledContentColor.copy(alpha = 0.80f)
|
||||
val leadingContentColor = if (enabled) colors.leadingContentColor else colors.disabledLeadingContentColor
|
||||
val trailingContentColor = if (enabled) colors.trailingContentColor else colors.disabledTrailingContentColor
|
||||
|
||||
val decoratedHeadlineContent: @Composable () -> Unit = {
|
||||
CompositionLocalProvider(
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ class KonsistComposableTest {
|
|||
"CompoundSemanticColorsLightHc",
|
||||
"CompoundSemanticColorsDark",
|
||||
"CompoundSemanticColorsDarkHc",
|
||||
"HorizontalFloatingToolbarItem",
|
||||
"HorizontalFloatingToolbarSeparator",
|
||||
)
|
||||
.assertTrue(
|
||||
additionalMessage =
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:bf07c13a8f8b7da568e59441c7597de071f5d4ca728930a7cfba67500d981efd
|
||||
size 12334
|
||||
oid sha256:499d48e33c188e42e066e30644d2ce4d1a2516b6b26d15c385d613234777d738
|
||||
size 12105
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:81bfe2cfe21bb21a41579e0cf81e020997de0c0f12b66b6db172d71120f72b90
|
||||
size 11420
|
||||
oid sha256:1f9d7c7900c41fbc10b27a68bf079e4750c28cfdcc4d96db35a79f3606cd5796
|
||||
size 11205
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:711645c8cd9bcd04105d2f0d1cf37376691d574340b815e5d9b98e9ecc8b8b23
|
||||
size 85538
|
||||
oid sha256:f3ac57efcab393ce13794dde2ad7e0d60757c0ef7fd0b09ff0a3c338de9a9edd
|
||||
size 85467
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:67a160a71f24d46778cf03d7011d98ac6094b6efd1ba47845c4c36114fcec932
|
||||
size 38969
|
||||
oid sha256:f0567c1fe44efb4f9e188252a6840c228eb03e8d7954c95b79c693ac31451cd2
|
||||
size 38840
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:67a160a71f24d46778cf03d7011d98ac6094b6efd1ba47845c4c36114fcec932
|
||||
size 38969
|
||||
oid sha256:f0567c1fe44efb4f9e188252a6840c228eb03e8d7954c95b79c693ac31451cd2
|
||||
size 38840
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:30b3ee70ad7dbd0b4f2db3b00b1edacecbbf3e2370798c60dc7696fe75cc843d
|
||||
size 24704
|
||||
oid sha256:ecd79d3f8c4efbb54efa6a5b8dee79274ae9957b01146025dab42a45fc328fc0
|
||||
size 24740
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:45296f7e74f888e3b84f56f45b0d926970363013704ceb62df2afa132f81cbd5
|
||||
size 83671
|
||||
oid sha256:0f8a54913bd0c207088cec3c0fff9bcab4dca084884493a32a615fa728c40625
|
||||
size 83659
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b9b9a37c8ed9650d16f498c3f00a182a83dc53892cbc8558c30138e0de56ad94
|
||||
size 37669
|
||||
oid sha256:949b1843a373b86fde0bb5a0a0637f938e87aeb3d36b8c146052e99874dfb4dd
|
||||
size 37667
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b9b9a37c8ed9650d16f498c3f00a182a83dc53892cbc8558c30138e0de56ad94
|
||||
size 37669
|
||||
oid sha256:949b1843a373b86fde0bb5a0a0637f938e87aeb3d36b8c146052e99874dfb4dd
|
||||
size 37667
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b4649d1e05ab3b05d3bd730bc69a5e4398a0cb024027e9720be3bee2f49a4d01
|
||||
size 23757
|
||||
oid sha256:0fd37517b8913e2bac3275f717aa15bed18055a7525e0404b25b43cb8bd8422d
|
||||
size 23840
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:86696c9ef71c5cf5edddf908e477d1e392fc9b3334a390df0fd2c2419c703de1
|
||||
size 142152
|
||||
oid sha256:c4bd92f12e7926f39cf7bb74fedd85b8295bff34da08e45229e2e1a8f83956c3
|
||||
size 144306
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dc87652e8e0ab0a215ca08ad64def6eb59a3c44a66af0f837cbeb7e1fd06701d
|
||||
size 65071
|
||||
oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e
|
||||
size 67665
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7bdf23256bdc64325fab24411b39abc9fa62ced7f0bda1b24a4df387917064df
|
||||
size 33352
|
||||
oid sha256:763715d657faecd68e201b7a110d022c04e27592bff499355662848455e2adc3
|
||||
size 36373
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:6eca672ad59f17058a552f712ce0fb27cca807bf2fcd1a96962fbf799861b5d3
|
||||
size 28046
|
||||
oid sha256:b0ecffc6b05c1bc3d0c6ba578d7ca7d50ac9c7a4948c53fe96d427c3ad6b4e4e
|
||||
size 32289
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:583da21c83fff6ec3e81c3602b2cb8c1c3e5753f32892ab7ae70633ef6cf59e9
|
||||
size 83978
|
||||
oid sha256:b659de7521274ae555f962639d7e1652a22958c4b066dae3f2dd1aa70d93b78e
|
||||
size 89194
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7ca16a8b022e217c954b322f463bf4cad125eed488a67d64712aefe04276a34e
|
||||
size 82657
|
||||
oid sha256:bd11e404d07f8d790b1554c760f24e4e82614a331e16219c67c326b0375313f9
|
||||
size 84336
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f5f1c19e5c138ba9b4573041c11e771b74c6916faf7fec505cd9d545556d1583
|
||||
size 51083
|
||||
oid sha256:5406580880491251a8d61fc2fe26dab90153e6337f95dae3d6e4b1c5df7ac8f4
|
||||
size 53764
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:750a7b57fd2fd99f3cd0ad6e970692cdd8a7ad191dfb8fff0b5d0935461789db
|
||||
size 42594
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dc87652e8e0ab0a215ca08ad64def6eb59a3c44a66af0f837cbeb7e1fd06701d
|
||||
size 65071
|
||||
oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e
|
||||
size 67665
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dc87652e8e0ab0a215ca08ad64def6eb59a3c44a66af0f837cbeb7e1fd06701d
|
||||
size 65071
|
||||
oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e
|
||||
size 67665
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:11e49c75d058dde6b661ed69684b679b0a86832e1f51e097ed96df03af29ef3f
|
||||
size 61748
|
||||
oid sha256:f8bdb8d3e2dbb468115c4077f5bce6415a7708cbd04f825225139c1a2cbf788d
|
||||
size 64647
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d31d6ae0f15ca0b2db8425cdd0588ee1be0ccae543588be32b34dda5d9d4246f
|
||||
size 52454
|
||||
oid sha256:1ed6905e2833c7e927c84f0407a6218a4859a28f5a36a34c3a9b92f66347308a
|
||||
size 56117
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:dc87652e8e0ab0a215ca08ad64def6eb59a3c44a66af0f837cbeb7e1fd06701d
|
||||
size 65071
|
||||
oid sha256:5f106b4672b1d96665fe731de28b7ccbb98f986580fd95cc6609a7b64348c60e
|
||||
size 67665
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7ca4ab313876d1c530d0829433b6a2c998afc4e761a1061364e3dbb457487646
|
||||
size 82515
|
||||
oid sha256:521e3b0b36dbed830eab8cd884a1924381bd9a50c189ff9ef074ed468aaf9b23
|
||||
size 84195
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5dd233a5b5a17dfcdd16f70c354d33e74b6eb24180cc2235b41019684a1ab7fc
|
||||
size 61852
|
||||
oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b
|
||||
size 62502
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ae78be15862aef18f0fe889c4df469cc7a3d77ebffbcf09c4b4c7baebb177e2f
|
||||
size 30332
|
||||
oid sha256:86305c47144ed620efd27045239c0ca66f11cb5f2088b4df8e7f9e7a254576fa
|
||||
size 31166
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:ab5ddcdbb507c6c0953cd8b3bbddb73d9e98733d8edee5be37e012275a594db1
|
||||
size 24749
|
||||
oid sha256:cee0eefc4639ede46fd6539da213f0398de0611fc1e6f2002c6e014318c04380
|
||||
size 26665
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5fc942ea686b3a58d930266a5cc7a9f663ff634512397be6f06850956f419b1e
|
||||
size 79978
|
||||
oid sha256:1605040770a4b5d8928b41afab2e2f970f18283942659b2b869451e5c04d3d5b
|
||||
size 83224
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:74ac553cb7d2bc0883cc1cc5f12d692dcaa63df6c1f6d84cf6e5cb099ad15159
|
||||
size 78750
|
||||
oid sha256:90bf5140e04bd22af001ed9d23513b26d555f2d73864d9012c8e05f452659fd8
|
||||
size 78641
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:03ed724447496e01989773821c20594325c738389f61fd2af162e2d7d82b2651
|
||||
size 47386
|
||||
oid sha256:828d2d972c03e2cdb837e591c957c93fd61c1f49e3e4fcf19a8bf18963d4eb95
|
||||
size 48307
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:b1d6080fd17d90e63b4aae91c6a2c93bd16314eacc6007f57073e981c4dfb1c6
|
||||
size 37378
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5dd233a5b5a17dfcdd16f70c354d33e74b6eb24180cc2235b41019684a1ab7fc
|
||||
size 61852
|
||||
oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b
|
||||
size 62502
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5dd233a5b5a17dfcdd16f70c354d33e74b6eb24180cc2235b41019684a1ab7fc
|
||||
size 61852
|
||||
oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b
|
||||
size 62502
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:3c966a3f7d1fe4ba6e1fe73ca5fad71ef818433bc5fc35cc77b537f875dde0af
|
||||
size 58907
|
||||
oid sha256:71e33566c0404f1930831b846a2e78952dd33138ffde5257c3d413739e225040
|
||||
size 60212
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:7c889d00a2dedf3f6ad596a819709daf9d6537314679a72143efbc2932d687da
|
||||
size 50622
|
||||
oid sha256:363efc8054e6a1e04d0482e5351d7e190febf55167a0358d4251101ee6ebd659
|
||||
size 50942
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:5dd233a5b5a17dfcdd16f70c354d33e74b6eb24180cc2235b41019684a1ab7fc
|
||||
size 61852
|
||||
oid sha256:00af046190654a77e02d1152e8d44f538302b2fecfbd31b8790cdfa6f202dc1b
|
||||
size 62502
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:f4dbf6e03444e3d28756abd6985be2f394317cc9e982a0b059f10fdc2d562d50
|
||||
size 78607
|
||||
oid sha256:465ffe0ea53fe7bde74c9dddb1be5e9f2861436b5292956f889dcf60db621af2
|
||||
size 78499
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:75de341f705bb22955f9399180519b65ad59c2e1917317d56e50ea4db78f35bc
|
||||
size 12102
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:4811667dec0f32accc5e2c8a5dd5c0b34017fcff8d1e0376ee7a4708426bca0f
|
||||
size 9838
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:16dee1dfe746cd40dac9fe8f0af3ecb42cd14bab5cc490917b589beed065ed1b
|
||||
size 14686
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
version https://git-lfs.github.com/spec/v1
|
||||
oid sha256:d57df7110371c9224e232b707d6a1b10ce14afcb56c803a78220792f2a0d4cf2
|
||||
size 11354
|
||||
Loading…
Add table
Add a link
Reference in a new issue