refactor: centralize playable media state

Move playback-related media state into shared model types and make the player consume a single PlayableMedia object instead of separately loading MediaItems, track preferences, resume positions, and media segments.

This updates PlayableMediaRepository to return playable media bundles, seeds the player playlist with the current item, keeps next-up entries in the same model, restores resume/segment handling, and fixes current queue highlighting.

The change also moves track preference models into core-model, centralizes Jellyfin BaseItemDto conversion, removes placeholder movie audio/subtitle fields, bumps the offline Room schema, and updates mobile/TV queue UI code for the playlist model.

Verification:
./gradlew --no-daemon :core-model:compileDebugKotlin :core:compileDebugKotlin :data:compileDebugKotlin :app:compileDebugKotlin
This commit is contained in:
2026-04-25 18:08:23 +02:00
parent 2433ececac
commit f7f9fc1058
36 changed files with 440 additions and 549 deletions

View File

@@ -51,8 +51,8 @@ kotlin {
}
dependencies {
implementation(project(":data"))
implementation(project(":core"))
implementation(project(":core-model"))
implementation(project(":core-ui"))
implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)

View File

@@ -40,7 +40,7 @@ import androidx.compose.ui.test.performSemanticsAction
import androidx.compose.ui.test.pressKey
import androidx.compose.ui.unit.dp
import hu.bbara.purefin.player.model.PlayerUiState
import hu.bbara.purefin.player.model.QueueItemUi
import hu.bbara.purefin.player.model.PlaylistElementUiModel
import hu.bbara.purefin.player.model.TrackOption
import hu.bbara.purefin.player.model.TrackType
import hu.bbara.purefin.ui.screen.player.TV_HIDDEN_STOP_FEEDBACK_MS
@@ -247,14 +247,14 @@ class TvPlayerControlsOverlayTest {
OverlayHost(
uiState = samplePlayerState().copy(
queue = listOf(
QueueItemUi(
PlaylistElementUiModel(
id = "first",
title = "Episode 1",
subtitle = "Fallback entry",
artworkUrl = null,
isCurrent = false
),
QueueItemUi(
PlaylistElementUiModel(
id = "second",
title = "Episode 2",
subtitle = "Later",
@@ -871,21 +871,21 @@ private fun samplePlayerState(): PlayerUiState = PlayerUiState(
positionMs = 120_000,
bufferedMs = 240_000,
queue = listOf(
QueueItemUi(
PlaylistElementUiModel(
id = "played",
title = "Already Played",
subtitle = "Episode 0",
artworkUrl = null,
isCurrent = false
),
QueueItemUi(
PlaylistElementUiModel(
id = "current",
title = "Currently Playing",
subtitle = "Episode 1",
artworkUrl = null,
isCurrent = true
),
QueueItemUi(
PlaylistElementUiModel(
id = "next",
title = "Episode 2",
subtitle = "Up next",

View File

@@ -276,7 +276,7 @@ fun TvPlayerScreen(
onExpandPlaylist = expandPlaylist,
onCollapsePlaylist = collapsePlaylistToControls,
onSelectQueueItem = { id ->
viewModel.playQueueItem(id, TV_CONTROLS_AUTO_HIDE_MS)
viewModel.playQueueItem(id)
collapsePlaylistToControls()
},
qualityButtonEnabled = uiState.qualityTracks.isNotEmpty(),

View File

@@ -20,11 +20,11 @@ import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.withFrameNanos
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.withFrameNanos
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.focus.FocusRequester
@@ -41,9 +41,9 @@ import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import hu.bbara.purefin.player.model.PlayerUiState
import hu.bbara.purefin.player.model.QueueItemUi
import coil3.compose.AsyncImage
import hu.bbara.purefin.player.model.PlayerUiState
import hu.bbara.purefin.player.model.PlaylistElementUiModel
internal const val TvPlayerPlaylistRowTag = "tv_player_playlist_row"
internal const val TvPlayerPlaylistCurrentItemTag = "tv_player_playlist_current_item"
@@ -159,7 +159,7 @@ internal fun TvPlayerQueuePanel(
@Composable
private fun TvQueueRowCard(
item: QueueItemUi,
item: PlaylistElementUiModel,
isCurrent: Boolean,
isFirst: Boolean,
isLast: Boolean,