Skip to content

Commit

Permalink
feat: playlist tabs list.
Browse files Browse the repository at this point in the history
  • Loading branch information
oxyroid committed May 17, 2024
1 parent dd77a10 commit 157458b
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,19 @@ package com.m3u.features.playlist.components

import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedContent
import androidx.compose.foundation.background
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyRow
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
Expand All @@ -28,6 +32,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
Expand All @@ -36,76 +41,138 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.hapticfeedback.HapticFeedbackType
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import com.m3u.material.components.IconButton
import com.m3u.material.ktx.thenIf
import com.m3u.material.model.LocalHazeState
import com.m3u.material.model.LocalSpacing
import dev.chrisbanes.haze.HazeDefaults
import dev.chrisbanes.haze.haze

@Composable
internal fun PlaylistTabRow(
selectedCategory: String,
categories: List<String>,
isExpanded: Boolean,
bottomContentPadding: PaddingValues,
onCategoryChanged: (String) -> Unit,
pinnedCategories: List<String>,
onPinOrUnpinCategory: (String) -> Unit,
onHideCategory: (String) -> Unit,
onExpanded: () -> Unit,
modifier: Modifier = Modifier
) {
val spacing = LocalSpacing.current
val hapticFeedback = LocalHapticFeedback.current
val state = rememberLazyListState()

Box(modifier) {
if (categories.size > 1) {
var focusCategory: String? by rememberSaveable { mutableStateOf(null) }
var focusCategory: String? by rememberSaveable { mutableStateOf(null) }
val header = @Composable {
AnimatedContent(
targetState = focusCategory,
label = "playlist-tab-row-action-buttons",
modifier = Modifier.background(MaterialTheme.colorScheme.surface)
) { name ->
Box(
modifier = Modifier.thenIf(isExpanded) {
Modifier.fillMaxWidth()
}
) {
if (name != null) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
) {
IconButton(
icon = Icons.Rounded.PushPin,
contentDescription = "pin",
onClick = {
name.let(onPinOrUnpinCategory)
focusCategory = null
}
)
IconButton(
icon = Icons.Rounded.VisibilityOff,
contentDescription = "hide",
onClick = {
name.let(onHideCategory)
focusCategory = null
}
)
}
} else {
IconButton(
icon = Icons.Rounded.Menu,
contentDescription = "",
onClick = onExpanded
)
}
}
}
}
LaunchedEffect(Unit) {
val index = categories.indexOf(selectedCategory)
if (index != -1) {
state.scrollToItem(index)
}
}
if (isExpanded) {
LazyColumn(
state = state,
horizontalAlignment = Alignment.Start,
verticalArrangement = Arrangement.spacedBy(spacing.extraSmall),
contentPadding = bottomContentPadding,
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colorScheme.surface)
.haze(
LocalHazeState.current,
HazeDefaults.style(MaterialTheme.colorScheme.surface)
)
) {
stickyHeader {
header()
HorizontalDivider()
}
items(categories) { category ->
PlaylistTabRowItem(
name = category,
selected = category == selectedCategory,
pinned = category in pinnedCategories,
focused = category == focusCategory,
hasOtherFocused = focusCategory != null && focusCategory != category,
onClick = {
if (focusCategory == null) {
onCategoryChanged(category)
}
},
onLongClick = {
focusCategory = category
onCategoryChanged(category)
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
},
modifier = Modifier.fillMaxWidth()
)
}
}
} else {
Column {
LazyRow(
state = state,
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(spacing.extraSmall),
modifier = Modifier.fillMaxWidth()
modifier = Modifier
.background(MaterialTheme.colorScheme.surface)
.fillMaxWidth()
) {
stickyHeader {
AnimatedContent(
targetState = focusCategory,
label = "playlist-tab-row-action-buttons"
) { name ->
if (name != null) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.End
) {
IconButton(
icon = Icons.Rounded.PushPin,
contentDescription = "pin",
onClick = {
name.let(onPinOrUnpinCategory)
focusCategory = null
}
)
IconButton(
icon = Icons.Rounded.VisibilityOff,
contentDescription = "hide",
onClick = {
name.let(onHideCategory)
focusCategory = null
}
)
}
} else {
IconButton(
icon = Icons.Rounded.Menu,
contentDescription = "",
onClick = { /*TODO*/ }
)
}
}
}
stickyHeader { header() }
items(categories) { category ->
PlaylistTabRowItem(
name = category,
Expand All @@ -128,9 +195,9 @@ internal fun PlaylistTabRow(
}
HorizontalDivider()
}
BackHandler(focusCategory != null) {
focusCategory = null
}
}
BackHandler(focusCategory != null) {
focusCategory = null
}
}
}
Expand Down Expand Up @@ -164,9 +231,9 @@ private fun PlaylistTabRowItem(
Card(
colors = CardDefaults.cardColors(
containerColor = if (focused) LocalContentColor.current
else Color.Transparent,
else MaterialTheme.colorScheme.surface,
contentColor = if (focused) MaterialTheme.colorScheme.surfaceVariant
else LocalContentColor.current
else MaterialTheme.colorScheme.onSurface
),
shape = shape,
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ internal fun SmartphoneStreamItem(
OutlinedCard(
modifier = Modifier.semantics(mergeDescendants = true) { },
border = CardDefaults.outlinedCardBorder(zapping),
colors = CardDefaults.cardColors(Color.Transparent),
colors = CardDefaults.cardColors(MaterialTheme.colorScheme.surfaceContainer),
shape = AbsoluteSmoothCornerShape(spacing.medium, 65)
) {
when {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import com.m3u.features.playlist.components.SmartphoneStreamGallery
import com.m3u.i18n.R.string
import com.m3u.material.components.TextField
import com.m3u.material.ktx.isAtTop
import com.m3u.material.ktx.only
import com.m3u.material.ktx.split
import com.m3u.material.model.LocalHazeState
import com.m3u.material.model.LocalSpacing
Expand Down Expand Up @@ -205,17 +206,24 @@ internal fun SmartphonePlaylistScreenImpl(
else -> rowCount
}
}
Column(
Modifier.background(MaterialTheme.colorScheme.background)
) {
var isExpanded by remember { mutableStateOf(false) }
BackHandler(isExpanded) { isExpanded = false }

val tabs = @Composable {
PlaylistTabRow(
selectedCategory = category,
categories = categories,
isExpanded = isExpanded,
bottomContentPadding = contentPadding only WindowInsetsSides.Bottom,
onExpanded = { isExpanded = !isExpanded },
onCategoryChanged = { category = it },
pinnedCategories = pinnedCategories,
onPinOrUnpinCategory = onPinOrUnpinCategory,
onHideCategory = onHideCategory
)
}

val gallery = @Composable {
val channel = channels.find { it.category == category }
SmartphoneStreamGallery(
state = state,
Expand All @@ -230,21 +238,35 @@ internal fun SmartphonePlaylistScreenImpl(
mediaSheetValue = MediaSheetValue.PlaylistScreen(it)
},
getProgrammeCurrently = getProgrammeCurrently,
modifier = modifier.haze(
modifier = Modifier.haze(
LocalHazeState.current,
HazeDefaults.style(MaterialTheme.colorScheme.surface)
)
)
}
Column(
Modifier.background(MaterialTheme.colorScheme.surfaceContainerHighest)
) {
if (!isExpanded) {
if (categories.size > 1) {
tabs()
}
gallery()
} else {
if (categories.size > 1) {
tabs()
}
}
}
},
backLayerBackgroundColor = Color.Transparent,
backLayerContentColor = currentContentColor,
frontLayerScrimColor = currentColor.copy(alpha = 0.45f),
frontLayerBackgroundColor = Color.Transparent,
modifier = Modifier
modifier = modifier
.padding(outer)
.nestedScroll(
connection = connection,
connection = connection
)
)

Expand Down

0 comments on commit 157458b

Please sign in to comment.