Reorganize app-tv packages and align test imports

This commit is contained in:
2026-04-15 20:35:46 +02:00
parent ad930e899f
commit 29747a1031
65 changed files with 193 additions and 224 deletions

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.media
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Assert.assertEquals

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.episode
package hu.bbara.purefin.ui.screen.episode
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.ExperimentalTestApi
@@ -16,6 +16,7 @@ import androidx.compose.ui.input.key.Key
import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.ui.theme.AppTheme
import hu.bbara.purefin.ui.screen.episode.components.EpisodePlayButtonTag
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Box
@@ -17,15 +17,15 @@ import androidx.compose.ui.test.pressKey
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.unit.dp
import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.core.model.LibraryKind
import hu.bbara.purefin.core.model.MediaKind
import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.feature.browse.home.ContinueWatchingItem
import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.feature.browse.home.NextUpItem
import hu.bbara.purefin.feature.browse.home.PosterItem
import hu.bbara.purefin.tv.home.TvHomeScreen
import hu.bbara.purefin.ui.screen.home.TvHomeScreen
import hu.bbara.purefin.ui.theme.AppTheme
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CollectionType
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
@@ -298,7 +298,7 @@ class TvHomeContentTest {
private fun sampleContinueWatching(): List<ContinueWatchingItem> {
return listOf(
ContinueWatchingItem(
type = BaseItemKind.MOVIE,
type = MediaKind.MOVIE,
movie = sampleMovie(
id = "11111111-1111-1111-1111-111111111111",
title = "Blade Runner 2049",
@@ -311,7 +311,7 @@ class TvHomeContentTest {
private fun sampleContinueWatchingRow(): List<ContinueWatchingItem> {
return listOf(
ContinueWatchingItem(
type = BaseItemKind.MOVIE,
type = MediaKind.MOVIE,
movie = sampleMovie(
id = "11111111-1111-1111-1111-111111111111",
title = "Blade Runner 2049",
@@ -319,7 +319,7 @@ class TvHomeContentTest {
)
),
ContinueWatchingItem(
type = BaseItemKind.MOVIE,
type = MediaKind.MOVIE,
movie = sampleMovie(
id = "55555555-5555-5555-5555-555555555555",
title = "Mad Max: Fury Road",
@@ -363,7 +363,7 @@ class TvHomeContentTest {
LibraryItem(
id = sampleLibraryId(),
name = "Movies",
type = CollectionType.MOVIES,
type = LibraryKind.MOVIES,
posterUrl = "",
isEmpty = false
)
@@ -376,7 +376,7 @@ class TvHomeContentTest {
return mapOf(
libraryId to listOf(
PosterItem(
type = BaseItemKind.MOVIE,
type = MediaKind.MOVIE,
movie = sampleMovie(
id = "44444444-4444-4444-4444-444444444444",
title = "Arrival",

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.activity.ComponentActivity
import androidx.compose.foundation.layout.Box

View File

@@ -1,12 +1,12 @@
package hu.bbara.purefin.tv.library.ui
package hu.bbara.purefin.ui.screen.libraries
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.performClick
import hu.bbara.purefin.core.model.LibraryKind
import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.ui.theme.AppTheme
import org.jellyfin.sdk.model.api.CollectionType
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test
@@ -23,14 +23,14 @@ class TvLibrariesOverviewScreenTest {
LibraryItem(
id = UUID.fromString("11111111-1111-1111-1111-111111111111"),
name = "Movies",
type = CollectionType.MOVIES,
type = LibraryKind.MOVIES,
posterUrl = "",
isEmpty = false
),
LibraryItem(
id = UUID.fromString("22222222-2222-2222-2222-222222222222"),
name = "Shows",
type = CollectionType.TVSHOWS,
type = LibraryKind.SERIES,
posterUrl = "",
isEmpty = false
)

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.movie
package hu.bbara.purefin.ui.screen.movie
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.ExperimentalTestApi
@@ -16,6 +16,7 @@ import androidx.compose.ui.input.key.Key
import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.ui.theme.AppTheme
import hu.bbara.purefin.ui.screen.movie.components.MoviePlayButtonTag
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.player.components
package hu.bbara.purefin.ui.screen.player.components
import androidx.activity.ComponentActivity
import androidx.compose.animation.AnimatedVisibility
@@ -44,10 +44,10 @@ import hu.bbara.purefin.core.player.model.PlayerUiState
import hu.bbara.purefin.core.player.model.QueueItemUi
import hu.bbara.purefin.core.player.model.TrackOption
import hu.bbara.purefin.core.player.model.TrackType
import hu.bbara.purefin.tv.player.TV_HIDDEN_STOP_FEEDBACK_MS
import hu.bbara.purefin.tv.player.TvPlayerHiddenStopFeedback
import hu.bbara.purefin.tv.player.TvPlayerHiddenStopFeedbackTag
import hu.bbara.purefin.tv.player.handleTvPlayerRootKeyEvent
import hu.bbara.purefin.ui.screen.player.TV_HIDDEN_STOP_FEEDBACK_MS
import hu.bbara.purefin.ui.screen.player.TvPlayerHiddenStopFeedback
import hu.bbara.purefin.ui.screen.player.TvPlayerHiddenStopFeedbackTag
import hu.bbara.purefin.ui.screen.player.handleTvPlayerRootKeyEvent
import hu.bbara.purefin.ui.theme.AppTheme
import kotlinx.coroutines.delay
import org.junit.Rule

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.series
package hu.bbara.purefin.ui.screen.series
import androidx.activity.ComponentActivity
import androidx.compose.ui.test.ExperimentalTestApi
@@ -16,6 +16,8 @@ import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.core.model.Season
import hu.bbara.purefin.core.model.Series
import hu.bbara.purefin.ui.theme.AppTheme
import hu.bbara.purefin.ui.screen.series.components.SeriesFirstSeasonTabTag
import hu.bbara.purefin.ui.screen.series.components.SeriesPlayButtonTag
import org.junit.Assert.assertEquals
import org.junit.Rule
import org.junit.Test

View File

@@ -14,7 +14,7 @@
android:required="true" />
<application
android:name=".TvApplication"
android:name="hu.bbara.purefin.TvApplication"
android:allowBackup="true"
android:banner="@drawable/banner"
android:dataExtractionRules="@xml/data_extraction_rules"
@@ -25,7 +25,7 @@
android:supportsRtl="true"
android:theme="@style/Theme.Purefin">
<activity
android:name=".TvActivity"
android:name="hu.bbara.purefin.TvActivity"
android:exported="true"
android:theme="@style/Theme.Purefin">
<intent-filter>

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv
package hu.bbara.purefin
import android.content.pm.ApplicationInfo
import android.os.Bundle
@@ -36,16 +36,16 @@ import coil3.network.okhttp.OkHttpNetworkFetcherFactory
import coil3.request.crossfade
import coil3.util.DebugLogger
import dagger.hilt.android.AndroidEntryPoint
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.core.data.SessionBootstrapper
import hu.bbara.purefin.data.jellyfin.client.JellyfinAuthInterceptor
import hu.bbara.purefin.core.data.session.UserSessionRepository
import hu.bbara.purefin.login.ui.LoginScreen
import hu.bbara.purefin.core.navigation.NavigationCommand
import hu.bbara.purefin.core.navigation.NavigationManager
import hu.bbara.purefin.core.navigation.Route
import hu.bbara.purefin.tv.navigation.LocalNavigationBackStack
import hu.bbara.purefin.tv.navigation.LocalNavigationManager
import hu.bbara.purefin.data.jellyfin.client.JellyfinAuthInterceptor
import hu.bbara.purefin.navigation.LocalNavigationBackStack
import hu.bbara.purefin.navigation.LocalNavigationManager
import hu.bbara.purefin.ui.screen.login.LoginScreen
import hu.bbara.purefin.ui.screen.waiting.PurefinWaitingScreen
import hu.bbara.purefin.ui.theme.AppTheme
import hu.bbara.purefin.ui.theme.backgroundDark
import kotlinx.coroutines.launch

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv
package hu.bbara.purefin
import android.app.Application
import dagger.hilt.android.HiltAndroidApp

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.navigation
package hu.bbara.purefin.modules
import androidx.navigation3.runtime.EntryProviderScope
import dagger.Module
@@ -7,6 +7,13 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityRetainedComponent
import dagger.multibindings.IntoSet
import hu.bbara.purefin.core.navigation.Route
import hu.bbara.purefin.navigation.tvEpisodeSection
import hu.bbara.purefin.navigation.tvHomeSection
import hu.bbara.purefin.navigation.tvLibrarySection
import hu.bbara.purefin.navigation.tvLoginSection
import hu.bbara.purefin.navigation.tvMovieSection
import hu.bbara.purefin.navigation.tvPlayerSection
import hu.bbara.purefin.navigation.tvSeriesSection
@Module
@InstallIn(ActivityRetainedComponent::class)

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.di
package hu.bbara.purefin.modules
import dagger.Module
import dagger.Provides

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.navigation
package hu.bbara.purefin.navigation
import androidx.compose.runtime.ProvidableCompositionLocal
import androidx.compose.runtime.compositionLocalOf

View File

@@ -1,14 +1,14 @@
package hu.bbara.purefin.tv.navigation
package hu.bbara.purefin.navigation
import androidx.navigation3.runtime.EntryProviderScope
import hu.bbara.purefin.app.content.episode.TvEpisodeScreen
import hu.bbara.purefin.app.content.movie.TvMovieScreen
import hu.bbara.purefin.app.content.series.TvSeriesScreen
import hu.bbara.purefin.ui.screen.episode.TvEpisodeScreen
import hu.bbara.purefin.ui.screen.movie.TvMovieScreen
import hu.bbara.purefin.ui.screen.series.TvSeriesScreen
import hu.bbara.purefin.core.navigation.Route
import hu.bbara.purefin.login.ui.LoginScreen
import hu.bbara.purefin.tv.TvAppScreen
import hu.bbara.purefin.tv.library.ui.TvLibraryScreen
import hu.bbara.purefin.tv.player.TvPlayerScreen
import hu.bbara.purefin.ui.screen.login.LoginScreen
import hu.bbara.purefin.ui.screen.TvAppScreen
import hu.bbara.purefin.ui.screen.library.TvLibraryScreen
import hu.bbara.purefin.ui.screen.player.TvPlayerScreen
fun EntryProviderScope<Route>.tvHomeSection() {
entry<Route.Home> {

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.badge
import androidx.compose.foundation.background
import androidx.compose.foundation.border
@@ -17,7 +17,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@Composable
fun UnwatchedEpisodeIndicator(
fun UnwatchedEpisodeBadge(
unwatchedCount: Int,
foregroundColor: Color = MaterialTheme.colorScheme.onPrimary,
backgroundColor: Color = MaterialTheme.colorScheme.primary,

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.badge
import androidx.compose.foundation.background
import androidx.compose.foundation.border
@@ -20,7 +20,7 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@Composable
fun WatchStateIndicator(
fun WatchStateBadge(
watched: Boolean,
started: Boolean,
watchedColor: Color = MaterialTheme.colorScheme.onPrimary,
@@ -63,19 +63,19 @@ fun WatchStateIndicator(
@Preview
@Composable
private fun WatchStateIndicatorPreview() {
private fun WatchStateBadgePreview() {
Column() {
WatchStateIndicator(
WatchStateBadge(
watched = false,
started = false
)
WatchStateIndicator(
WatchStateBadge(
watched = true,
started = false
)
WatchStateIndicator(
WatchStateBadge(
watched = false,
started = true
)
}
}
}

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.bar
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.button
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.button
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.button
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.button
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.button
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui
package hu.bbara.purefin.ui.common.button
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material3.Button

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui
package hu.bbara.purefin.ui.common.card
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
@@ -29,9 +29,9 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.common.ui.components.UnwatchedEpisodeIndicator
import hu.bbara.purefin.common.ui.components.WatchStateIndicator
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import hu.bbara.purefin.ui.common.badge.UnwatchedEpisodeBadge
import hu.bbara.purefin.ui.common.badge.WatchStateBadge
import hu.bbara.purefin.feature.browse.home.FocusableItem
import hu.bbara.purefin.feature.browse.home.PosterItem
import java.util.UUID
@@ -101,7 +101,7 @@ fun PosterCard(
when (item.type) {
MediaKind.MOVIE -> {
val m = item.movie!!
WatchStateIndicator(
WatchStateBadge(
size = indicatorSize,
modifier = Modifier.align(Alignment.TopEnd)
.padding(indicatorPadding),
@@ -111,7 +111,7 @@ fun PosterCard(
}
MediaKind.EPISODE -> {
val ep = item.episode!!
WatchStateIndicator(
WatchStateBadge(
size = indicatorSize,
modifier = Modifier.align(Alignment.TopEnd)
.padding(indicatorPadding),
@@ -119,7 +119,7 @@ fun PosterCard(
started = (ep.progress ?: 0.0) > 0
)
}
MediaKind.SERIES -> UnwatchedEpisodeIndicator(
MediaKind.SERIES -> UnwatchedEpisodeBadge(
size = indicatorSize,
modifier = Modifier.align(Alignment.TopEnd)
.padding(indicatorPadding),

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.image
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui
package hu.bbara.purefin.ui.common.media
import androidx.compose.foundation.background
import androidx.compose.foundation.border
@@ -33,7 +33,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.TextUnit
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import hu.bbara.purefin.core.model.CastMember
@Composable

View File

@@ -1,6 +1,6 @@
@file:OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class)
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.media
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.BringIntoViewSpec
@@ -31,7 +31,7 @@ import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.MediaSynopsis
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import hu.bbara.purefin.core.image.ImageUrlBuilder
import hu.bbara.purefin.core.image.ArtworkKind

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.media
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
@@ -37,6 +37,7 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.ui.common.button.GhostIconButton
internal data class MediaDetailsTopBarShortcut(
val label: String,

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.media
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui
package hu.bbara.purefin.ui.common.media
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui
package hu.bbara.purefin.ui.common.textfield
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui
package hu.bbara.purefin.ui.common.textfield
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui.components
package hu.bbara.purefin.ui.common.visual
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.EnterTransition

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv
package hu.bbara.purefin.ui.screen
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.icons.Icons
@@ -16,11 +16,11 @@ import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import hu.bbara.purefin.feature.browse.home.AppViewModel
import hu.bbara.purefin.tv.home.TvHomeScreen
import hu.bbara.purefin.tv.home.ui.TvDrawerDestination
import hu.bbara.purefin.tv.home.ui.TvDrawerDestinationItem
import hu.bbara.purefin.tv.home.ui.TvNavigationDrawer
import hu.bbara.purefin.tv.library.ui.TvLibrariesOverviewScreen
import hu.bbara.purefin.ui.screen.home.TvHomeScreen
import hu.bbara.purefin.ui.screen.home.components.TvDrawerDestination
import hu.bbara.purefin.ui.screen.home.components.TvDrawerDestinationItem
import hu.bbara.purefin.ui.screen.home.components.TvNavigationDrawer
import hu.bbara.purefin.ui.screen.libraries.TvLibrariesOverviewScreen
import hu.bbara.purefin.core.model.LibraryKind
@Composable

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.episode
package hu.bbara.purefin.ui.screen.episode
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -13,16 +13,17 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.MediaCastRow
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection
import hu.bbara.purefin.common.ui.components.MediaDetailPlaybackSection
import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle
import hu.bbara.purefin.common.ui.components.TvMediaDetailBodyBox
import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold
import hu.bbara.purefin.ui.common.media.MediaCastRow
import hu.bbara.purefin.ui.screen.waiting.PurefinWaitingScreen
import hu.bbara.purefin.ui.common.media.MediaDetailOverviewSection
import hu.bbara.purefin.ui.common.media.MediaDetailPlaybackSection
import hu.bbara.purefin.ui.common.media.MediaDetailSectionTitle
import hu.bbara.purefin.ui.common.media.TvMediaDetailBodyBox
import hu.bbara.purefin.ui.common.media.TvMediaDetailScaffold
import hu.bbara.purefin.ui.screen.episode.components.TvEpisodeHeroSection
import hu.bbara.purefin.core.image.ImageUrlBuilder
import hu.bbara.purefin.core.navigation.EpisodeDto
import hu.bbara.purefin.tv.navigation.LocalNavigationManager
import hu.bbara.purefin.navigation.LocalNavigationManager
import hu.bbara.purefin.core.navigation.Route
import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.feature.content.episode.EpisodeScreenViewModel

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.episode
package hu.bbara.purefin.ui.screen.episode.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -20,8 +20,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.MediaMetaChip
import hu.bbara.purefin.common.ui.components.MediaResumeButton
import hu.bbara.purefin.ui.common.media.MediaMetaChip
import hu.bbara.purefin.ui.common.button.MediaResumeButton
import hu.bbara.purefin.core.model.Episode
internal const val EpisodePlayButtonTag = "episode-play-button"

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home
package hu.bbara.purefin.ui.screen.home
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.BoxWithConstraints
@@ -13,9 +13,9 @@ import hu.bbara.purefin.feature.browse.home.ContinueWatchingItem
import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.feature.browse.home.NextUpItem
import hu.bbara.purefin.feature.browse.home.PosterItem
import hu.bbara.purefin.tv.home.ui.TvFocusedItemHero
import hu.bbara.purefin.tv.home.ui.TvHomeContent
import hu.bbara.purefin.tv.home.ui.rememberTvHomeHeroState
import hu.bbara.purefin.ui.screen.home.components.TvFocusedItemHero
import hu.bbara.purefin.ui.screen.home.components.TvHomeContent
import hu.bbara.purefin.ui.screen.home.components.rememberTvHomeHeroState
import java.util.UUID
private const val TvHomeHeroHeightFraction = 0.32f

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import hu.bbara.purefin.core.image.ImageUrlBuilder
import hu.bbara.purefin.core.model.Episode

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.animation.Crossfade
import androidx.compose.animation.core.tween
@@ -23,7 +23,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
internal const val TvHomeHeroTitleTag = "tv-home-hero-title"
internal const val TvHomeHeroProgressLabelTag = "tv-home-hero-progress-label"

View File

@@ -1,6 +1,6 @@
@file:OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class)
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.foundation.gestures.BringIntoViewSpec
import androidx.compose.ui.unit.dp

View File

@@ -1,6 +1,6 @@
@file:OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class)
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.LocalBringIntoViewSpec

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.ui.graphics.vector.ImageVector

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.ExperimentalFoundationApi
@@ -44,9 +44,9 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.PosterCard
import hu.bbara.purefin.common.ui.components.MediaProgressBar
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.ui.common.card.PosterCard
import hu.bbara.purefin.ui.common.bar.MediaProgressBar
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import hu.bbara.purefin.core.image.ImageUrlBuilder
import hu.bbara.purefin.feature.browse.home.ContinueWatchingItem
import hu.bbara.purefin.feature.browse.home.FocusableItem

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.animateDpAsState

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.library.ui
package hu.bbara.purefin.ui.screen.libraries
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
@@ -43,7 +43,7 @@ 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.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.core.model.LibraryKind

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.library.ui
package hu.bbara.purefin.ui.screen.library
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -22,8 +22,8 @@ import androidx.compose.runtime.collectAsState
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.PosterCard
import hu.bbara.purefin.common.ui.components.PurefinIconButton
import hu.bbara.purefin.ui.common.card.PosterCard
import hu.bbara.purefin.ui.common.button.PurefinIconButton
import hu.bbara.purefin.core.navigation.LibraryDto
import hu.bbara.purefin.feature.browse.home.PosterItem
import hu.bbara.purefin.feature.browse.library.LibraryViewModel

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.login.ui
package hu.bbara.purefin.ui.screen.login
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Arrangement
@@ -37,10 +37,10 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.PurefinComplexTextField
import hu.bbara.purefin.common.ui.PurefinPasswordField
import hu.bbara.purefin.common.ui.PurefinTextButton
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.ui.common.textfield.PurefinComplexTextField
import hu.bbara.purefin.ui.common.textfield.PurefinPasswordField
import hu.bbara.purefin.ui.common.button.PurefinTextButton
import hu.bbara.purefin.ui.screen.waiting.PurefinWaitingScreen
import hu.bbara.purefin.feature.login.LoginViewModel
import kotlinx.coroutines.launch

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.movie
package hu.bbara.purefin.ui.screen.movie
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -13,14 +13,15 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.MediaCastRow
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection
import hu.bbara.purefin.common.ui.components.MediaDetailPlaybackSection
import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle
import hu.bbara.purefin.common.ui.components.TvMediaDetailBodyBox
import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold
import hu.bbara.purefin.common.ui.components.tvMediaDetailBackgroundImageUrl
import hu.bbara.purefin.ui.common.media.MediaCastRow
import hu.bbara.purefin.ui.screen.waiting.PurefinWaitingScreen
import hu.bbara.purefin.ui.common.media.MediaDetailOverviewSection
import hu.bbara.purefin.ui.common.media.MediaDetailPlaybackSection
import hu.bbara.purefin.ui.common.media.MediaDetailSectionTitle
import hu.bbara.purefin.ui.common.media.TvMediaDetailBodyBox
import hu.bbara.purefin.ui.common.media.TvMediaDetailScaffold
import hu.bbara.purefin.ui.common.media.tvMediaDetailBackgroundImageUrl
import hu.bbara.purefin.ui.screen.movie.components.TvMovieHeroSection
import hu.bbara.purefin.core.navigation.MovieDto
import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.feature.content.movie.MovieScreenViewModel

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.movie
package hu.bbara.purefin.ui.screen.movie.components
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
@@ -20,8 +20,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import hu.bbara.purefin.common.ui.MediaMetaChip
import hu.bbara.purefin.common.ui.components.MediaResumeButton
import hu.bbara.purefin.ui.common.media.MediaMetaChip
import hu.bbara.purefin.ui.common.button.MediaResumeButton
import hu.bbara.purefin.core.model.Movie
internal const val MoviePlayButtonTag = "movie-play-button"

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.player
package hu.bbara.purefin.ui.screen.player
import android.app.Activity
import android.view.WindowManager
@@ -50,10 +50,10 @@ import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView
import hu.bbara.purefin.core.player.viewmodel.ControlsAutoHideBlocker
import hu.bbara.purefin.core.player.viewmodel.PlayerViewModel
import hu.bbara.purefin.tv.player.components.TvPlayerControlsOverlay
import hu.bbara.purefin.tv.player.components.TvPlayerLoadingErrorEndCard
import hu.bbara.purefin.tv.player.components.TvTrackPanelType
import hu.bbara.purefin.tv.player.components.TvTrackSelectionPanel
import hu.bbara.purefin.ui.screen.player.components.TvPlayerControlsOverlay
import hu.bbara.purefin.ui.screen.player.components.TvPlayerLoadingErrorEndCard
import hu.bbara.purefin.ui.screen.player.components.TvTrackPanelType
import hu.bbara.purefin.ui.screen.player.components.TvTrackSelectionPanel
import kotlinx.coroutines.delay
private const val TV_CONTROLS_AUTO_HIDE_MS = 5_000L

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.player.components
package hu.bbara.purefin.ui.screen.player.components
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.player.components
package hu.bbara.purefin.ui.screen.player.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.player.components
package hu.bbara.purefin.ui.screen.player.components
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.background

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.player.components
package hu.bbara.purefin.ui.screen.player.components
import androidx.compose.foundation.background
import androidx.compose.foundation.border

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.player.components
package hu.bbara.purefin.ui.screen.player.components
import androidx.compose.foundation.Canvas
import androidx.compose.foundation.focusable

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.tv.player.components
package hu.bbara.purefin.ui.screen.player.components
import androidx.compose.foundation.background
import androidx.compose.foundation.border

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.series
package hu.bbara.purefin.ui.screen.series
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
@@ -16,12 +16,17 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
import hu.bbara.purefin.common.ui.components.MediaDetailOverviewSection
import hu.bbara.purefin.common.ui.components.MediaDetailSectionTitle
import hu.bbara.purefin.common.ui.components.TvMediaDetailBodyBox
import hu.bbara.purefin.common.ui.components.TvMediaDetailScaffold
import hu.bbara.purefin.common.ui.components.tvMediaDetailBackgroundImageUrl
import hu.bbara.purefin.ui.screen.waiting.PurefinWaitingScreen
import hu.bbara.purefin.ui.common.media.MediaDetailOverviewSection
import hu.bbara.purefin.ui.common.media.MediaDetailSectionTitle
import hu.bbara.purefin.ui.common.media.TvMediaDetailBodyBox
import hu.bbara.purefin.ui.common.media.TvMediaDetailScaffold
import hu.bbara.purefin.ui.common.media.tvMediaDetailBackgroundImageUrl
import hu.bbara.purefin.ui.screen.series.components.CastRow
import hu.bbara.purefin.ui.screen.series.components.SeriesFirstSeasonTabTag
import hu.bbara.purefin.ui.screen.series.components.TvEpisodeCarousel
import hu.bbara.purefin.ui.screen.series.components.TvSeasonTabs
import hu.bbara.purefin.ui.screen.series.components.TvSeriesHeroSection
import hu.bbara.purefin.core.navigation.SeriesDto
import hu.bbara.purefin.core.model.Season
import hu.bbara.purefin.core.model.Series

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.app.content.series
package hu.bbara.purefin.ui.screen.series.components
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
@@ -53,12 +53,12 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.hilt.navigation.compose.hiltViewModel
import hu.bbara.purefin.common.ui.MediaCastRow
import hu.bbara.purefin.common.ui.MediaMetaChip
import hu.bbara.purefin.common.ui.components.MediaProgressBar
import hu.bbara.purefin.common.ui.components.MediaResumeButton
import hu.bbara.purefin.common.ui.components.PurefinAsyncImage
import hu.bbara.purefin.common.ui.components.WatchStateIndicator
import hu.bbara.purefin.ui.common.media.MediaCastRow
import hu.bbara.purefin.ui.common.media.MediaMetaChip
import hu.bbara.purefin.ui.common.bar.MediaProgressBar
import hu.bbara.purefin.ui.common.button.MediaResumeButton
import hu.bbara.purefin.ui.common.image.PurefinAsyncImage
import hu.bbara.purefin.ui.common.badge.WatchStateBadge
import hu.bbara.purefin.core.image.ImageUrlBuilder
import hu.bbara.purefin.core.model.CastMember
import hu.bbara.purefin.core.model.Episode
@@ -335,7 +335,7 @@ private fun TvEpisodeCard(
.align(Alignment.BottomStart)
)
} else {
WatchStateIndicator(
WatchStateBadge(
watched = episode.watched,
started = (episode.progress ?: 0.0) > 0.0,
modifier = Modifier

View File

@@ -1,4 +1,4 @@
package hu.bbara.purefin.common.ui
package hu.bbara.purefin.ui.screen.waiting
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.RepeatMode

View File

@@ -1,37 +0,0 @@
package hu.bbara.purefin.app.content.episode
import hu.bbara.purefin.core.data.navigation.Route
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Assert.assertTrue
import org.junit.Test
class EpisodeTopBarShortcutTest {
@Test
fun `home route exposes series shortcut`() {
var clicked = false
val shortcut = episodeTopBarShortcut(Route.Home) {
clicked = true
}
assertNotNull(shortcut)
assertEquals("Series", shortcut?.label)
shortcut?.onClick?.invoke()
assertTrue(clicked)
}
@Test
fun `non home route hides series shortcut`() {
val shortcut = episodeTopBarShortcut(
previousRoute = Route.PlayerRoute(mediaId = "episode-1"),
onSeriesClick = {}
)
assertNull(shortcut)
}
}

View File

@@ -1,37 +1,32 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import hu.bbara.purefin.core.image.ImageUrlBuilder
import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.core.model.MediaKind
import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.core.model.Series
import hu.bbara.purefin.feature.browse.home.ContinueWatchingItem
import hu.bbara.purefin.feature.browse.home.NextUpItem
import hu.bbara.purefin.feature.browse.home.PosterItem
import org.jellyfin.sdk.model.api.BaseItemKind
import hu.bbara.purefin.core.image.ArtworkKind
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import java.util.UUID
class TvFocusedItemHeroTest {
@Test
fun movieItem_mapsProgressMetadataAndBackdrop() {
fun movieItem_mapsMetadataAndBackdrop() {
val movie = sampleMovie(progress = 42.0)
val item = ContinueWatchingItem(
type = BaseItemKind.MOVIE,
type = MediaKind.MOVIE,
movie = movie
)
val hero = item.toTvFocusedHeroModel()
assertEquals("Continue watching", hero.eyebrowText)
assertEquals("Blade Runner 2049", hero.title)
assertEquals("2017 • 16+ • 164m • 4K", hero.metadataText)
assertEquals(0.42f, hero.progressFraction!!, 0.0001f)
assertEquals("42%", hero.progressLabel)
assertNull(hero.watchedText)
assertEquals(
ImageUrlBuilder.finishImageUrl(movie.imageUrlPrefix, ArtworkKind.BACKDROP),
hero.backdropImageUrl
@@ -50,7 +45,7 @@ class TvFocusedItemHeroTest {
}
@Test
fun episodeItem_prefersWatchedStateOverProgress() {
fun episodeItem_mapsEpisodeMetadata() {
val item = NextUpItem(
episode = sampleEpisode(
progress = 96.0,
@@ -60,29 +55,21 @@ class TvFocusedItemHeroTest {
val hero = item.toTvFocusedHeroModel()
assertEquals("Next up", hero.eyebrowText)
assertEquals("The Very Pulse of the Machine", hero.title)
assertEquals("Episode 3 • 2022-05-20 • 16m • 12+ • HD", hero.metadataText)
assertEquals("Watched", hero.watchedText)
assertNull(hero.progressFraction)
assertNull(hero.progressLabel)
}
@Test
fun seriesItem_usesSeasonAndUnwatchedMetadataWithoutProgress() {
fun seriesItem_usesSeasonAndUnwatchedMetadata() {
val item = PosterItem(
type = BaseItemKind.SERIES,
type = MediaKind.SERIES,
series = sampleSeries()
)
val hero = item.toTvFocusedHeroModel()
assertEquals("Series", hero.eyebrowText)
assertEquals("Love, Death & Robots", hero.title)
assertEquals("2019 • 3 seasons • 5 unwatched", hero.metadataText)
assertNull(hero.watchedText)
assertNull(hero.progressFraction)
assertNull(hero.progressLabel)
}
private fun sampleMovie(progress: Double? = 42.0): Movie {

View File

@@ -1,13 +1,13 @@
package hu.bbara.purefin.tv.home.ui
package hu.bbara.purefin.ui.screen.home.components
import hu.bbara.purefin.core.model.Episode
import hu.bbara.purefin.core.model.LibraryKind
import hu.bbara.purefin.core.model.MediaKind
import hu.bbara.purefin.core.model.Movie
import hu.bbara.purefin.feature.browse.home.ContinueWatchingItem
import hu.bbara.purefin.feature.browse.home.LibraryItem
import hu.bbara.purefin.feature.browse.home.NextUpItem
import hu.bbara.purefin.feature.browse.home.PosterItem
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.CollectionType
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
@@ -108,7 +108,7 @@ class TvHomeHeroStateTest {
return LibraryItem(
id = id,
name = "Movies",
type = CollectionType.MOVIES,
type = LibraryKind.MOVIES,
posterUrl = "",
isEmpty = isEmpty
)
@@ -116,7 +116,7 @@ class TvHomeHeroStateTest {
private fun continueWatchingItem(id: String, title: String): ContinueWatchingItem {
return ContinueWatchingItem(
type = BaseItemKind.MOVIE,
type = MediaKind.MOVIE,
movie = sampleMovie(id = id, title = title)
)
}
@@ -144,7 +144,7 @@ class TvHomeHeroStateTest {
private fun posterItem(id: String, libraryId: UUID): PosterItem {
return PosterItem(
type = BaseItemKind.MOVIE,
type = MediaKind.MOVIE,
movie = sampleMovie(id = id, title = "Arrival", libraryId = libraryId)
)
}