Skip to content

Commit e4d8bcb

Browse files
committed
feat: implement liquid glass effect in bottom navigation and mini player
1 parent f32749d commit e4d8bcb

13 files changed

Lines changed: 581 additions & 283 deletions

File tree

app/src/main/java/com/maxrave/simpmusic/extension/UIExt.kt

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import androidx.compose.ui.graphics.Color
4646
import androidx.compose.ui.graphics.ColorFilter
4747
import androidx.compose.ui.graphics.ColorMatrix
4848
import androidx.compose.ui.graphics.Paint
49+
import androidx.compose.ui.graphics.Shape
4950
import androidx.compose.ui.graphics.asImageBitmap
5051
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
5152
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
@@ -60,12 +61,18 @@ import androidx.compose.ui.platform.LocalResources
6061
import androidx.compose.ui.platform.LocalView
6162
import androidx.compose.ui.text.TextStyle
6263
import androidx.compose.ui.unit.IntSize
64+
import androidx.compose.ui.unit.dp
6365
import androidx.core.app.PictureInPictureModeChangedInfo
6466
import androidx.core.content.res.ResourcesCompat
6567
import androidx.core.graphics.ColorUtils
6668
import androidx.core.graphics.drawable.toBitmap
6769
import androidx.core.util.Consumer
6870
import com.kmpalette.palette.graphics.Palette
71+
import com.kyant.backdrop.Backdrop
72+
import com.kyant.backdrop.drawBackdrop
73+
import com.kyant.backdrop.effects.dispersion
74+
import com.kyant.backdrop.effects.refraction
75+
import com.kyant.backdrop.effects.saturation
6976
import com.maxrave.domain.data.model.ui.ScreenSizeInfo
7077
import com.maxrave.logger.Logger
7178
import com.maxrave.simpmusic.ui.theme.md_theme_dark_background
@@ -557,4 +564,29 @@ fun animateAlignmentAsState(targetAlignment: Alignment): State<Alignment> {
557564
val horizontal by animateFloatAsState(biased.horizontalBias)
558565
val vertical by animateFloatAsState(biased.verticalBias)
559566
return remember { derivedStateOf { BiasAlignment(horizontal, vertical) } }
560-
}
567+
}
568+
569+
fun Modifier.drawBackdropCustomShape(
570+
backdrop: Backdrop,
571+
shape: Shape,
572+
alpha: Float = 0.6f,
573+
): Modifier =
574+
this.drawBackdrop(
575+
backdrop = backdrop,
576+
shapeProvider = { shape },
577+
onDrawSurface = { drawRect(Color.Black.copy(alpha = alpha.coerceIn(0f, 1f))) },
578+
) {
579+
// saturation boost
580+
saturation()
581+
// blur
582+
// lens
583+
refraction(
584+
height = 24f.dp.toPx(),
585+
amount = 64f.dp.toPx(),
586+
hasDepthEffect = true,
587+
)
588+
dispersion(
589+
height = 12.dp.toPx(),
590+
amount = 24.dp.toPx(),
591+
)
592+
}

