Skip to content

Commit

Permalink
Like artists and albums
Browse files Browse the repository at this point in the history
  • Loading branch information
siper committed Feb 2, 2025
1 parent 1b9530e commit bf21406
Show file tree
Hide file tree
Showing 24 changed files with 329 additions and 79 deletions.
8 changes: 8 additions & 0 deletions .idea/deploymentTargetSelector.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,14 @@ class SubsonicApi(

suspend fun unstarSong(vararg id: String) = api.unstar(id = id.asList())

suspend fun starAlbum(vararg id: String) = api.star(albumIds = id.asList())

suspend fun unstarAlbum(vararg id: String) = api.unstar(albumIds = id.asList())

suspend fun starArtist(vararg id: String) = api.star(artistIds = id.asList())

suspend fun unstarArtist(vararg id: String) = api.unstar(artistIds = id.asList())

suspend fun scrobble(
id: String,
time: Long? = null,
Expand Down
145 changes: 145 additions & 0 deletions core/ui/src/main/java/ru/stersh/youamp/core/ui/HeaderButtons.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
package ru.stersh.youamp.core.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Favorite
import androidx.compose.material.icons.rounded.FavoriteBorder
import androidx.compose.material.icons.rounded.PlayArrow
import androidx.compose.material.icons.rounded.Shuffle
import androidx.compose.material3.FilledTonalIconButton
import androidx.compose.material3.FilledTonalIconToggleButton
import androidx.compose.material3.Icon
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.Stable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp

@Composable
fun FavoriteButton(
isFavorite: Boolean,
onChange: (isFavorite: Boolean) -> Unit,
modifier: Modifier = Modifier
) {
val text = if (isFavorite) {
stringResource(R.string.dislike_title)
} else {
stringResource(R.string.like_title)
}
ButtonLayout(
button = {
FilledTonalIconToggleButton(
checked = isFavorite,
onCheckedChange = onChange,
modifier = modifier.size(ButtonSize)
) {
Icon(
imageVector = if (isFavorite) {
Icons.Rounded.Favorite
} else {
Icons.Rounded.FavoriteBorder
},
contentDescription = text
)
}
},
title = {
Text(
text = text,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center
)
},
modifier = modifier
)
}

@Composable
fun PlayAllButton(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
ButtonLayout(
button = {
FilledTonalIconButton(
onClick = onClick,
modifier = modifier.size(ButtonSize)
) {
Icon(
imageVector = Icons.Rounded.PlayArrow,
contentDescription = stringResource(R.string.play_all_title)
)
}
},
title = {
Text(
text = stringResource(R.string.play_all_title),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center
)
},
modifier = modifier
)
}

@Composable
fun PlayShuffledButton(
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
ButtonLayout(
button = {
FilledTonalIconButton(
onClick = onClick,
modifier = modifier.size(ButtonSize)
) {
Icon(
imageVector = Icons.Rounded.Shuffle,
contentDescription = stringResource(R.string.shuffle_title)
)
}
},
title = {
Text(
text = stringResource(R.string.shuffle_title),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center
)
},
modifier = modifier
)
}

@Stable
private val ButtonSize = 64.dp

@Composable
private fun ButtonLayout(
button: @Composable () -> Unit,
title: @Composable () -> Unit,
modifier: Modifier = Modifier
) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(8.dp),
modifier = modifier.width(72.dp)
) {
button()
CompositionLocalProvider(LocalTextStyle provides MaterialTheme.typography.labelSmall) {
title()
}
}
}
46 changes: 0 additions & 46 deletions core/ui/src/main/java/ru/stersh/youamp/core/ui/PlayButtons.kt

This file was deleted.

2 changes: 2 additions & 0 deletions core/ui/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@
<string name="error_title">Oops, something went wrong</string>
<string name="empty_state_title">There\'s nothing here yet…</string>
<string name="user_avatar_title">User avatar</string>
<string name="dislike_title">Dislike</string>
<string name="like_title">Like</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ package ru.stersh.youamp.feature.album

import org.koin.core.module.dsl.viewModel
import org.koin.dsl.module
import ru.stersh.youamp.feature.album.data.AlbumFavoriteRepositoryImpl
import ru.stersh.youamp.feature.album.data.AlbumInfoRepositoryImpl
import ru.stersh.youamp.feature.album.domain.AlbumFavoriteRepository
import ru.stersh.youamp.feature.album.domain.AlbumInfoRepository
import ru.stersh.youamp.feature.album.ui.AlbumInfoViewModel

val albumInfoModule = module {
single<AlbumInfoRepository> { AlbumInfoRepositoryImpl(get()) }
single<AlbumFavoriteRepository> { AlbumFavoriteRepositoryImpl(get()) }

viewModel { (id: String) ->
AlbumInfoViewModel(id, get(), get())
AlbumInfoViewModel(id, get(), get(), get())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package ru.stersh.youamp.feature.album.data

import ru.stersh.youamp.core.api.provider.ApiProvider
import ru.stersh.youamp.feature.album.domain.AlbumFavoriteRepository

internal class AlbumFavoriteRepositoryImpl(
private val apiProvider: ApiProvider
) : AlbumFavoriteRepository {

override suspend fun setFavorite(id: String, isFavorite: Boolean) {
val api = apiProvider.getApi()
if (isFavorite) {
api.starAlbum(id)
} else {
api.unstarAlbum(id)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package ru.stersh.youamp.feature.album.data

import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import ru.stersh.youamp.core.api.Album
import ru.stersh.youamp.core.api.Song
import ru.stersh.youamp.core.api.SubsonicApi
Expand All @@ -13,19 +15,27 @@ internal class AlbumInfoRepositoryImpl(
private val apiProvider: ApiProvider
) : AlbumInfoRepository {

override suspend fun getAlbumInfo(id: String): AlbumInfo {
override suspend fun getAlbumInfo(id: String): AlbumInfo = coroutineScope {
val api = apiProvider.getApi()
return api
.getAlbum(id)
.toDomain(api)
val starred = async { api.getStarred2() }
val albumInfo = async { api.getAlbum(id) }
val isFavorite = starred
.await()
.starred2Result
.album
?.any { it.id == id } == true
return@coroutineScope albumInfo
.await()
.toDomain(api, isFavorite)
}

private fun Album.toDomain(api: SubsonicApi): AlbumInfo {
private fun Album.toDomain(api: SubsonicApi, isFavorite: Boolean): AlbumInfo {
return AlbumInfo(
title = requireNotNull(name ?: album),
artist = artist,
year = year?.toString(),
artworkUrl = api.getCoverArtUrl(coverArt),
isFavorite = isFavorite,
songs = song
.orEmpty()
.map { it.toDomain() }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package ru.stersh.youamp.feature.album.domain

internal interface AlbumFavoriteRepository {

suspend fun setFavorite(id: String, isFavorite: Boolean)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ internal data class AlbumInfo(
val title: String,
val artist: String,
val year: String?,
val isFavorite: Boolean,
val songs: List<AlbumSong>
)
Loading

0 comments on commit bf21406

Please sign in to comment.