Improve codebase
This commit is contained in:
parent
0372d8b406
commit
e6b5c68ad1
6 changed files with 993 additions and 1039 deletions
|
@ -0,0 +1,99 @@
|
|||
package it.vfsfitvnm.vimusic.ui.components.themed
|
||||
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.foundation.text.BasicText
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.unit.sp
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.utils.medium
|
||||
|
||||
|
||||
@Composable
|
||||
fun DropDownSection(content: @Composable ColumnScope.() -> Unit) {
|
||||
val (colorPalette) = LocalAppearance.current
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.shadow(
|
||||
elevation = 2.dp,
|
||||
shape = RoundedCornerShape(16.dp)
|
||||
)
|
||||
.background(colorPalette.elevatedBackground)
|
||||
.width(IntrinsicSize.Max),
|
||||
content = content
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DropDownSectionSpacer() {
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.height(4.dp)
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DropDownTextItem(
|
||||
text: String,
|
||||
isSelected: Boolean,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val (colorPalette) = LocalAppearance.current
|
||||
|
||||
DropDownTextItem(
|
||||
text = text,
|
||||
textColor = if (isSelected) {
|
||||
colorPalette.onPrimaryContainer
|
||||
} else {
|
||||
colorPalette.textSecondary
|
||||
},
|
||||
backgroundColor = if (isSelected) {
|
||||
colorPalette.primaryContainer
|
||||
} else {
|
||||
colorPalette.elevatedBackground
|
||||
},
|
||||
onClick = onClick
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun DropDownTextItem(
|
||||
text: String,
|
||||
backgroundColor: Color? = null,
|
||||
textColor: Color? = null,
|
||||
onClick: () -> Unit
|
||||
) {
|
||||
val (colorPalette, typography) = LocalAppearance.current
|
||||
|
||||
BasicText(
|
||||
text = text,
|
||||
style = typography.xxs.medium.copy(
|
||||
color = textColor ?: colorPalette.text,
|
||||
letterSpacing = 1.sp
|
||||
),
|
||||
modifier = Modifier
|
||||
.clip(RoundedCornerShape(16.dp))
|
||||
.clickable(
|
||||
indication = rememberRipple(bounded = true),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = onClick
|
||||
)
|
||||
.background(backgroundColor ?: colorPalette.elevatedBackground)
|
||||
.fillMaxWidth()
|
||||
.widthIn(min = 124.dp, max = 248.dp)
|
||||
.padding(
|
||||
horizontal = 16.dp,
|
||||
vertical = 8.dp
|
||||
)
|
||||
)
|
||||
}
|
File diff suppressed because it is too large
Load diff
219
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/AlbumsTab.kt
Normal file
219
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/AlbumsTab.kt
Normal file
|
@ -0,0 +1,219 @@
|
|||
package it.vfsfitvnm.vimusic.ui.views
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.text.BasicText
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import it.vfsfitvnm.vimusic.Database
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.enums.AlbumSortBy
|
||||
import it.vfsfitvnm.vimusic.enums.SortOrder
|
||||
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
||||
import it.vfsfitvnm.vimusic.models.Album
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropDownSection
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropDownSectionSpacer
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropDownTextItem
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropdownMenu
|
||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||
import it.vfsfitvnm.vimusic.utils.secondary
|
||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
|
||||
@ExperimentalFoundationApi
|
||||
@Composable
|
||||
fun AlbumsTab(
|
||||
onAlbumClicked: (Album) -> Unit
|
||||
) {
|
||||
val (colorPalette, typography) = LocalAppearance.current
|
||||
|
||||
var sortBy by rememberPreference("albumSortBy", AlbumSortBy.DateAdded)
|
||||
var sortOrder by rememberPreference("albumSortOrder", SortOrder.Descending)
|
||||
|
||||
val albums by remember(sortBy, sortOrder) {
|
||||
Database.albums(sortBy, sortOrder).distinctUntilChanged()
|
||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
||||
|
||||
val thumbnailSizePx = with(LocalDensity.current) { Dimensions.thumbnails.song.roundToPx() }
|
||||
|
||||
Box {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End,
|
||||
modifier = Modifier
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(
|
||||
colorPalette.background,
|
||||
Color.Transparent
|
||||
)
|
||||
)
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.zIndex(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Box {
|
||||
var isSortMenuDisplayed by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.sort),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
isSortMenuDisplayed = true
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
isDisplayed = isSortMenuDisplayed,
|
||||
onDismissRequest = {
|
||||
isSortMenuDisplayed = false
|
||||
}
|
||||
) {
|
||||
DropDownSection {
|
||||
DropDownTextItem(
|
||||
text = "NAME",
|
||||
isSelected = sortBy == AlbumSortBy.Title,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = AlbumSortBy.Title
|
||||
}
|
||||
)
|
||||
|
||||
DropDownTextItem(
|
||||
text = "YEAR",
|
||||
isSelected = sortBy == AlbumSortBy.Year,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = AlbumSortBy.Year
|
||||
}
|
||||
)
|
||||
|
||||
DropDownTextItem(
|
||||
text = "DATE ADDED",
|
||||
isSelected = sortBy == AlbumSortBy.DateAdded,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = AlbumSortBy.DateAdded
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
DropDownSectionSpacer()
|
||||
|
||||
DropDownSection {
|
||||
DropDownTextItem(
|
||||
text = when (sortOrder) {
|
||||
SortOrder.Ascending -> "ASCENDING"
|
||||
SortOrder.Descending -> "DESCENDING"
|
||||
},
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortOrder = !sortOrder
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(contentPadding = PaddingValues(top = 36.dp)) {
|
||||
items(
|
||||
items = albums,
|
||||
key = Album::id
|
||||
) { album ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
indication = rememberRipple(bounded = true),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { onAlbumClicked(album) }
|
||||
)
|
||||
.animateItemPlacement()
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp)
|
||||
.padding(start = 16.dp, end = 16.dp)
|
||||
) {
|
||||
SubcomposeAsyncImage(
|
||||
model = album.thumbnailUrl?.thumbnail(thumbnailSizePx),
|
||||
contentDescription = null,
|
||||
error = {
|
||||
Box {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.disc),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.textSecondary),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(36.dp)
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.clip(ThumbnailRoundness.shape)
|
||||
.size(Dimensions.thumbnails.song)
|
||||
)
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
) {
|
||||
BasicText(
|
||||
text = album.title ?: "Unknown",
|
||||
style = typography.xs.semiBold,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis
|
||||
)
|
||||
album.authorsText?.let {
|
||||
BasicText(
|
||||
text = album.authorsText,
|
||||
style = typography.xs.semiBold.secondary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
album.year?.let {
|
||||
BasicText(
|
||||
text = album.year,
|
||||
style = typography.xxs.secondary,
|
||||
maxLines = 1,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
189
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/ArtistsTab.kt
Normal file
189
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/ArtistsTab.kt
Normal file
|
@ -0,0 +1,189 @@
|
|||
package it.vfsfitvnm.vimusic.ui.views
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.BasicText
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import coil.compose.SubcomposeAsyncImage
|
||||
import it.vfsfitvnm.vimusic.Database
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.enums.ArtistSortBy
|
||||
import it.vfsfitvnm.vimusic.enums.SortOrder
|
||||
import it.vfsfitvnm.vimusic.models.Artist
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropDownSection
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropDownSectionSpacer
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropDownTextItem
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.DropdownMenu
|
||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||
import it.vfsfitvnm.vimusic.utils.semiBold
|
||||
import it.vfsfitvnm.vimusic.utils.thumbnail
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
|
||||
@ExperimentalFoundationApi
|
||||
@Composable
|
||||
fun ArtistsTab(
|
||||
onArtistClicked: (Artist) -> Unit
|
||||
) {
|
||||
val (colorPalette, typography) = LocalAppearance.current
|
||||
|
||||
var sortBy by rememberPreference("artistSortBy", ArtistSortBy.Name)
|
||||
var sortOrder by rememberPreference("artistSortOrder", SortOrder.Ascending)
|
||||
|
||||
val artists by remember(sortBy, sortOrder) {
|
||||
Database.artists(sortBy, sortOrder).distinctUntilChanged()
|
||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
||||
|
||||
val thumbnailSizePx = with(LocalDensity.current) { Dimensions.thumbnails.song.roundToPx() }
|
||||
|
||||
Box {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End,
|
||||
modifier = Modifier
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(
|
||||
colorPalette.background,
|
||||
Color.Transparent
|
||||
)
|
||||
)
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.zIndex(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Box {
|
||||
var isSortMenuDisplayed by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.sort),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
isSortMenuDisplayed = true
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
isDisplayed = isSortMenuDisplayed,
|
||||
onDismissRequest = {
|
||||
isSortMenuDisplayed = false
|
||||
}
|
||||
) {
|
||||
DropDownSection {
|
||||
DropDownTextItem(
|
||||
text = "NAME",
|
||||
isSelected = sortBy == ArtistSortBy.Name,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = ArtistSortBy.Name
|
||||
}
|
||||
)
|
||||
|
||||
DropDownTextItem(
|
||||
text = "DATE ADDED",
|
||||
isSelected = sortBy == ArtistSortBy.DateAdded,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = ArtistSortBy.DateAdded
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
DropDownSectionSpacer()
|
||||
|
||||
DropDownSection {
|
||||
DropDownTextItem(
|
||||
text = when (sortOrder) {
|
||||
SortOrder.Ascending -> "ASCENDING"
|
||||
SortOrder.Descending -> "DESCENDING"
|
||||
},
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortOrder = !sortOrder
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(contentPadding = PaddingValues(top = 36.dp)) {
|
||||
items(
|
||||
items = artists,
|
||||
key = Artist::id
|
||||
) { artist ->
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(12.dp),
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
indication = rememberRipple(bounded = true),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { onArtistClicked(artist) }
|
||||
)
|
||||
.animateItemPlacement()
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp)
|
||||
.padding(start = 16.dp, end = 16.dp)
|
||||
) {
|
||||
SubcomposeAsyncImage(
|
||||
model = artist.thumbnailUrl?.thumbnail(thumbnailSizePx),
|
||||
contentDescription = null,
|
||||
error = {
|
||||
Box {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.person),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.textSecondary),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(24.dp)
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.clip(CircleShape)
|
||||
.size(Dimensions.thumbnails.song)
|
||||
)
|
||||
|
||||
BasicText(
|
||||
text = artist.name,
|
||||
style = typography.xs.semiBold,
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
package it.vfsfitvnm.vimusic.ui.views
|
||||
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import it.vfsfitvnm.vimusic.Database
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.enums.BuiltInPlaylist
|
||||
import it.vfsfitvnm.vimusic.enums.PlaylistSortBy
|
||||
import it.vfsfitvnm.vimusic.enums.SortOrder
|
||||
import it.vfsfitvnm.vimusic.models.Playlist
|
||||
import it.vfsfitvnm.vimusic.query
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.utils.isCachedPlaylistShownKey
|
||||
import it.vfsfitvnm.vimusic.utils.rememberPreference
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
@ExperimentalFoundationApi
|
||||
@Composable
|
||||
fun PlaylistsTab(
|
||||
onBuiltInPlaylistClicked: (BuiltInPlaylist) -> Unit,
|
||||
onPlaylistClicked: (Playlist) -> Unit,
|
||||
) {
|
||||
val (colorPalette, typography) = LocalAppearance.current
|
||||
|
||||
val isCachedPlaylistShown by rememberPreference(isCachedPlaylistShownKey, false)
|
||||
var sortBy by rememberPreference("playlistSortBy", PlaylistSortBy.DateAdded)
|
||||
var sortOrder by rememberPreference("playlistSortOrder", SortOrder.Ascending)
|
||||
|
||||
val playlistPreviews by remember(sortBy, sortOrder) {
|
||||
Database.playlistPreviews(sortBy, sortOrder)
|
||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
||||
|
||||
var isCreatingANewPlaylist by rememberSaveable {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
if (isCreatingANewPlaylist) {
|
||||
TextFieldDialog(
|
||||
hintText = "Enter the playlist name",
|
||||
onDismiss = {
|
||||
isCreatingANewPlaylist = false
|
||||
},
|
||||
onDone = { text ->
|
||||
query {
|
||||
Database.insert(Playlist(name = text))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Box {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End,
|
||||
modifier = Modifier
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(
|
||||
colorPalette.background,
|
||||
Color.Transparent
|
||||
)
|
||||
)
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.zIndex(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.add),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
isCreatingANewPlaylist = true
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
Box {
|
||||
var isSortMenuDisplayed by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.sort),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
isSortMenuDisplayed = true
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
isDisplayed = isSortMenuDisplayed,
|
||||
onDismissRequest = {
|
||||
isSortMenuDisplayed = false
|
||||
}
|
||||
) {
|
||||
DropDownSection {
|
||||
DropDownTextItem(
|
||||
text = "NAME",
|
||||
isSelected = sortBy == PlaylistSortBy.Name,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = PlaylistSortBy.Name
|
||||
}
|
||||
)
|
||||
|
||||
DropDownTextItem(
|
||||
text = "DATE ADDED",
|
||||
isSelected = sortBy == PlaylistSortBy.DateAdded,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = PlaylistSortBy.DateAdded
|
||||
}
|
||||
)
|
||||
|
||||
DropDownTextItem(
|
||||
text = "SONG COUNT",
|
||||
isSelected = sortBy == PlaylistSortBy.SongCount,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = PlaylistSortBy.SongCount
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
DropDownSectionSpacer()
|
||||
|
||||
DropDownSection {
|
||||
DropDownTextItem(
|
||||
text = when (sortOrder) {
|
||||
SortOrder.Ascending -> "ASCENDING"
|
||||
SortOrder.Descending -> "DESCENDING"
|
||||
},
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortOrder = !sortOrder
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(contentPadding = PaddingValues(top = 36.dp)) {
|
||||
item(key = "favorites") {
|
||||
BuiltInPlaylistItem(
|
||||
icon = R.drawable.heart,
|
||||
colorTint = colorPalette.red,
|
||||
name = "Favorites",
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
indication = rememberRipple(bounded = true),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { onBuiltInPlaylistClicked(BuiltInPlaylist.Favorites) }
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
if (isCachedPlaylistShown) {
|
||||
item(key = "cached") {
|
||||
BuiltInPlaylistItem(
|
||||
icon = R.drawable.download,
|
||||
colorTint = colorPalette.blue,
|
||||
name = "Cached",
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
indication = rememberRipple(bounded = true),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { onBuiltInPlaylistClicked(BuiltInPlaylist.Cached) }
|
||||
)
|
||||
.animateItemPlacement()
|
||||
)
|
||||
}
|
||||
}
|
||||
items(
|
||||
items = playlistPreviews,
|
||||
key = { it.playlist.id }
|
||||
) { playlistPreview ->
|
||||
PlaylistPreviewItem(
|
||||
playlistPreview = playlistPreview,
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
indication = rememberRipple(bounded = true),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { onPlaylistClicked(playlistPreview.playlist) }
|
||||
)
|
||||
.animateItemPlacement()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
216
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/SongsTab.kt
Normal file
216
app/src/main/kotlin/it/vfsfitvnm/vimusic/ui/views/SongsTab.kt
Normal file
|
@ -0,0 +1,216 @@
|
|||
package it.vfsfitvnm.vimusic.ui.views
|
||||
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.foundation.text.BasicText
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.zIndex
|
||||
import it.vfsfitvnm.vimusic.Database
|
||||
import it.vfsfitvnm.vimusic.LocalPlayerServiceBinder
|
||||
import it.vfsfitvnm.vimusic.R
|
||||
import it.vfsfitvnm.vimusic.enums.SongSortBy
|
||||
import it.vfsfitvnm.vimusic.enums.SortOrder
|
||||
import it.vfsfitvnm.vimusic.enums.ThumbnailRoundness
|
||||
import it.vfsfitvnm.vimusic.models.DetailedSong
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.*
|
||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.ui.styling.px
|
||||
import it.vfsfitvnm.vimusic.utils.*
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
||||
@ExperimentalFoundationApi
|
||||
@ExperimentalAnimationApi
|
||||
@Composable
|
||||
fun SongsTab() {
|
||||
val (colorPalette, typography) = LocalAppearance.current
|
||||
|
||||
var sortBy by rememberPreference("songSortBy", SongSortBy.DateAdded)
|
||||
var sortOrder by rememberPreference("songSortOrder", SortOrder.Ascending)
|
||||
|
||||
val songs by remember(sortBy, sortOrder) {
|
||||
Database.songs(sortBy, sortOrder)
|
||||
}.collectAsState(initial = emptyList(), context = Dispatchers.IO)
|
||||
|
||||
Box {
|
||||
val binder = LocalPlayerServiceBinder.current
|
||||
val thumbnailSize = Dimensions.thumbnails.song.px
|
||||
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End,
|
||||
modifier = Modifier
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(
|
||||
colorPalette.background,
|
||||
Color.Transparent
|
||||
)
|
||||
)
|
||||
)
|
||||
.fillMaxWidth()
|
||||
.zIndex(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.shuffle),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable(enabled = songs.isNotEmpty()) {
|
||||
binder?.stopRadio()
|
||||
binder?.player?.forcePlayFromBeginning(
|
||||
songs
|
||||
.shuffled()
|
||||
.map(DetailedSong::asMediaItem)
|
||||
)
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
Box {
|
||||
var isSortMenuDisplayed by remember {
|
||||
mutableStateOf(false)
|
||||
}
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.sort),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
isSortMenuDisplayed = true
|
||||
}
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
DropdownMenu(
|
||||
isDisplayed = isSortMenuDisplayed,
|
||||
onDismissRequest = {
|
||||
isSortMenuDisplayed = false
|
||||
}
|
||||
) {
|
||||
DropDownSection {
|
||||
DropDownTextItem(
|
||||
text = "PLAY TIME",
|
||||
isSelected = sortBy == SongSortBy.PlayTime,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = SongSortBy.PlayTime
|
||||
}
|
||||
)
|
||||
|
||||
DropDownTextItem(
|
||||
text = "TITLE",
|
||||
isSelected = sortBy == SongSortBy.Title,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = SongSortBy.Title
|
||||
}
|
||||
)
|
||||
|
||||
DropDownTextItem(
|
||||
text = "DATE ADDED",
|
||||
isSelected = sortBy == SongSortBy.DateAdded,
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortBy = SongSortBy.DateAdded
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
DropDownSectionSpacer()
|
||||
|
||||
DropDownSection {
|
||||
DropDownTextItem(
|
||||
text = when (sortOrder) {
|
||||
SortOrder.Ascending -> "ASCENDING"
|
||||
SortOrder.Descending -> "DESCENDING"
|
||||
},
|
||||
onClick = {
|
||||
isSortMenuDisplayed = false
|
||||
sortOrder = !sortOrder
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyColumn(contentPadding = PaddingValues(top = 36.dp)) {
|
||||
itemsIndexed(
|
||||
items = songs,
|
||||
key = { _, song -> song.song.id }
|
||||
) { index, song ->
|
||||
SongItem(
|
||||
song = song,
|
||||
thumbnailSize = thumbnailSize,
|
||||
onClick = {
|
||||
binder?.stopRadio()
|
||||
binder?.player?.forcePlayAtIndex(
|
||||
songs.map(DetailedSong::asMediaItem),
|
||||
index
|
||||
)
|
||||
},
|
||||
menuContent = {
|
||||
InHistoryMediaItemMenu(song = song)
|
||||
},
|
||||
onThumbnailContent = {
|
||||
AnimatedVisibility(
|
||||
visible = sortBy == SongSortBy.PlayTime,
|
||||
enter = fadeIn(),
|
||||
exit = fadeOut(),
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
) {
|
||||
BasicText(
|
||||
text = song.song.formattedTotalPlayTime,
|
||||
style = typography.xxs.semiBold.center.color(
|
||||
Color.White
|
||||
),
|
||||
maxLines = 2,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
brush = Brush.verticalGradient(
|
||||
colors = listOf(
|
||||
Color.Transparent,
|
||||
Color.Black.copy(alpha = 0.75f)
|
||||
)
|
||||
),
|
||||
shape = ThumbnailRoundness.shape
|
||||
)
|
||||
.padding(
|
||||
horizontal = 8.dp,
|
||||
vertical = 4.dp
|
||||
)
|
||||
)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.animateItemPlacement()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue