Add IconButton composable
This commit is contained in:
parent
185c5ec726
commit
7fe9c1dee8
7 changed files with 299 additions and 366 deletions
|
@ -23,17 +23,12 @@ fun HeaderIconButton(
|
|||
modifier: Modifier = Modifier,
|
||||
enabled: Boolean = true
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(icon),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(color),
|
||||
IconButton(
|
||||
icon = icon,
|
||||
color = color,
|
||||
onClick = onClick,
|
||||
enabled = enabled,
|
||||
modifier = modifier
|
||||
.clickable(
|
||||
indication = rememberRipple(bounded = false),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
enabled = enabled,
|
||||
onClick = onClick
|
||||
)
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
)
|
||||
|
@ -51,12 +46,13 @@ fun IconButton(
|
|||
painter = painterResource(icon),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(color),
|
||||
modifier = modifier
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
indication = rememberRipple(bounded = false),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
enabled = enabled,
|
||||
onClick = onClick
|
||||
)
|
||||
.then(modifier)
|
||||
)
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package it.vfsfitvnm.vimusic.ui.screens.album
|
|||
import android.content.Intent
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
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.BoxWithConstraints
|
||||
|
@ -21,9 +20,7 @@ import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import com.valentinilk.shimmer.shimmer
|
||||
|
@ -39,6 +36,7 @@ import it.vfsfitvnm.vimusic.savers.InnertubePlaylistOrAlbumPageSaver
|
|||
import it.vfsfitvnm.vimusic.savers.innertubeItemsPageSaver
|
||||
import it.vfsfitvnm.vimusic.savers.nullableSaver
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.HeaderIconButton
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.HeaderPlaceholder
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Scaffold
|
||||
import it.vfsfitvnm.vimusic.ui.items.AlbumItem
|
||||
|
@ -143,49 +141,39 @@ fun AlbumScreen(browseId: String) {
|
|||
.weight(1f)
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(
|
||||
if (album?.bookmarkedAt == null) {
|
||||
R.drawable.bookmark_outline
|
||||
} else {
|
||||
R.drawable.bookmark
|
||||
}
|
||||
),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.accent),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
val bookmarkedAt =
|
||||
if (album?.bookmarkedAt == null) System.currentTimeMillis() else null
|
||||
HeaderIconButton(
|
||||
icon = if (album?.bookmarkedAt == null) {
|
||||
R.drawable.bookmark_outline
|
||||
} else {
|
||||
R.drawable.bookmark
|
||||
},
|
||||
color = colorPalette.accent,
|
||||
onClick = {
|
||||
val bookmarkedAt =
|
||||
if (album?.bookmarkedAt == null) System.currentTimeMillis() else null
|
||||
|
||||
query {
|
||||
album
|
||||
?.copy(bookmarkedAt = bookmarkedAt)
|
||||
?.let(Database::update)
|
||||
}
|
||||
query {
|
||||
album
|
||||
?.copy(bookmarkedAt = bookmarkedAt)
|
||||
?.let(Database::update)
|
||||
}
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
}
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.share_social),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
album?.shareUrl?.let { url ->
|
||||
val sendIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, url)
|
||||
}
|
||||
|
||||
context.startActivity(Intent.createChooser(sendIntent, null))
|
||||
HeaderIconButton(
|
||||
icon = R.drawable.share_social,
|
||||
color = colorPalette.text,
|
||||
onClick = {
|
||||
album?.shareUrl?.let { url ->
|
||||
val sendIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, url)
|
||||
}
|
||||
|
||||
context.startActivity(Intent.createChooser(sendIntent, null))
|
||||
}
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,7 +3,6 @@ package it.vfsfitvnm.vimusic.ui.screens.artist
|
|||
import android.content.Intent
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
|
@ -21,9 +20,7 @@ import androidx.compose.runtime.saveable.rememberSaveableStateHolder
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import com.valentinilk.shimmer.shimmer
|
||||
|
@ -40,6 +37,7 @@ import it.vfsfitvnm.vimusic.savers.InnertubeSongsPageSaver
|
|||
import it.vfsfitvnm.vimusic.savers.nullableSaver
|
||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.HeaderIconButton
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.HeaderPlaceholder
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.NonQueuedMediaItemMenu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Scaffold
|
||||
|
@ -96,7 +94,11 @@ fun ArtistScreen(browseId: String) {
|
|||
stateSaver = nullableSaver(InnertubeArtistPageSaver),
|
||||
tabIndex < 4
|
||||
) {
|
||||
if (value != null || (tabIndex == 4 && withContext(Dispatchers.IO) { Database.artistTimestamp(browseId) } != null)) return@produceSaveableState
|
||||
if (value != null || (tabIndex == 4 && withContext(Dispatchers.IO) {
|
||||
Database.artistTimestamp(
|
||||
browseId
|
||||
)
|
||||
} != null)) return@produceSaveableState
|
||||
|
||||
withContext(Dispatchers.IO) {
|
||||
Innertube.artistPage(BrowseBody(browseId = browseId))
|
||||
|
@ -154,35 +156,33 @@ fun ArtistScreen(browseId: String) {
|
|||
}
|
||||
}
|
||||
|
||||
val headerContent: @Composable (textButton: (@Composable () -> Unit)?) -> Unit = { textButton ->
|
||||
if (artist?.timestamp == null) {
|
||||
HeaderPlaceholder(
|
||||
modifier = Modifier
|
||||
.shimmer()
|
||||
)
|
||||
} else {
|
||||
val context = LocalContext.current
|
||||
|
||||
Header(title = artist?.name ?: "Unknown") {
|
||||
textButton?.invoke()
|
||||
|
||||
Spacer(
|
||||
val headerContent: @Composable (textButton: (@Composable () -> Unit)?) -> Unit =
|
||||
{ textButton ->
|
||||
if (artist?.timestamp == null) {
|
||||
HeaderPlaceholder(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.shimmer()
|
||||
)
|
||||
} else {
|
||||
val (colorPalette) = LocalAppearance.current
|
||||
val context = LocalContext.current
|
||||
|
||||
Image(
|
||||
painter = painterResource(
|
||||
if (artist?.bookmarkedAt == null) {
|
||||
Header(title = artist?.name ?: "Unknown") {
|
||||
textButton?.invoke()
|
||||
|
||||
Spacer(
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
)
|
||||
|
||||
HeaderIconButton(
|
||||
icon = if (artist?.bookmarkedAt == null) {
|
||||
R.drawable.bookmark_outline
|
||||
} else {
|
||||
R.drawable.bookmark
|
||||
}
|
||||
),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(LocalAppearance.current.colorPalette.accent),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
},
|
||||
color = colorPalette.accent,
|
||||
onClick = {
|
||||
val bookmarkedAt =
|
||||
if (artist?.bookmarkedAt == null) System.currentTimeMillis() else null
|
||||
|
||||
|
@ -192,16 +192,12 @@ fun ArtistScreen(browseId: String) {
|
|||
?.let(Database::update)
|
||||
}
|
||||
}
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
)
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.share_social),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(LocalAppearance.current.colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
HeaderIconButton(
|
||||
icon = R.drawable.share_social,
|
||||
color = colorPalette.text,
|
||||
onClick = {
|
||||
val sendIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "text/plain"
|
||||
|
@ -211,19 +207,12 @@ fun ArtistScreen(browseId: String) {
|
|||
)
|
||||
}
|
||||
|
||||
context.startActivity(
|
||||
Intent.createChooser(
|
||||
sendIntent,
|
||||
null
|
||||
)
|
||||
)
|
||||
context.startActivity(Intent.createChooser(sendIntent, null))
|
||||
}
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Scaffold(
|
||||
topIconButtonId = R.drawable.chevron_back,
|
||||
|
@ -256,36 +245,36 @@ fun ArtistScreen(browseId: String) {
|
|||
val thumbnailSizeDp = Dimensions.thumbnails.song
|
||||
val thumbnailSizePx = thumbnailSizeDp.px
|
||||
|
||||
|
||||
|
||||
ItemsPage(
|
||||
stateSaver = InnertubeSongsPageSaver,
|
||||
headerContent = headerContent,
|
||||
itemsPageProvider = youtubeArtist?.let {({ continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicResponsiveListItemRenderer = Innertube.SongItem::from,
|
||||
)
|
||||
} ?: youtubeArtist
|
||||
?.songsEndpoint
|
||||
?.takeIf { it.browseId != null }
|
||||
?.let { endpoint ->
|
||||
itemsPageProvider = youtubeArtist?.let {
|
||||
({ continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(
|
||||
browseId = endpoint.browseId!!,
|
||||
params = endpoint.params,
|
||||
),
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicResponsiveListItemRenderer = Innertube.SongItem::from,
|
||||
)
|
||||
}
|
||||
?: Result.success(
|
||||
Innertube.ItemsPage(
|
||||
items = youtubeArtist?.songs,
|
||||
continuation = null
|
||||
} ?: youtubeArtist
|
||||
?.songsEndpoint
|
||||
?.takeIf { it.browseId != null }
|
||||
?.let { endpoint ->
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(
|
||||
browseId = endpoint.browseId!!,
|
||||
params = endpoint.params,
|
||||
),
|
||||
fromMusicResponsiveListItemRenderer = Innertube.SongItem::from,
|
||||
)
|
||||
}
|
||||
?: Result.success(
|
||||
Innertube.ItemsPage(
|
||||
items = youtubeArtist?.songs,
|
||||
continuation = null
|
||||
)
|
||||
)
|
||||
)
|
||||
})},
|
||||
})
|
||||
},
|
||||
itemContent = { song ->
|
||||
SongItem(
|
||||
song = song,
|
||||
|
@ -320,31 +309,33 @@ fun ArtistScreen(browseId: String) {
|
|||
stateSaver = InnertubeAlbumsPageSaver,
|
||||
headerContent = headerContent,
|
||||
emptyItemsText = "This artist didn't release any album",
|
||||
itemsPageProvider = youtubeArtist?.let {({ continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
} ?: youtubeArtist
|
||||
?.albumsEndpoint
|
||||
?.takeIf { it.browseId != null }
|
||||
?.let { endpoint ->
|
||||
itemsPageProvider = youtubeArtist?.let {
|
||||
({ continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(
|
||||
browseId = endpoint.browseId!!,
|
||||
params = endpoint.params,
|
||||
),
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
}
|
||||
?: Result.success(
|
||||
Innertube.ItemsPage(
|
||||
items = youtubeArtist?.albums,
|
||||
continuation = null
|
||||
} ?: youtubeArtist
|
||||
?.albumsEndpoint
|
||||
?.takeIf { it.browseId != null }
|
||||
?.let { endpoint ->
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(
|
||||
browseId = endpoint.browseId!!,
|
||||
params = endpoint.params,
|
||||
),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
}
|
||||
?: Result.success(
|
||||
Innertube.ItemsPage(
|
||||
items = youtubeArtist?.albums,
|
||||
continuation = null
|
||||
)
|
||||
)
|
||||
)
|
||||
})},
|
||||
})
|
||||
},
|
||||
itemContent = { album ->
|
||||
AlbumItem(
|
||||
album = album,
|
||||
|
@ -368,31 +359,33 @@ fun ArtistScreen(browseId: String) {
|
|||
stateSaver = InnertubeAlbumsPageSaver,
|
||||
headerContent = headerContent,
|
||||
emptyItemsText = "This artist didn't release any single",
|
||||
itemsPageProvider = youtubeArtist?.let {({ continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
} ?: youtubeArtist
|
||||
?.singlesEndpoint
|
||||
?.takeIf { it.browseId != null }
|
||||
?.let { endpoint ->
|
||||
itemsPageProvider = youtubeArtist?.let {
|
||||
({ continuation ->
|
||||
continuation?.let {
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(
|
||||
browseId = endpoint.browseId!!,
|
||||
params = endpoint.params,
|
||||
),
|
||||
body = ContinuationBody(continuation = continuation),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
}
|
||||
?: Result.success(
|
||||
Innertube.ItemsPage(
|
||||
items = youtubeArtist?.singles,
|
||||
continuation = null
|
||||
} ?: youtubeArtist
|
||||
?.singlesEndpoint
|
||||
?.takeIf { it.browseId != null }
|
||||
?.let { endpoint ->
|
||||
Innertube.itemsPage(
|
||||
body = BrowseBody(
|
||||
browseId = endpoint.browseId!!,
|
||||
params = endpoint.params,
|
||||
),
|
||||
fromMusicTwoRowItemRenderer = Innertube.AlbumItem::from,
|
||||
)
|
||||
}
|
||||
?: Result.success(
|
||||
Innertube.ItemsPage(
|
||||
items = youtubeArtist?.singles,
|
||||
continuation = null
|
||||
)
|
||||
)
|
||||
)
|
||||
})},
|
||||
})
|
||||
},
|
||||
itemContent = { album ->
|
||||
AlbumItem(
|
||||
album = album,
|
||||
|
|
|
@ -40,6 +40,7 @@ import it.vfsfitvnm.vimusic.transaction
|
|||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.ConfirmationDialog
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.HeaderIconButton
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.InPlaylistMediaItemMenu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.PrimaryButton
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.SecondaryTextButton
|
||||
|
@ -164,59 +165,46 @@ fun LocalPlaylistSongs(
|
|||
)
|
||||
|
||||
playlistWithSongs?.playlist?.browseId?.let { browseId ->
|
||||
Image(
|
||||
painter = painterResource(R.drawable.sync),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
transaction {
|
||||
runBlocking(Dispatchers.IO) {
|
||||
withContext(Dispatchers.IO) {
|
||||
Innertube.playlistPage(BrowseBody(browseId = browseId))?.completed()
|
||||
}
|
||||
}?.getOrNull()?.let { remotePlaylist ->
|
||||
Database.clearPlaylist(playlistId)
|
||||
|
||||
remotePlaylist.
|
||||
songsPage
|
||||
?.items
|
||||
?.map(Innertube.SongItem::asMediaItem)
|
||||
?.onEach(Database::insert)
|
||||
?.mapIndexed { position, mediaItem ->
|
||||
SongPlaylistMap(
|
||||
songId = mediaItem.mediaId,
|
||||
playlistId = playlistId,
|
||||
position = position
|
||||
)
|
||||
}?.let(Database::insertSongPlaylistMaps)
|
||||
HeaderIconButton(
|
||||
icon = R.drawable.sync,
|
||||
color = colorPalette.text,
|
||||
onClick = {
|
||||
transaction {
|
||||
runBlocking(Dispatchers.IO) {
|
||||
withContext(Dispatchers.IO) {
|
||||
Innertube.playlistPage(BrowseBody(browseId = browseId))?.completed()
|
||||
}
|
||||
}?.getOrNull()?.let { remotePlaylist ->
|
||||
Database.clearPlaylist(playlistId)
|
||||
|
||||
remotePlaylist.
|
||||
songsPage
|
||||
?.items
|
||||
?.map(Innertube.SongItem::asMediaItem)
|
||||
?.onEach(Database::insert)
|
||||
?.mapIndexed { position, mediaItem ->
|
||||
SongPlaylistMap(
|
||||
songId = mediaItem.mediaId,
|
||||
playlistId = playlistId,
|
||||
position = position
|
||||
)
|
||||
}?.let(Database::insertSongPlaylistMaps)
|
||||
}
|
||||
}
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.pencil),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable { isRenaming = true }
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
HeaderIconButton(
|
||||
icon = R.drawable.pencil,
|
||||
color = colorPalette.text,
|
||||
onClick = { isRenaming = true }
|
||||
)
|
||||
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.trash),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable { isDeleting = true }
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
HeaderIconButton(
|
||||
icon = R.drawable.trash,
|
||||
color = colorPalette.text,
|
||||
onClick = { isDeleting = true }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,7 @@ import it.vfsfitvnm.vimusic.ui.components.BottomSheet
|
|||
import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
|
||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||
import it.vfsfitvnm.vimusic.ui.components.MusicBars
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.IconButton
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.QueuedMediaItemMenu
|
||||
import it.vfsfitvnm.vimusic.ui.items.SongItem
|
||||
import it.vfsfitvnm.vimusic.ui.items.SongItemPlaceholder
|
||||
|
@ -227,7 +228,10 @@ fun PlayerBottomSheet(
|
|||
}
|
||||
)
|
||||
.animateItemPlacement(reorderingState = reorderingState)
|
||||
.draggedItem(reorderingState = reorderingState, index = window.firstPeriodIndex)
|
||||
.draggedItem(
|
||||
reorderingState = reorderingState,
|
||||
index = window.firstPeriodIndex
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -257,14 +261,13 @@ fun PlayerBottomSheet(
|
|||
.height(64.dp + bottomPadding)
|
||||
.background(colorPalette.background2)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 8.dp)
|
||||
.padding(horizontal = 12.dp)
|
||||
.padding(bottom = bottomPadding)
|
||||
) {
|
||||
BasicText(
|
||||
text = "${windows.size} songs",
|
||||
style = typography.xxs.medium,
|
||||
modifier = Modifier
|
||||
.padding(start = 4.dp)
|
||||
.background(color = colorPalette.background1, shape = RoundedCornerShape(16.dp))
|
||||
.align(Alignment.CenterStart)
|
||||
.padding(all = 8.dp)
|
||||
|
@ -279,22 +282,20 @@ fun PlayerBottomSheet(
|
|||
.size(18.dp)
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.shuffle),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.padding(end = 2.dp)
|
||||
.clickable {
|
||||
reorderingState.coroutineScope.launch {
|
||||
reorderingState.lazyListState.smoothScrollToTop()
|
||||
}.invokeOnCompletion {
|
||||
binder.player.shuffleQueue()
|
||||
}
|
||||
IconButton(
|
||||
icon = R.drawable.shuffle,
|
||||
color = colorPalette.text,
|
||||
onClick = {
|
||||
reorderingState.coroutineScope.launch {
|
||||
reorderingState.lazyListState.smoothScrollToTop()
|
||||
}.invokeOnCompletion {
|
||||
binder.player.shuffleQueue()
|
||||
}
|
||||
.align(Alignment.CenterEnd)
|
||||
.padding(all = 8.dp)
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
.align(Alignment.CenterEnd)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,7 @@ import androidx.activity.compose.LocalActivityResultRegistryOwner
|
|||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
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.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
|
@ -40,12 +38,10 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.media3.common.Player
|
||||
|
@ -58,6 +54,7 @@ import it.vfsfitvnm.vimusic.ui.components.BottomSheetState
|
|||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||
import it.vfsfitvnm.vimusic.ui.components.rememberBottomSheetState
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.BaseMediaItemMenu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.IconButton
|
||||
import it.vfsfitvnm.vimusic.ui.styling.Dimensions
|
||||
import it.vfsfitvnm.vimusic.ui.styling.LocalAppearance
|
||||
import it.vfsfitvnm.vimusic.ui.styling.collapsedPlayerProgressBar
|
||||
|
@ -178,44 +175,32 @@ fun PlayerView(
|
|||
modifier = Modifier
|
||||
.height(Dimensions.collapsedPlayer)
|
||||
) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
if (shouldBePlaying) {
|
||||
binder.player.pause()
|
||||
} else {
|
||||
if (binder.player.playbackState == Player.STATE_IDLE) {
|
||||
binder.player.prepare()
|
||||
}
|
||||
binder.player.play()
|
||||
IconButton(
|
||||
icon = if (shouldBePlaying) R.drawable.pause else R.drawable.play,
|
||||
color = colorPalette.text,
|
||||
onClick = {
|
||||
if (shouldBePlaying) {
|
||||
binder.player.pause()
|
||||
} else {
|
||||
if (binder.player.playbackState == Player.STATE_IDLE) {
|
||||
binder.player.prepare()
|
||||
}
|
||||
binder.player.play()
|
||||
}
|
||||
.padding(horizontal = 4.dp, vertical = 8.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(if (shouldBePlaying) R.drawable.pause else R.drawable.play),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(20.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Box(
|
||||
},
|
||||
modifier = Modifier
|
||||
.clickable(onClick = binder.player::seekToNext)
|
||||
.padding(horizontal = 4.dp, vertical = 8.dp)
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.play_skip_forward),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.align(Alignment.Center)
|
||||
.size(20.dp)
|
||||
)
|
||||
}
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
IconButton(
|
||||
icon = R.drawable.play_skip_forward,
|
||||
color = colorPalette.text,
|
||||
onClick = binder.player::seekToNext,
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Spacer(
|
||||
|
@ -335,65 +320,60 @@ fun PlayerView(
|
|||
.padding(horizontal = 8.dp)
|
||||
.fillMaxHeight()
|
||||
) {
|
||||
Image(
|
||||
painter = painterResource(R.drawable.ellipsis_horizontal),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
menuState.display {
|
||||
val resultRegistryOwner =
|
||||
LocalActivityResultRegistryOwner.current
|
||||
IconButton(
|
||||
icon = R.drawable.ellipsis_horizontal,
|
||||
color = colorPalette.text,
|
||||
onClick = {
|
||||
menuState.display {
|
||||
val resultRegistryOwner =
|
||||
LocalActivityResultRegistryOwner.current
|
||||
|
||||
BaseMediaItemMenu(
|
||||
mediaItem = mediaItem,
|
||||
onStartRadio = {
|
||||
binder.stopRadio()
|
||||
binder.player.seamlessPlay(mediaItem)
|
||||
binder.setupRadio(
|
||||
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId)
|
||||
)
|
||||
},
|
||||
onGoToEqualizer = {
|
||||
val intent =
|
||||
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply {
|
||||
putExtra(
|
||||
AudioEffect.EXTRA_AUDIO_SESSION,
|
||||
binder.player.audioSessionId
|
||||
)
|
||||
putExtra(
|
||||
AudioEffect.EXTRA_PACKAGE_NAME,
|
||||
context.packageName
|
||||
)
|
||||
putExtra(
|
||||
AudioEffect.EXTRA_CONTENT_TYPE,
|
||||
AudioEffect.CONTENT_TYPE_MUSIC
|
||||
)
|
||||
}
|
||||
|
||||
if (intent.resolveActivity(context.packageManager) != null) {
|
||||
val contract =
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
|
||||
resultRegistryOwner?.activityResultRegistry
|
||||
?.register("", contract) {}
|
||||
?.launch(intent)
|
||||
} else {
|
||||
Toast
|
||||
.makeText(
|
||||
context,
|
||||
"No equalizer app found!",
|
||||
Toast.LENGTH_SHORT
|
||||
)
|
||||
.show()
|
||||
BaseMediaItemMenu(
|
||||
mediaItem = mediaItem,
|
||||
onStartRadio = {
|
||||
binder.stopRadio()
|
||||
binder.player.seamlessPlay(mediaItem)
|
||||
binder.setupRadio(
|
||||
NavigationEndpoint.Endpoint.Watch(videoId = mediaItem.mediaId)
|
||||
)
|
||||
},
|
||||
onGoToEqualizer = {
|
||||
val intent =
|
||||
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL).apply {
|
||||
putExtra(
|
||||
AudioEffect.EXTRA_AUDIO_SESSION,
|
||||
binder.player.audioSessionId
|
||||
)
|
||||
putExtra(
|
||||
AudioEffect.EXTRA_PACKAGE_NAME,
|
||||
context.packageName
|
||||
)
|
||||
putExtra(
|
||||
AudioEffect.EXTRA_CONTENT_TYPE,
|
||||
AudioEffect.CONTENT_TYPE_MUSIC
|
||||
)
|
||||
}
|
||||
},
|
||||
onSetSleepTimer = {},
|
||||
onDismiss = menuState::hide
|
||||
)
|
||||
}
|
||||
|
||||
if (intent.resolveActivity(context.packageManager) != null) {
|
||||
val contract =
|
||||
ActivityResultContracts.StartActivityForResult()
|
||||
|
||||
resultRegistryOwner?.activityResultRegistry
|
||||
?.register("", contract) {}
|
||||
?.launch(intent)
|
||||
} else {
|
||||
Toast
|
||||
.makeText(context, "No equalizer app found!", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
},
|
||||
onSetSleepTimer = {},
|
||||
onDismiss = menuState::hide
|
||||
)
|
||||
}
|
||||
.padding(all = 8.dp)
|
||||
},
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 4.dp, vertical = 8.dp)
|
||||
.size(20.dp)
|
||||
)
|
||||
|
||||
|
|
|
@ -3,9 +3,7 @@ package it.vfsfitvnm.vimusic.ui.screens.playlist
|
|||
import android.content.Intent
|
||||
import androidx.compose.animation.ExperimentalAnimationApi
|
||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
|
@ -28,9 +26,7 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.ColorFilter
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import coil.compose.AsyncImage
|
||||
import com.valentinilk.shimmer.shimmer
|
||||
|
@ -45,6 +41,7 @@ import it.vfsfitvnm.vimusic.savers.resultSaver
|
|||
import it.vfsfitvnm.vimusic.transaction
|
||||
import it.vfsfitvnm.vimusic.ui.components.LocalMenuState
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.Header
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.HeaderIconButton
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.HeaderPlaceholder
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.NonQueuedMediaItemMenu
|
||||
import it.vfsfitvnm.vimusic.ui.components.themed.PrimaryButton
|
||||
|
@ -137,57 +134,47 @@ fun PlaylistSongList(
|
|||
.weight(1f)
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(
|
||||
if (isImported == true) R.drawable.bookmark else R.drawable.bookmark_outline
|
||||
),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.accent),
|
||||
modifier = Modifier
|
||||
.clickable(enabled = isImported == false) {
|
||||
transaction {
|
||||
val playlistId =
|
||||
Database.insert(
|
||||
Playlist(
|
||||
name = playlist.title ?: "Unknown",
|
||||
browseId = browseId
|
||||
)
|
||||
HeaderIconButton(
|
||||
icon = if (isImported == true) R.drawable.bookmark else R.drawable.bookmark_outline,
|
||||
color = colorPalette.accent,
|
||||
onClick = {
|
||||
transaction {
|
||||
val playlistId =
|
||||
Database.insert(
|
||||
Playlist(
|
||||
name = playlist.title ?: "Unknown",
|
||||
browseId = browseId
|
||||
)
|
||||
)
|
||||
|
||||
playlist.songsPage?.items
|
||||
?.map(Innertube.SongItem::asMediaItem)
|
||||
?.onEach(Database::insert)
|
||||
?.mapIndexed { index, mediaItem ->
|
||||
SongPlaylistMap(
|
||||
songId = mediaItem.mediaId,
|
||||
playlistId = playlistId,
|
||||
position = index
|
||||
)
|
||||
}?.let(Database::insertSongPlaylistMaps)
|
||||
}
|
||||
playlist.songsPage?.items
|
||||
?.map(Innertube.SongItem::asMediaItem)
|
||||
?.onEach(Database::insert)
|
||||
?.mapIndexed { index, mediaItem ->
|
||||
SongPlaylistMap(
|
||||
songId = mediaItem.mediaId,
|
||||
playlistId = playlistId,
|
||||
position = index
|
||||
)
|
||||
}?.let(Database::insertSongPlaylistMaps)
|
||||
}
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
}
|
||||
)
|
||||
|
||||
Image(
|
||||
painter = painterResource(R.drawable.share_social),
|
||||
contentDescription = null,
|
||||
colorFilter = ColorFilter.tint(colorPalette.text),
|
||||
modifier = Modifier
|
||||
.clickable {
|
||||
(playlist.url ?: "https://music.youtube.com/playlist?list=${browseId.removePrefix("VL")}").let { url ->
|
||||
val sendIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, url)
|
||||
}
|
||||
|
||||
context.startActivity(Intent.createChooser(sendIntent, null))
|
||||
HeaderIconButton(
|
||||
icon = R.drawable.share_social,
|
||||
color = colorPalette.text,
|
||||
onClick = {
|
||||
(playlist.url ?: "https://music.youtube.com/playlist?list=${browseId.removePrefix("VL")}").let { url ->
|
||||
val sendIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
type = "text/plain"
|
||||
putExtra(Intent.EXTRA_TEXT, url)
|
||||
}
|
||||
|
||||
context.startActivity(Intent.createChooser(sendIntent, null))
|
||||
}
|
||||
.padding(all = 4.dp)
|
||||
.size(18.dp)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue