Skip to content

Commit

Permalink
artis: improve remote/local screen
Browse files Browse the repository at this point in the history
- If lost connection, change to local screen
- If no connection, don't change to remote
- fix local header being ellipsed when it shouldn't
  • Loading branch information
mattcarter11 committed Dec 8, 2024
1 parent 9a9db07 commit fcaaa35
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 82 deletions.
185 changes: 103 additions & 82 deletions app/src/main/java/com/dd3boh/outertune/ui/screens/artist/ArtistScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
Expand All @@ -71,11 +72,13 @@ import androidx.hilt.navigation.compose.hiltViewModel
import androidx.navigation.NavController
import coil.compose.AsyncImage
import com.dd3boh.outertune.LocalDatabase
import com.dd3boh.outertune.LocalNetworkStatus
import com.dd3boh.outertune.LocalPlayerAwareWindowInsets
import com.dd3boh.outertune.LocalPlayerConnection
import com.dd3boh.outertune.R
import com.dd3boh.outertune.constants.AppBarHeight
import com.dd3boh.outertune.db.entities.ArtistEntity
import com.dd3boh.outertune.db.entities.Song
import com.dd3boh.outertune.extensions.toMediaItem
import com.dd3boh.outertune.extensions.togglePlayPause
import com.dd3boh.outertune.models.toMediaMetadata
Expand Down Expand Up @@ -119,6 +122,7 @@ fun ArtistScreen(
val context = LocalContext.current
val database = LocalDatabase.current
val menuState = LocalMenuState.current
val isNetworkConnected = LocalNetworkStatus.current
val coroutineScope = rememberCoroutineScope()
val playerConnection = LocalPlayerConnection.current ?: return
val isPlaying by playerConnection.isPlaying.collectAsState()
Expand All @@ -131,113 +135,126 @@ fun ArtistScreen(

val lazyListState = rememberLazyListState()
val snackbarHostState = remember { SnackbarHostState() }
var showLocal by rememberSaveable { mutableStateOf(false) }
var showLocal by rememberSaveable { mutableStateOf(!isNetworkConnected) }

val transparentAppBar by remember {
derivedStateOf {
lazyListState.firstVisibleItemIndex == 0
}
}

LaunchedEffect(isNetworkConnected) {
if (!showLocal) {
showLocal = true
}
}

val artistHead = @Composable {
val thumbnail = artistPage?.artist?.thumbnail ?: libraryArtist?.artist?.thumbnailUrl
if (artistPage != null || libraryArtist != null) {
val thumbnail = artistPage?.artist?.thumbnail ?: libraryArtist?.artist?.thumbnailUrl
val artistName = artistPage?.artist?.title ?: libraryArtist?.artist?.name

Column {
Box(
modifier = Modifier
.fillMaxWidth()
.then(
if (thumbnail != null) Modifier.aspectRatio(4f / 3) else Modifier
)
) {
if (thumbnail != null) {
AsyncImage(
model = thumbnail.resize(1200, 900),
contentDescription = null,
modifier = Modifier
.align(Alignment.Center)
.fadingEdge(
top = WindowInsets.systemBars
.asPaddingValues()
.calculateTopPadding() + AppBarHeight,
bottom = 64.dp
)
)
}
AutoResizeText(
text = artistPage?.artist?.title ?: libraryArtist?.artist?.name ?: "Unknown",
style = MaterialTheme.typography.displayLarge,
fontSizeRange = FontSizeRange(32.sp, 58.sp),
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center,
Column {
Box(
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(horizontal = 48.dp)
.fillMaxWidth()
.then(
if (thumbnail == null) {
Modifier.padding(
if (thumbnail != null) Modifier.aspectRatio(4f / 3) else Modifier
)
) {
if (thumbnail != null) {
AsyncImage(
model = thumbnail.resize(1200, 900),
contentDescription = null,
modifier = Modifier
.align(Alignment.Center)
.fadingEdge(
top = WindowInsets.systemBars
.asPaddingValues()
.calculateTopPadding() + AppBarHeight
.calculateTopPadding() + AppBarHeight,
bottom = 64.dp
)
} else {
Modifier
}
)
)
}
}
AutoResizeText(
text = artistName
?: "Unknown",
style = MaterialTheme.typography.displayLarge,
fontSizeRange = FontSizeRange(32.sp, 58.sp),
fontWeight = FontWeight.Bold,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center,
modifier = Modifier
.align(Alignment.BottomCenter)
.padding(horizontal = 48.dp)
.then(
if (thumbnail == null) {
Modifier.padding(
top = WindowInsets.systemBars
.asPaddingValues()
.calculateTopPadding() + AppBarHeight
)
} else {
Modifier
}
)
)
}

if (artistPage?.artist != null){
Row(
horizontalArrangement = Arrangement.spacedBy(12.dp),
modifier = Modifier.padding(12.dp)
) {
(artistPage.artist.shuffleEndpoint ?: artistPage.artist.playEndpoint)?.let { shuffleEndpoint ->
Button(
onClick = {
playerConnection.playQueue(
YouTubeQueue(shuffleEndpoint),
title = artistPage.artist.title
)
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
modifier = Modifier.weight(1f)
) {
Icon(
imageVector = Icons.Rounded.Shuffle,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize)
Button(
onClick = {
val watchEndpoint = artistPage?.artist?.shuffleEndpoint?: artistPage?.artist?.playEndpoint
playerConnection.playQueue(
if (!showLocal && watchEndpoint != null) YouTubeQueue(watchEndpoint)
else ListQueue(
title = artistName,
items = librarySongs.shuffled().map(Song::toMediaMetadata),
),
title = artistName
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(
text = stringResource(R.string.shuffle)
)
}
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
modifier = Modifier.weight(1f)
) {
Icon(
imageVector = Icons.Rounded.Shuffle,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(
text = stringResource(R.string.shuffle)
)
}

artistPage.artist.radioEndpoint?.let { radioEndpoint ->
OutlinedButton(
onClick = {
playerConnection.playQueue(
YouTubeQueue(radioEndpoint),
title = "Radio: ${artistPage.artist.title}"
if (!showLocal){
artistPage?.artist?.radioEndpoint?.let { radioEndpoint ->
OutlinedButton(
onClick = {
playerConnection.playQueue(
YouTubeQueue(radioEndpoint),
title = "Radio: ${artistPage.artist.title}"
)
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
modifier = Modifier.weight(1f)
) {
Icon(
imageVector = Icons.Rounded.Radio,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
},
contentPadding = ButtonDefaults.ButtonWithIconContentPadding,
modifier = Modifier.weight(1f)
) {
Icon(
imageVector = Icons.Rounded.Radio,
contentDescription = null,
modifier = Modifier.size(ButtonDefaults.IconSize)
)
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(stringResource(R.string.radio))
Spacer(Modifier.size(ButtonDefaults.IconSpacing))
Text(stringResource(R.string.radio))
}
}
}
}
}
}
}
}
Expand Down Expand Up @@ -540,7 +557,11 @@ fun ArtistScreen(
lazyListState = lazyListState,
icon = if (showLocal) Icons.Rounded.LibraryMusic else Icons.Rounded.Language,
onClick = {
showLocal = showLocal.not()
if (isNetworkConnected){
showLocal = showLocal.not()
if (!showLocal && artistPage == null) viewModel.fetchArtistsFromYTM()
}
else showLocal = true
}
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class ArtistViewModel @Inject constructor(
.stateIn(viewModelScope, SharingStarted.Lazily, emptyList())

init {
fetchArtistsFromYTM()
}

fun fetchArtistsFromYTM() {
viewModelScope.launch {
YouTube.artist(artistId)
.onSuccess {
Expand Down

0 comments on commit fcaaa35

Please sign in to comment.