Skip to content

Commit

Permalink
songs: add play when offline logic (only play offline items)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattcarter11 committed Dec 17, 2024
1 parent b1df1a1 commit 3ad3895
Show file tree
Hide file tree
Showing 14 changed files with 128 additions and 67 deletions.
6 changes: 3 additions & 3 deletions app/src/main/java/com/dd3boh/outertune/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ class MainActivity : ComponentActivity() {

setContent {
val connectivityObserver = NetworkConnectivityObserver(this)
val isInternetConnected by connectivityObserver.networkStatus.collectAsState(false)
val isNetworkConnected by connectivityObserver.networkStatus.collectAsState(false)

val enableDynamicTheme by rememberPreference(DynamicThemeKey, defaultValue = true)
val darkTheme by rememberEnumPreference(DarkModeKey, defaultValue = DarkMode.AUTO)
Expand Down Expand Up @@ -680,7 +680,7 @@ class MainActivity : ComponentActivity() {
LocalDownloadUtil provides downloadUtil,
LocalShimmerTheme provides ShimmerTheme,
LocalSyncUtils provides syncUtils,
LocalIsInternetConnected provides isInternetConnected
LocalIsNetworkConnected provides isNetworkConnected
) {
Scaffold(
topBar = {
Expand Down Expand Up @@ -1227,4 +1227,4 @@ val LocalPlayerConnection = staticCompositionLocalOf<PlayerConnection?> { error(
val LocalPlayerAwareWindowInsets = compositionLocalOf<WindowInsets> { error("No WindowInsets provided") }
val LocalDownloadUtil = staticCompositionLocalOf<DownloadUtil> { error("No DownloadUtil provided") }
val LocalSyncUtils = staticCompositionLocalOf<SyncUtils> { error("No SyncUtils provided") }
val LocalIsInternetConnected = staticCompositionLocalOf<Boolean> { error("No Network Status provided") }
val LocalIsNetworkConnected = staticCompositionLocalOf<Boolean> { error("No Network Status provided") }
6 changes: 3 additions & 3 deletions app/src/main/java/com/dd3boh/outertune/ui/component/Items.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.dd3boh.outertune.LocalDatabase
import com.dd3boh.outertune.LocalDownloadUtil
import com.dd3boh.outertune.LocalIsInternetConnected
import com.dd3boh.outertune.LocalIsNetworkConnected
import com.dd3boh.outertune.LocalPlayerConnection
import com.dd3boh.outertune.R
import com.dd3boh.outertune.constants.GridThumbnailHeight
Expand Down Expand Up @@ -374,7 +374,7 @@ fun SongListItem(
) {
val menuState = LocalMenuState.current
val haptic = LocalHapticFeedback.current
val isNetworkConnected = LocalIsInternetConnected.current
val isNetworkConnected = LocalIsNetworkConnected.current
val available = song.song.isAvailableOffline() || isNetworkConnected

val playerConnection = LocalPlayerConnection.current ?: return
Expand Down Expand Up @@ -1169,7 +1169,7 @@ fun YouTubeListItem(
isPlaying: Boolean = false,
trailingContent: @Composable RowScope.() -> Unit = {},
) {
val isNetworkConnected = LocalIsInternetConnected.current
val isNetworkConnected = LocalIsNetworkConnected.current
val downloads by LocalDownloadUtil.current.downloads.collectAsState()

var available = true
Expand Down
46 changes: 29 additions & 17 deletions app/src/main/java/com/dd3boh/outertune/ui/menu/AlbumMenu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.dd3boh.outertune.LocalDatabase
import com.dd3boh.outertune.LocalDownloadUtil
import com.dd3boh.outertune.LocalIsNetworkConnected
import com.dd3boh.outertune.LocalPlayerConnection
import com.dd3boh.outertune.R
import com.dd3boh.outertune.constants.ListItemHeight
Expand Down Expand Up @@ -89,6 +90,7 @@ fun AlbumMenu(
val database = LocalDatabase.current
val downloadUtil = LocalDownloadUtil.current
val playerConnection = LocalPlayerConnection.current ?: return
val isNetworkConnected = LocalIsNetworkConnected.current
val scope = rememberCoroutineScope()
val libraryAlbum by database.album(originalAlbum.id).collectAsState(initial = originalAlbum)
val album = libraryAlbum ?: originalAlbum
Expand All @@ -98,6 +100,13 @@ fun AlbumMenu(
val allInLibrary = remember(songs) {
songs.all { it.song.inLibrary != null }
}

val songsAvailable = {
songs.filter { it.song.isAvailableOffline() || isNetworkConnected }
.map { it.toMediaMetadata() }
.toList()
}

// for when local albums are a thing
// val allLocal by remember(songs) { // if only local songs in this selection
// mutableStateOf(songs.isNotEmpty() && songs.all { it.song.isLocal })
Expand Down Expand Up @@ -155,7 +164,7 @@ fun AlbumMenu(
AddToQueueDialog(
isVisible = showChooseQueueDialog,
onAdd = { queueName ->
queueBoard.add(queueName, songs.map { it.toMediaMetadata() }, playerConnection,
queueBoard.add(queueName, songsAvailable(), playerConnection,
forceInsert = true, delta = false)
queueBoard.setCurrQueue(playerConnection)
},
Expand Down Expand Up @@ -263,7 +272,7 @@ fun AlbumMenu(
title = R.string.play_next
) {
onDismiss()
playerConnection.playNext(songs.map { it.toMediaItem() })
playerConnection.playNext(songsAvailable().map { it.toMediaItem() })
}
GridMenuItem(
icon = Icons.AutoMirrored.Rounded.QueueMusic,
Expand Down Expand Up @@ -330,21 +339,24 @@ fun AlbumMenu(
showSelectArtistDialog = true
}
}
GridMenuItem(
icon = {
Icon(
imageVector = Icons.Rounded.Sync,
contentDescription = null,
modifier = Modifier.graphicsLayer(rotationZ = rotationAnimation)
)
},
title = R.string.refetch
) {
refetchIconDegree -= 360
scope.launch(Dispatchers.IO) {
YouTube.album(album.id).onSuccess {
database.transaction {
update(album.album, it)
if (isNetworkConnected)
{
GridMenuItem(
icon = {
Icon(
imageVector = Icons.Rounded.Sync,
contentDescription = null,
modifier = Modifier.graphicsLayer(rotationZ = rotationAnimation)
)
},
title = R.string.refetch
) {
refetchIconDegree -= 360
scope.launch(Dispatchers.IO) {
YouTube.album(album.id).onSuccess {
database.transaction {
update(album.album, it)
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/com/dd3boh/outertune/ui/menu/ArtistMenu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.dd3boh.outertune.LocalDatabase
import com.dd3boh.outertune.LocalIsNetworkConnected
import com.dd3boh.outertune.LocalPlayerConnection
import com.dd3boh.outertune.R
import com.dd3boh.outertune.constants.ArtistSongSortType
Expand All @@ -45,6 +46,7 @@ fun ArtistMenu(
val context = LocalContext.current
val database = LocalDatabase.current
val playerConnection = LocalPlayerConnection.current ?: return
val isNetworkConnected = LocalIsNetworkConnected.current
val artistState = database.artist(originalArtist.id).collectAsState(initial = originalArtist)
val artist = artistState.value ?: originalArtist

Expand Down Expand Up @@ -86,6 +88,7 @@ fun ArtistMenu(
coroutineScope.launch {
val songs = withContext(Dispatchers.IO) {
database.artistSongs(artist.id, ArtistSongSortType.CREATE_DATE, true).first()
.filter { it.song.isAvailableOffline() || isNetworkConnected }
.map { it.toMediaMetadata() }
}

Expand All @@ -110,6 +113,7 @@ fun ArtistMenu(
coroutineScope.launch {
val songs = withContext(Dispatchers.IO) {
database.artistSongs(artist.id, ArtistSongSortType.CREATE_DATE, true).first()
.filter { it.song.isAvailableOffline() || isNetworkConnected }
.map { it.toMediaMetadata() }
.shuffled()
}
Expand Down
41 changes: 26 additions & 15 deletions app/src/main/java/com/dd3boh/outertune/ui/menu/PlaylistMenu.kt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ import androidx.media3.exoplayer.offline.Download
import androidx.media3.exoplayer.offline.DownloadService
import com.dd3boh.outertune.LocalDatabase
import com.dd3boh.outertune.LocalDownloadUtil
import com.dd3boh.outertune.LocalIsNetworkConnected
import com.dd3boh.outertune.LocalPlayerConnection
import com.dd3boh.outertune.R
import com.dd3boh.outertune.db.entities.Playlist
Expand Down Expand Up @@ -76,11 +77,18 @@ fun PlaylistMenu(
val database = LocalDatabase.current
val downloadUtil = LocalDownloadUtil.current
val playerConnection = LocalPlayerConnection.current ?: return
val isNetworkConnected = LocalIsNetworkConnected.current
val dbPlaylist by database.playlist(playlist.id).collectAsState(initial = playlist)
var songs by remember {
mutableStateOf(emptyList<Song>())
}

val songsAvailable = {
songs.filter { it.song.isAvailableOffline() || isNetworkConnected }
.map { it.toMediaMetadata() }
.toList()
}

LaunchedEffect(Unit) {
database.playlistSongs(playlist.id).collect {
songs = it.map(PlaylistSong::song)
Expand Down Expand Up @@ -227,7 +235,7 @@ fun PlaylistMenu(
AddToQueueDialog(
isVisible = showChooseQueueDialog,
onAdd = { queueName ->
queueBoard.add(queueName, songs.map { it.toMediaMetadata() }, playerConnection,
queueBoard.add(queueName, songsAvailable(), playerConnection,
forceInsert = true, delta = false)
queueBoard.setCurrQueue(playerConnection)
},
Expand Down Expand Up @@ -294,7 +302,7 @@ fun PlaylistMenu(
onDismiss()
playerConnection.playQueue(ListQueue(
title = playlist.playlist.name,
items = songs.map { it.toMediaMetadata()},
items = songsAvailable(),
playlistId = playlist.playlist.browseId
))
}
Expand All @@ -306,22 +314,25 @@ fun PlaylistMenu(
onDismiss()
playerConnection.playQueue(ListQueue(
title = playlist.playlist.name,
items = songs.shuffled().map { it.toMediaMetadata() },
items = songsAvailable().shuffled(),
playlistId = playlist.playlist.browseId
))
}

playlist.playlist.browseId?.let { browseId ->
playlist.playlist.radioEndpointParams?.let { radioEndpointParams ->
GridMenuItem(
icon = Icons.Rounded.Radio,
title = R.string.start_radio
) {
playerConnection.playQueue(YouTubeQueue(WatchEndpoint(
playlistId = "RDAMPL$browseId",
params = radioEndpointParams,
)))
onDismiss()
if (isNetworkConnected)
{
playlist.playlist.browseId?.let { browseId ->
playlist.playlist.radioEndpointParams?.let { radioEndpointParams ->
GridMenuItem(
icon = Icons.Rounded.Radio,
title = R.string.start_radio
) {
playerConnection.playQueue(YouTubeQueue(WatchEndpoint(
playlistId = "RDAMPL$browseId",
params = radioEndpointParams,
)))
onDismiss()
}
}
}
}
Expand All @@ -331,7 +342,7 @@ fun PlaylistMenu(
title = R.string.play_next
) {
coroutineScope.launch {
playerConnection.playNext(songs.map { it.toMediaItem() })
playerConnection.playNext(songsAvailable().map { it.toMediaItem() })
}
onDismiss()
}
Expand Down
15 changes: 10 additions & 5 deletions app/src/main/java/com/dd3boh/outertune/ui/screens/AlbumScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,14 @@ import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.dd3boh.outertune.LocalDatabase
import com.dd3boh.outertune.LocalDownloadUtil
import com.dd3boh.outertune.LocalIsInternetConnected
import com.dd3boh.outertune.LocalIsNetworkConnected
import com.dd3boh.outertune.LocalPlayerAwareWindowInsets
import com.dd3boh.outertune.LocalPlayerConnection
import com.dd3boh.outertune.R
import com.dd3boh.outertune.constants.AlbumThumbnailSize
import com.dd3boh.outertune.constants.CONTENT_TYPE_HEADER
import com.dd3boh.outertune.constants.ThumbnailCornerRadius
import com.dd3boh.outertune.db.entities.Album
import com.dd3boh.outertune.db.entities.Song
import com.dd3boh.outertune.extensions.getAvailableSongs
import com.dd3boh.outertune.models.toMediaMetadata
import com.dd3boh.outertune.playback.ExoDownloadService
Expand Down Expand Up @@ -123,7 +122,7 @@ fun AlbumScreen(
val menuState = LocalMenuState.current
val database = LocalDatabase.current
val playerConnection = LocalPlayerConnection.current ?: return
val isNetworkConnected = LocalIsInternetConnected.current
val isNetworkConnected = LocalIsNetworkConnected.current

val scope = rememberCoroutineScope()

Expand All @@ -134,6 +133,12 @@ fun AlbumScreen(
val otherVersions by viewModel.otherVersions.collectAsState()
val state = rememberLazyListState()

val songsAvailable = {
albumWithSongs?.songs?.filter { it.song.isAvailableOffline() || isNetworkConnected }
?.map { it.toMediaMetadata() }
?.toList() ?: emptyList()
}

// multiselect
var inSelectMode by rememberSaveable { mutableStateOf(false) }
val selection = rememberSaveable(
Expand Down Expand Up @@ -339,7 +344,7 @@ fun AlbumScreen(
playerConnection.playQueue(
ListQueue(
title = albumWithSongsLocal.album.title,
items = albumWithSongsLocal.songs.map(Song::toMediaMetadata),
items = songsAvailable(),
playlistId = albumWithSongsLocal.album.playlistId
)
)
Expand All @@ -363,7 +368,7 @@ fun AlbumScreen(
playerConnection.playQueue(
ListQueue(
title = albumWithSongsLocal.album.title,
items = albumWithSongsLocal.songs.shuffled().map(Song::toMediaMetadata),
items = songsAvailable().shuffled(),
playlistId = albumWithSongsLocal.album.playlistId
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import com.dd3boh.outertune.LocalDatabase
import com.dd3boh.outertune.LocalDownloadUtil
import com.dd3boh.outertune.LocalIsInternetConnected
import com.dd3boh.outertune.LocalIsNetworkConnected
import com.dd3boh.outertune.LocalPlayerAwareWindowInsets
import com.dd3boh.outertune.LocalPlayerConnection
import com.dd3boh.outertune.R
Expand Down Expand Up @@ -104,7 +104,7 @@ fun HistoryScreen(
val context = LocalContext.current
val menuState = LocalMenuState.current
val playerConnection = LocalPlayerConnection.current ?: return
val isNetworkConnected = LocalIsInternetConnected.current
val isNetworkConnected = LocalIsNetworkConnected.current
val downloads by LocalDownloadUtil.current.downloads.collectAsState()
val isPlaying by playerConnection.isPlaying.collectAsState()
val mediaMetadata by playerConnection.mediaMetadata.collectAsState()
Expand Down Expand Up @@ -442,7 +442,9 @@ fun HistoryScreen(
playerConnection.playQueue(
ListQueue(
title = context.getString(R.string.history),
items = filteredEventIndex.values.map { it.song.toMediaMetadata() }.shuffled(),
items = filteredEventIndex.values
.filter { it.song.song.isAvailableOffline() || isNetworkConnected }
.map { it.song.toMediaMetadata() }.shuffled(),
)
)
}
Expand Down
Loading

0 comments on commit 3ad3895

Please sign in to comment.