This commit is contained in:
ponzischeme89
2026-08-21 16:30:29 +12:00
parent 891d3dfedc
commit 57edfaa60b
7 changed files with 29 additions and 34 deletions
+1
View File
@@ -1,6 +1,7 @@
## 0.2.92 - 2026-08-21 ## 0.2.92 - 2026-08-21
- Improved: App design / layout tweaks. - Improved: App design / layout tweaks.
- Improved: Many behind the scenes tweaks, bug fixes to make the app run smoother. - Improved: Many behind the scenes tweaks, bug fixes to make the app run smoother.
- Improved: Gateway updated to version 0.1.63.
## 0.2.84 - 2026-08-21 ## 0.2.84 - 2026-08-21
- Improved: Loading and performance of the continue watching row. - Improved: Loading and performance of the continue watching row.
+1 -1
View File
@@ -64,7 +64,7 @@ val projectNoticeText =
// A release workflow can derive the app version from its Git tag without editing the // A release workflow can derive the app version from its Git tag without editing the
// source tree. Local builds keep using the checked-in default. // source tree. Local builds keep using the checked-in default.
val defaultVersionName = "0.2.92" val defaultVersionName = "0.2.93"
val membyVersionName: String = val membyVersionName: String =
(project.findProperty("memby.versionName") as String?) (project.findProperty("memby.versionName") as String?)
?.trim() ?.trim()
@@ -83,6 +83,11 @@ import java.util.Date
import java.util.Calendar import java.util.Calendar
import kotlin.time.Duration.Companion.milliseconds import kotlin.time.Duration.Companion.milliseconds
// The focused metadata hero now owns year/runtime/certificate for browse destinations.
// Search and Genres keep their own card context through PosterGridCard instead.
private const val BROWSE_ROW_SECONDARY_METADATA = false
private const val CONTINUE_ROW_SECONDARY_METADATA = true
@Composable @Composable
internal fun PlaybackLaunchOverlay(item: BaseItem, modifier: Modifier = Modifier) { internal fun PlaybackLaunchOverlay(item: BaseItem, modifier: Modifier = Modifier) {
val rotation by rememberInfiniteTransition(label = "playback-launch").animateFloat( val rotation by rememberInfiniteTransition(label = "playback-launch").animateFloat(
@@ -277,7 +282,6 @@ internal fun FocusedHomeBackdrop(homeViewModel: HomeViewModel) {
@Composable @Composable
internal fun FocusedHomeMetadata( internal fun FocusedHomeMetadata(
homeViewModel: HomeViewModel, homeViewModel: HomeViewModel,
sectionLabel: String,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
val focusedItem by homeViewModel.focusedItem.collectAsStateWithLifecycle() val focusedItem by homeViewModel.focusedItem.collectAsStateWithLifecycle()
@@ -288,7 +292,6 @@ internal fun FocusedHomeMetadata(
MetadataHero( MetadataHero(
item = focusedItem, item = focusedItem,
loading = homeContent.loading.isNotEmpty(), loading = homeContent.loading.isNotEmpty(),
sectionLabel = sectionLabel,
modifier = modifier, modifier = modifier,
) )
} }
@@ -480,7 +483,10 @@ internal fun serverHomeRows(state: HomeUiState, settings: Settings): List<HomeBr
"movie-schedule" -> "No monitored movies have a digital release in the next 5 days" "movie-schedule" -> "No monitored movies have a digital release in the next 5 days"
else -> "Nothing to show here yet" else -> "Nothing to show here yet"
}, },
showSecondaryMetadata = settings.showHomeCardMetadata, showSecondaryMetadata = when (row.kind) {
"continue" -> CONTINUE_ROW_SECONDARY_METADATA
else -> BROWSE_ROW_SECONDARY_METADATA
},
) )
} }
return applyHomeRowPreferences(mapped, settings) return applyHomeRowPreferences(mapped, settings)
@@ -558,7 +564,7 @@ internal fun homeRowsFor(
kind = MediaRowKind.CONTINUE, kind = MediaRowKind.CONTINUE,
loading = HomeSection.CONTINUE in state.loading, loading = HomeSection.CONTINUE in state.loading,
emptyMessage = "Nothing in progress", emptyMessage = "Nothing in progress",
showSecondaryMetadata = settings.showHomeCardMetadata, showSecondaryMetadata = CONTINUE_ROW_SECONDARY_METADATA,
) )
val latestMovies = HomeBrowseRow( val latestMovies = HomeBrowseRow(
id = "latest-movies", id = "latest-movies",
@@ -567,7 +573,7 @@ internal fun homeRowsFor(
kind = MediaRowKind.MOVIES, kind = MediaRowKind.MOVIES,
loading = HomeSection.LATEST in state.loading, loading = HomeSection.LATEST in state.loading,
emptyMessage = "No recent movies found", emptyMessage = "No recent movies found",
showSecondaryMetadata = settings.showHomeCardMetadata, showSecondaryMetadata = BROWSE_ROW_SECONDARY_METADATA,
) )
val favorites = HomeBrowseRow( val favorites = HomeBrowseRow(
id = "favorites", id = "favorites",
@@ -576,7 +582,7 @@ internal fun homeRowsFor(
kind = MediaRowKind.FAVORITES, kind = MediaRowKind.FAVORITES,
loading = HomeSection.FAVORITES in state.loading, loading = HomeSection.FAVORITES in state.loading,
emptyMessage = "Your favourites will appear here", emptyMessage = "Your favourites will appear here",
showSecondaryMetadata = settings.showHomeCardMetadata, showSecondaryMetadata = BROWSE_ROW_SECONDARY_METADATA,
) )
val destinationRows = when (destination) { val destinationRows = when (destination) {
// The gateway composes the home screen — including rows this app has no concept // The gateway composes the home screen — including rows this app has no concept
@@ -609,6 +615,11 @@ internal fun homeRowsFor(
row.id.startsWith("curated:movies:") row.id.startsWith("curated:movies:")
} }
.distinctBy(HomeBrowseRow::id) + listOf( .distinctBy(HomeBrowseRow::id) + listOf(
continueRow.copy(
id = "continue-movies",
title = "Continue Watching",
items = state.continueWatching.filter(BaseItem::isMovie),
),
favorites.copy( favorites.copy(
id = "favourite-movies", id = "favourite-movies",
title = "Favourite Movies", title = "Favourite Movies",
@@ -726,7 +737,7 @@ internal fun forYouBrowseRows(
kind = MediaRowKind.MOVIES, kind = MediaRowKind.MOVIES,
loading = state.loading, loading = state.loading,
emptyMessage = state.error ?: "Watch and browse a little more to shape your picks", emptyMessage = state.error ?: "Watch and browse a little more to shape your picks",
showSecondaryMetadata = true, showSecondaryMetadata = BROWSE_ROW_SECONDARY_METADATA,
), ),
) )
} }
@@ -738,8 +749,7 @@ internal fun forYouBrowseRows(
kind = MediaRowKind.MOVIES, kind = MediaRowKind.MOVIES,
loading = state.loading && row.items.isEmpty(), loading = state.loading && row.items.isEmpty(),
emptyMessage = state.error ?: "No picks fit this time window yet", emptyMessage = state.error ?: "No picks fit this time window yet",
// Reasons are the primary secondary metadata in this destination. showSecondaryMetadata = BROWSE_ROW_SECONDARY_METADATA,
showSecondaryMetadata = true,
) )
} }
} }
@@ -739,7 +739,6 @@ internal fun HomeScreen(
forYouState, forYouState,
selectedDestination, selectedDestination,
settings.homeSections, settings.homeSections,
settings.showHomeCardMetadata,
settings.hideWatchedMovies, settings.hideWatchedMovies,
) { ) {
val destinationRows = if (selectedDestination == BrowseDestination.FOR_YOU) { val destinationRows = if (selectedDestination == BrowseDestination.FOR_YOU) {
@@ -1377,7 +1376,6 @@ internal fun HomeScreen(
} else { } else {
FocusedHomeMetadata( FocusedHomeMetadata(
homeViewModel = homeViewModel, homeViewModel = homeViewModel,
sectionLabel = selectedDestination.label,
modifier = Modifier modifier = Modifier
.height(metadataHeight) .height(metadataHeight)
// LazyColumn is drawn later as a sibling. Keep the hero // LazyColumn is drawn later as a sibling. Keep the hero
@@ -1393,7 +1391,7 @@ internal fun HomeScreen(
Text( Text(
// The gateway's maintenance notice when it sent one, and the // The gateway's maintenance notice when it sent one, and the
// generic wording otherwise. // generic wording otherwise.
homeStatus.statusMessage ?: "Connection is slow — showing available content", homeStatus.statusMessage ?: "Memby Server is updating/busy.... slow. Please wait.",
color = MembyMutedText, color = MembyMutedText,
fontSize = 14.sp, fontSize = 14.sp,
modifier = Modifier.padding( modifier = Modifier.padding(
@@ -34,7 +34,6 @@ import com.ponzischeme89.memby.ui.theme.MembySurface
internal fun MetadataHero( internal fun MetadataHero(
item: BaseItem?, item: BaseItem?,
loading: Boolean, loading: Boolean,
sectionLabel: String,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Box( Box(
@@ -70,7 +69,6 @@ internal fun MetadataHero(
MediaMetadataPanel( MediaMetadataPanel(
item = item, item = item,
loading = loading, loading = loading,
sectionLabel = sectionLabel,
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding( .padding(
@@ -135,8 +135,8 @@ private val RailSurface: Color get() = MembySurface.copy(alpha = 0.95f)
private val MutedText: Color get() = MembyMutedText private val MutedText: Color get() = MembyMutedText
private val QuietText: Color get() = MembyQuietText private val QuietText: Color get() = MembyQuietText
private val BACKDROP_SETTLE_DELAY = 240.milliseconds private val BACKDROP_SETTLE_DELAY = 240.milliseconds
private val MetadataHeroLogoMaxWidth = 420.dp private val MetadataHeroLogoMaxWidth = 360.dp
private val MetadataHeroLogoMaxHeight = 92.dp private val MetadataHeroLogoMaxHeight = 72.dp
@Composable @Composable
fun BackdropLayer(item: BaseItem?, modifier: Modifier = Modifier) { fun BackdropLayer(item: BaseItem?, modifier: Modifier = Modifier) {
@@ -196,7 +196,6 @@ fun BackdropLayer(item: BaseItem?, modifier: Modifier = Modifier) {
fun MediaMetadataPanel( fun MediaMetadataPanel(
item: BaseItem?, item: BaseItem?,
loading: Boolean, loading: Boolean,
sectionLabel: String,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
BoxWithConstraints(modifier) { BoxWithConstraints(modifier) {
@@ -211,7 +210,6 @@ fun MediaMetadataPanel(
modifier = Modifier.width(contentWidth), modifier = Modifier.width(contentWidth),
verticalArrangement = Arrangement.spacedBy(if (compactLayout) 7.dp else 10.dp), verticalArrangement = Arrangement.spacedBy(if (compactLayout) 7.dp else 10.dp),
) { ) {
Text(sectionLabel, color = QuietText, fontSize = 12.sp, fontWeight = FontWeight.SemiBold)
Text( Text(
"Your library", "Your library",
color = Color.White, color = Color.White,
@@ -221,7 +219,7 @@ fun MediaMetadataPanel(
Text("Choose something to watch.", color = MutedText, fontSize = 14.sp) Text("Choose something to watch.", color = MutedText, fontSize = 14.sp)
} }
} }
else -> MetadataContent(item, sectionLabel, contentWidth, compactLayout) else -> MetadataContent(item, contentWidth, compactLayout)
} }
} }
} }
@@ -262,12 +260,11 @@ private fun SkeletonBlock(width: Dp, height: Dp) {
@Composable @Composable
private fun MetadataContent( private fun MetadataContent(
item: BaseItem, item: BaseItem,
sectionLabel: String,
contentWidth: Dp, contentWidth: Dp,
compact: Boolean, compact: Boolean,
) { ) {
if (item.isSchedule) { if (item.isSchedule) {
ScheduleMetadataContent(item, sectionLabel, contentWidth, compact) ScheduleMetadataContent(item, contentWidth, compact)
return return
} }
val repository = ServiceLocator.repository val repository = ServiceLocator.repository
@@ -285,7 +282,6 @@ private fun MetadataContent(
modifier = Modifier.width(contentWidth).fillMaxHeight(), modifier = Modifier.width(contentWidth).fillMaxHeight(),
verticalArrangement = Arrangement.spacedBy(if (compact) 5.dp else 8.dp), verticalArrangement = Arrangement.spacedBy(if (compact) 5.dp else 8.dp),
) { ) {
Text(sectionLabel.uppercase(), color = EmbyGreen, fontSize = 11.sp, fontWeight = FontWeight.Bold, letterSpacing = 1.1.sp)
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
@@ -296,13 +292,13 @@ private fun MetadataContent(
Modifier.heightIn(max = MetadataHeroLogoMaxHeight) Modifier.heightIn(max = MetadataHeroLogoMaxHeight)
}, },
), ),
contentAlignment = Alignment.BottomStart, contentAlignment = Alignment.TopStart,
) { ) {
if (logo != null) { if (logo != null) {
TitleLogoImage( TitleLogoImage(
logoUrl = logo, logoUrl = logo,
contentDescription = item.seriesName?.takeIf { item.isEpisode } ?: item.name, contentDescription = item.seriesName?.takeIf { item.isEpisode } ?: item.name,
alignment = Alignment.BottomStart, alignment = Alignment.TopStart,
modifier = Modifier modifier = Modifier
.width(MetadataHeroLogoMaxWidth) .width(MetadataHeroLogoMaxWidth)
.height(MetadataHeroLogoMaxHeight), .height(MetadataHeroLogoMaxHeight),
@@ -383,7 +379,6 @@ private fun MetadataContent(
@Composable @Composable
private fun ScheduleMetadataContent( private fun ScheduleMetadataContent(
item: BaseItem, item: BaseItem,
sectionLabel: String,
contentWidth: Dp, contentWidth: Dp,
compact: Boolean, compact: Boolean,
) { ) {
@@ -391,13 +386,6 @@ private fun ScheduleMetadataContent(
modifier = Modifier.width(contentWidth).fillMaxHeight(), modifier = Modifier.width(contentWidth).fillMaxHeight(),
verticalArrangement = Arrangement.spacedBy(if (compact) 5.dp else 8.dp), verticalArrangement = Arrangement.spacedBy(if (compact) 5.dp else 8.dp),
) { ) {
Text(
sectionLabel.uppercase(),
color = EmbyGreen,
fontSize = 11.sp,
fontWeight = FontWeight.Bold,
letterSpacing = 1.2.sp,
)
Text( Text(
item.name, item.name,
color = Color.White, color = Color.White,
+1 -1
View File
@@ -1 +1 @@
0.1.61 0.1.63