mirror of
https://github.com/bbara04/Purefin.git
synced 2026-03-31 17:10:08 +02:00
Fix interactive episode navigation buttons
This commit is contained in:
@@ -34,6 +34,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
||||||
import hu.bbara.purefin.core.data.client.JellyfinApiClient
|
import hu.bbara.purefin.core.data.client.JellyfinApiClient
|
||||||
import hu.bbara.purefin.core.data.client.JellyfinAuthInterceptor
|
import hu.bbara.purefin.core.data.client.JellyfinAuthInterceptor
|
||||||
|
import hu.bbara.purefin.core.data.navigation.LocalNavigationBackStack
|
||||||
import hu.bbara.purefin.core.data.navigation.LocalNavigationManager
|
import hu.bbara.purefin.core.data.navigation.LocalNavigationManager
|
||||||
import hu.bbara.purefin.core.data.navigation.NavigationCommand
|
import hu.bbara.purefin.core.data.navigation.NavigationCommand
|
||||||
import hu.bbara.purefin.core.data.navigation.NavigationManager
|
import hu.bbara.purefin.core.data.navigation.NavigationManager
|
||||||
@@ -164,7 +165,10 @@ class TvActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositionLocalProvider(LocalNavigationManager provides navigationManager) {
|
CompositionLocalProvider(
|
||||||
|
LocalNavigationManager provides navigationManager,
|
||||||
|
LocalNavigationBackStack provides backStack.toList()
|
||||||
|
) {
|
||||||
NavDisplay(
|
NavDisplay(
|
||||||
backStack = backStack,
|
backStack = backStack,
|
||||||
onBack = { navigationManager.pop() },
|
onBack = { navigationManager.pop() },
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
||||||
import hu.bbara.purefin.core.data.client.JellyfinApiClient
|
import hu.bbara.purefin.core.data.client.JellyfinApiClient
|
||||||
import hu.bbara.purefin.core.data.client.JellyfinAuthInterceptor
|
import hu.bbara.purefin.core.data.client.JellyfinAuthInterceptor
|
||||||
|
import hu.bbara.purefin.core.data.navigation.LocalNavigationBackStack
|
||||||
import hu.bbara.purefin.core.data.navigation.LocalNavigationManager
|
import hu.bbara.purefin.core.data.navigation.LocalNavigationManager
|
||||||
import hu.bbara.purefin.core.data.navigation.NavigationCommand
|
import hu.bbara.purefin.core.data.navigation.NavigationCommand
|
||||||
import hu.bbara.purefin.core.data.navigation.NavigationManager
|
import hu.bbara.purefin.core.data.navigation.NavigationManager
|
||||||
@@ -165,7 +166,10 @@ class PurefinActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CompositionLocalProvider(LocalNavigationManager provides navigationManager) {
|
CompositionLocalProvider(
|
||||||
|
LocalNavigationManager provides navigationManager,
|
||||||
|
LocalNavigationBackStack provides backStack.toList()
|
||||||
|
) {
|
||||||
NavDisplay(
|
NavDisplay(
|
||||||
backStack = backStack,
|
backStack = backStack,
|
||||||
onBack = { navigationManager.pop() },
|
onBack = { navigationManager.pop() },
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.padding
|
|||||||
import androidx.compose.foundation.layout.sizeIn
|
import androidx.compose.foundation.layout.sizeIn
|
||||||
import androidx.compose.foundation.layout.statusBarsPadding
|
import androidx.compose.foundation.layout.statusBarsPadding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.outlined.Add
|
import androidx.compose.material.icons.outlined.Add
|
||||||
@@ -49,9 +50,23 @@ import hu.bbara.purefin.core.model.Episode
|
|||||||
import hu.bbara.purefin.feature.download.DownloadState
|
import hu.bbara.purefin.feature.download.DownloadState
|
||||||
import hu.bbara.purefin.player.PlayerActivity
|
import hu.bbara.purefin.player.PlayerActivity
|
||||||
|
|
||||||
|
internal sealed interface EpisodeTopBarShortcut {
|
||||||
|
val label: String
|
||||||
|
val onClick: () -> Unit
|
||||||
|
|
||||||
|
data class Series(override val onClick: () -> Unit) : EpisodeTopBarShortcut {
|
||||||
|
override val label: String = "Series"
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Home(override val onClick: () -> Unit) : EpisodeTopBarShortcut {
|
||||||
|
override val label: String = "Home"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
internal fun EpisodeTopBar(
|
internal fun EpisodeTopBar(
|
||||||
seriesTitle: String?,
|
seriesTitle: String?,
|
||||||
|
shortcut: EpisodeTopBarShortcut?,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onSeriesClick: () -> Unit,
|
onSeriesClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
@@ -70,29 +85,50 @@ internal fun EpisodeTopBar(
|
|||||||
contentDescription = "Back",
|
contentDescription = "Back",
|
||||||
onClick = onBack
|
onClick = onBack
|
||||||
)
|
)
|
||||||
if (!seriesTitle.isNullOrBlank()) {
|
when {
|
||||||
|
shortcut != null -> {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.height(52.dp)
|
||||||
|
.clickable(onClick = shortcut.onClick),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = shortcut.label,
|
||||||
|
color = scheme.onBackground,
|
||||||
|
fontSize = 16.sp,
|
||||||
|
fontWeight = FontWeight.SemiBold,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
modifier = Modifier
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(scheme.background.copy(alpha = 0.65f))
|
||||||
|
.padding(horizontal = 16.dp, vertical = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
!seriesTitle.isNullOrBlank() -> {
|
||||||
Box(
|
Box(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.height(52.dp)
|
||||||
.padding(horizontal = 12.dp),
|
.clickable(onClick = onSeriesClick),
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center
|
||||||
) {
|
) {
|
||||||
Text(
|
Text(
|
||||||
text = seriesTitle,
|
text = seriesTitle,
|
||||||
color = scheme.onBackground,
|
color = scheme.onBackground,
|
||||||
fontSize = 14.sp,
|
fontSize = 16.sp,
|
||||||
fontWeight = FontWeight.SemiBold,
|
fontWeight = FontWeight.SemiBold,
|
||||||
maxLines = 1,
|
maxLines = 1,
|
||||||
overflow = TextOverflow.Ellipsis,
|
overflow = TextOverflow.Ellipsis,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(RoundedCornerShape(999.dp))
|
.clip(CircleShape)
|
||||||
.background(scheme.background.copy(alpha = 0.65f))
|
.background(scheme.background.copy(alpha = 0.65f))
|
||||||
.clickable(onClick = onSeriesClick)
|
|
||||||
.padding(horizontal = 16.dp, vertical = 10.dp)
|
.padding(horizontal = 16.dp, vertical = 10.dp)
|
||||||
)
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
else -> Spacer(modifier = Modifier.weight(1f))
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
|
||||||
}
|
}
|
||||||
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
Row(horizontalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||||
GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { })
|
GhostIconButton(icon = Icons.Outlined.Cast, contentDescription = "Cast", onClick = { })
|
||||||
|
|||||||
@@ -15,12 +15,16 @@ import androidx.compose.material3.Scaffold
|
|||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
import hu.bbara.purefin.common.ui.PurefinWaitingScreen
|
||||||
import hu.bbara.purefin.common.ui.components.MediaHero
|
import hu.bbara.purefin.common.ui.components.MediaHero
|
||||||
import hu.bbara.purefin.core.data.navigation.EpisodeDto
|
import hu.bbara.purefin.core.data.navigation.EpisodeDto
|
||||||
|
import hu.bbara.purefin.core.data.navigation.LocalNavigationBackStack
|
||||||
|
import hu.bbara.purefin.core.data.navigation.LocalNavigationManager
|
||||||
|
import hu.bbara.purefin.core.data.navigation.Route
|
||||||
import hu.bbara.purefin.core.model.Episode
|
import hu.bbara.purefin.core.model.Episode
|
||||||
import hu.bbara.purefin.feature.download.DownloadState
|
import hu.bbara.purefin.feature.download.DownloadState
|
||||||
import hu.bbara.purefin.feature.shared.content.episode.EpisodeScreenViewModel
|
import hu.bbara.purefin.feature.shared.content.episode.EpisodeScreenViewModel
|
||||||
@@ -31,6 +35,9 @@ fun EpisodeScreen(
|
|||||||
viewModel: EpisodeScreenViewModel = hiltViewModel(),
|
viewModel: EpisodeScreenViewModel = hiltViewModel(),
|
||||||
modifier: Modifier = Modifier
|
modifier: Modifier = Modifier
|
||||||
) {
|
) {
|
||||||
|
val navigationManager = LocalNavigationManager.current
|
||||||
|
val backStack = LocalNavigationBackStack.current
|
||||||
|
val previousRoute = remember(backStack) { backStack.getOrNull(backStack.lastIndex - 1) }
|
||||||
|
|
||||||
LaunchedEffect(episode) {
|
LaunchedEffect(episode) {
|
||||||
viewModel.selectEpisode(
|
viewModel.selectEpisode(
|
||||||
@@ -69,6 +76,15 @@ fun EpisodeScreen(
|
|||||||
EpisodeScreenInternal(
|
EpisodeScreenInternal(
|
||||||
episode = episode.value!!,
|
episode = episode.value!!,
|
||||||
seriesTitle = seriesTitle.value,
|
seriesTitle = seriesTitle.value,
|
||||||
|
topBarShortcut = remember(previousRoute) {
|
||||||
|
when (previousRoute) {
|
||||||
|
is Route.SeriesRoute -> EpisodeTopBarShortcut.Home {
|
||||||
|
navigationManager.replaceAll(Route.Home)
|
||||||
|
}
|
||||||
|
Route.Home -> EpisodeTopBarShortcut.Series(viewModel::onSeriesClick)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
},
|
||||||
downloadState = downloadState.value,
|
downloadState = downloadState.value,
|
||||||
onBack = viewModel::onBack,
|
onBack = viewModel::onBack,
|
||||||
onSeriesClick = viewModel::onSeriesClick,
|
onSeriesClick = viewModel::onSeriesClick,
|
||||||
@@ -81,6 +97,7 @@ fun EpisodeScreen(
|
|||||||
private fun EpisodeScreenInternal(
|
private fun EpisodeScreenInternal(
|
||||||
episode: Episode,
|
episode: Episode,
|
||||||
seriesTitle: String?,
|
seriesTitle: String?,
|
||||||
|
topBarShortcut: EpisodeTopBarShortcut?,
|
||||||
downloadState: DownloadState,
|
downloadState: DownloadState,
|
||||||
onBack: () -> Unit,
|
onBack: () -> Unit,
|
||||||
onSeriesClick: () -> Unit,
|
onSeriesClick: () -> Unit,
|
||||||
@@ -94,6 +111,7 @@ private fun EpisodeScreenInternal(
|
|||||||
topBar = {
|
topBar = {
|
||||||
EpisodeTopBar(
|
EpisodeTopBar(
|
||||||
seriesTitle = seriesTitle,
|
seriesTitle = seriesTitle,
|
||||||
|
shortcut = topBarShortcut,
|
||||||
onBack = onBack,
|
onBack = onBack,
|
||||||
onSeriesClick = onSeriesClick,
|
onSeriesClick = onSeriesClick,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
@@ -123,3 +141,5 @@ private fun EpisodeScreenInternal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package hu.bbara.purefin.core.data.navigation
|
package hu.bbara.purefin.core.data.navigation
|
||||||
|
|
||||||
import androidx.compose.runtime.ProvidableCompositionLocal
|
import androidx.compose.runtime.ProvidableCompositionLocal
|
||||||
|
import androidx.compose.runtime.compositionLocalOf
|
||||||
import androidx.compose.runtime.staticCompositionLocalOf
|
import androidx.compose.runtime.staticCompositionLocalOf
|
||||||
import kotlinx.coroutines.channels.BufferOverflow
|
import kotlinx.coroutines.channels.BufferOverflow
|
||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
@@ -43,3 +44,5 @@ class DefaultNavigationManager : NavigationManager {
|
|||||||
|
|
||||||
val LocalNavigationManager: ProvidableCompositionLocal<NavigationManager> =
|
val LocalNavigationManager: ProvidableCompositionLocal<NavigationManager> =
|
||||||
staticCompositionLocalOf { error("NavigationManager not provided") }
|
staticCompositionLocalOf { error("NavigationManager not provided") }
|
||||||
|
|
||||||
|
val LocalNavigationBackStack = compositionLocalOf<List<Route>> { emptyList() }
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import androidx.lifecycle.viewModelScope
|
|||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import hu.bbara.purefin.core.data.AppContentRepository
|
import hu.bbara.purefin.core.data.AppContentRepository
|
||||||
import hu.bbara.purefin.core.data.navigation.NavigationManager
|
import hu.bbara.purefin.core.data.navigation.NavigationManager
|
||||||
|
import hu.bbara.purefin.core.data.navigation.Route
|
||||||
|
import hu.bbara.purefin.core.data.navigation.SeriesDto
|
||||||
import hu.bbara.purefin.core.model.Episode
|
import hu.bbara.purefin.core.model.Episode
|
||||||
import hu.bbara.purefin.feature.download.DownloadState
|
import hu.bbara.purefin.feature.download.DownloadState
|
||||||
import hu.bbara.purefin.feature.download.MediaDownloadManager
|
import hu.bbara.purefin.feature.download.MediaDownloadManager
|
||||||
@@ -50,7 +52,8 @@ class EpisodeScreenViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun onSeriesClick() {
|
fun onSeriesClick() {
|
||||||
navigationManager.pop()
|
val seriesId = _seriesId.value ?: return
|
||||||
|
navigationManager.navigate(Route.SeriesRoute(SeriesDto(id = seriesId)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun selectEpisode(seriesId: UUID, seasonId: UUID, episodeId: UUID) {
|
fun selectEpisode(seriesId: UUID, seasonId: UUID, episodeId: UUID) {
|
||||||
|
|||||||
Reference in New Issue
Block a user