Skip to content

Commit 0f8ef92

Browse files
maxrave-devMinh Nguyen Duc Tuan
authored andcommitted
feat: Update UI components with new color themes and enhance navigation interactions
1 parent 11cc51a commit 0f8ef92

9 files changed

Lines changed: 288 additions & 135 deletions

File tree

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

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.maxrave.simpmusic.extension
22

3+
import androidx.compose.ui.graphics.lerp as colorLerp
34
import android.app.Activity
45
import android.content.Context
56
import android.content.ContextWrapper
@@ -25,6 +26,7 @@ import androidx.compose.foundation.layout.calculateStartPadding
2526
import androidx.compose.foundation.layout.fillMaxWidth
2627
import androidx.compose.foundation.lazy.LazyListItemInfo
2728
import androidx.compose.foundation.lazy.LazyListState
29+
import androidx.compose.foundation.lazy.grid.LazyGridState
2830
import androidx.compose.material3.ExperimentalMaterial3Api
2931
import androidx.compose.material3.SheetState
3032
import androidx.compose.material3.SheetValue
@@ -46,6 +48,7 @@ import androidx.compose.ui.BiasAlignment
4648
import androidx.compose.ui.Modifier
4749
import androidx.compose.ui.composed
4850
import androidx.compose.ui.draw.DrawModifier
51+
import androidx.compose.ui.draw.blur
4952
import androidx.compose.ui.draw.drawBehind
5053
import androidx.compose.ui.geometry.Offset
5154
import androidx.compose.ui.geometry.Rect
@@ -55,9 +58,11 @@ import androidx.compose.ui.graphics.ColorFilter
5558
import androidx.compose.ui.graphics.ColorMatrix
5659
import androidx.compose.ui.graphics.Paint
5760
import androidx.compose.ui.graphics.Shape
61+
import androidx.compose.ui.graphics.TransformOrigin
5862
import androidx.compose.ui.graphics.asImageBitmap
5963
import androidx.compose.ui.graphics.drawscope.ContentDrawScope
6064
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
65+
import androidx.compose.ui.graphics.layer.GraphicsLayer
6166
import androidx.compose.ui.graphics.painter.BitmapPainter
6267
import androidx.compose.ui.graphics.painter.Painter
6368
import androidx.compose.ui.layout.boundsInWindow
@@ -72,6 +77,7 @@ import androidx.compose.ui.text.TextStyle
7277
import androidx.compose.ui.unit.Dp
7378
import androidx.compose.ui.unit.IntSize
7479
import androidx.compose.ui.unit.dp
80+
import androidx.compose.ui.util.lerp
7581
import androidx.core.app.PictureInPictureModeChangedInfo
7682
import androidx.core.content.res.ResourcesCompat
7783
import androidx.core.graphics.ColorUtils
@@ -81,6 +87,8 @@ import com.kmpalette.palette.graphics.Palette
8187
import com.kyant.backdrop.Backdrop
8288
import com.kyant.backdrop.drawBackdrop
8389
import com.kyant.backdrop.effects.blur
90+
import com.kyant.backdrop.effects.colorControls
91+
import com.kyant.backdrop.effects.colorFilter
8492
import com.kyant.backdrop.effects.dispersion
8593
import com.kyant.backdrop.effects.refraction
8694
import com.kyant.backdrop.effects.saturation
@@ -97,6 +105,7 @@ import kotlin.math.cos
97105
import kotlin.math.hypot
98106
import kotlin.math.max
99107
import kotlin.math.min
108+
import kotlin.math.sign
100109
import kotlin.math.sin
101110
import kotlin.random.Random
102111

@@ -464,6 +473,37 @@ fun LazyListState.isScrollingUp(): Boolean {
464473
}.value
465474
}
466475

