mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-11 07:29:14 +01:00
home: paginate the offline lists and add More to each downloaded section
This commit is contained in:
@@ -727,6 +727,15 @@ interface LibraryDao {
|
|||||||
)
|
)
|
||||||
suspend fun downloadedSongIds(sourceId: Long): List<String>
|
suspend fun downloadedSongIds(sourceId: Long): List<String>
|
||||||
|
|
||||||
|
@Query(
|
||||||
|
"SELECT songs.*, albums.coverArt AS coverArt FROM songs " +
|
||||||
|
"LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " +
|
||||||
|
"JOIN song_downloads d ON d.sourceId = songs.sourceId AND d.songId = songs.id " +
|
||||||
|
"WHERE songs.sourceId = :sourceId AND d.status = 'Completed' " +
|
||||||
|
"ORDER BY songs.title COLLATE NOCASE, songs.id",
|
||||||
|
)
|
||||||
|
fun homeDownloadedSongs(sourceId: Long): PagingSource<Int, AlbumSongItem>
|
||||||
|
|
||||||
@Query(
|
@Query(
|
||||||
"SELECT songs.*, albums.coverArt AS coverArt FROM songs " +
|
"SELECT songs.*, albums.coverArt AS coverArt FROM songs " +
|
||||||
"LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " +
|
"LEFT JOIN albums ON albums.sourceId = songs.sourceId AND albums.id = songs.albumId " +
|
||||||
|
|||||||
@@ -94,6 +94,8 @@ class LibraryRepository(
|
|||||||
|
|
||||||
suspend fun downloadedSongIds(sourceId: Long): List<String> = db.libraryDao().downloadedSongIds(sourceId)
|
suspend fun downloadedSongIds(sourceId: Long): List<String> = db.libraryDao().downloadedSongIds(sourceId)
|
||||||
|
|
||||||
|
fun downloadedSongsPage(sourceId: Long): Flow<PagingData<AlbumSongItem>> = pager(60) { db.libraryDao().homeDownloadedSongs(sourceId) }
|
||||||
|
|
||||||
fun songsByGenre(
|
fun songsByGenre(
|
||||||
sourceId: Long,
|
sourceId: Long,
|
||||||
genre: String,
|
genre: String,
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ import com.subtracks.ui.downloads.DownloadsRoute
|
|||||||
import com.subtracks.ui.home.HomeListRequest
|
import com.subtracks.ui.home.HomeListRequest
|
||||||
import com.subtracks.ui.home.HomeListRoute
|
import com.subtracks.ui.home.HomeListRoute
|
||||||
import com.subtracks.ui.home.HomeSection
|
import com.subtracks.ui.home.HomeSection
|
||||||
|
import com.subtracks.ui.home.OfflineListKind
|
||||||
import com.subtracks.ui.library.AlbumDetailRoute
|
import com.subtracks.ui.library.AlbumDetailRoute
|
||||||
import com.subtracks.ui.library.ArtistDetailRoute
|
import com.subtracks.ui.library.ArtistDetailRoute
|
||||||
import com.subtracks.ui.library.LibraryRoute
|
import com.subtracks.ui.library.LibraryRoute
|
||||||
@@ -123,6 +124,7 @@ private object Routes {
|
|||||||
const val HOME_SECTION = "home/more/{section}"
|
const val HOME_SECTION = "home/more/{section}"
|
||||||
const val HOME_GENRE = "home/genre/{genre}"
|
const val HOME_GENRE = "home/genre/{genre}"
|
||||||
const val HOME_DECADE = "home/decade/{decade}"
|
const val HOME_DECADE = "home/decade/{decade}"
|
||||||
|
const val HOME_DOWNLOADED = "home/downloaded/{kind}"
|
||||||
|
|
||||||
fun album(
|
fun album(
|
||||||
id: String,
|
id: String,
|
||||||
@@ -143,6 +145,8 @@ private object Routes {
|
|||||||
fun homeGenre(genre: String) = "home/genre/${Uri.encode(genre)}"
|
fun homeGenre(genre: String) = "home/genre/${Uri.encode(genre)}"
|
||||||
|
|
||||||
fun homeDecade(decade: Long) = "home/decade/$decade"
|
fun homeDecade(decade: Long) = "home/decade/$decade"
|
||||||
|
|
||||||
|
fun homeDownloaded(kind: OfflineListKind) = "home/downloaded/${kind.name}"
|
||||||
}
|
}
|
||||||
|
|
||||||
private val DETAIL_ROUTES =
|
private val DETAIL_ROUTES =
|
||||||
@@ -364,6 +368,7 @@ private fun MainNavigation() {
|
|||||||
navigateDetail(Routes.ARTIST_DETAIL, "artistId", artistId, Routes.artist(artistId))
|
navigateDetail(Routes.ARTIST_DETAIL, "artistId", artistId, Routes.artist(artistId))
|
||||||
},
|
},
|
||||||
onHomeMore = { section -> navController.navigate(Routes.homeSection(section)) },
|
onHomeMore = { section -> navController.navigate(Routes.homeSection(section)) },
|
||||||
|
onHomeDownloaded = { kind -> navController.navigate(Routes.homeDownloaded(kind)) },
|
||||||
onGenreClick = { genre -> navController.navigate(Routes.homeGenre(genre)) },
|
onGenreClick = { genre -> navController.navigate(Routes.homeGenre(genre)) },
|
||||||
onDecadeClick = { decade -> navController.navigate(Routes.homeDecade(decade)) },
|
onDecadeClick = { decade -> navController.navigate(Routes.homeDecade(decade)) },
|
||||||
contextMenuHost = contextMenuHost,
|
contextMenuHost = contextMenuHost,
|
||||||
@@ -526,6 +531,35 @@ private fun MainNavigation() {
|
|||||||
setStar = libraryRepository::star,
|
setStar = libraryRepository::star,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
composable(
|
||||||
|
route = Routes.HOME_DOWNLOADED,
|
||||||
|
arguments = listOf(navArgument("kind") { type = NavType.StringType }),
|
||||||
|
) { entry ->
|
||||||
|
val kind =
|
||||||
|
OfflineListKind.entries.firstOrNull { it.name == entry.arguments?.getString("kind") }
|
||||||
|
?: return@composable
|
||||||
|
HomeListRoute(
|
||||||
|
request = HomeListRequest(title = kind.title, downloaded = kind),
|
||||||
|
onBack = { navController.popBackStack() },
|
||||||
|
onAlbumClick = { album ->
|
||||||
|
navigateDetail(Routes.ALBUM_DETAIL, "albumId", album.id, Routes.album(album.id, album.coverArt))
|
||||||
|
},
|
||||||
|
onArtistClick = { artist ->
|
||||||
|
navigateDetail(Routes.ARTIST_DETAIL, "artistId", artist.id, Routes.artist(artist.id, artist.coverArt))
|
||||||
|
},
|
||||||
|
onPlaylistClick = { playlist ->
|
||||||
|
navigateDetail(Routes.PLAYLIST_DETAIL, "playlistId", playlist.id, Routes.playlist(playlist.id))
|
||||||
|
},
|
||||||
|
onViewAlbum = { albumId -> navigateDetail(Routes.ALBUM_DETAIL, "albumId", albumId, Routes.album(albumId)) },
|
||||||
|
onViewArtist = { artistId ->
|
||||||
|
navigateDetail(Routes.ARTIST_DETAIL, "artistId", artistId, Routes.artist(artistId))
|
||||||
|
},
|
||||||
|
onGenreClick = { genre -> navController.navigate(Routes.homeGenre(genre)) },
|
||||||
|
onDecadeClick = { decade -> navController.navigate(Routes.homeDecade(decade)) },
|
||||||
|
contextMenuHost = contextMenuHost,
|
||||||
|
setStar = libraryRepository::star,
|
||||||
|
)
|
||||||
|
}
|
||||||
composable(Routes.ADD_SERVER) {
|
composable(Routes.ADD_SERVER) {
|
||||||
AddSourceRoute(
|
AddSourceRoute(
|
||||||
onSaved = { navController.popBackStack() },
|
onSaved = { navController.popBackStack() },
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import com.subtracks.data.model.Album
|
|||||||
import com.subtracks.data.model.AlbumSongItem
|
import com.subtracks.data.model.AlbumSongItem
|
||||||
import com.subtracks.data.model.Artist
|
import com.subtracks.data.model.Artist
|
||||||
import com.subtracks.data.model.CoverArtRef
|
import com.subtracks.data.model.CoverArtRef
|
||||||
|
import com.subtracks.data.model.Playlist
|
||||||
import com.subtracks.data.model.Song
|
import com.subtracks.data.model.Song
|
||||||
import com.subtracks.data.source.StarType
|
import com.subtracks.data.source.StarType
|
||||||
import com.subtracks.playback.PlaybackController
|
import com.subtracks.playback.PlaybackController
|
||||||
@@ -53,6 +54,7 @@ import com.subtracks.ui.components.CoverArt
|
|||||||
import com.subtracks.ui.components.ItemActions
|
import com.subtracks.ui.components.ItemActions
|
||||||
import com.subtracks.ui.components.LoadingState
|
import com.subtracks.ui.components.LoadingState
|
||||||
import com.subtracks.ui.components.MenuTarget
|
import com.subtracks.ui.components.MenuTarget
|
||||||
|
import com.subtracks.ui.library.PlaylistsContent
|
||||||
import com.subtracks.ui.library.SongRow
|
import com.subtracks.ui.library.SongRow
|
||||||
import org.koin.compose.koinInject
|
import org.koin.compose.koinInject
|
||||||
import org.koin.compose.viewmodel.koinViewModel
|
import org.koin.compose.viewmodel.koinViewModel
|
||||||
@@ -64,6 +66,7 @@ fun HomeListRoute(
|
|||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onAlbumClick: (Album) -> Unit,
|
onAlbumClick: (Album) -> Unit,
|
||||||
onArtistClick: (Artist) -> Unit,
|
onArtistClick: (Artist) -> Unit,
|
||||||
|
onPlaylistClick: (Playlist) -> Unit = {},
|
||||||
onViewAlbum: (String) -> Unit,
|
onViewAlbum: (String) -> Unit,
|
||||||
onViewArtist: (String) -> Unit,
|
onViewArtist: (String) -> Unit,
|
||||||
onGenreClick: (String) -> Unit,
|
onGenreClick: (String) -> Unit,
|
||||||
@@ -91,6 +94,7 @@ fun HomeListRoute(
|
|||||||
albums = viewModel.albums.collectAsLazyPagingItems(),
|
albums = viewModel.albums.collectAsLazyPagingItems(),
|
||||||
artists = viewModel.artists.collectAsLazyPagingItems(),
|
artists = viewModel.artists.collectAsLazyPagingItems(),
|
||||||
songs = viewModel.songs.collectAsLazyPagingItems(),
|
songs = viewModel.songs.collectAsLazyPagingItems(),
|
||||||
|
playlists = viewModel.playlists.collectAsLazyPagingItems(),
|
||||||
genres = genres,
|
genres = genres,
|
||||||
decades = decades,
|
decades = decades,
|
||||||
coverArt = viewModel::coverArt,
|
coverArt = viewModel::coverArt,
|
||||||
@@ -98,6 +102,7 @@ fun HomeListRoute(
|
|||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onAlbumClick = onAlbumClick,
|
onAlbumClick = onAlbumClick,
|
||||||
onArtistClick = onArtistClick,
|
onArtistClick = onArtistClick,
|
||||||
|
onPlaylistClick = onPlaylistClick,
|
||||||
onSongClick = viewModel::play,
|
onSongClick = viewModel::play,
|
||||||
onLongClick = { contextMenuHost?.show(it, actions) },
|
onLongClick = { contextMenuHost?.show(it, actions) },
|
||||||
onGenreClick = onGenreClick,
|
onGenreClick = onGenreClick,
|
||||||
@@ -112,6 +117,7 @@ fun HomeListScreen(
|
|||||||
albums: LazyPagingItems<Album>,
|
albums: LazyPagingItems<Album>,
|
||||||
artists: LazyPagingItems<Artist>,
|
artists: LazyPagingItems<Artist>,
|
||||||
songs: LazyPagingItems<AlbumSongItem>,
|
songs: LazyPagingItems<AlbumSongItem>,
|
||||||
|
playlists: LazyPagingItems<Playlist>,
|
||||||
genres: List<String> = emptyList(),
|
genres: List<String> = emptyList(),
|
||||||
decades: List<Long> = emptyList(),
|
decades: List<Long> = emptyList(),
|
||||||
coverArt: (String?, Boolean) -> CoverArtRef? = { _, _ -> null },
|
coverArt: (String?, Boolean) -> CoverArtRef? = { _, _ -> null },
|
||||||
@@ -119,6 +125,7 @@ fun HomeListScreen(
|
|||||||
onBack: () -> Unit = {},
|
onBack: () -> Unit = {},
|
||||||
onAlbumClick: (Album) -> Unit = {},
|
onAlbumClick: (Album) -> Unit = {},
|
||||||
onArtistClick: (Artist) -> Unit = {},
|
onArtistClick: (Artist) -> Unit = {},
|
||||||
|
onPlaylistClick: (Playlist) -> Unit = {},
|
||||||
onSongClick: (Song) -> Unit = {},
|
onSongClick: (Song) -> Unit = {},
|
||||||
onLongClick: (MenuTarget) -> Unit = {},
|
onLongClick: (MenuTarget) -> Unit = {},
|
||||||
onGenreClick: (String) -> Unit = {},
|
onGenreClick: (String) -> Unit = {},
|
||||||
@@ -139,6 +146,54 @@ fun HomeListScreen(
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { padding ->
|
) { padding ->
|
||||||
|
val downloaded = request.downloaded
|
||||||
|
if (downloaded != null) {
|
||||||
|
when (downloaded) {
|
||||||
|
OfflineListKind.Albums -> {
|
||||||
|
AlbumsList(
|
||||||
|
albums = albums,
|
||||||
|
coverArt = coverArt,
|
||||||
|
info = { albumListInfo(request, it, now) },
|
||||||
|
onAlbumClick = onAlbumClick,
|
||||||
|
onLongClick = onLongClick,
|
||||||
|
modifier = Modifier.padding(padding),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
OfflineListKind.Artists -> {
|
||||||
|
ArtistsList(
|
||||||
|
artists = artists,
|
||||||
|
coverArt = coverArt,
|
||||||
|
info = { artistListInfo(request, it, now) },
|
||||||
|
onArtistClick = onArtistClick,
|
||||||
|
onLongClick = onLongClick,
|
||||||
|
modifier = Modifier.padding(padding),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
OfflineListKind.Songs -> {
|
||||||
|
SongsList(
|
||||||
|
songs = songs,
|
||||||
|
coverArt = coverArt,
|
||||||
|
playingSongId = playingSongId,
|
||||||
|
onSongClick = onSongClick,
|
||||||
|
onLongClick = onLongClick,
|
||||||
|
modifier = Modifier.padding(padding),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
OfflineListKind.Playlists -> {
|
||||||
|
PlaylistsContent(
|
||||||
|
items = playlists,
|
||||||
|
coverArt = coverArt,
|
||||||
|
bottomInset = 0.dp,
|
||||||
|
onPlaylistClick = onPlaylistClick,
|
||||||
|
onLongClick = onLongClick,
|
||||||
|
modifier = Modifier.padding(padding),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
when (request.section) {
|
when (request.section) {
|
||||||
HomeSection.Genres -> {
|
HomeSection.Genres -> {
|
||||||
PlainList(
|
PlainList(
|
||||||
@@ -209,6 +264,7 @@ fun HomeListScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
private fun <T> PlainList(
|
private fun <T> PlainList(
|
||||||
|
|||||||
@@ -8,7 +8,12 @@ import com.subtracks.data.model.Album
|
|||||||
import com.subtracks.data.model.AlbumSongItem
|
import com.subtracks.data.model.AlbumSongItem
|
||||||
import com.subtracks.data.model.Artist
|
import com.subtracks.data.model.Artist
|
||||||
import com.subtracks.data.model.CoverArtRef
|
import com.subtracks.data.model.CoverArtRef
|
||||||
|
import com.subtracks.data.model.Playlist
|
||||||
import com.subtracks.data.model.Song
|
import com.subtracks.data.model.Song
|
||||||
|
import com.subtracks.data.prefs.AlbumSort
|
||||||
|
import com.subtracks.data.prefs.ArtistSort
|
||||||
|
import com.subtracks.data.prefs.PlaylistSort
|
||||||
|
import com.subtracks.data.prefs.StarredFilter
|
||||||
import com.subtracks.data.repo.LibraryRepository
|
import com.subtracks.data.repo.LibraryRepository
|
||||||
import com.subtracks.data.repo.SourceRepository
|
import com.subtracks.data.repo.SourceRepository
|
||||||
import com.subtracks.playback.PlaybackController
|
import com.subtracks.playback.PlaybackController
|
||||||
@@ -26,8 +31,18 @@ data class HomeListRequest(
|
|||||||
val section: HomeSection? = null,
|
val section: HomeSection? = null,
|
||||||
val genre: String? = null,
|
val genre: String? = null,
|
||||||
val decade: Long? = null,
|
val decade: Long? = null,
|
||||||
|
val downloaded: OfflineListKind? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
enum class OfflineListKind(
|
||||||
|
val title: String,
|
||||||
|
) {
|
||||||
|
Albums("Downloaded albums"),
|
||||||
|
Artists("Downloaded artists"),
|
||||||
|
Songs("Downloaded songs"),
|
||||||
|
Playlists("Downloaded playlists"),
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class HomeListViewModel(
|
class HomeListViewModel(
|
||||||
private val libraryRepository: LibraryRepository,
|
private val libraryRepository: LibraryRepository,
|
||||||
@@ -41,6 +56,17 @@ class HomeListViewModel(
|
|||||||
sourceId
|
sourceId
|
||||||
.flatMapLatest { id ->
|
.flatMapLatest { id ->
|
||||||
when {
|
when {
|
||||||
|
request.downloaded == OfflineListKind.Albums -> {
|
||||||
|
libraryRepository.albums(
|
||||||
|
sourceId = id,
|
||||||
|
sort = AlbumSort.Added,
|
||||||
|
descending = false,
|
||||||
|
starred = StarredFilter.Any,
|
||||||
|
search = "",
|
||||||
|
downloaded = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
request.decade != null -> {
|
request.decade != null -> {
|
||||||
libraryRepository.albumsByDecade(id, request.decade)
|
libraryRepository.albumsByDecade(id, request.decade)
|
||||||
}
|
}
|
||||||
@@ -80,15 +106,43 @@ class HomeListViewModel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
|
if (request.downloaded == OfflineListKind.Artists) {
|
||||||
|
libraryRepository.artists(
|
||||||
|
sourceId = id,
|
||||||
|
sort = ArtistSort.Name,
|
||||||
|
descending = false,
|
||||||
|
starred = StarredFilter.Any,
|
||||||
|
search = "",
|
||||||
|
downloaded = true,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
flowOf(PagingData.empty<Artist>())
|
flowOf(PagingData.empty<Artist>())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}.cachedIn(viewModelScope)
|
||||||
|
|
||||||
|
val playlists: Flow<PagingData<Playlist>> =
|
||||||
|
sourceId
|
||||||
|
.flatMapLatest { id ->
|
||||||
|
if (request.downloaded == OfflineListKind.Playlists) {
|
||||||
|
libraryRepository.playlists(
|
||||||
|
sourceId = id,
|
||||||
|
sort = PlaylistSort.Name,
|
||||||
|
descending = false,
|
||||||
|
search = "",
|
||||||
|
downloaded = true,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
flowOf(PagingData.empty<Playlist>())
|
||||||
|
}
|
||||||
}.cachedIn(viewModelScope)
|
}.cachedIn(viewModelScope)
|
||||||
|
|
||||||
val songs: Flow<PagingData<AlbumSongItem>> =
|
val songs: Flow<PagingData<AlbumSongItem>> =
|
||||||
sourceId
|
sourceId
|
||||||
.flatMapLatest { id ->
|
.flatMapLatest { id ->
|
||||||
when {
|
when {
|
||||||
|
request.downloaded == OfflineListKind.Songs -> libraryRepository.downloadedSongsPage(id)
|
||||||
request.genre != null -> libraryRepository.songsByGenre(id, request.genre)
|
request.genre != null -> libraryRepository.songsByGenre(id, request.genre)
|
||||||
request.section == HomeSection.RecentlyStarredSongs -> libraryRepository.starredSongs(id)
|
request.section == HomeSection.RecentlyStarredSongs -> libraryRepository.starredSongs(id)
|
||||||
else -> flowOf(PagingData.empty<AlbumSongItem>())
|
else -> flowOf(PagingData.empty<AlbumSongItem>())
|
||||||
@@ -117,6 +171,10 @@ class HomeListViewModel(
|
|||||||
viewModelScope.playGenreList(libraryRepository, playbackController, genre, song)
|
viewModelScope.playGenreList(libraryRepository, playbackController, genre, song)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.downloaded == OfflineListKind.Songs -> {
|
||||||
|
viewModelScope.playDownloadedList(libraryRepository, playbackController, song)
|
||||||
|
}
|
||||||
|
|
||||||
request.section == HomeSection.RecentlyStarredSongs -> {
|
request.section == HomeSection.RecentlyStarredSongs -> {
|
||||||
viewModelScope.playStarredList(
|
viewModelScope.playStarredList(
|
||||||
libraryRepository,
|
libraryRepository,
|
||||||
|
|||||||
@@ -86,6 +86,7 @@ fun HomeRoute(
|
|||||||
onViewAlbum: (String) -> Unit,
|
onViewAlbum: (String) -> Unit,
|
||||||
onViewArtist: (String) -> Unit,
|
onViewArtist: (String) -> Unit,
|
||||||
onMore: (HomeSection) -> Unit,
|
onMore: (HomeSection) -> Unit,
|
||||||
|
onDownloadedMore: (OfflineListKind) -> Unit,
|
||||||
onGenreClick: (String) -> Unit,
|
onGenreClick: (String) -> Unit,
|
||||||
onDecadeClick: (Long) -> Unit,
|
onDecadeClick: (Long) -> Unit,
|
||||||
contextMenuHost: ContextMenuHost? = null,
|
contextMenuHost: ContextMenuHost? = null,
|
||||||
@@ -121,6 +122,7 @@ fun HomeRoute(
|
|||||||
onPlaylistClick = onPlaylistClick,
|
onPlaylistClick = onPlaylistClick,
|
||||||
onSongPlay = viewModel::playDownloaded,
|
onSongPlay = viewModel::playDownloaded,
|
||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
|
onMore = onDownloadedMore,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
val feed by viewModel.feed.collectAsStateWithLifecycle()
|
val feed by viewModel.feed.collectAsStateWithLifecycle()
|
||||||
@@ -277,6 +279,7 @@ fun OfflineHomeScreen(
|
|||||||
onPlaylistClick: (Playlist) -> Unit = {},
|
onPlaylistClick: (Playlist) -> Unit = {},
|
||||||
onSongPlay: (Song) -> Unit = {},
|
onSongPlay: (Song) -> Unit = {},
|
||||||
onLongClick: (MenuTarget) -> Unit = {},
|
onLongClick: (MenuTarget) -> Unit = {},
|
||||||
|
onMore: (OfflineListKind) -> Unit = {},
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
) {
|
) {
|
||||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
|
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onBackground) {
|
||||||
@@ -285,9 +288,9 @@ fun OfflineHomeScreen(
|
|||||||
contentPadding = PaddingValues(top = topInset + 8.dp, bottom = bottomInset + 24.dp),
|
contentPadding = PaddingValues(top = topInset + 8.dp, bottom = bottomInset + 24.dp),
|
||||||
) {
|
) {
|
||||||
homeTitle()
|
homeTitle()
|
||||||
downloadedAlbumRow(albums, coverArt, onAlbumClick, onLongClick)
|
downloadedAlbumRow(albums, coverArt, onAlbumClick, onLongClick) { onMore(OfflineListKind.Albums) }
|
||||||
downloadedArtistRow(artists, coverArt, onArtistClick, onLongClick)
|
downloadedArtistRow(artists, coverArt, onArtistClick, onLongClick) { onMore(OfflineListKind.Artists) }
|
||||||
downloadedPlaylistRow(playlists, coverArt, onPlaylistClick, onLongClick)
|
downloadedPlaylistRow(playlists, coverArt, onPlaylistClick, onLongClick) { onMore(OfflineListKind.Playlists) }
|
||||||
songList(
|
songList(
|
||||||
key = "downloaded-songs",
|
key = "downloaded-songs",
|
||||||
title = "Downloaded songs",
|
title = "Downloaded songs",
|
||||||
@@ -296,7 +299,7 @@ fun OfflineHomeScreen(
|
|||||||
playingSongId = playingSongId,
|
playingSongId = playingSongId,
|
||||||
onSongPlay = onSongPlay,
|
onSongPlay = onSongPlay,
|
||||||
onLongClick = onLongClick,
|
onLongClick = onLongClick,
|
||||||
onMore = null,
|
onMore = { onMore(OfflineListKind.Songs) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,10 +310,11 @@ private fun LazyListScope.downloadedAlbumRow(
|
|||||||
coverArt: (String?, Boolean) -> CoverArtRef?,
|
coverArt: (String?, Boolean) -> CoverArtRef?,
|
||||||
onAlbumClick: (Album) -> Unit,
|
onAlbumClick: (Album) -> Unit,
|
||||||
onLongClick: (MenuTarget) -> Unit,
|
onLongClick: (MenuTarget) -> Unit,
|
||||||
|
onMore: () -> Unit,
|
||||||
) {
|
) {
|
||||||
if (albums.itemCount == 0) return
|
if (albums.itemCount == 0) return
|
||||||
item(key = "downloaded-albums-header") {
|
item(key = "downloaded-albums-header") {
|
||||||
HomeSectionHeader("Downloaded albums", null)
|
HomeSectionHeader("Downloaded albums") { onMore() }
|
||||||
}
|
}
|
||||||
item(key = "downloaded-albums-row") {
|
item(key = "downloaded-albums-row") {
|
||||||
LazyRow(
|
LazyRow(
|
||||||
@@ -339,10 +343,11 @@ private fun LazyListScope.downloadedArtistRow(
|
|||||||
coverArt: (String?, Boolean) -> CoverArtRef?,
|
coverArt: (String?, Boolean) -> CoverArtRef?,
|
||||||
onArtistClick: (Artist) -> Unit,
|
onArtistClick: (Artist) -> Unit,
|
||||||
onLongClick: (MenuTarget) -> Unit,
|
onLongClick: (MenuTarget) -> Unit,
|
||||||
|
onMore: () -> Unit,
|
||||||
) {
|
) {
|
||||||
if (artists.itemCount == 0) return
|
if (artists.itemCount == 0) return
|
||||||
item(key = "downloaded-artists-header") {
|
item(key = "downloaded-artists-header") {
|
||||||
HomeSectionHeader("Downloaded artists", null)
|
HomeSectionHeader("Downloaded artists") { onMore() }
|
||||||
}
|
}
|
||||||
item(key = "downloaded-artists-row") {
|
item(key = "downloaded-artists-row") {
|
||||||
LazyRow(
|
LazyRow(
|
||||||
@@ -371,10 +376,11 @@ private fun LazyListScope.downloadedPlaylistRow(
|
|||||||
coverArt: (String?, Boolean) -> CoverArtRef?,
|
coverArt: (String?, Boolean) -> CoverArtRef?,
|
||||||
onPlaylistClick: (Playlist) -> Unit,
|
onPlaylistClick: (Playlist) -> Unit,
|
||||||
onLongClick: (MenuTarget) -> Unit,
|
onLongClick: (MenuTarget) -> Unit,
|
||||||
|
onMore: () -> Unit,
|
||||||
) {
|
) {
|
||||||
if (playlists.itemCount == 0) return
|
if (playlists.itemCount == 0) return
|
||||||
item(key = "downloaded-playlists-header") {
|
item(key = "downloaded-playlists-header") {
|
||||||
HomeSectionHeader("Downloaded playlists", null)
|
HomeSectionHeader("Downloaded playlists") { onMore() }
|
||||||
}
|
}
|
||||||
item(key = "downloaded-playlists-row") {
|
item(key = "downloaded-playlists-row") {
|
||||||
LazyRow(
|
LazyRow(
|
||||||
|
|||||||
@@ -104,7 +104,9 @@ class HomeViewModel(
|
|||||||
}.cachedIn(viewModelScope)
|
}.cachedIn(viewModelScope)
|
||||||
|
|
||||||
val downloadedSongs: Flow<List<AlbumSongItem>> =
|
val downloadedSongs: Flow<List<AlbumSongItem>> =
|
||||||
activeSource.flatMapLatest { libraryRepository.downloadedSongs(it) }
|
activeSource
|
||||||
|
.flatMapLatest { libraryRepository.downloadedSongs(it) }
|
||||||
|
.map { it.take(HOME_STARRED_LIMIT) }
|
||||||
|
|
||||||
val feed: StateFlow<HomeFeed> =
|
val feed: StateFlow<HomeFeed> =
|
||||||
libraryRepository.activeSourceId
|
libraryRepository.activeSourceId
|
||||||
|
|||||||
@@ -127,6 +127,7 @@ import com.subtracks.ui.components.bulkRef
|
|||||||
import com.subtracks.ui.components.statusBarScrim
|
import com.subtracks.ui.components.statusBarScrim
|
||||||
import com.subtracks.ui.home.HomeRoute
|
import com.subtracks.ui.home.HomeRoute
|
||||||
import com.subtracks.ui.home.HomeSection
|
import com.subtracks.ui.home.HomeSection
|
||||||
|
import com.subtracks.ui.home.OfflineListKind
|
||||||
import com.subtracks.ui.theme.ArtworkColors
|
import com.subtracks.ui.theme.ArtworkColors
|
||||||
import com.subtracks.ui.theme.librarySurfaceColor
|
import com.subtracks.ui.theme.librarySurfaceColor
|
||||||
import com.subtracks.ui.theme.playerSurfaceColor
|
import com.subtracks.ui.theme.playerSurfaceColor
|
||||||
@@ -208,6 +209,7 @@ fun LibraryRoute(
|
|||||||
onViewAlbum: (String) -> Unit,
|
onViewAlbum: (String) -> Unit,
|
||||||
onViewArtist: (String) -> Unit,
|
onViewArtist: (String) -> Unit,
|
||||||
onHomeMore: (HomeSection) -> Unit = {},
|
onHomeMore: (HomeSection) -> Unit = {},
|
||||||
|
onHomeDownloaded: (OfflineListKind) -> Unit = {},
|
||||||
onGenreClick: (String) -> Unit = {},
|
onGenreClick: (String) -> Unit = {},
|
||||||
onDecadeClick: (Long) -> Unit = {},
|
onDecadeClick: (Long) -> Unit = {},
|
||||||
contextMenuHost: ContextMenuHost? = null,
|
contextMenuHost: ContextMenuHost? = null,
|
||||||
@@ -327,6 +329,7 @@ fun LibraryRoute(
|
|||||||
onViewAlbum = onViewAlbum,
|
onViewAlbum = onViewAlbum,
|
||||||
onViewArtist = onViewArtist,
|
onViewArtist = onViewArtist,
|
||||||
onMore = onHomeMore,
|
onMore = onHomeMore,
|
||||||
|
onDownloadedMore = onHomeDownloaded,
|
||||||
onGenreClick = onGenreClick,
|
onGenreClick = onGenreClick,
|
||||||
onDecadeClick = onDecadeClick,
|
onDecadeClick = onDecadeClick,
|
||||||
contextMenuHost = contextMenuHost,
|
contextMenuHost = contextMenuHost,
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ class HomeScreenshotTest {
|
|||||||
albums = remember { flowOf(PagingData.from(albums)) }.collectAsLazyPagingItems(),
|
albums = remember { flowOf(PagingData.from(albums)) }.collectAsLazyPagingItems(),
|
||||||
artists = remember { flowOf(PagingData.empty<Artist>()) }.collectAsLazyPagingItems(),
|
artists = remember { flowOf(PagingData.empty<Artist>()) }.collectAsLazyPagingItems(),
|
||||||
songs = remember { flowOf(PagingData.empty<AlbumSongItem>()) }.collectAsLazyPagingItems(),
|
songs = remember { flowOf(PagingData.empty<AlbumSongItem>()) }.collectAsLazyPagingItems(),
|
||||||
|
playlists = remember { flowOf(PagingData.empty<Playlist>()) }.collectAsLazyPagingItems(),
|
||||||
coverArt = { _, _ -> null },
|
coverArt = { _, _ -> null },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -121,6 +122,7 @@ class HomeScreenshotTest {
|
|||||||
albums = remember { flowOf(PagingData.empty<Album>()) }.collectAsLazyPagingItems(),
|
albums = remember { flowOf(PagingData.empty<Album>()) }.collectAsLazyPagingItems(),
|
||||||
artists = remember { flowOf(PagingData.from(artists)) }.collectAsLazyPagingItems(),
|
artists = remember { flowOf(PagingData.from(artists)) }.collectAsLazyPagingItems(),
|
||||||
songs = remember { flowOf(PagingData.empty<AlbumSongItem>()) }.collectAsLazyPagingItems(),
|
songs = remember { flowOf(PagingData.empty<AlbumSongItem>()) }.collectAsLazyPagingItems(),
|
||||||
|
playlists = remember { flowOf(PagingData.empty<Playlist>()) }.collectAsLazyPagingItems(),
|
||||||
coverArt = { _, _ -> null },
|
coverArt = { _, _ -> null },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user