mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-10 15:11:58 +01:00
address the review: blank source name, synchronous title reset, shared scrim
- QueueRepository.sourceName returns null for a blank album/playlist name so the now playing title fallback applies instead of rendering empty - resolve the now playing source title with remember + LaunchedEffect instead of produceState so it resets synchronously when the queue context changes - extract the repeated status bar scrim into Modifier.statusBarScrim() and use it in AppRoot, LibraryScreen and HeroDetailScaffold
This commit is contained in:
@@ -127,9 +127,25 @@ class QueueRepository(
|
||||
): String? {
|
||||
val library = db.libraryDao()
|
||||
return when (kind) {
|
||||
QueueKind.Album -> library.album(sourceId, refId).first()?.name
|
||||
QueueKind.Playlist -> library.playlist(sourceId, refId).first()?.name
|
||||
QueueKind.Songs, QueueKind.Song -> null
|
||||
QueueKind.Album -> {
|
||||
library
|
||||
.album(sourceId, refId)
|
||||
.first()
|
||||
?.name
|
||||
?.takeIf { it.isNotBlank() }
|
||||
}
|
||||
|
||||
QueueKind.Playlist -> {
|
||||
library
|
||||
.playlist(sourceId, refId)
|
||||
.first()
|
||||
?.name
|
||||
?.takeIf { it.isNotBlank() }
|
||||
}
|
||||
|
||||
QueueKind.Songs, QueueKind.Song -> {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ import androidx.compose.animation.slideInHorizontally
|
||||
import androidx.compose.animation.slideInVertically
|
||||
import androidx.compose.animation.slideOutHorizontally
|
||||
import androidx.compose.animation.slideOutVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.gestures.Orientation
|
||||
import androidx.compose.foundation.gestures.draggable
|
||||
import androidx.compose.foundation.gestures.rememberDraggableState
|
||||
@@ -25,12 +24,9 @@ import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.consumeWindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.imeAnimationTarget
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.navigationBars
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.DisposableEffect
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
@@ -44,8 +40,6 @@ import androidx.compose.runtime.saveable.rememberSaveable
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.layout.positionInRoot
|
||||
@@ -63,6 +57,7 @@ import androidx.navigation.navArgument
|
||||
import com.subtracks.data.repo.SourceRepository
|
||||
import com.subtracks.playback.PlaybackController
|
||||
import com.subtracks.ui.components.LoadingState
|
||||
import com.subtracks.ui.components.statusBarScrim
|
||||
import com.subtracks.ui.library.AlbumDetailRoute
|
||||
import com.subtracks.ui.library.ArtistDetailRoute
|
||||
import com.subtracks.ui.library.LibraryRoute
|
||||
@@ -173,7 +168,6 @@ private fun MainNavigation() {
|
||||
}
|
||||
val density = LocalDensity.current
|
||||
val navBarInset = with(density) { WindowInsets.navigationBars.getBottom(this).toDp() }
|
||||
val statusBarInset = with(density) { WindowInsets.statusBars.getTop(this).toDp() }
|
||||
val keyboardUp = WindowInsets.imeAnimationTarget.getBottom(density) > 0
|
||||
val showMiniPlayer = playerVisible && !keyboardUp
|
||||
val bottomInset by animateDpAsState(
|
||||
@@ -349,15 +343,10 @@ private fun MainNavigation() {
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.TopCenter)
|
||||
.fillMaxWidth()
|
||||
.height(statusBarInset + 8.dp)
|
||||
.statusBarScrim()
|
||||
.graphicsLayer {
|
||||
alpha = ((nowPlayingProgress - SCRIM_FADE_START) / (1f - SCRIM_FADE_START)).coerceIn(0f, 1f)
|
||||
}.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(Color.Black.copy(alpha = 0.55f), Color.Transparent),
|
||||
),
|
||||
),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,9 +9,13 @@ import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.BoxScope
|
||||
import androidx.compose.foundation.layout.BoxWithConstraints
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.WindowInsets
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.statusBars
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
@@ -26,7 +30,10 @@ import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.shadow
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
@@ -259,3 +266,16 @@ fun FilteredEmptyState(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Modifier.statusBarScrim(): Modifier {
|
||||
val top = with(LocalDensity.current) { WindowInsets.statusBars.getTop(this).toDp() }
|
||||
return this
|
||||
.fillMaxWidth()
|
||||
.height(top + 8.dp)
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(Color.Black.copy(alpha = 0.55f), Color.Transparent),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.graphicsLayer
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
@@ -153,13 +152,8 @@ fun HeroDetailScaffold(
|
||||
Box(
|
||||
Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.fillMaxWidth()
|
||||
.height(statusBarDp + 8.dp)
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(Color.Black.copy(alpha = 0.55f), Color.Transparent),
|
||||
),
|
||||
).graphicsLayer { alpha = 1f - barFraction },
|
||||
.statusBarScrim()
|
||||
.graphicsLayer { alpha = 1f - barFraction },
|
||||
)
|
||||
|
||||
TopAppBar(
|
||||
|
||||
@@ -79,7 +79,6 @@ import androidx.compose.ui.geometry.CornerRadius
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.geometry.Rect
|
||||
import androidx.compose.ui.geometry.Size
|
||||
import androidx.compose.ui.graphics.Brush
|
||||
import androidx.compose.ui.graphics.ClipOp
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.graphics.Path
|
||||
@@ -115,6 +114,7 @@ import com.subtracks.data.prefs.PlaylistSort
|
||||
import com.subtracks.data.prefs.SongSort
|
||||
import com.subtracks.data.prefs.StarredFilter
|
||||
import com.subtracks.playback.PlaybackController
|
||||
import com.subtracks.ui.components.statusBarScrim
|
||||
import com.subtracks.ui.theme.ArtworkColors
|
||||
import com.subtracks.ui.theme.librarySurfaceColor
|
||||
import com.subtracks.ui.theme.playerSurfaceColor
|
||||
@@ -430,13 +430,7 @@ fun LibraryScreen(
|
||||
modifier =
|
||||
Modifier
|
||||
.align(Alignment.TopStart)
|
||||
.fillMaxWidth()
|
||||
.height(statusBarTop + 8.dp)
|
||||
.background(
|
||||
Brush.verticalGradient(
|
||||
listOf(Color.Black.copy(alpha = 0.55f), Color.Transparent),
|
||||
),
|
||||
),
|
||||
.statusBarScrim(),
|
||||
)
|
||||
|
||||
if (!searchActive) {
|
||||
|
||||
@@ -43,7 +43,6 @@ import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableFloatStateOf
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
@@ -91,9 +90,10 @@ fun NowPlayingRoute(
|
||||
} else {
|
||||
state.item?.album?.takeIf { it.isNotBlank() } ?: "Library"
|
||||
}
|
||||
val sourceTitle by produceState<String>(initialValue = fallbackTitle, queueContext) {
|
||||
value = fallbackTitle
|
||||
value = controller.sourceTitle(queueContext) ?: fallbackTitle
|
||||
val sourceTitle = remember(queueContext, fallbackTitle) { mutableStateOf(fallbackTitle) }
|
||||
LaunchedEffect(queueContext, fallbackTitle) {
|
||||
sourceTitle.value = fallbackTitle
|
||||
sourceTitle.value = controller.sourceTitle(queueContext)?.takeIf { it.isNotBlank() } ?: fallbackTitle
|
||||
}
|
||||
LaunchedEffect(state.item?.id, state.hasNext) {
|
||||
if (!state.hasNext) return@LaunchedEffect
|
||||
@@ -102,7 +102,7 @@ fun NowPlayingRoute(
|
||||
}
|
||||
NowPlayingScreen(
|
||||
state = state,
|
||||
title = sourceTitle,
|
||||
title = sourceTitle.value,
|
||||
coverArt = art,
|
||||
thumbnailRef = thumbnail,
|
||||
artwork = rememberArtworkColors(thumbnail ?: art),
|
||||
|
||||
Reference in New Issue
Block a user