@@ -3,6 +3,7 @@ package project.pipepipe.app.ui.component
33import android.annotation.SuppressLint
44import androidx.compose.foundation.layout.BoxWithConstraints
55import androidx.compose.foundation.layout.height
6+ import androidx.compose.material3.Icon
67import androidx.compose.material3.MaterialTheme
78import androidx.compose.material3.ScrollableTabRow
89import androidx.compose.material3.Tab
@@ -12,13 +13,16 @@ import androidx.compose.runtime.Composable
1213import androidx.compose.runtime.remember
1314import androidx.compose.runtime.rememberCoroutineScope
1415import androidx.compose.ui.Modifier
16+ import androidx.compose.ui.graphics.Color
17+ import androidx.compose.ui.graphics.vector.ImageVector
1518import androidx.compose.ui.platform.LocalDensity
1619import androidx.compose.ui.text.AnnotatedString
1720import androidx.compose.ui.text.rememberTextMeasurer
1821import androidx.compose.ui.text.style.TextOverflow
1922import androidx.compose.ui.unit.dp
2023import androidx.compose.ui.unit.sp
2124import kotlinx.coroutines.launch
25+ import project.pipepipe.app.ui.theme.onCustomTopBarColor
2226
2327
2428@SuppressLint(" UnusedBoxWithConstraintsScope" )
@@ -27,6 +31,8 @@ fun ResponsiveTabs(
2731 titles : List <String >,
2832 selectedIndex : Int ,
2933 modifier : Modifier = Modifier ,
34+ icons : List <ImageVector >? = null,
35+ containerColor : Color = MaterialTheme .colorScheme.surface,
3036 onTabSelected : (Int ) -> Unit ,
3137) {
3238 if (titles.isEmpty()) return
@@ -39,20 +45,28 @@ fun ResponsiveTabs(
3945 val textStyle = MaterialTheme .typography.labelLarge.copy(
4046 fontSize = 14 .sp
4147 )
42- val tabWidthsPx = remember(titles) {
43- titles.map { title ->
44- val textLayout = textMeasurer.measure(
45- text = AnnotatedString (title),
46- style = textStyle
47- )
48- val horizontalPaddingPx = with (density) { 32 .dp.roundToPx() }
49- textLayout.size.width + horizontalPaddingPx
48+ val tabWidthsPx = remember(titles, icons) {
49+ titles.mapIndexed { index, title ->
50+ val hasIcon = icons != null && index < icons.size
51+ val textLayout = if (title.isNotEmpty()) {
52+ textMeasurer.measure(
53+ text = AnnotatedString (title),
54+ style = textStyle
55+ )
56+ } else null
57+
58+ val textWidth = textLayout?.size?.width ? : 0
59+ val iconWidth = if (hasIcon) with (density) { 24 .dp.roundToPx() } else 0
60+ val horizontalPaddingPx = with (density) { 24 .dp.roundToPx() }
61+
62+ textWidth + iconWidth + horizontalPaddingPx
5063 }
5164 }
5265
53- val totalTabsWidthPx = tabWidthsPx.sum()
66+ val maxTabWidthPx = tabWidthsPx.maxOrNull() ? : 0
67+ val requiredWidthForFixedTabRow = maxTabWidthPx * titles.size
5468 val containerWidthPx = constraints.maxWidth
55- val shouldScroll = totalTabsWidthPx > containerWidthPx
69+ val shouldScroll = requiredWidthForFixedTabRow > containerWidthPx
5670
5771 val tabContent: @Composable () -> Unit = {
5872 titles.forEachIndexed { index, title ->
@@ -63,15 +77,27 @@ fun ResponsiveTabs(
6377 onTabSelected(index)
6478 }
6579 },
66- modifier = Modifier .height(44 .dp)
67- ) {
68- Text (
69- text = title,
70- maxLines = 1 ,
71- overflow = TextOverflow .Ellipsis ,
72- style = MaterialTheme .typography.labelLarge
73- )
74- }
80+ modifier = Modifier .height(44 .dp),
81+ icon = if (icons != null && index < icons.size) {
82+ {
83+ Icon (
84+ imageVector = icons[index],
85+ contentDescription = title.ifEmpty { null },
86+ tint = onCustomTopBarColor()
87+ )
88+ }
89+ } else null ,
90+ text = if (title.isNotEmpty()) {
91+ {
92+ Text (
93+ text = title,
94+ maxLines = 1 ,
95+ overflow = TextOverflow .Ellipsis ,
96+ style = MaterialTheme .typography.labelLarge
97+ )
98+ }
99+ } else null
100+ )
75101 }
76102 }
77103
@@ -80,12 +106,14 @@ fun ResponsiveTabs(
80106 selectedTabIndex = selectedIndex,
81107 modifier = modifier,
82108 edgePadding = 0 .dp,
109+ containerColor = containerColor,
83110 tabs = tabContent
84111 )
85112 } else {
86113 TabRow (
87114 selectedTabIndex = selectedIndex,
88115 modifier = modifier,
116+ containerColor = containerColor,
89117 tabs = tabContent
90118 )
91119 }
0 commit comments