From db6b670e56a1f47cacf55bcd2fef6fe43a3d0b64 Mon Sep 17 00:00:00 2001 From: Xavier Molloy <44061143+xavimolloy@users.noreply.github.com> Date: Fri, 2 Feb 2024 08:41:39 +0100 Subject: [PATCH] feat: [ANDROAPP-5890] add shadow to Listcards and samples to ListCard screen (#183) * feat: [ANDROAPP-5890] add shadow to Listcards and samples to ListCard screen * feat: [ANDROAPP-5890] refactor parameter names --- .../kotlin/org/hisp/dhis/common/App.kt | 3 +- .../dhis/common/screens/ListCardScreen.kt | 80 ++++++++++++++++++- .../ui/designsystem/theme/Shadow.android.kt | 34 ++++++++ .../ui/designsystem/component/ListCard.kt | 36 +++++++-- .../mobile/ui/designsystem/theme/Shadow.kt | 2 + .../ui/designsystem/theme/Shadow.desktop.kt | 9 +++ 6 files changed, 152 insertions(+), 12 deletions(-) create mode 100644 designsystem/src/androidMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.android.kt create mode 100644 designsystem/src/desktopMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.desktop.kt diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt index be4a6c74d..185a0a097 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/App.kt @@ -94,7 +94,8 @@ fun App() { @Composable fun Main() { - val currentScreen = remember { mutableStateOf(Components.INDICATOR_INPUT) } + val currentScreen = remember { mutableStateOf(Components.LIST_CARD) } + var expanded by remember { mutableStateOf(false) } Column( diff --git a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/ListCardScreen.kt b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/ListCardScreen.kt index 5eda60e65..81bcba487 100644 --- a/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/ListCardScreen.kt +++ b/common/src/commonMain/kotlin/org/hisp/dhis/common/screens/ListCardScreen.kt @@ -84,6 +84,7 @@ fun ListCardScreen() { mutableStateOf(false) } SubTitle("Tei list:") + SubTitle("With shadow") ListCard( listAvatar = { Avatar( @@ -110,7 +111,7 @@ fun ListCardScreen() { ) }, onCardClick = {}, - showLoading = showLoading1, + loading = showLoading1, ) var showLoading2 by remember { mutableStateOf(false) @@ -141,13 +142,15 @@ fun ListCardScreen() { ) }, onCardClick = {}, - showLoading = showLoading2, + loading = showLoading2, ) + SubTitle("Without shadow") var showLoading3 by remember { mutableStateOf(false) } ListCard( + shadow = false, listAvatar = { Avatar( metadataAvatar = { @@ -183,7 +186,7 @@ fun ListCardScreen() { ) }, onCardClick = {}, - showLoading = showLoading3, + loading = showLoading3, ) var showLoading4 by remember { @@ -248,13 +251,38 @@ fun ListCardScreen() { ) }, onCardClick = {}, - showLoading = showLoading4, + loading = showLoading4, ) Spacer(Modifier.size(Spacing.Spacing16)) SubTitle("Single events list:") + SubTitle("With shadow:") ListCard( + title = "12/18/2021", + lastUpdated = "now", + additionalInfoList = basicAdditionalItemList, + actionButton = { + Button( + style = ButtonStyle.TONAL, + text = "Retry sync", + icon = { + Icon( + imageVector = Icons.Outlined.Sync, + contentDescription = "Icon Button", + tint = TextColor.OnPrimaryContainer, + ) + }, + onClick = { }, + modifier = Modifier.fillMaxWidth(), + ) + }, + onCardClick = {}, + ) + Spacer(Modifier.size(Spacing.Spacing16)) + SubTitle("Without shadow:") + ListCard( + shadow = false, title = "12/18/2021", lastUpdated = "now", additionalInfoList = basicAdditionalItemList, @@ -277,8 +305,52 @@ fun ListCardScreen() { ) Spacer(Modifier.size(Spacing.Spacing16)) SubTitle("Events in timeline in TEI dashboard:") + SubTitle("With shadow:") + + ListCard( + listAvatar = { + Avatar( + metadataAvatar = { + MetadataAvatar( + icon = { + Icon( + painter = provideDHIS2Icon("dhis2_baby_male_0203m_positive"), + contentDescription = "Button", + + ) + }, + iconTint = Color(0xFF11D9D9), + size = AvatarSize.Large, + ) + }, + style = AvatarStyle.METADATA, + ) + }, + title = "12/18/2021 at 16:30", + lastUpdated = "now", + additionalInfoList = eventsTimelineTeiDashboardList, + actionButton = { + Button( + style = ButtonStyle.TONAL, + text = "Retry sync", + icon = { + Icon( + imageVector = Icons.Outlined.Sync, + contentDescription = "Icon Button", + tint = TextColor.OnPrimaryContainer, + ) + }, + onClick = {}, + modifier = Modifier.fillMaxWidth(), + ) + }, + onCardClick = {}, + ) + Spacer(Modifier.size(Spacing.Spacing16)) + SubTitle("Without shadow:") ListCard( + shadow = false, listAvatar = { Avatar( metadataAvatar = { diff --git a/designsystem/src/androidMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.android.kt b/designsystem/src/androidMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.android.kt new file mode 100644 index 000000000..92cc6d2dd --- /dev/null +++ b/designsystem/src/androidMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.android.kt @@ -0,0 +1,34 @@ +package org.hisp.dhis.mobile.ui.designsystem.theme + +import android.graphics.BlurMaskFilter +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawBehind +import androidx.compose.ui.graphics.Paint +import androidx.compose.ui.graphics.drawscope.drawIntoCanvas +import androidx.compose.ui.graphics.toArgb + +internal actual fun Modifier.listCardShadow(modifier: Modifier): Modifier = this.then( + drawBehind { + drawIntoCanvas { canvas -> + val paint = Paint() + val frameworkPaint = paint.asFrameworkPaint() + + frameworkPaint.maskFilter = (BlurMaskFilter(Spacing.Spacing10.toPx(), BlurMaskFilter.Blur.NORMAL)) + + frameworkPaint.color = SurfaceColor.Container.toArgb() + + val leftPixel = Spacing.Spacing0.toPx() + val topPixel = Spacing.Spacing4.toPx() + val rightPixel = size.width + topPixel + val bottomPixel = size.height + leftPixel + + canvas.drawRect( + left = leftPixel, + top = topPixel, + right = rightPixel, + bottom = bottomPixel, + paint = paint, + ) + } + }, +) diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/ListCard.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/ListCard.kt index 305112535..d53b00c39 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/ListCard.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/component/ListCard.kt @@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth @@ -52,6 +53,7 @@ import org.hisp.dhis.mobile.ui.designsystem.theme.Spacing.Spacing4 import org.hisp.dhis.mobile.ui.designsystem.theme.SurfaceColor import org.hisp.dhis.mobile.ui.designsystem.theme.TextColor import org.hisp.dhis.mobile.ui.designsystem.theme.hoverPointerIcon +import org.hisp.dhis.mobile.ui.designsystem.theme.listCardShadow /** * DHIS2 ListCard. @@ -77,8 +79,9 @@ fun ListCard( actionButton: @Composable (() -> Unit)? = null, expandLabelText: String = provideStringResource("show_more"), shrinkLabelText: String = provideStringResource("show_less"), - showLoading: Boolean = false, + loading: Boolean = false, onCardClick: () -> Unit, + shadow: Boolean = true, modifier: Modifier = Modifier, ) { val expandableItemList = mutableListOf() @@ -95,6 +98,9 @@ fun ListCard( Row( modifier = modifier + .conditional(shadow, { + listCardShadow(modifier) + }) .background(color = TextColor.OnPrimary) .clip(shape = RoundedCornerShape(Radius.S)) .clickable( @@ -105,8 +111,8 @@ fun ListCard( ), onClick = onCardClick, ) - .padding(Spacing.Spacing8) - .hoverPointerIcon(true), + .hoverPointerIcon(true) + .padding(getPaddingValues(shadow, listAvatar != null)), ) { listAvatar?.let { it.invoke() @@ -138,7 +144,7 @@ fun ListCard( color = SurfaceColor.Primary, isConstantItem = false, ), - showLoading = showLoading, + loading = loading, ) actionButton?.invoke() } @@ -217,7 +223,7 @@ fun CardDetail( color = SurfaceColor.Primary, isConstantItem = false, ), - showLoading = showLoading, + loading = showLoading, ) actionButton?.invoke() } @@ -287,12 +293,12 @@ private fun AdditionalInfoColumn( expandableItems: List? = null, constantItems: List, syncProgressItem: AdditionalInfoItem, - showLoading: Boolean, + loading: Boolean, isDetailCard: Boolean = false, expandLabelText: String, shrinkLabelText: String, ) { - val loadingSectionState by remember(showLoading) { mutableStateOf(showLoading) } + val loadingSectionState by remember(loading) { mutableStateOf(loading) } var sectionState by remember(SectionState.CLOSE) { mutableStateOf(SectionState.CLOSE) } var expandableItemList: List @@ -469,6 +475,22 @@ private fun KeyValueList( } } +@Composable +private fun getPaddingValues( + hasShadow: Boolean, + hasAvatar: Boolean, +): PaddingValues { + return if (!hasShadow) { + PaddingValues(Spacing.Spacing8) + } else { + if (hasAvatar) { + PaddingValues(Spacing.Spacing8, Spacing.Spacing16, Spacing.Spacing16, Spacing.Spacing16) + } else { + PaddingValues(Spacing.Spacing16) + } + } +} + enum class AvatarStyle { TEXT, diff --git a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.kt b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.kt index 331a3ce45..0ed5c0104 100644 --- a/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.kt +++ b/designsystem/src/commonMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.kt @@ -93,3 +93,5 @@ internal fun Modifier.iconCardShadow( ) } }.padding(bottom = shadowRadius) + +internal expect fun Modifier.listCardShadow(modifier: Modifier): Modifier diff --git a/designsystem/src/desktopMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.desktop.kt b/designsystem/src/desktopMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.desktop.kt new file mode 100644 index 000000000..a91aa2187 --- /dev/null +++ b/designsystem/src/desktopMain/kotlin/org/hisp/dhis/mobile/ui/designsystem/theme/Shadow.desktop.kt @@ -0,0 +1,9 @@ +package org.hisp.dhis.mobile.ui.designsystem.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.shadow + +internal actual fun Modifier.listCardShadow(modifier: Modifier): Modifier = this.then( + modifier.shadow(elevation = Spacing.Spacing10, shape = RoundedCornerShape(Radius.S), spotColor = SurfaceColor.Container), +)