Move Downloads out of Settings into a dynamic Library collection
Downloads is no longer a Settings sub-screen - it's now a pinned entry at the top of Library > Playlists (Settings keeps only the Wi-Fi-only and default-quality preference toggles, which govern how downloads behave rather than being downloaded content itself). The Downloads screen it opens is no longer a flat track list. It now splits into two sections, both fully reactive to what's actually on disk: - Playlists: any playlist with at least one downloaded track. Tapping one opens the real PlaylistDetailScreen, not a special-cased view - this is a live filter over existing playlists, not a copy of their data. - Tracks: downloaded tracks that aren't a member of any playlist. A track belonging to a playlist is never listed twice - that playlist already qualifies for the Playlists section by virtue of this same track being downloaded, so once it's shown there this list skips it. New PlaylistDao.observeAllMemberships() (and PlaylistRepository.observeTrackIdsByPlaylist()) exposes the full playlist-to-track-id membership map in one reactive query, so working out which playlists have a downloaded track doesn't require loading every playlist's full track list. DownloadsViewModel combines that with the existing downloaded-tracks and playlists flows to derive both sections - no new database tables, this is a computed view over the same Room state Phase 5 and Phase 6 already maintain. Verified on-device: Settings no longer shows a Downloads row; the Library tab shows the new pinned "Downloads" entry; added a downloaded track to a test playlist and confirmed it moved from the flat Tracks list into a Playlists entry with no duplication; confirmed tapping that entry opens the actual playlist detail screen; deleted the playlist and confirmed the track reactively reverted to the flat Tracks list with no manual refresh. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
53d4a73309
commit
49f941b8b9
@@ -13,6 +13,10 @@ data class PlaylistWithCount(
|
||||
val trackCount: Int,
|
||||
)
|
||||
|
||||
/** One (playlist, track) membership row - the raw shape the Downloads collection needs to work
|
||||
* out which playlists contain a downloaded track, without loading every playlist's full track list. */
|
||||
data class PlaylistTrackMembership(val playlistLocalId: String, val trackId: String)
|
||||
|
||||
@Dao
|
||||
interface PlaylistDao {
|
||||
@Query(
|
||||
@@ -51,6 +55,9 @@ interface PlaylistDao {
|
||||
@Query("SELECT * FROM playlist_tracks WHERE playlistLocalId = :localId ORDER BY position ASC")
|
||||
fun observeTracks(localId: String): Flow<List<PlaylistTrackEntity>>
|
||||
|
||||
@Query("SELECT playlistLocalId, trackId FROM playlist_tracks")
|
||||
fun observeAllMemberships(): Flow<List<PlaylistTrackMembership>>
|
||||
|
||||
@Query("SELECT * FROM playlist_tracks WHERE playlistLocalId = :localId ORDER BY position ASC")
|
||||
suspend fun getTracks(localId: String): List<PlaylistTrackEntity>
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ class PlaylistRepository @Inject constructor(
|
||||
fun observeTracks(localId: String): Flow<List<Song>> =
|
||||
playlistDao.observeTracks(localId).map { list -> list.map { it.toDomain() } }
|
||||
|
||||
/** playlistId -> the set of track ids it contains, for the Downloads collection to work out
|
||||
* which playlists have a downloaded track without loading every playlist's full track list. */
|
||||
fun observeTrackIdsByPlaylist(): Flow<Map<String, Set<String>>> =
|
||||
playlistDao.observeAllMemberships()
|
||||
.map { rows -> rows.groupBy({ it.playlistLocalId }, { it.trackId }).mapValues { it.value.toSet() } }
|
||||
|
||||
suspend fun createPlaylist(name: String, initialTracks: List<Song> = emptyList()): String {
|
||||
val localId = UUID.randomUUID().toString()
|
||||
val now = System.currentTimeMillis()
|
||||
|
||||
@@ -5,6 +5,7 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
@@ -12,6 +13,7 @@ import androidx.compose.material.icons.filled.Delete
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Text
|
||||
@@ -21,6 +23,7 @@ import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.pluralStringResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
@@ -28,6 +31,7 @@ import androidx.media3.common.util.UnstableApi
|
||||
import com.InfernalAquatics.deepwave.R
|
||||
import com.InfernalAquatics.deepwave.data.local.download.DownloadStatus
|
||||
import com.InfernalAquatics.deepwave.data.local.download.DownloadedTrackEntity
|
||||
import com.InfernalAquatics.deepwave.data.model.Playlist
|
||||
import com.InfernalAquatics.deepwave.data.network.coverArtUrl
|
||||
import com.InfernalAquatics.deepwave.ui.components.TrackRow
|
||||
import com.InfernalAquatics.deepwave.ui.theme.DeepwaveTheme
|
||||
@@ -36,12 +40,14 @@ import com.InfernalAquatics.deepwave.ui.theme.DeepwaveTheme
|
||||
@Composable
|
||||
fun DownloadsScreen(
|
||||
onBack: () -> Unit,
|
||||
onPlaylistClick: (String) -> Unit,
|
||||
viewModel: DownloadsViewModel = hiltViewModel(),
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
DownloadsContent(
|
||||
uiState = uiState,
|
||||
onBack = onBack,
|
||||
onPlaylistClick = onPlaylistClick,
|
||||
onTrackClick = viewModel::playTrack,
|
||||
onRemove = viewModel::remove,
|
||||
)
|
||||
@@ -52,6 +58,7 @@ fun DownloadsScreen(
|
||||
private fun DownloadsContent(
|
||||
uiState: DownloadsUiState,
|
||||
onBack: () -> Unit,
|
||||
onPlaylistClick: (String) -> Unit,
|
||||
onTrackClick: (Int) -> Unit,
|
||||
onRemove: (String) -> Unit,
|
||||
) {
|
||||
@@ -67,40 +74,56 @@ private fun DownloadsContent(
|
||||
)
|
||||
},
|
||||
) { innerPadding ->
|
||||
if (uiState.tracks.isEmpty()) {
|
||||
if (uiState.downloadedPlaylists.isEmpty() && uiState.looseTracks.isEmpty()) {
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding),
|
||||
modifier = Modifier.fillMaxSize().padding(innerPadding),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
Text(text = stringResource(R.string.downloads_empty), style = MaterialTheme.typography.bodyLarge)
|
||||
}
|
||||
} else {
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.padding(innerPadding),
|
||||
) {
|
||||
itemsIndexed(uiState.tracks, key = { _, track -> track.trackId }) { index, track ->
|
||||
TrackRow(
|
||||
title = track.title,
|
||||
subtitle = track.artistName.orEmpty(),
|
||||
coverArtUrl = coverArtUrl(track.coverArtId),
|
||||
onClick = { onTrackClick(index) },
|
||||
trailingContent = {
|
||||
IconButton(onClick = { onRemove(track.trackId) }) {
|
||||
Icon(Icons.Filled.Delete, contentDescription = stringResource(R.string.download_remove))
|
||||
}
|
||||
},
|
||||
)
|
||||
LazyColumn(modifier = Modifier.fillMaxSize().padding(innerPadding)) {
|
||||
if (uiState.downloadedPlaylists.isNotEmpty()) {
|
||||
item { SectionHeader(stringResource(R.string.downloads_section_playlists)) }
|
||||
items(uiState.downloadedPlaylists, key = { "playlist:${it.id}" }) { playlist ->
|
||||
TrackRow(
|
||||
title = playlist.name,
|
||||
subtitle = pluralStringResource(R.plurals.playlist_track_count, playlist.trackCount, playlist.trackCount),
|
||||
coverArtUrl = coverArtUrl(playlist.coverArtId),
|
||||
onClick = { onPlaylistClick(playlist.id) },
|
||||
)
|
||||
}
|
||||
}
|
||||
if (uiState.looseTracks.isNotEmpty()) {
|
||||
item { SectionHeader(stringResource(R.string.downloads_section_tracks)) }
|
||||
itemsIndexed(uiState.looseTracks, key = { _, track -> "track:${track.trackId}" }) { index, track ->
|
||||
TrackRow(
|
||||
title = track.title,
|
||||
subtitle = track.artistName.orEmpty(),
|
||||
coverArtUrl = coverArtUrl(track.coverArtId),
|
||||
onClick = { onTrackClick(index) },
|
||||
trailingContent = {
|
||||
IconButton(onClick = { onRemove(track.trackId) }) {
|
||||
Icon(Icons.Filled.Delete, contentDescription = stringResource(R.string.download_remove))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val sampleTracks = List(3) { index ->
|
||||
@Composable
|
||||
private fun SectionHeader(title: String) {
|
||||
ListItem(headlineContent = { Text(title, style = MaterialTheme.typography.titleMedium) })
|
||||
}
|
||||
|
||||
private val samplePlaylists = listOf(
|
||||
Playlist(id = "1", name = "Riddim Favs", coverArtId = null, trackCount = 12, isSynced = true),
|
||||
)
|
||||
private val sampleTracks = List(2) { index ->
|
||||
DownloadedTrackEntity(
|
||||
trackId = "sample-$index",
|
||||
title = "Sample Track ${index + 1}",
|
||||
@@ -120,7 +143,13 @@ private val sampleTracks = List(3) { index ->
|
||||
@Composable
|
||||
private fun DownloadsContentPreview() {
|
||||
DeepwaveTheme {
|
||||
DownloadsContent(uiState = DownloadsUiState(tracks = sampleTracks), onBack = {}, onTrackClick = {}, onRemove = {})
|
||||
DownloadsContent(
|
||||
uiState = DownloadsUiState(downloadedPlaylists = samplePlaylists, looseTracks = sampleTracks),
|
||||
onBack = {},
|
||||
onPlaylistClick = {},
|
||||
onTrackClick = {},
|
||||
onRemove = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,6 +157,6 @@ private fun DownloadsContentPreview() {
|
||||
@Composable
|
||||
private fun DownloadsContentEmptyPreview() {
|
||||
DeepwaveTheme {
|
||||
DownloadsContent(uiState = DownloadsUiState(), onBack = {}, onTrackClick = {}, onRemove = {})
|
||||
DownloadsContent(uiState = DownloadsUiState(), onBack = {}, onPlaylistClick = {}, onTrackClick = {}, onRemove = {})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,31 +6,56 @@ import androidx.media3.common.util.UnstableApi
|
||||
import com.InfernalAquatics.deepwave.data.download.DownloadRepository
|
||||
import com.InfernalAquatics.deepwave.data.local.download.DownloadStatus
|
||||
import com.InfernalAquatics.deepwave.data.local.download.DownloadedTrackEntity
|
||||
import com.InfernalAquatics.deepwave.data.model.Playlist
|
||||
import com.InfernalAquatics.deepwave.data.playlist.PlaylistRepository
|
||||
import com.InfernalAquatics.deepwave.media.PlaybackController
|
||||
import com.InfernalAquatics.deepwave.media.toMediaItem
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.launch
|
||||
import javax.inject.Inject
|
||||
|
||||
data class DownloadsUiState(val tracks: List<DownloadedTrackEntity> = emptyList())
|
||||
/**
|
||||
* [downloadedPlaylists]: any playlist with at least one downloaded track. [looseTracks]:
|
||||
* downloaded tracks that aren't a member of any playlist - a track belonging to a playlist is
|
||||
* never listed twice, since that playlist already qualifies for [downloadedPlaylists] by virtue
|
||||
* of this same track being downloaded.
|
||||
*/
|
||||
data class DownloadsUiState(
|
||||
val downloadedPlaylists: List<Playlist> = emptyList(),
|
||||
val looseTracks: List<DownloadedTrackEntity> = emptyList(),
|
||||
)
|
||||
|
||||
@UnstableApi
|
||||
@HiltViewModel
|
||||
class DownloadsViewModel @Inject constructor(
|
||||
private val downloadRepository: DownloadRepository,
|
||||
private val playlistRepository: PlaylistRepository,
|
||||
private val playbackController: PlaybackController,
|
||||
) : ViewModel() {
|
||||
|
||||
val uiState: StateFlow<DownloadsUiState> = downloadRepository.downloadedTracks()
|
||||
.map { tracks -> DownloadsUiState(tracks.filter { it.status == DownloadStatus.COMPLETE }) }
|
||||
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), DownloadsUiState())
|
||||
val uiState: StateFlow<DownloadsUiState> = combine(
|
||||
downloadRepository.downloadedTracks(),
|
||||
playlistRepository.observePlaylists(),
|
||||
playlistRepository.observeTrackIdsByPlaylist(),
|
||||
) { tracks, playlists, trackIdsByPlaylist ->
|
||||
val downloaded = tracks.filter { it.status == DownloadStatus.COMPLETE }
|
||||
val downloadedIds = downloaded.map { it.trackId }.toSet()
|
||||
|
||||
val downloadedPlaylists = playlists.filter { playlist ->
|
||||
trackIdsByPlaylist[playlist.id].orEmpty().any { it in downloadedIds }
|
||||
}
|
||||
val trackIdsInAnyPlaylist = trackIdsByPlaylist.values.flatten().toSet()
|
||||
val looseTracks = downloaded.filter { it.trackId !in trackIdsInAnyPlaylist }
|
||||
|
||||
DownloadsUiState(downloadedPlaylists, looseTracks)
|
||||
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5_000), DownloadsUiState())
|
||||
|
||||
fun playTrack(index: Int) {
|
||||
val tracks = uiState.value.tracks
|
||||
val tracks = uiState.value.looseTracks
|
||||
if (index !in tracks.indices) return
|
||||
viewModelScope.launch {
|
||||
playbackController.ensureConnected()
|
||||
|
||||
@@ -31,6 +31,7 @@ private enum class LibrarySection(val labelRes: Int) {
|
||||
fun LibraryScreen(
|
||||
onArtistClick: (String) -> Unit,
|
||||
onPlaylistClick: (String) -> Unit,
|
||||
onOpenDownloads: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var section by remember { mutableStateOf(LibrarySection.Playlists) }
|
||||
@@ -47,7 +48,11 @@ fun LibraryScreen(
|
||||
}
|
||||
}
|
||||
when (section) {
|
||||
LibrarySection.Playlists -> PlaylistsScreen(onPlaylistClick = onPlaylistClick, modifier = Modifier.weight(1f))
|
||||
LibrarySection.Playlists -> PlaylistsScreen(
|
||||
onPlaylistClick = onPlaylistClick,
|
||||
onOpenDownloads = onOpenDownloads,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
LibrarySection.Artists -> ArtistsScreen(onArtistClick = onArtistClick, modifier = Modifier.weight(1f))
|
||||
}
|
||||
}
|
||||
@@ -57,6 +62,6 @@ fun LibraryScreen(
|
||||
@Composable
|
||||
private fun LibraryScreenPreview() {
|
||||
DeepwaveTheme {
|
||||
LibraryScreen(onArtistClick = {}, onPlaylistClick = {})
|
||||
LibraryScreen(onArtistClick = {}, onPlaylistClick = {}, onOpenDownloads = {})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,7 @@ fun DeepwaveNavHost(
|
||||
onOpenArtist = { artistId -> navController.navigate(Route.ArtistDetail(artistId)) },
|
||||
onOpenAlbum = { albumId -> navController.navigate(Route.AlbumDetail(albumId)) },
|
||||
onOpenPlaylist = { playlistId -> navController.navigate(Route.PlaylistDetail(playlistId)) },
|
||||
onOpenDownloads = { navController.navigate(Route.Downloads) },
|
||||
)
|
||||
}
|
||||
composable<Route.Settings> {
|
||||
@@ -105,11 +106,13 @@ fun DeepwaveNavHost(
|
||||
popUpTo<Route.Main> { inclusive = true }
|
||||
}
|
||||
},
|
||||
onOpenDownloads = { navController.navigate(Route.Downloads) },
|
||||
)
|
||||
}
|
||||
composable<Route.Downloads> {
|
||||
DownloadsScreen(onBack = { navController.popBackStack() })
|
||||
DownloadsScreen(
|
||||
onBack = { navController.popBackStack() },
|
||||
onPlaylistClick = { playlistId -> navController.navigate(Route.PlaylistDetail(playlistId)) },
|
||||
)
|
||||
}
|
||||
composable<Route.ArtistDetail> {
|
||||
ArtistDetailScreen(
|
||||
|
||||
@@ -41,6 +41,7 @@ fun MainScreen(
|
||||
onOpenArtist: (String) -> Unit,
|
||||
onOpenAlbum: (String) -> Unit,
|
||||
onOpenPlaylist: (String) -> Unit,
|
||||
onOpenDownloads: () -> Unit,
|
||||
) {
|
||||
var selectedTab by remember { mutableStateOf(BottomTab.Home) }
|
||||
|
||||
@@ -67,7 +68,11 @@ fun MainScreen(
|
||||
when (selectedTab) {
|
||||
BottomTab.Home -> HomeScreen(onAlbumClick = onOpenAlbum)
|
||||
BottomTab.Search -> SearchScreen(onArtistClick = onOpenArtist, onAlbumClick = onOpenAlbum)
|
||||
BottomTab.Library -> LibraryScreen(onArtistClick = onOpenArtist, onPlaylistClick = onOpenPlaylist)
|
||||
BottomTab.Library -> LibraryScreen(
|
||||
onArtistClick = onOpenArtist,
|
||||
onPlaylistClick = onOpenPlaylist,
|
||||
onOpenDownloads = onOpenDownloads,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -78,6 +83,6 @@ fun MainScreen(
|
||||
@Composable
|
||||
private fun MainScreenPreview() {
|
||||
DeepwaveTheme {
|
||||
MainScreen(onOpenSettings = {}, onOpenArtist = {}, onOpenAlbum = {}, onOpenPlaylist = {})
|
||||
MainScreen(onOpenSettings = {}, onOpenArtist = {}, onOpenAlbum = {}, onOpenPlaylist = {}, onOpenDownloads = {})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Download
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.ListItem
|
||||
import androidx.compose.material3.Text
|
||||
@@ -27,6 +28,7 @@ import com.InfernalAquatics.deepwave.ui.theme.DeepwaveTheme
|
||||
@Composable
|
||||
fun PlaylistsScreen(
|
||||
onPlaylistClick: (String) -> Unit,
|
||||
onOpenDownloads: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
viewModel: PlaylistsViewModel = hiltViewModel(),
|
||||
) {
|
||||
@@ -34,6 +36,7 @@ fun PlaylistsScreen(
|
||||
PlaylistsContent(
|
||||
uiState = uiState,
|
||||
onPlaylistClick = onPlaylistClick,
|
||||
onOpenDownloads = onOpenDownloads,
|
||||
onNewPlaylist = viewModel::openCreate,
|
||||
modifier = modifier,
|
||||
)
|
||||
@@ -47,6 +50,7 @@ fun PlaylistsScreen(
|
||||
private fun PlaylistsContent(
|
||||
uiState: PlaylistsUiState,
|
||||
onPlaylistClick: (String) -> Unit,
|
||||
onOpenDownloads: () -> Unit,
|
||||
onNewPlaylist: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
@@ -58,6 +62,17 @@ private fun PlaylistsContent(
|
||||
modifier = Modifier.clickable(onClick = onNewPlaylist),
|
||||
)
|
||||
}
|
||||
item {
|
||||
// Pinned, not a real Room playlist: its membership is computed live from what's
|
||||
// actually on disk (see DownloadsViewModel), so it never drifts from reality and
|
||||
// never syncs to the server - downloads are inherently per-device.
|
||||
ListItem(
|
||||
headlineContent = { Text(stringResource(R.string.downloads_title)) },
|
||||
supportingContent = { Text(stringResource(R.string.downloads_subtitle)) },
|
||||
leadingContent = { Icon(Icons.Filled.Download, contentDescription = null) },
|
||||
modifier = Modifier.clickable(onClick = onOpenDownloads),
|
||||
)
|
||||
}
|
||||
if (uiState.playlists.isEmpty()) {
|
||||
item {
|
||||
ListItem(headlineContent = { Text(stringResource(R.string.playlist_empty)) })
|
||||
@@ -84,7 +99,12 @@ private val samplePlaylists = listOf(
|
||||
@Composable
|
||||
private fun PlaylistsContentPreview() {
|
||||
DeepwaveTheme {
|
||||
PlaylistsContent(uiState = PlaylistsUiState(playlists = samplePlaylists), onPlaylistClick = {}, onNewPlaylist = {})
|
||||
PlaylistsContent(
|
||||
uiState = PlaylistsUiState(playlists = samplePlaylists),
|
||||
onPlaylistClick = {},
|
||||
onOpenDownloads = {},
|
||||
onNewPlaylist = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +112,6 @@ private fun PlaylistsContentPreview() {
|
||||
@Composable
|
||||
private fun PlaylistsContentEmptyPreview() {
|
||||
DeepwaveTheme {
|
||||
PlaylistsContent(uiState = PlaylistsUiState(), onPlaylistClick = {}, onNewPlaylist = {})
|
||||
PlaylistsContent(uiState = PlaylistsUiState(), onPlaylistClick = {}, onOpenDownloads = {}, onNewPlaylist = {})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import com.InfernalAquatics.deepwave.ui.theme.DeepwaveTheme
|
||||
fun SettingsScreen(
|
||||
onBack: () -> Unit,
|
||||
onLoggedOut: () -> Unit,
|
||||
onOpenDownloads: () -> Unit,
|
||||
viewModel: SettingsViewModel = hiltViewModel(),
|
||||
) {
|
||||
val uiState by viewModel.uiState.collectAsState()
|
||||
@@ -46,7 +45,6 @@ fun SettingsScreen(
|
||||
defaultBitrate = defaultBitrate,
|
||||
onBack = onBack,
|
||||
onLogOutClick = { viewModel.logout(onLoggedOut) },
|
||||
onOpenDownloads = onOpenDownloads,
|
||||
onWifiOnlyChange = viewModel::setWifiOnly,
|
||||
onOpenDefaultQualityPicker = viewModel::openDefaultQualityPicker,
|
||||
onDismissDefaultQualityPicker = viewModel::dismissDefaultQualityPicker,
|
||||
@@ -62,7 +60,6 @@ private fun SettingsContent(
|
||||
defaultBitrate: BitrateOption,
|
||||
onBack: () -> Unit,
|
||||
onLogOutClick: () -> Unit,
|
||||
onOpenDownloads: () -> Unit,
|
||||
onWifiOnlyChange: (Boolean) -> Unit,
|
||||
onOpenDefaultQualityPicker: () -> Unit,
|
||||
onDismissDefaultQualityPicker: () -> Unit,
|
||||
@@ -81,12 +78,6 @@ private fun SettingsContent(
|
||||
},
|
||||
) { innerPadding ->
|
||||
Column(modifier = Modifier.fillMaxSize().padding(innerPadding)) {
|
||||
ListItem(
|
||||
headlineContent = { Text(stringResource(R.string.settings_downloads)) },
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.clickable(onClick = onOpenDownloads),
|
||||
)
|
||||
ListItem(
|
||||
headlineContent = { Text(stringResource(R.string.settings_wifi_only_downloads)) },
|
||||
trailingContent = { Switch(checked = wifiOnly, onCheckedChange = onWifiOnlyChange) },
|
||||
@@ -124,7 +115,6 @@ private fun SettingsContentPreview() {
|
||||
defaultBitrate = BitrateOption.Normal,
|
||||
onBack = {},
|
||||
onLogOutClick = {},
|
||||
onOpenDownloads = {},
|
||||
onWifiOnlyChange = {},
|
||||
onOpenDefaultQualityPicker = {},
|
||||
onDismissDefaultQualityPicker = {},
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
<string name="settings_title">Settings</string>
|
||||
<string name="settings_log_out">Log out</string>
|
||||
<string name="settings_downloads">Downloads</string>
|
||||
<string name="settings_wifi_only_downloads">Download over Wi-Fi only</string>
|
||||
<string name="settings_default_quality">Default download quality</string>
|
||||
|
||||
@@ -33,6 +32,9 @@
|
||||
|
||||
<string name="downloads_title">Downloads</string>
|
||||
<string name="downloads_empty">No downloads yet</string>
|
||||
<string name="downloads_subtitle">Available offline</string>
|
||||
<string name="downloads_section_playlists">Playlists</string>
|
||||
<string name="downloads_section_tracks">Tracks</string>
|
||||
|
||||
<string name="player_nothing_playing">Nothing playing</string>
|
||||
<string name="player_play">Play</string>
|
||||
|
||||
Reference in New Issue
Block a user