app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ import androidx.compose.ui.window.DialogProperties
5252
import androidx.core.net.toUri
5353
import androidx.core.os.LocaleListCompat
5454
import androidx.lifecycle.compose.collectAsStateWithLifecycle
55+
import androidx.navigation.NavDestination.Companion.hasRoute
5556
import androidx.navigation.compose.currentBackStackEntryAsState
5657
import androidx.navigation.compose.rememberNavController
5758
import com.kyant.backdrop.backdrop
@@ -68,10 +69,12 @@ import com.maxrave.domain.mediaservice.handler.MediaPlayerHandler
6869
import com.maxrave.logger.Logger
6970
import com.maxrave.simpmusic.di.viewModelModule
7071
import com.maxrave.simpmusic.ui.component.AppBottomNavigationBar
72+
import com.maxrave.simpmusic.ui.component.LiquidGlassAppBottomNavigationBar
7173
import com.maxrave.simpmusic.ui.navigation.destination.home.NotificationDestination
7274
import com.maxrave.simpmusic.ui.navigation.destination.list.AlbumDestination
7375
import com.maxrave.simpmusic.ui.navigation.destination.list.ArtistDestination
7476
import com.maxrave.simpmusic.ui.navigation.destination.list.PlaylistDestination
77+
import com.maxrave.simpmusic.ui.navigation.destination.search.SearchDestination
7578
import com.maxrave.simpmusic.ui.navigation.graph.AppNavigationGraph
7679
import com.maxrave.simpmusic.ui.screen.MiniPlayer
7780
import com.maxrave.simpmusic.ui.screen.player.NowPlayingScreen
@@ -238,11 +241,16 @@ class MainActivity : AppCompatActivity() {
238241
val intent by viewModel.intent.collectAsStateWithLifecycle()
239242

240243
val isTranslucentBottomBar by viewModel.getTranslucentBottomBar().collectAsStateWithLifecycle(DataStoreManager.FALSE)
244+
val isLiquidGlassEnabled by viewModel.getEnableLiquidGlass().collectAsStateWithLifecycle(DataStoreManager.FALSE)
241245
// MiniPlayer visibility logic
242246
var isShowMiniPlayer by rememberSaveable {
243247
mutableStateOf(true)
244248
}
245249

250+
var isInSearchPage by rememberSaveable {
251+
mutableStateOf(false)
252+
}
253+
246254
// Now playing screen
247255
var isShowNowPlaylistScreen by rememberSaveable {
248256
mutableStateOf(false)
@@ -349,6 +357,9 @@ class MainActivity : AppCompatActivity() {
349357
if (navBackStackEntry?.destination?.route?.contains("FullscreenDestination") == true) {
350358
isShowNowPlaylistScreen = false
351359
}
360+
navBackStackEntry?.destination?.let { current ->
361+
isInSearchPage = current.hasRoute(SearchDestination::class)
362+
}
352363
}
353364
val backdrop = rememberBackdrop()
354365
AppTheme {
@@ -361,7 +372,7 @@ class MainActivity : AppCompatActivity() {
361372
) {
362373
Column {
363374
AnimatedVisibility(
364-
isShowMiniPlayer,
375+
isShowMiniPlayer && (!isInSearchPage || isLiquidGlassEnabled == DataStoreManager.FALSE),
365376
enter = fadeIn() + slideInHorizontally(),
366377
exit = fadeOut(),
367378
) {
@@ -374,6 +385,7 @@ class MainActivity : AppCompatActivity() {
374385
).padding(
375386
bottom = 4.dp,
376387
),
388+
backdrop = backdrop,
377389
onClick = {
378390
isShowNowPlaylistScreen = true
379391
},
@@ -383,12 +395,23 @@ class MainActivity : AppCompatActivity() {
383395
},
384396
)
385397
}
386-
AppBottomNavigationBar(
387-
navController = navController,
388-
isTranslucentBackground = isTranslucentBottomBar == DataStoreManager.TRUE,
389-
backdrop = backdrop,
390-
) { klass ->
391-
viewModel.reloadDestination(klass)
398+
if (isLiquidGlassEnabled == DataStoreManager.TRUE) {
399+
LiquidGlassAppBottomNavigationBar(
400+
navController = navController,
401+
backdrop = backdrop,
402+
viewModel = viewModel,
403+
shouldShowMiniPlayer = isShowMiniPlayer,
404+
onOpenNowPlaying = { isShowNowPlaylistScreen = true },
405+
) { klass ->
406+
viewModel.reloadDestination(klass)
407+
}
408+
} else {
409+
AppBottomNavigationBar(
410+
navController = navController,
411+
isTranslucentBackground = isTranslucentBottomBar == DataStoreManager.TRUE,
412+
) { klass ->
413+
viewModel.reloadDestination(klass)
414+
}
392415
}
393416
}
394417
}

0 commit comments

Comments
 (0)