feat: implement haze effect and UI enhancements in AppLargePlayer and AppShell

This commit is contained in:
Kingkor Roy Tirtho 2026-07-20 13:22:14 +06:00
parent 12dea49c2c
commit edc7cdd3fa
2 changed files with 222 additions and 184 deletions

View File

@ -18,18 +18,23 @@
package dev.krtirtho.spotube.modules.shell package dev.krtirtho.spotube.modules.shell
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.navigationBars
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.layout.windowInsetsPadding
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
@ -45,9 +50,14 @@ import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.blur.HazeColorEffect
import dev.chrisbanes.haze.blur.blurEffect
import dev.chrisbanes.haze.hazeEffect
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil3.compose.AsyncImage import coil3.compose.AsyncImage
import dev.krtirtho.spotube.core.audioplayer.AudioPlayer import dev.krtirtho.spotube.core.audioplayer.AudioPlayer
@ -100,6 +110,7 @@ import kotlin.time.Duration.Companion.milliseconds
@Composable @Composable
fun AppLargePlayer( fun AppLargePlayer(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
hazeState: HazeState,
onQueue: () -> Unit = {}, onQueue: () -> Unit = {},
onAlternativeSource: () -> Unit = {}, onAlternativeSource: () -> Unit = {},
onMoreOptions: () -> Unit = {}, onMoreOptions: () -> Unit = {},
@ -171,10 +182,30 @@ fun AppLargePlayer(
} }
} }
val surfaceTint = MaterialTheme.colorScheme.surface.copy(alpha = 0.85f)
Surface( Surface(
modifier = modifier.fillMaxWidth(), modifier = modifier
tonalElevation = 0.dp, .windowInsetsPadding(WindowInsets.navigationBars),
shadowElevation = 0.dp color = Color.Transparent,
shadowElevation = 0.dp,
) {
HorizontalDivider(
modifier = Modifier.fillMaxWidth(),
color = Color.Gray,
thickness = 1.dp,
)
Box(
modifier = Modifier
.fillMaxWidth()
.hazeEffect(state = hazeState) {
blurEffect {
blurRadius = 20.dp
colorEffects = listOf(
HazeColorEffect.tint(surfaceTint)
)
}
}
) { ) {
Row( Row(
modifier = Modifier modifier = Modifier
@ -379,5 +410,6 @@ fun AppLargePlayer(
} }
} }
} }
}
} }

View File

@ -39,6 +39,7 @@ import androidx.compose.material3.BottomSheetScaffold
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.SheetValue import androidx.compose.material3.SheetValue
import androidx.compose.material3.Text
import androidx.compose.material3.VerticalDivider import androidx.compose.material3.VerticalDivider
import androidx.compose.material3.rememberBottomSheetScaffoldState import androidx.compose.material3.rememberBottomSheetScaffoldState
import androidx.compose.material3.rememberStandardBottomSheetState import androidx.compose.material3.rememberStandardBottomSheetState
@ -57,6 +58,8 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.rememberHazeState
import androidx.compose.ui.window.Dialog import androidx.compose.ui.window.Dialog
import androidx.compose.ui.window.DialogProperties import androidx.compose.ui.window.DialogProperties
import dev.krtirtho.spotube.core.navigation.NavigationCommands import dev.krtirtho.spotube.core.navigation.NavigationCommands
@ -116,8 +119,13 @@ fun AppShell(
CompositionLocalProvider(LocalAppShellBottomInset provides bottomOverlayInset) { CompositionLocalProvider(LocalAppShellBottomInset provides bottomOverlayInset) {
if (useSidebar) { if (useSidebar) {
Column(modifier = Modifier.fillMaxSize()) { val hazeState = rememberHazeState()
Box(modifier = Modifier.fillMaxSize().weight(1f)) { Box(modifier = Modifier.fillMaxSize()) {
Box(
modifier = Modifier
.fillMaxSize()
.hazeSource(hazeState)
) {
Row(modifier = Modifier.fillMaxSize()) { Row(modifier = Modifier.fillMaxSize()) {
AppSidebar( AppSidebar(
navigator = navigator, navigationState = navigationState navigator = navigator, navigationState = navigationState
@ -174,13 +182,11 @@ fun AppShell(
) )
} }
} }
HorizontalDivider(
modifier = Modifier.fillMaxWidth(),
color = Color.Gray.copy(alpha = 0.2f),
thickness = 1.dp,
)
AppLargePlayer( AppLargePlayer(
modifier = Modifier.fillMaxWidth(), hazeState = hazeState,
modifier = Modifier
.fillMaxWidth()
.align(Alignment.BottomCenter),
onQueue = queueViewModel::toggleQueueVisibility, onQueue = queueViewModel::toggleQueueVisibility,
onAlternativeSource = alternativeViewModel::toggleAlternativeVisibility, onAlternativeSource = alternativeViewModel::toggleAlternativeVisibility,
onLyrics = { navigatorCommands.navigateTo(Routes.Lyrics) }, onLyrics = { navigatorCommands.navigateTo(Routes.Lyrics) },