Skip to content

Commit

Permalink
Merge pull request #511 from Shreyassp002/Feat-Mini-Music-Player
Browse files Browse the repository at this point in the history
Feat: Handle mini music player like spotify
  • Loading branch information
07jasjeet authored Dec 27, 2024
2 parents 1fa26e5 + 5f03c61 commit 82838d4
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 95 deletions.
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ dependencies {
implementation(libs.androidx.work.runtime.ktx)
implementation(libs.androidx.paging.runtime)
implementation(libs.androidx.paging.compose)
implementation(libs.androidx.palette.ktx)

//Room DB
implementation(libs.androidx.room.runtime)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
package org.listenbrainz.android.ui.components

import androidx.annotation.FloatRange
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectDragGestures
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.material.Slider
import androidx.compose.material.SliderDefaults
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.semantics.ProgressBarRangeInfo
import androidx.compose.ui.semantics.progressBarRangeInfo
import androidx.compose.ui.semantics.semantics
import androidx.compose.ui.unit.dp
import org.listenbrainz.android.R

@Composable
Expand All @@ -25,6 +38,61 @@ fun SeekBar(
thumbColor = colorResource(id = R.color.app_bg),
activeTrackColor = colorResource(id = R.color.bp_color_primary)
)

)
}
}

@Composable
fun CustomSeekBar(
modifier: Modifier = Modifier,
@FloatRange(from = 0.0, to = 1.0)
progress: Float,
onValueChange: (Float) -> Unit,
remainingProgressColor: Color = Color.Transparent
) {
val range = 0f..1f

Box(
modifier = modifier
.fillMaxWidth()
.semantics(mergeDescendants = true) {
progressBarRangeInfo = ProgressBarRangeInfo(progress, range)
}
.pointerInput(Unit) {
detectDragGestures(
onDragStart = { offset ->
val width = size.width.toFloat()
val newProgress = (offset.x / width).coerceIn(range)
onValueChange(newProgress)
},
onDrag = { change, _ ->
val width = size.width.toFloat()
val newProgress = (change.position.x / width).coerceIn(range)
onValueChange(newProgress)
}
)
}
.pointerInput(Unit) {
detectTapGestures { offset ->
val width = size.width.toFloat()
val newProgress = (offset.x / width).coerceIn(range)
onValueChange(newProgress)
}
}
) {
Box(
modifier = Modifier
.fillMaxWidth()
.height(4.dp)
.graphicsLayer {
alpha = 0.2f
}
.background(remainingProgressColor)
)
Box(
modifier = Modifier
.fillMaxWidth(progress)
.height(4.dp)
.background(colorResource(id = R.color.bp_color_primary))
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
Expand All @@ -76,6 +77,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.lerp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import androidx.lifecycle.viewmodel.compose.viewModel
import coil.compose.AsyncImage
import kotlinx.coroutines.launch
Expand All @@ -86,6 +88,7 @@ import org.listenbrainz.android.model.Playlist.Companion.recentlyPlayed
import org.listenbrainz.android.model.RepeatMode
import org.listenbrainz.android.model.Song
import org.listenbrainz.android.model.feed.FeedListenArtist
import org.listenbrainz.android.ui.components.CustomSeekBar
import org.listenbrainz.android.ui.components.ListenCardSmall
import org.listenbrainz.android.ui.components.PlayPauseIcon
import org.listenbrainz.android.ui.components.SeekBar
Expand All @@ -108,24 +111,24 @@ fun BrainzPlayerBackDropScreen(
paddingValues: PaddingValues,
backLayerContent: @Composable () -> Unit
) {
val isShuffled by brainzPlayerViewModel.isShuffled.collectAsState()
val isShuffled by brainzPlayerViewModel.isShuffled.collectAsStateWithLifecycle()
val currentlyPlayingSong =
brainzPlayerViewModel.currentlyPlayingSong.collectAsState().value.toSong
brainzPlayerViewModel.currentlyPlayingSong.collectAsStateWithLifecycle().value.toSong
var maxDelta by rememberSaveable {
mutableFloatStateOf(0F)
}
val repeatMode by brainzPlayerViewModel.repeatMode.collectAsState()
val repeatMode by brainzPlayerViewModel.repeatMode.collectAsStateWithLifecycle()

/** 56.dp is default bottom navigation height. 80.dp is our mini player's height. */
val headerHeight by animateDpAsState(targetValue = if (currentlyPlayingSong.title == "null" && currentlyPlayingSong.artist == "null") 56.dp else 136.dp)
/** 56.dp is default bottom navigation height. 70.dp is our mini player's height. */
val headerHeight by animateDpAsState(targetValue = if (currentlyPlayingSong.title == "null" && currentlyPlayingSong.artist == "null") 56.dp else 126.dp)
val isPlaying = brainzPlayerViewModel.isPlaying.collectAsState().value

BackdropScaffold(
modifier = Modifier.padding(top = paddingValues.calculateTopPadding()),
frontLayerShape = RectangleShape,
backLayerBackgroundColor = MaterialTheme.colorScheme.background,
frontLayerScrimColor = Color.Unspecified,
headerHeight = if (isPlaying) headerHeight else 56.dp, // 136.dp is optimal header height.
headerHeight = headerHeight, // 126.dp is optimal header height.
peekHeight = 0.dp,
scaffoldState = backdropScaffoldState,
backLayerContent = {
Expand Down Expand Up @@ -257,14 +260,17 @@ fun PlayerScreen(
item {
Box {
val progress by brainzPlayerViewModel.progress.collectAsState()
SeekBar(
CustomSeekBar(
modifier = Modifier
.height(10.dp)
.fillMaxWidth(0.98F)
.padding(horizontal = 20.dp),
progress = progress,
onValueChange = brainzPlayerViewModel::onSeek,
onValueChanged = brainzPlayerViewModel::onSeeked
onValueChange = { newProgress ->
brainzPlayerViewModel.onSeek(newProgress)
brainzPlayerViewModel.onSeeked()
},
remainingProgressColor = colorResource(id = R.color.bp_color_primary)
)
}
Row(
Expand Down Expand Up @@ -457,8 +463,7 @@ fun PlayerScreen(
) { index, song ->
val isChecked = checkedSongs.contains(song)
BoxWithConstraints {
val maxWidth =
(maxWidth - 70.dp)
val maxWidth = (this@BoxWithConstraints.maxWidth - 70.dp)
Row(
horizontalArrangement = Arrangement.Start,
verticalAlignment = Alignment.CenterVertically,
Expand Down Expand Up @@ -530,14 +535,6 @@ fun PlayerScreen(
Spacer(modifier = Modifier.height(56.dp))
}
}

// TODO: fix this
val cache = App.context?.let { CacheService<Song>(it, RECENTLY_PLAYED_KEY) }
cache?.saveData(currentlyPlayingSong, Song::class.java)
val data = cache?.getData(Song::class.java)
if (data != null) {
recentlyPlayed.items = data.filter { it.title != "null" }.toList().reversed()
}
}

@OptIn(ExperimentalFoundationApi::class)
Expand Down Expand Up @@ -624,3 +621,4 @@ fun BrainzPlayerBackDropScreenPreview() {
) {}
}


Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ fun BrainzPlayerScreen() {
topAlbums.add(Album())

Column(
modifier = Modifier
.fillMaxSize()
modifier = Modifier.fillMaxSize()
) {
Navigation(albums = albums, previewAlbums = topAlbums, artists = artists, previewArtists = topArtists, playlists, songsPlayedToday, songsPlayedThisWeek ,topRecents ,songs, albumSongsMap)
}
Expand All @@ -108,7 +107,8 @@ fun BrainzPlayerHomeScreen(
brainzPlayerViewModel.currentlyPlayingSong.collectAsState().value.toSong
val isPlaying = brainzPlayerViewModel.isPlaying
Column {
Row(modifier = Modifier
Row(
modifier = Modifier
.fillMaxWidth()
.horizontalScroll(rememberScrollState())
.background(
Expand All @@ -118,7 +118,8 @@ fun BrainzPlayerHomeScreen(
Color.Transparent
)
)
)) {
)
) {
Spacer(modifier = Modifier.width(ListenBrainzTheme.paddings.chipsHorizontal / 2))
repeat(5) { position ->
ElevatedSuggestionChip(
Expand Down
Loading

0 comments on commit 82838d4

Please sign in to comment.