mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
implement library navigation and screen
- Implement `LibraryScreen` with a responsive grid layout for displaying library contents. - Create `LibraryViewModel` to handle fetching items for a specific library via `JellyfinApiClient`. - Integrate dynamic library navigation in `HomePage` by mapping Jellyfin user views to drawer navigation items. - Add `Route.Library` and `Route.Login` to the navigation graph. - Update `SeriesCard` and `SeriesViewModel` to adjust hero height and use backdrop images for episodes. - Refactor `HomePageViewModel` to support library selection and rename episode selection logic for consistency. - Enhance `PosterCard` with default colors and `PlayerActivity` with a black background. - Remove redundant play button from `SeriesComponents`.
This commit is contained in:
@@ -32,7 +32,7 @@ fun SeriesCard(
|
|||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.background(SeriesBackgroundDark)
|
.background(SeriesBackgroundDark)
|
||||||
) {
|
) {
|
||||||
val heroHeight = maxHeight * 0.6f
|
val heroHeight = maxHeight * 0.4f
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
|
|||||||
@@ -127,12 +127,6 @@ internal fun SeriesHero(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
Box(
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
PlayButton(size = 80.dp)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class SeriesViewModel @Inject constructor(
|
|||||||
title = episode.name ?: "Unknown",
|
title = episode.name ?: "Unknown",
|
||||||
description = episode.overview ?: "",
|
description = episode.overview ?: "",
|
||||||
duration = "58m",
|
duration = "58m",
|
||||||
imageUrl = JellyfinImageHelper.toImageUrl(url = serverUrl, itemId = episode.id, type = ImageType.PRIMARY)
|
imageUrl = JellyfinImageHelper.toImageUrl(url = serverUrl, itemId = episode.id, type = ImageType.BACKDROP)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
SeriesSeasonUiModel(
|
SeriesSeasonUiModel(
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ package hu.bbara.purefin.app.home
|
|||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.outlined.Collections
|
||||||
|
import androidx.compose.material.icons.outlined.Movie
|
||||||
|
import androidx.compose.material.icons.outlined.Tv
|
||||||
import androidx.compose.material3.DrawerValue
|
import androidx.compose.material3.DrawerValue
|
||||||
import androidx.compose.material3.ModalDrawerSheet
|
import androidx.compose.material3.ModalDrawerSheet
|
||||||
import androidx.compose.material3.ModalNavigationDrawer
|
import androidx.compose.material3.ModalNavigationDrawer
|
||||||
@@ -17,9 +21,11 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
|||||||
import hu.bbara.purefin.app.home.ui.HomeContent
|
import hu.bbara.purefin.app.home.ui.HomeContent
|
||||||
import hu.bbara.purefin.app.home.ui.HomeDrawerContent
|
import hu.bbara.purefin.app.home.ui.HomeDrawerContent
|
||||||
import hu.bbara.purefin.app.home.ui.HomeMockData
|
import hu.bbara.purefin.app.home.ui.HomeMockData
|
||||||
|
import hu.bbara.purefin.app.home.ui.HomeNavItem
|
||||||
import hu.bbara.purefin.app.home.ui.HomeTopBar
|
import hu.bbara.purefin.app.home.ui.HomeTopBar
|
||||||
import hu.bbara.purefin.app.home.ui.rememberHomeColors
|
import hu.bbara.purefin.app.home.ui.rememberHomeColors
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import org.jellyfin.sdk.model.api.CollectionType
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun HomePage(
|
fun HomePage(
|
||||||
@@ -30,6 +36,17 @@ fun HomePage(
|
|||||||
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
val drawerState = rememberDrawerState(DrawerValue.Closed)
|
||||||
val coroutineScope = rememberCoroutineScope()
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
val libraries = viewModel.libraries.collectAsState().value.map {
|
||||||
|
HomeNavItem(
|
||||||
|
id = it.id,
|
||||||
|
label = it.name,
|
||||||
|
icon = when (it.type) {
|
||||||
|
CollectionType.MOVIES -> Icons.Outlined.Movie
|
||||||
|
CollectionType.TVSHOWS -> Icons.Outlined.Tv
|
||||||
|
else -> Icons.Outlined.Collections
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
val continueWatching = viewModel.continueWatching.collectAsState()
|
val continueWatching = viewModel.continueWatching.collectAsState()
|
||||||
|
|
||||||
ModalNavigationDrawer(
|
ModalNavigationDrawer(
|
||||||
@@ -46,9 +63,9 @@ fun HomePage(
|
|||||||
title = "Jellyfin",
|
title = "Jellyfin",
|
||||||
subtitle = "Library Dashboard",
|
subtitle = "Library Dashboard",
|
||||||
colors = colors,
|
colors = colors,
|
||||||
primaryNavItems = HomeMockData.primaryNavItems,
|
primaryNavItems = libraries,
|
||||||
secondaryNavItems = HomeMockData.secondaryNavItems,
|
secondaryNavItems = HomeMockData.secondaryNavItems,
|
||||||
user = HomeMockData.user
|
user = HomeMockData.user,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ import androidx.lifecycle.ViewModel
|
|||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import hu.bbara.purefin.app.home.ui.ContinueWatchingItem
|
import hu.bbara.purefin.app.home.ui.ContinueWatchingItem
|
||||||
|
import hu.bbara.purefin.app.home.ui.HomeNavItem
|
||||||
import hu.bbara.purefin.app.home.ui.LibraryItem
|
import hu.bbara.purefin.app.home.ui.LibraryItem
|
||||||
import hu.bbara.purefin.app.home.ui.PosterItem
|
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||||
import hu.bbara.purefin.client.JellyfinApiClient
|
import hu.bbara.purefin.client.JellyfinApiClient
|
||||||
import hu.bbara.purefin.navigation.ItemDto
|
import hu.bbara.purefin.navigation.ItemDto
|
||||||
|
import hu.bbara.purefin.navigation.LibraryDto
|
||||||
import hu.bbara.purefin.navigation.NavigationManager
|
import hu.bbara.purefin.navigation.NavigationManager
|
||||||
import hu.bbara.purefin.navigation.Route
|
import hu.bbara.purefin.navigation.Route
|
||||||
import hu.bbara.purefin.session.UserSessionRepository
|
import hu.bbara.purefin.session.UserSessionRepository
|
||||||
@@ -46,6 +48,12 @@ class HomePageViewModel @Inject constructor(
|
|||||||
loadHomePageData()
|
loadHomePageData()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun onLibrarySelected(library : HomeNavItem) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
navigationManager.navigate(Route.Library(library = LibraryDto(id = library.id, name = library.label)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun onMovieSelected(movieId: String) {
|
fun onMovieSelected(movieId: String) {
|
||||||
navigationManager.navigate(Route.Movie(ItemDto(id = UUID.fromString(movieId), type = BaseItemKind.MOVIE)))
|
navigationManager.navigate(Route.Movie(ItemDto(id = UUID.fromString(movieId), type = BaseItemKind.MOVIE)))
|
||||||
}
|
}
|
||||||
@@ -56,7 +64,7 @@ class HomePageViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onSelectEpisode(episodeId: String) {
|
fun onEpisodeSelected(episodeId: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
navigationManager.navigate(Route.Episode(ItemDto(id = UUID.fromString(episodeId), type = BaseItemKind.EPISODE)))
|
navigationManager.navigate(Route.Episode(ItemDto(id = UUID.fromString(episodeId), type = BaseItemKind.EPISODE)))
|
||||||
}
|
}
|
||||||
@@ -111,7 +119,8 @@ class HomePageViewModel @Inject constructor(
|
|||||||
LibraryItem(
|
LibraryItem(
|
||||||
name = it.name!!,
|
name = it.name!!,
|
||||||
id = it.id,
|
id = it.id,
|
||||||
isEmpty = it.childCount!! == 0
|
isEmpty = it.childCount!! == 0,
|
||||||
|
type = it.collectionType!!
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_libraries.value = mappedLibraries
|
_libraries.value = mappedLibraries
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ fun HomeDrawerContent(
|
|||||||
secondaryNavItems: List<HomeNavItem>,
|
secondaryNavItems: List<HomeNavItem>,
|
||||||
user: HomeUser,
|
user: HomeUser,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onNavItemClick: (HomeNavItem) -> Unit = {}
|
|
||||||
) {
|
) {
|
||||||
Column(modifier = modifier.fillMaxSize()) {
|
Column(modifier = modifier.fillMaxSize()) {
|
||||||
HomeDrawerHeader(
|
HomeDrawerHeader(
|
||||||
@@ -49,7 +48,6 @@ fun HomeDrawerContent(
|
|||||||
primaryItems = primaryNavItems,
|
primaryItems = primaryNavItems,
|
||||||
secondaryItems = secondaryNavItems,
|
secondaryItems = secondaryNavItems,
|
||||||
colors = colors,
|
colors = colors,
|
||||||
onNavItemClick = onNavItemClick
|
|
||||||
)
|
)
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
HomeDrawerFooter(user = user, colors = colors)
|
HomeDrawerFooter(user = user, colors = colors)
|
||||||
@@ -105,7 +103,6 @@ fun HomeDrawerNav(
|
|||||||
secondaryItems: List<HomeNavItem>,
|
secondaryItems: List<HomeNavItem>,
|
||||||
colors: HomeColors,
|
colors: HomeColors,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onNavItemClick: (HomeNavItem) -> Unit = {}
|
|
||||||
) {
|
) {
|
||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
@@ -113,7 +110,7 @@ fun HomeDrawerNav(
|
|||||||
.padding(vertical = 16.dp)
|
.padding(vertical = 16.dp)
|
||||||
) {
|
) {
|
||||||
primaryItems.forEach { item ->
|
primaryItems.forEach { item ->
|
||||||
HomeDrawerNavItem(item = item, colors = colors) { onNavItemClick(item) }
|
HomeDrawerNavItem(item = item, colors = colors)
|
||||||
}
|
}
|
||||||
if (secondaryItems.isNotEmpty()) {
|
if (secondaryItems.isNotEmpty()) {
|
||||||
HorizontalDivider(
|
HorizontalDivider(
|
||||||
@@ -122,7 +119,7 @@ fun HomeDrawerNav(
|
|||||||
color = colors.divider
|
color = colors.divider
|
||||||
)
|
)
|
||||||
secondaryItems.forEach { item ->
|
secondaryItems.forEach { item ->
|
||||||
HomeDrawerNavItem(item = item, colors = colors) { onNavItemClick(item) }
|
HomeDrawerNavItem(item = item, colors = colors)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,7 +130,7 @@ fun HomeDrawerNavItem(
|
|||||||
item: HomeNavItem,
|
item: HomeNavItem,
|
||||||
colors: HomeColors,
|
colors: HomeColors,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
onClick: () -> Unit = {}
|
viewModel: HomePageViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
val background = if (item.selected) colors.primary.copy(alpha = 0.12f) else Color.Transparent
|
val background = if (item.selected) colors.primary.copy(alpha = 0.12f) else Color.Transparent
|
||||||
val tint = if (item.selected) colors.primary else colors.textSecondary
|
val tint = if (item.selected) colors.primary else colors.textSecondary
|
||||||
@@ -142,7 +139,7 @@ fun HomeDrawerNavItem(
|
|||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(horizontal = 16.dp, vertical = 4.dp)
|
.padding(horizontal = 16.dp, vertical = 4.dp)
|
||||||
.background(background, RoundedCornerShape(12.dp))
|
.background(background, RoundedCornerShape(12.dp))
|
||||||
.clickable { onClick() }
|
.clickable { viewModel.onLibrarySelected(item) }
|
||||||
.padding(horizontal = 16.dp, vertical = 12.dp),
|
.padding(horizontal = 16.dp, vertical = 12.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically
|
verticalAlignment = Alignment.CenterVertically
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -6,19 +6,20 @@ import androidx.compose.material.icons.outlined.Movie
|
|||||||
import androidx.compose.material.icons.outlined.Search
|
import androidx.compose.material.icons.outlined.Search
|
||||||
import androidx.compose.material.icons.outlined.Settings
|
import androidx.compose.material.icons.outlined.Settings
|
||||||
import androidx.compose.material.icons.outlined.Tv
|
import androidx.compose.material.icons.outlined.Tv
|
||||||
|
import org.jellyfin.sdk.model.UUID
|
||||||
|
|
||||||
object HomeMockData {
|
object HomeMockData {
|
||||||
val user = HomeUser(name = "Alex User", plan = "Premium Account")
|
val user = HomeUser(name = "Alex User", plan = "Premium Account")
|
||||||
|
|
||||||
val primaryNavItems = listOf(
|
val primaryNavItems = listOf(
|
||||||
HomeNavItem(label = "Home", icon = Icons.Outlined.Home, selected = true),
|
HomeNavItem(id = UUID.randomUUID(), label = "Home", icon = Icons.Outlined.Home, selected = true),
|
||||||
HomeNavItem(label = "Movies", icon = Icons.Outlined.Movie),
|
HomeNavItem(id = UUID.randomUUID(), label = "Movies", icon = Icons.Outlined.Movie),
|
||||||
HomeNavItem(label = "TV Shows", icon = Icons.Outlined.Tv),
|
HomeNavItem(id = UUID.randomUUID(), label = "TV Shows", icon = Icons.Outlined.Tv),
|
||||||
HomeNavItem(label = "Search", icon = Icons.Outlined.Search)
|
HomeNavItem(id = UUID.randomUUID(), label = "Search", icon = Icons.Outlined.Search)
|
||||||
)
|
)
|
||||||
|
|
||||||
val secondaryNavItems = listOf(
|
val secondaryNavItems = listOf(
|
||||||
HomeNavItem(label = "Settings", icon = Icons.Outlined.Settings)
|
HomeNavItem(id = UUID.randomUUID(), label = "Settings", icon = Icons.Outlined.Settings)
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import androidx.compose.ui.graphics.Color
|
|||||||
import androidx.compose.ui.graphics.vector.ImageVector
|
import androidx.compose.ui.graphics.vector.ImageVector
|
||||||
import org.jellyfin.sdk.model.UUID
|
import org.jellyfin.sdk.model.UUID
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
|
import org.jellyfin.sdk.model.api.CollectionType
|
||||||
|
|
||||||
data class ContinueWatchingItem(
|
data class ContinueWatchingItem(
|
||||||
val id: UUID,
|
val id: UUID,
|
||||||
@@ -15,8 +16,9 @@ data class ContinueWatchingItem(
|
|||||||
)
|
)
|
||||||
|
|
||||||
data class LibraryItem(
|
data class LibraryItem(
|
||||||
val name: String,
|
|
||||||
val id: UUID,
|
val id: UUID,
|
||||||
|
val name: String,
|
||||||
|
val type: CollectionType,
|
||||||
val isEmpty: Boolean
|
val isEmpty: Boolean
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,6 +32,7 @@ data class PosterItem(
|
|||||||
}
|
}
|
||||||
|
|
||||||
data class HomeNavItem(
|
data class HomeNavItem(
|
||||||
|
val id: UUID,
|
||||||
val label: String,
|
val label: String,
|
||||||
val icon: ImageVector,
|
val icon: ImageVector,
|
||||||
val selected: Boolean = false
|
val selected: Boolean = false
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ fun ContinueWatchingCard(
|
|||||||
fun openItem(item: ContinueWatchingItem) {
|
fun openItem(item: ContinueWatchingItem) {
|
||||||
when (item.type) {
|
when (item.type) {
|
||||||
BaseItemKind.MOVIE -> viewModel.onMovieSelected(item.id.toString())
|
BaseItemKind.MOVIE -> viewModel.onMovieSelected(item.id.toString())
|
||||||
BaseItemKind.EPISODE -> viewModel.onSelectEpisode(item.id.toString())
|
BaseItemKind.EPISODE -> viewModel.onEpisodeSelected(item.id.toString())
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package hu.bbara.purefin.app.library
|
||||||
|
|
||||||
|
import androidx.lifecycle.ViewModel
|
||||||
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||||
|
import hu.bbara.purefin.client.JellyfinApiClient
|
||||||
|
import hu.bbara.purefin.navigation.NavigationManager
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import org.jellyfin.sdk.model.UUID
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@HiltViewModel
|
||||||
|
class LibraryViewModel @Inject constructor(
|
||||||
|
private val jellyfinApiClient: JellyfinApiClient,
|
||||||
|
private val navigationManager: NavigationManager
|
||||||
|
) : ViewModel() {
|
||||||
|
private val _contents = MutableStateFlow<List<PosterItem>>(emptyList())
|
||||||
|
val contents = _contents.asStateFlow()
|
||||||
|
|
||||||
|
fun selectLibrary(libraryId: UUID) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
val libraryItems = jellyfinApiClient.getLibrary(libraryId)
|
||||||
|
_contents.value = libraryItems.map {
|
||||||
|
PosterItem(
|
||||||
|
id = it.id,
|
||||||
|
title = it.name ?: "Unknown",
|
||||||
|
type = it.type
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
package hu.bbara.purefin.app.library.ui
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.lazy.grid.GridCells
|
||||||
|
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
|
||||||
|
import androidx.compose.foundation.lazy.grid.items
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||||
|
import hu.bbara.purefin.app.library.LibraryViewModel
|
||||||
|
import hu.bbara.purefin.common.ui.PosterCard
|
||||||
|
import hu.bbara.purefin.navigation.LibraryDto
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LibraryScreen(
|
||||||
|
library: LibraryDto,
|
||||||
|
viewModel: LibraryViewModel = hiltViewModel(),
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
LaunchedEffect(library) {
|
||||||
|
viewModel.selectLibrary(libraryId = library.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
val libraryItems = viewModel.contents.collectAsState()
|
||||||
|
|
||||||
|
|
||||||
|
LibraryPosterGrid(libraryItems = libraryItems.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun LibraryPosterGrid(
|
||||||
|
libraryItems: List<PosterItem>,
|
||||||
|
modifier: Modifier = Modifier
|
||||||
|
) {
|
||||||
|
LazyVerticalGrid(
|
||||||
|
columns = GridCells.Adaptive(minSize = 120.dp),
|
||||||
|
contentPadding = PaddingValues(16.dp),
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
|
modifier = modifier.background(Color.Black)
|
||||||
|
) {
|
||||||
|
items(libraryItems) { item ->
|
||||||
|
PosterCard(
|
||||||
|
item = item,
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,7 +103,7 @@ class JellyfinApiClient @Inject constructor(
|
|||||||
}
|
}
|
||||||
val response = api.userViewsApi.getUserViews(
|
val response = api.userViewsApi.getUserViews(
|
||||||
userId = getUserId(),
|
userId = getUserId(),
|
||||||
includeHidden = false
|
includeHidden = false,
|
||||||
)
|
)
|
||||||
Log.d("getLibraries response: {}", response.content.toString())
|
Log.d("getLibraries response: {}", response.content.toString())
|
||||||
return response.content.items
|
return response.content.items
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import coil3.compose.AsyncImage
|
|||||||
import hu.bbara.purefin.app.home.HomePageViewModel
|
import hu.bbara.purefin.app.home.HomePageViewModel
|
||||||
import hu.bbara.purefin.app.home.ui.HomeColors
|
import hu.bbara.purefin.app.home.ui.HomeColors
|
||||||
import hu.bbara.purefin.app.home.ui.PosterItem
|
import hu.bbara.purefin.app.home.ui.PosterItem
|
||||||
|
import hu.bbara.purefin.app.home.ui.rememberHomeColors
|
||||||
import hu.bbara.purefin.image.JellyfinImageHelper
|
import hu.bbara.purefin.image.JellyfinImageHelper
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
import org.jellyfin.sdk.model.api.ImageType
|
import org.jellyfin.sdk.model.api.ImageType
|
||||||
@@ -29,7 +30,7 @@ import org.jellyfin.sdk.model.api.ImageType
|
|||||||
@Composable
|
@Composable
|
||||||
fun PosterCard(
|
fun PosterCard(
|
||||||
item: PosterItem,
|
item: PosterItem,
|
||||||
colors: HomeColors,
|
colors: HomeColors = rememberHomeColors(),
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
viewModel: HomePageViewModel = hiltViewModel()
|
viewModel: HomePageViewModel = hiltViewModel()
|
||||||
) {
|
) {
|
||||||
@@ -37,7 +38,7 @@ fun PosterCard(
|
|||||||
when (posterItem.type) {
|
when (posterItem.type) {
|
||||||
BaseItemKind.MOVIE -> viewModel.onMovieSelected(posterItem.id.toString())
|
BaseItemKind.MOVIE -> viewModel.onMovieSelected(posterItem.id.toString())
|
||||||
BaseItemKind.SERIES -> viewModel.onSeriesSelected(posterItem.id.toString())
|
BaseItemKind.SERIES -> viewModel.onSeriesSelected(posterItem.id.toString())
|
||||||
BaseItemKind.EPISODE -> viewModel.onSelectEpisode(posterItem.id.toString())
|
BaseItemKind.EPISODE -> viewModel.onEpisodeSelected(posterItem.id.toString())
|
||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
app/src/main/java/hu/bbara/purefin/navigation/LibraryDto.kt
Normal file
12
app/src/main/java/hu/bbara/purefin/navigation/LibraryDto.kt
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
package hu.bbara.purefin.navigation
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import org.jellyfin.sdk.model.UUID
|
||||||
|
import org.jellyfin.sdk.model.serializer.UUIDSerializer
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LibraryDto (
|
||||||
|
@Serializable(with = UUIDSerializer::class)
|
||||||
|
val id: UUID,
|
||||||
|
val name: String
|
||||||
|
)
|
||||||
@@ -15,4 +15,10 @@ sealed interface Route : NavKey {
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Episode(val item : ItemDto) : Route
|
data class Episode(val item : ItemDto) : Route
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Library(val library : LibraryDto) : Route
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data object Login : Route
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import hu.bbara.purefin.app.content.episode.EpisodeScreen
|
|||||||
import hu.bbara.purefin.app.content.movie.MovieScreen
|
import hu.bbara.purefin.app.content.movie.MovieScreen
|
||||||
import hu.bbara.purefin.app.content.series.SeriesScreen
|
import hu.bbara.purefin.app.content.series.SeriesScreen
|
||||||
import hu.bbara.purefin.app.home.HomePage
|
import hu.bbara.purefin.app.home.HomePage
|
||||||
|
import hu.bbara.purefin.app.library.ui.LibraryScreen
|
||||||
|
import hu.bbara.purefin.login.ui.LoginScreen
|
||||||
|
|
||||||
fun EntryProviderScope<Route>.appRouteEntryBuilder() {
|
fun EntryProviderScope<Route>.appRouteEntryBuilder() {
|
||||||
entry<Route.Home> {
|
entry<Route.Home> {
|
||||||
@@ -19,4 +21,10 @@ fun EntryProviderScope<Route>.appRouteEntryBuilder() {
|
|||||||
entry<Route.Episode> {
|
entry<Route.Episode> {
|
||||||
EpisodeScreen(episode = it.item)
|
EpisodeScreen(episode = it.item)
|
||||||
}
|
}
|
||||||
|
entry<Route.Library> {
|
||||||
|
LibraryScreen(library = it.library)
|
||||||
|
}
|
||||||
|
entry<Route.Login> {
|
||||||
|
LoginScreen()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,12 +3,14 @@ package hu.bbara.purefin.player
|
|||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.media3.ui.PlayerView
|
import androidx.media3.ui.PlayerView
|
||||||
@@ -22,7 +24,10 @@ class PlayerActivity : ComponentActivity() {
|
|||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
val viewModel = hiltViewModel<PlayerViewModel>()
|
val viewModel = hiltViewModel<PlayerViewModel>()
|
||||||
Box(modifier = Modifier.fillMaxSize()) {
|
Box(
|
||||||
|
modifier = Modifier.fillMaxSize()
|
||||||
|
.background(Color.Black)
|
||||||
|
) {
|
||||||
AndroidView(
|
AndroidView(
|
||||||
factory = { context ->
|
factory = { context ->
|
||||||
PlayerView(context).also {
|
PlayerView(context).also {
|
||||||
|
|||||||
Reference in New Issue
Block a user