Skip to content

Commit

Permalink
fix tabs review comments
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Pajuelo Cabezas <[email protected]>
  • Loading branch information
Balcan committed Jan 31, 2025
1 parent 2a1fbf8 commit 8805779
Show file tree
Hide file tree
Showing 7 changed files with 132 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ fun TabsScreen() {
}

enum class Tabs(val label: String) {
VERTICAL_TONAL_TABS_LABEL_ONLY("Tonal label only"),
VERTICAL_TONAL_TABS_ICON_ONLY("Tonal icon only"),
VERTICAL_TONAL_TABS_ICON_LABEL("Tonal icon and label"),
VERTICAL_PRIMARY_TABS_LABEL_ONLY("Primary label only"),
VERTICAL_PRIMARY_TABS_ICON_ONLY("Primary icon only"),
VERTICAL_PRIMARY_TABS_ICON_LABEL("Primary icon and label"),
VERTICAL_TONAL_TABS_LABEL_ONLY("Vertical tabs: Tonal label only"),
VERTICAL_TONAL_TABS_ICON_ONLY("Vertical tabs: Tonal icon only"),
VERTICAL_TONAL_TABS_ICON_LABEL("Vertical tabs: Tonal icon and label"),
VERTICAL_PRIMARY_TABS_LABEL_ONLY("Vertical tabs: Primary label only"),
VERTICAL_PRIMARY_TABS_ICON_ONLY("Vertical tabs: Primary icon only"),
VERTICAL_PRIMARY_TABS_ICON_LABEL("Vertical tabs: Primary icon and label"),
NO_COMPONENT_SELECTED("No component selected"),
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
package org.hisp.dhis.common.screens.tabs

import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle
import androidx.compose.material.icons.filled.Bookmarks
import androidx.compose.material.icons.filled.Event
import androidx.compose.material.icons.filled.Home
import androidx.compose.material.icons.filled.Settings
import androidx.compose.material.icons.outlined.AccountCircle
import androidx.compose.material.icons.outlined.Bookmarks
import androidx.compose.material.icons.outlined.Event
import androidx.compose.material.icons.outlined.Home
import androidx.compose.material.icons.outlined.Settings
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import org.hisp.dhis.mobile.ui.designsystem.component.ColumnScreenContainer
import org.hisp.dhis.mobile.ui.designsystem.component.VerticalTabs
import org.hisp.dhis.mobile.ui.designsystem.component.model.IconData
import org.hisp.dhis.mobile.ui.designsystem.component.model.Tab
import org.hisp.dhis.mobile.ui.designsystem.component.model.TabColorStyle
import org.hisp.dhis.mobile.ui.designsystem.component.model.TabStyle
Expand All @@ -15,17 +31,50 @@ fun VerticalTabsScreen(
tabStyle: TabStyle,
tabColorStyle: TabColorStyle,
) {
VerticalTabs(
modifier = Modifier.fillMaxSize()
.padding(Spacing.Spacing16),
tabs = listOf(
Tab(id = "1", label = "Tab 1"),
Tab(id = "2", label = "Tab 2"),
Tab(id = "3", label = "Tab 3"),
),
tabStyle = tabStyle,
tabColorStyle = tabColorStyle,
onSectionSelected = {
},
)
val modifier = if (tabStyle is TabStyle.IconOnly) {
Modifier.width(100.dp)
} else {
Modifier.fillMaxSize()
}

ColumnScreenContainer(scrollable = false) {
VerticalTabs(
modifier = modifier
.padding(Spacing.Spacing16),
tabs = buildList {
repeat(drawableOutlinedList.size) { index ->
add(
Tab(
id = "${index + 1}",
label = "Tab ${index + 1}",
iconData = getIcon(index),
),
)
}
},
tabStyle = tabStyle,
tabColorStyle = tabColorStyle,
onSectionSelected = {
},
contentPadding = PaddingValues(horizontal = Spacing.Spacing12),
)
}
}

private val drawableOutlinedList = listOf(
Icons.Outlined.Home,
Icons.Outlined.Bookmarks,
Icons.Outlined.Event,
Icons.Outlined.AccountCircle,
Icons.Outlined.Settings,
)

private val drawableFilledList = listOf(
Icons.Filled.Home,
Icons.Filled.Bookmarks,
Icons.Filled.Event,
Icons.Filled.AccountCircle,
Icons.Filled.Settings,
)

private fun getIcon(index: Int) = IconData(drawableOutlinedList[index], drawableFilledList[index])
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ fun ColumnScreenContainer(
modifier: Modifier = Modifier,
verticalArrangement: Arrangement.Vertical = Arrangement.spacedBy(Spacing.Spacing16),
horizontalAlignment: Alignment.Horizontal = Alignment.Start,
scrollable: Boolean = true,
content: @Composable (() -> Unit),
) {
Column(
Expand All @@ -47,7 +48,7 @@ fun ColumnScreenContainer(
modifier = modifier
.fillMaxSize().background(Color.White, Shape.LargeTop)
.padding(horizontal = Spacing.Spacing16)
.verticalScroll(rememberScrollState()),
.then(if (scrollable)Modifier.verticalScroll(rememberScrollState())else Modifier),
) {
title?.let {
Title(title, modifier = Modifier.padding(top = Spacing.Spacing16))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement.spacedBy
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
Expand All @@ -17,14 +18,14 @@ import androidx.compose.foundation.layout.requiredHeight
import androidx.compose.foundation.layout.requiredWidth
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Circle
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.ripple
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -34,6 +35,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
Expand All @@ -49,12 +52,22 @@ fun VerticalTabs(
tabStyle: TabStyle = TabStyle.LabelOnly,
tabColorStyle: TabColorStyle = TabColorStyle.Tonal,
initialSelectedTabIndex: Int = 0,
backgroundShape: Shape = MaterialTheme.shapes.large,
backgroundShape: Shape = MaterialTheme.shapes.medium,
onSectionSelected: (String) -> Unit,
contentPadding: PaddingValues = PaddingValues(),
) {
val density = LocalDensity.current
var selectedSection by remember { mutableStateOf(initialSelectedTabIndex) }

val scrollState = rememberLazyListState()
val scrollOffset by remember {
derivedStateOf {
VerticalTabsDefaults.tabHeight * scrollState.firstVisibleItemIndex + with(density) { scrollState.firstVisibleItemScrollOffset.toDp() }
}
}

val indicatorVerticalOffset by animateDpAsState(
targetValue = VerticalTabsDefaults.tabHeight * selectedSection,
targetValue = VerticalTabsDefaults.tabHeight * selectedSection - scrollOffset,
label = "",
)

Expand All @@ -67,12 +80,15 @@ fun VerticalTabs(
.clip(backgroundShape),
) {
LazyColumn(
state = scrollState,
modifier = Modifier.fillMaxSize(),
contentPadding = contentPadding,
) {
itemsIndexed(tabs) { index, tab ->
VerticalTab(
label = tab.label,
selected = index == selectedSection,
iconImage = tab.icon(index == selectedSection),
tabStyle = tabStyle,
tabColorStyle = tabColorStyle,
defaultVerticalTabHeight = VerticalTabsDefaults.tabHeight,
Expand Down Expand Up @@ -100,6 +116,7 @@ internal fun VerticalTab(
selected: Boolean,
tabStyle: TabStyle,
tabColorStyle: TabColorStyle,
iconImage: ImageVector?,
defaultVerticalTabHeight: Dp,
onTabClick: () -> Unit,
) {
Expand All @@ -108,26 +125,35 @@ internal fun VerticalTab(
modifier = Modifier
.fillMaxWidth()
.height(defaultVerticalTabHeight)
.padding(
horizontal = if (tabStyle is TabStyle.IconOnly) {
Spacing.Spacing5
} else {
Spacing.Spacing16
},
vertical = Spacing.Spacing5,
)
.clickable(
onClick = onTabClick,
role = Role.Tab,
interactionSource = interactionSource,
indication = ripple(
color = MaterialTheme.colorScheme.primary,
),
)
.padding(horizontal = Spacing.Spacing16, vertical = Spacing.Spacing5),
),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = spacedBy(Spacing.Spacing2),
horizontalArrangement = spacedBy(Spacing.Spacing4),
) {
when (tabStyle) {
TabStyle.IconAndLabel -> {
Icon(
modifier = Modifier.padding(Spacing.Spacing6),
imageVector = Icons.Filled.Circle,
contentDescription = "",
tint = VerticalTabsDefaults.textColor(tabColorStyle, selected),
)
iconImage?.let {
Icon(
modifier = Modifier.padding(Spacing.Spacing6),
imageVector = iconImage,
contentDescription = "",
tint = VerticalTabsDefaults.textColor(tabColorStyle, selected),
)
}
Text(
text = label,
color = VerticalTabsDefaults.textColor(tabColorStyle, selected),
Expand All @@ -140,12 +166,14 @@ internal fun VerticalTab(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center,
) {
Icon(
modifier = Modifier.padding(Spacing.Spacing6),
imageVector = Icons.Filled.Circle,
contentDescription = "",
tint = VerticalTabsDefaults.textColor(tabColorStyle, selected),
)
iconImage?.let {
Icon(
modifier = Modifier.padding(Spacing.Spacing6),
imageVector = iconImage,
contentDescription = "",
tint = VerticalTabsDefaults.textColor(tabColorStyle, selected),
)
}
}

TabStyle.LabelOnly ->
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
package org.hisp.dhis.mobile.ui.designsystem.component.model

import androidx.compose.ui.graphics.vector.ImageVector

data class Tab(
val id: String,
val label: String,
private val iconData: IconData? = null,
) {
fun icon(selected: Boolean) =
iconData?.selectedIcon?.takeIf { selected } ?: iconData?.defaultIcon
}

data class IconData(
val defaultIcon: ImageVector,
val selectedIcon: ImageVector?,
)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8805779

Please sign in to comment.