Skip to content

Commit 8afbf26

Browse files
UI: update tab layout
1 parent 78d3814 commit 8afbf26

File tree

2 files changed

+56
-42
lines changed

2 files changed

+56
-42
lines changed

android/src/main/kotlin/project/pipepipe/app/ui/component/ResponsiveTabs.kt

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package project.pipepipe.app.ui.component
33
import android.annotation.SuppressLint
44
import androidx.compose.foundation.layout.BoxWithConstraints
55
import androidx.compose.foundation.layout.height
6+
import androidx.compose.material3.Icon
67
import androidx.compose.material3.MaterialTheme
78
import androidx.compose.material3.ScrollableTabRow
89
import androidx.compose.material3.Tab
@@ -12,13 +13,16 @@ import androidx.compose.runtime.Composable
1213
import androidx.compose.runtime.remember
1314
import androidx.compose.runtime.rememberCoroutineScope
1415
import androidx.compose.ui.Modifier
16+
import androidx.compose.ui.graphics.Color
17+
import androidx.compose.ui.graphics.vector.ImageVector
1518
import androidx.compose.ui.platform.LocalDensity
1619
import androidx.compose.ui.text.AnnotatedString
1720
import androidx.compose.ui.text.rememberTextMeasurer
1821
import androidx.compose.ui.text.style.TextOverflow
1922
import androidx.compose.ui.unit.dp
2023
import androidx.compose.ui.unit.sp
2124
import 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
}

android/src/main/kotlin/project/pipepipe/app/ui/screens/TabNavigationScreen.kt

Lines changed: 9 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,27 @@ import androidx.compose.foundation.pager.rememberPagerState
77
import androidx.compose.material.icons.Icons
88
import androidx.compose.material.icons.filled.Menu
99
import androidx.compose.material.icons.filled.Search
10-
import androidx.compose.material.icons.filled.Settings
1110
import androidx.compose.material3.*
12-
import androidx.core.view.GravityCompat
1311
import androidx.compose.runtime.*
1412
import androidx.compose.ui.Alignment
1513
import androidx.compose.ui.Modifier
1614
import androidx.compose.ui.text.font.FontWeight
1715
import androidx.compose.ui.unit.dp
1816
import androidx.compose.ui.unit.sp
17+
import androidx.core.view.GravityCompat
1918
import androidx.navigation.NavController
2019
import dev.icerock.moko.resources.compose.stringResource
2120
import kotlinx.coroutines.launch
2221
import kotlinx.serialization.json.Json
2322
import kotlinx.serialization.json.JsonArray
2423
import kotlinx.serialization.json.JsonObject
25-
import kotlinx.serialization.json.jsonObject
2624
import kotlinx.serialization.json.jsonPrimitive
2725
import project.pipepipe.app.LocalDrawerLayout
2826
import project.pipepipe.app.MR
2927
import project.pipepipe.app.SharedContext
3028
import project.pipepipe.app.helper.MainScreenTabDefaults
3129
import project.pipepipe.app.helper.MainScreenTabHelper
30+
import project.pipepipe.app.ui.component.ResponsiveTabs
3231
import project.pipepipe.app.ui.screens.playlistdetail.PlaylistDetailScreen
3332
import project.pipepipe.app.ui.theme.customTopBarColor
3433
import project.pipepipe.app.ui.theme.onCustomTopBarColor
@@ -129,28 +128,15 @@ fun TabNavigationScreen(navController: NavController) {
129128
}
130129
}
131130

132-
TabRow(
133-
selectedTabIndex = pagerState.currentPage,
131+
ResponsiveTabs(
132+
titles = List(tabConfigs.size) { "" },
133+
selectedIndex = pagerState.currentPage,
134134
modifier = Modifier.fillMaxWidth(),
135+
icons = tabConfigs.map { MainScreenTabHelper.getTabIcon(it) },
135136
containerColor = customTopBarColor()
136-
) {
137-
tabConfigs.forEachIndexed { index, route ->
138-
Tab(
139-
selected = pagerState.currentPage == index,
140-
onClick = {
141-
scope.launch {
142-
pagerState.animateScrollToPage(index)
143-
}
144-
},
145-
icon = {
146-
Icon(
147-
imageVector = MainScreenTabHelper.getTabIcon(route),
148-
contentDescription = MainScreenTabHelper.getTabDisplayName(route),
149-
modifier = Modifier.size(22.dp),
150-
tint = onCustomTopBarColor()
151-
)
152-
}
153-
)
137+
) { index ->
138+
scope.launch {
139+
pagerState.animateScrollToPage(index)
154140
}
155141
}
156142

0 commit comments

Comments
 (0)