476+
@Composable
477+
fun LazyGridState.isScrollingUp(): State<Boolean> {
478+
var previousIndex by remember(this) { mutableIntStateOf(firstVisibleItemIndex) }
479+
var previousScrollOffset by remember(this) { mutableIntStateOf(firstVisibleItemScrollOffset) }
480+
481+
LaunchedEffect(Unit) {
482+
snapshotFlow { layoutInfo.totalItemsCount }.collect {
483+
Logger.w("isScrollingUp", "firstVisibleItemIndex: $firstVisibleItemIndex")
484+
previousIndex = firstVisibleItemIndex
485+
previousScrollOffset = firstVisibleItemScrollOffset
486+
}
487+
}
488+
489+
return remember(this) {
490+
derivedStateOf {
491+
if (firstVisibleItemIndex > 0) {
492+
if (previousIndex != firstVisibleItemIndex) {
493+
previousIndex > firstVisibleItemIndex
494+
} else {
495+
previousScrollOffset >= firstVisibleItemScrollOffset
496+
}.also {
497+
previousIndex = firstVisibleItemIndex
498+
previousScrollOffset = firstVisibleItemScrollOffset
499+
}
500+
} else {
501+
true
502+
}
503+
}
504+
}
505+
}
506+
467507
@Suppress("DEPRECATION")
468508
fun setStatusBarsColor(
469509
@ColorInt color: Int,
@@ -579,33 +619,35 @@ fun animateAlignmentAsState(targetAlignment: Alignment): State<Alignment> {
579619

580620
fun Modifier.drawBackdropCustomShape(
581621
backdrop: Backdrop,
622+
layer: GraphicsLayer,
623+
luminanceAnimation: Float,
582624
shape: Shape,
583-
alpha: Float = 0.3f,
584625
): Modifier =
585626
this.drawBackdrop(
586627
backdrop = backdrop,
587-
shapeProvider = { shape },
588-
onDrawSurface = {
589-
drawRect(
590-
Color.Black.copy(alpha = alpha.coerceIn(0f, 1f)),
628+
effects = {
629+
val l = (luminanceAnimation * 2f - 1f).let { sign(it) * it * it }
630+
colorControls(
631+
brightness =
632+
if (l > 0f) lerp(0.1f, 0.5f, l)
633+
else lerp(0.1f, -0.2f, -l),
634+
contrast =
635+
if (l > 0f) lerp(1f, 0f, l)
636+
else 1f,
637+
saturation = 1.5f
638+
)
639+
blur(
640+
if (l > 0f) lerp(8f.dp.toPx(), 16f.dp.toPx(), l)
641+
else lerp(8f.dp.toPx(), 2f.dp.toPx(), -l)
591642
)
643+
refraction(24f.dp.toPx(), size.minDimension / 2f, true)
592644
},
593-
) {
594-
// saturation boost
595-
saturation()
596-
// blur
597-
// lens
598-
refraction(
599-
height = 16f.dp.toPx(),
600-
amount = 84f.dp.toPx(),
601-
hasDepthEffect = true,
602-
)
603-
dispersion(
604-
height = 12.dp.toPx(),
605-
amount = 24.dp.toPx(),
606-
)
607-
blur(6.dp.toPx())
608-
}
645+
onDrawBackdrop = { drawBackdrop ->
646+
drawBackdrop()
647+
layer.record { drawBackdrop() }
648+
},
649+
shape = { shape },
650+
)
609651

610652
@Composable
611653
fun PaddingValues.copy(

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,10 @@ import androidx.activity.compose.setContent
1414
import androidx.activity.enableEdgeToEdge
1515
import androidx.appcompat.app.AppCompatActivity
1616
import androidx.appcompat.app.AppCompatDelegate
17+
import androidx.compose.animation.Animatable
1718
import androidx.compose.animation.AnimatedVisibility
19+
import androidx.compose.animation.core.Animatable
20+
import androidx.compose.animation.core.tween
1821
import androidx.compose.animation.fadeIn
1922
import androidx.compose.animation.fadeOut
2023
import androidx.compose.animation.slideInHorizontally
@@ -36,10 +39,13 @@ import androidx.compose.material3.TextButton
3639
import androidx.compose.runtime.LaunchedEffect
3740
import androidx.compose.runtime.getValue
3841
import androidx.compose.runtime.mutableStateOf
42+
import androidx.compose.runtime.remember
3943
import androidx.compose.runtime.saveable.rememberSaveable
4044
import androidx.compose.runtime.setValue
4145
import androidx.compose.ui.Modifier
4246
import androidx.compose.ui.graphics.Color
47+
import androidx.compose.ui.graphics.asAndroidBitmap
48+
import androidx.compose.ui.graphics.rememberGraphicsLayer
4349
import androidx.compose.ui.graphics.toArgb
4450
import androidx.compose.ui.res.stringResource
4551
import androidx.compose.ui.text.SpanStyle
@@ -49,13 +55,15 @@ import androidx.compose.ui.text.style.TextDecoration
4955
import androidx.compose.ui.unit.dp
5056
import androidx.compose.ui.unit.sp
5157
import androidx.compose.ui.window.DialogProperties
58+
import androidx.core.graphics.scale
5259
import androidx.core.net.toUri
5360
import androidx.core.os.LocaleListCompat
5461
import androidx.lifecycle.compose.collectAsStateWithLifecycle
5562
import androidx.navigation.compose.currentBackStackEntryAsState
5663
import androidx.navigation.compose.rememberNavController
5764
import com.kyant.backdrop.backdrop
58-
import com.kyant.backdrop.rememberBackdrop
65+
import com.kyant.backdrop.backdrops.layerBackdrop
66+
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
5967
import com.maxrave.common.FIRST_TIME_MIGRATION
6068
import com.maxrave.common.R
6169
import com.maxrave.common.SELECTED_LANGUAGE
@@ -83,10 +91,14 @@ import com.maxrave.simpmusic.utils.VersionManager
8391
import com.maxrave.simpmusic.viewModel.SharedViewModel
8492
import com.mikepenz.markdown.m3.Markdown
8593
import com.mikepenz.markdown.m3.markdownTypography
94+
import kotlinx.coroutines.Dispatchers
95+
import kotlinx.coroutines.launch
96+
import kotlinx.coroutines.withContext
8697
import org.koin.android.ext.android.inject
8798
import org.koin.core.context.loadKoinModules
8899
import org.koin.core.context.unloadKoinModules
89100
import pub.devrel.easypermissions.EasyPermissions
101+
import java.nio.IntBuffer
90102
import java.text.SimpleDateFormat
91103
import java.util.Locale
92104

@@ -356,7 +368,7 @@ class MainActivity : AppCompatActivity() {
356368
isShowNowPlaylistScreen = false
357369
}
358370
}
359-
val backdrop = rememberBackdrop()
371+
val backdrop = rememberLayerBackdrop()
360372
var isScrolledToTop by rememberSaveable {
361373
mutableStateOf(false)
362374
}
@@ -420,7 +432,7 @@ class MainActivity : AppCompatActivity() {
420432
.fillMaxSize()
421433
.then(
422434
if (isLiquidGlassEnabled == DataStoreManager.TRUE) {
423-
Modifier.backdrop(backdrop)
435+
Modifier.layerBackdrop(backdrop)
424436
} else {
425437
Modifier
426438
},

app/src/main/java/com/maxrave/simpmusic/ui/component/GridLibraryPlaylist.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,16 @@ import androidx.compose.foundation.shape.RoundedCornerShape
2323
import androidx.compose.material.icons.Icons
2424
import androidx.compose.material.icons.rounded.Add
2525
import androidx.compose.material3.Icon
26+
import androidx.compose.material3.OutlinedTextFieldDefaults.contentPadding
2627
import androidx.compose.material3.Text
2728
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
2829
import androidx.compose.material3.pulltorefresh.PullToRefreshDefaults
2930
import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
3031
import androidx.compose.runtime.Composable
3132
import androidx.compose.runtime.LaunchedEffect
33+
import androidx.compose.runtime.derivedStateOf
34+
import androidx.compose.runtime.getValue
35+
import androidx.compose.runtime.remember
3236
import androidx.compose.runtime.snapshotFlow
3337
import androidx.compose.ui.Alignment
3438
import androidx.compose.ui.Modifier
@@ -47,13 +51,15 @@ import com.maxrave.domain.data.type.PlaylistType
4751
import com.maxrave.domain.utils.LocalResource
4852
import com.maxrave.logger.Logger
4953
import com.maxrave.simpmusic.extension.angledGradientBackground
54+
import com.maxrave.simpmusic.extension.isScrollingUp
5055
import com.maxrave.simpmusic.ui.navigation.destination.list.AlbumDestination
5156
import com.maxrave.simpmusic.ui.navigation.destination.list.LocalPlaylistDestination
5257
import com.maxrave.simpmusic.ui.navigation.destination.list.PlaylistDestination
5358
import com.maxrave.simpmusic.ui.navigation.destination.list.PodcastDestination
5459
import com.maxrave.simpmusic.ui.theme.seed
5560
import com.maxrave.simpmusic.ui.theme.typo
5661
import com.maxrave.simpmusic.ui.theme.white
62+
import kotlinx.coroutines.flow.combine
5763

5864
@Composable
5965
inline fun <reified T> GridLibraryPlaylist(
@@ -66,10 +72,21 @@ inline fun <reified T> GridLibraryPlaylist(
6672
) {
6773
Logger.w("GridLibraryPlaylist", "Generic Type: ${T::class.java}")
6874
val state = rememberLazyGridState()
75+
val isScrollUp by state.isScrollingUp()
76+
77+
LaunchedEffect(isScrollUp) {
78+
if (state.firstVisibleItemIndex <= 1) {
79+
return@LaunchedEffect
80+
}
81+
onScrolling.invoke(isScrollUp)
82+
}
83+
6984
LaunchedEffect(state) {
7085
snapshotFlow { state.firstVisibleItemIndex }
7186
.collect {
72-
onScrolling.invoke(it <= 1)
87+
if (it <= 1) {
88+
onScrolling.invoke(true)
89+
}
7390
}
7491
}
7592
val pullToRefreshState = rememberPullToRefreshState()

0 commit comments

Comments
 (0)