Move NavigationManager to hilt

This commit is contained in:
Damontecres 2025-10-08 18:13:28 -04:00
parent b63e933386
commit 730a578117
No known key found for this signature in database
31 changed files with 159 additions and 145 deletions

View file

@ -103,7 +103,7 @@ android {
buildTypes { buildTypes {
release { release {
isMinifyEnabled = false isMinifyEnabled = false
signingConfig = signingConfigs.getByName("debug")
proguardFiles( proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"), getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro", "proguard-rules.pro",

View file

@ -53,6 +53,9 @@ class MainActivity : AppCompatActivity() {
@Inject @Inject
lateinit var okHttpClient: OkHttpClient lateinit var okHttpClient: OkHttpClient
@Inject
lateinit var navigationManager: NavigationManager
@OptIn(ExperimentalTvMaterial3Api::class) @OptIn(ExperimentalTvMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@ -95,7 +98,7 @@ class MainActivity : AppCompatActivity() {
createDeviceProfile(this@MainActivity, preferences, false) createDeviceProfile(this@MainActivity, preferences, false)
} }
val backStack = rememberNavBackStack(Destination.Main()) val backStack = rememberNavBackStack(Destination.Main())
val navigationManager = NavigationManager(backStack) navigationManager.backStack = backStack
if (server != null && user != null) { if (server != null && user != null) {
ApplicationContent( ApplicationContent(
@ -119,12 +122,10 @@ class MainActivity : AppCompatActivity() {
} else if (server != null) { } else if (server != null) {
// Have server but no user, go to user selection // Have server but no user, go to user selection
SwitchUserContent( SwitchUserContent(
navigationManager = navigationManager,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) )
} else { } else {
SwitchServerContent( SwitchServerContent(
navigationManager = navigationManager,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) )
} }

View file

@ -8,13 +8,13 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.github.damontecres.dolphin.data.model.BaseItem
import com.github.damontecres.dolphin.preferences.UserPreferences import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.ui.DefaultItemFields import com.github.damontecres.dolphin.ui.DefaultItemFields
import com.github.damontecres.dolphin.ui.OneTimeLaunchedEffect import com.github.damontecres.dolphin.ui.OneTimeLaunchedEffect
import com.github.damontecres.dolphin.ui.main.HomePageContent import com.github.damontecres.dolphin.ui.main.HomePageContent
import com.github.damontecres.dolphin.ui.main.HomeRow import com.github.damontecres.dolphin.ui.main.HomeRow
import com.github.damontecres.dolphin.ui.main.HomeSection import com.github.damontecres.dolphin.ui.main.HomeSection
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.util.ApiRequestPager import com.github.damontecres.dolphin.util.ApiRequestPager
import com.github.damontecres.dolphin.util.ExceptionHandler import com.github.damontecres.dolphin.util.ExceptionHandler
import com.github.damontecres.dolphin.util.GetItemsRequestHandler import com.github.damontecres.dolphin.util.GetItemsRequestHandler
@ -126,9 +126,9 @@ class RecommendedMovieViewModel
@Composable @Composable
fun RecommendedMovie( fun RecommendedMovie(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
parentId: UUID, parentId: UUID,
modifier: Modifier, onClickItem: (BaseItem) -> Unit,
modifier: Modifier = Modifier,
viewModel: RecommendedMovieViewModel = hiltViewModel(), viewModel: RecommendedMovieViewModel = hiltViewModel(),
) { ) {
OneTimeLaunchedEffect { OneTimeLaunchedEffect {
@ -144,8 +144,8 @@ fun RecommendedMovie(
LoadingState.Success -> LoadingState.Success ->
HomePageContent( HomePageContent(
navigationManager = navigationManager,
homeRows = rows, homeRows = rows,
onClickItem = onClickItem,
modifier = modifier, modifier = modifier,
) )
} }

View file

@ -8,13 +8,13 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.github.damontecres.dolphin.data.model.BaseItem
import com.github.damontecres.dolphin.preferences.UserPreferences import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.ui.DefaultItemFields import com.github.damontecres.dolphin.ui.DefaultItemFields
import com.github.damontecres.dolphin.ui.OneTimeLaunchedEffect import com.github.damontecres.dolphin.ui.OneTimeLaunchedEffect
import com.github.damontecres.dolphin.ui.main.HomePageContent import com.github.damontecres.dolphin.ui.main.HomePageContent
import com.github.damontecres.dolphin.ui.main.HomeRow import com.github.damontecres.dolphin.ui.main.HomeRow
import com.github.damontecres.dolphin.ui.main.HomeSection import com.github.damontecres.dolphin.ui.main.HomeSection
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.util.ApiRequestPager import com.github.damontecres.dolphin.util.ApiRequestPager
import com.github.damontecres.dolphin.util.ExceptionHandler import com.github.damontecres.dolphin.util.ExceptionHandler
import com.github.damontecres.dolphin.util.GetItemsRequestHandler import com.github.damontecres.dolphin.util.GetItemsRequestHandler
@ -138,9 +138,9 @@ class RecommendedTvShowViewModel
@Composable @Composable
fun RecommendedTvShow( fun RecommendedTvShow(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
parentId: UUID, parentId: UUID,
modifier: Modifier, onClickItem: (BaseItem) -> Unit,
modifier: Modifier = Modifier,
viewModel: RecommendedTvShowViewModel = hiltViewModel(), viewModel: RecommendedTvShowViewModel = hiltViewModel(),
) { ) {
OneTimeLaunchedEffect { OneTimeLaunchedEffect {
@ -156,8 +156,8 @@ fun RecommendedTvShow(
LoadingState.Success -> LoadingState.Success ->
HomePageContent( HomePageContent(
navigationManager = navigationManager,
homeRows = rows, homeRows = rows,
onClickItem = onClickItem,
modifier = modifier, modifier = modifier,
) )
} }

View file

@ -58,7 +58,7 @@ private const val DEBUG = false
@Composable @Composable
fun CardGrid( fun CardGrid(
pager: List<BaseItem?>, pager: List<BaseItem?>,
itemOnClick: (BaseItem) -> Unit, onClickItem: (BaseItem) -> Unit,
longClicker: (BaseItem) -> Unit, longClicker: (BaseItem) -> Unit,
letterPosition: suspend (Char) -> Int, letterPosition: suspend (Char) -> Int,
gridFocusRequester: FocusRequester, gridFocusRequester: FocusRequester,
@ -240,7 +240,7 @@ fun CardGrid(
onClick = { onClick = {
if (item != null) { if (item != null) {
focusedIndex = index focusedIndex = index
itemOnClick.invoke(item) onClickItem.invoke(item)
} }
}, },
onLongClick = { if (item != null) longClicker.invoke(item) }, onLongClick = { if (item != null) longClicker.invoke(item) },

View file

@ -39,7 +39,6 @@ import com.github.damontecres.dolphin.ui.data.SeriesSortOptions
import com.github.damontecres.dolphin.ui.data.SortAndDirection import com.github.damontecres.dolphin.ui.data.SortAndDirection
import com.github.damontecres.dolphin.ui.data.VideoSortOptions import com.github.damontecres.dolphin.ui.data.VideoSortOptions
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.ui.tryRequestFocus import com.github.damontecres.dolphin.ui.tryRequestFocus
import com.github.damontecres.dolphin.util.ApiRequestPager import com.github.damontecres.dolphin.util.ApiRequestPager
import com.github.damontecres.dolphin.util.GetItemsRequestHandler import com.github.damontecres.dolphin.util.GetItemsRequestHandler
@ -134,8 +133,8 @@ class CollectionFolderViewModel
@Composable @Composable
fun CollectionFolderDetails( fun CollectionFolderDetails(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.MediaItem, destination: Destination.MediaItem,
onClickItem: (BaseItem) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: CollectionFolderViewModel = hiltViewModel(), viewModel: CollectionFolderViewModel = hiltViewModel(),
initialSortAndDirection: SortAndDirection = initialSortAndDirection: SortAndDirection =
@ -162,12 +161,12 @@ fun CollectionFolderDetails(
pager?.let { pager -> pager?.let { pager ->
CollectionDetails( CollectionDetails(
preferences, preferences,
navigationManager,
library!!, library!!,
item!!, item!!,
pager, pager,
sortAndDirection = sortAndDirection, sortAndDirection = sortAndDirection,
modifier = modifier, modifier = modifier,
onClickItem = onClickItem,
onSortChange = { onSortChange = {
viewModel.loadResults(it) viewModel.loadResults(it)
}, },
@ -182,11 +181,11 @@ fun CollectionFolderDetails(
@Composable @Composable
fun CollectionDetails( fun CollectionDetails(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
library: Library, library: Library,
item: BaseItem, item: BaseItem,
pager: List<BaseItem?>, pager: List<BaseItem?>,
sortAndDirection: SortAndDirection, sortAndDirection: SortAndDirection,
onClickItem: (BaseItem) -> Unit,
onSortChange: (SortAndDirection) -> Unit, onSortChange: (SortAndDirection) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
showTitle: Boolean = true, showTitle: Boolean = true,
@ -232,15 +231,7 @@ fun CollectionDetails(
} }
CardGrid( CardGrid(
pager = pager, pager = pager,
itemOnClick = { onClickItem = onClickItem,
navigationManager.navigateTo(
Destination.MediaItem(
it.id,
it.type,
it,
),
)
},
longClicker = {}, longClicker = {},
letterPosition = { 0 }, letterPosition = { 0 },
gridFocusRequester = gridFocusRequester, gridFocusRequester = gridFocusRequester,

View file

@ -0,0 +1,36 @@
package com.github.damontecres.dolphin.ui.detail
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.preferences.PreferencesViewModel
@Composable
fun CollectionFolderGeneric(
preferences: UserPreferences,
destination: Destination.MediaItem,
modifier: Modifier = Modifier,
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
) {
var showHeader by remember { mutableStateOf(true) }
CollectionFolderDetails(
preferences = preferences,
onClickItem = { preferencesViewModel.navigationManager.navigateTo(it.destination()) },
destination = destination,
showTitle = showHeader,
modifier =
modifier
.padding(start = 16.dp),
positionCallback = { columns, position ->
showHeader = position < columns
},
)
}

View file

@ -29,20 +29,19 @@ import androidx.tv.material3.TabDefaults
import androidx.tv.material3.TabRow import androidx.tv.material3.TabRow
import androidx.tv.material3.TabRowDefaults import androidx.tv.material3.TabRowDefaults
import androidx.tv.material3.Text import androidx.tv.material3.Text
import com.github.damontecres.dolphin.data.model.BaseItem
import com.github.damontecres.dolphin.preferences.UserPreferences import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.preferences.rememberTab import com.github.damontecres.dolphin.preferences.rememberTab
import com.github.damontecres.dolphin.ui.components.ErrorMessage import com.github.damontecres.dolphin.ui.components.ErrorMessage
import com.github.damontecres.dolphin.ui.components.RecommendedMovie import com.github.damontecres.dolphin.ui.components.RecommendedMovie
import com.github.damontecres.dolphin.ui.ifElse import com.github.damontecres.dolphin.ui.ifElse
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.ui.preferences.PreferencesViewModel import com.github.damontecres.dolphin.ui.preferences.PreferencesViewModel
import com.github.damontecres.dolphin.ui.tryRequestFocus import com.github.damontecres.dolphin.ui.tryRequestFocus
@Composable @Composable
fun CollectionFolderMovie( fun CollectionFolderMovie(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.MediaItem, destination: Destination.MediaItem,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
preferencesViewModel: PreferencesViewModel = hiltViewModel(), preferencesViewModel: PreferencesViewModel = hiltViewModel(),
@ -72,6 +71,10 @@ fun CollectionFolderMovie(
} }
var showHeader by rememberSaveable { mutableStateOf(true) } var showHeader by rememberSaveable { mutableStateOf(true) }
val onClickItem = { item: BaseItem ->
preferencesViewModel.navigationManager.navigateTo(item.destination())
}
LaunchedEffect(Unit) { focusRequester.tryRequestFocus() } LaunchedEffect(Unit) { focusRequester.tryRequestFocus() }
Column( Column(
modifier = modifier, modifier = modifier,
@ -137,7 +140,7 @@ fun CollectionFolderMovie(
0 -> { 0 -> {
RecommendedMovie( RecommendedMovie(
preferences = preferences, preferences = preferences,
navigationManager = navigationManager, onClickItem = onClickItem,
parentId = destination.itemId, parentId = destination.itemId,
modifier = modifier =
Modifier Modifier
@ -149,7 +152,7 @@ fun CollectionFolderMovie(
1 -> { 1 -> {
CollectionFolderDetails( CollectionFolderDetails(
preferences = preferences, preferences = preferences,
navigationManager = navigationManager, onClickItem = onClickItem,
destination = destination, destination = destination,
showTitle = false, showTitle = false,
modifier = modifier =

View file

@ -29,20 +29,19 @@ import androidx.tv.material3.TabDefaults
import androidx.tv.material3.TabRow import androidx.tv.material3.TabRow
import androidx.tv.material3.TabRowDefaults import androidx.tv.material3.TabRowDefaults
import androidx.tv.material3.Text import androidx.tv.material3.Text
import com.github.damontecres.dolphin.data.model.BaseItem
import com.github.damontecres.dolphin.preferences.UserPreferences import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.preferences.rememberTab import com.github.damontecres.dolphin.preferences.rememberTab
import com.github.damontecres.dolphin.ui.components.ErrorMessage import com.github.damontecres.dolphin.ui.components.ErrorMessage
import com.github.damontecres.dolphin.ui.components.RecommendedTvShow import com.github.damontecres.dolphin.ui.components.RecommendedTvShow
import com.github.damontecres.dolphin.ui.ifElse import com.github.damontecres.dolphin.ui.ifElse
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.ui.preferences.PreferencesViewModel import com.github.damontecres.dolphin.ui.preferences.PreferencesViewModel
import com.github.damontecres.dolphin.ui.tryRequestFocus import com.github.damontecres.dolphin.ui.tryRequestFocus
@Composable @Composable
fun CollectionFolderTv( fun CollectionFolderTv(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.MediaItem, destination: Destination.MediaItem,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
preferencesViewModel: PreferencesViewModel = hiltViewModel(), preferencesViewModel: PreferencesViewModel = hiltViewModel(),
@ -70,6 +69,9 @@ fun CollectionFolderTv(
} }
} }
} }
val onClickItem = { item: BaseItem ->
preferencesViewModel.navigationManager.navigateTo(item.destination())
}
var showHeader by rememberSaveable { mutableStateOf(true) } var showHeader by rememberSaveable { mutableStateOf(true) }
@ -138,8 +140,8 @@ fun CollectionFolderTv(
0 -> { 0 -> {
RecommendedTvShow( RecommendedTvShow(
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
parentId = destination.itemId, parentId = destination.itemId,
onClickItem = onClickItem,
modifier = modifier =
Modifier Modifier
.padding(start = 16.dp) .padding(start = 16.dp)
@ -150,7 +152,6 @@ fun CollectionFolderTv(
1 -> { 1 -> {
CollectionFolderDetails( CollectionFolderDetails(
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
destination = destination, destination = destination,
showTitle = false, showTitle = false,
modifier = modifier =
@ -161,6 +162,7 @@ fun CollectionFolderTv(
positionCallback = { columns, position -> positionCallback = { columns, position ->
showHeader = position < columns showHeader = position < columns
}, },
onClickItem = onClickItem,
) )
} }
else -> ErrorMessage("Invalid tab index $selectedTabIndex", null) else -> ErrorMessage("Invalid tab index $selectedTabIndex", null)

View file

@ -33,7 +33,6 @@ import com.github.damontecres.dolphin.ui.components.LoadingPage
import com.github.damontecres.dolphin.ui.components.details.VideoDetailsHeader import com.github.damontecres.dolphin.ui.components.details.VideoDetailsHeader
import com.github.damontecres.dolphin.ui.isNotNullOrBlank import com.github.damontecres.dolphin.ui.isNotNullOrBlank
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.util.LoadingState import com.github.damontecres.dolphin.util.LoadingState
import com.github.damontecres.dolphin.util.seasonEpisode import com.github.damontecres.dolphin.util.seasonEpisode
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
@ -54,7 +53,6 @@ class EpisodeViewModel
@Composable @Composable
fun EpisodeDetails( fun EpisodeDetails(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.MediaItem, destination: Destination.MediaItem,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: EpisodeViewModel = hiltViewModel(), viewModel: EpisodeViewModel = hiltViewModel(),

View file

@ -41,6 +41,7 @@ class SeasonViewModel
@Inject @Inject
constructor( constructor(
api: ApiClient, api: ApiClient,
val navigationManager: NavigationManager,
) : ItemViewModel<Video>(api) { ) : ItemViewModel<Video>(api) {
val episodes = MutableLiveData<List<BaseItem?>>(listOf()) val episodes = MutableLiveData<List<BaseItem?>>(listOf())
@ -75,7 +76,6 @@ class SeasonViewModel
@Composable @Composable
fun SeasonDetails( fun SeasonDetails(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.MediaItem, destination: Destination.MediaItem,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: SeasonViewModel = hiltViewModel(), viewModel: SeasonViewModel = hiltViewModel(),
@ -100,7 +100,7 @@ fun SeasonDetails(
ItemRow( ItemRow(
title = "Episodes", title = "Episodes",
items = episodes, items = episodes,
onClickItem = { navigationManager.navigateTo(it.destination()) }, onClickItem = { viewModel.navigationManager.navigateTo(it.destination()) },
onLongClickItem = { }, onLongClickItem = { },
cardOnFocus = { isFocused, index -> cardOnFocus = { isFocused, index ->
if (isFocused) focusedChild = index if (isFocused) focusedChild = index

View file

@ -63,7 +63,6 @@ import com.github.damontecres.dolphin.ui.data.ItemDetailsDialogInfo
import com.github.damontecres.dolphin.ui.isNotNullOrBlank import com.github.damontecres.dolphin.ui.isNotNullOrBlank
import com.github.damontecres.dolphin.ui.letNotEmpty import com.github.damontecres.dolphin.ui.letNotEmpty
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.ui.playOnClickSound import com.github.damontecres.dolphin.ui.playOnClickSound
import com.github.damontecres.dolphin.ui.playSoundOnFocus import com.github.damontecres.dolphin.ui.playSoundOnFocus
import com.github.damontecres.dolphin.ui.roundMinutes import com.github.damontecres.dolphin.ui.roundMinutes
@ -75,7 +74,6 @@ import kotlin.time.Duration
@Composable @Composable
fun SeriesDetails( fun SeriesDetails(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.MediaItem, destination: Destination.MediaItem,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: SeriesViewModel = hiltViewModel(), viewModel: SeriesViewModel = hiltViewModel(),
@ -100,12 +98,12 @@ fun SeriesDetails(
val played = item.data.userData?.played ?: false val played = item.data.userData?.played ?: false
SeriesDetailsContent( SeriesDetailsContent(
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
series = item, series = item,
seasons = seasons, seasons = seasons,
people = people, people = people,
played = played, played = played,
modifier = modifier, modifier = modifier,
onClickItem = { viewModel.navigateTo(it.destination()) },
overviewOnClick = { overviewOnClick = {
overviewDialog = overviewDialog =
ItemDetailsDialogInfo( ItemDetailsDialogInfo(
@ -114,7 +112,7 @@ fun SeriesDetails(
files = listOf(), files = listOf(),
) )
}, },
playOnClick = { viewModel.playNextUp(navigationManager) }, playOnClick = { viewModel.playNextUp() },
watchOnClick = { showWatchConfirmation = true }, watchOnClick = { showWatchConfirmation = true },
) )
if (showWatchConfirmation) { if (showWatchConfirmation) {
@ -144,11 +142,11 @@ fun SeriesDetails(
@Composable @Composable
fun SeriesDetailsContent( fun SeriesDetailsContent(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
series: BaseItem, series: BaseItem,
seasons: ItemListAndMapping, seasons: ItemListAndMapping,
people: List<Person>, people: List<Person>,
played: Boolean, played: Boolean,
onClickItem: (BaseItem) -> Unit,
overviewOnClick: () -> Unit, overviewOnClick: () -> Unit,
playOnClick: () -> Unit, playOnClick: () -> Unit,
watchOnClick: () -> Unit, watchOnClick: () -> Unit,
@ -222,7 +220,7 @@ fun SeriesDetailsContent(
ItemRow( ItemRow(
title = "Seasons", title = "Seasons",
items = seasons.items, items = seasons.items,
onClickItem = { navigationManager.navigateTo(it.destination()) }, onClickItem = onClickItem,
onLongClickItem = { }, onLongClickItem = { },
cardOnFocus = { isFocused, index -> cardOnFocus = { isFocused, index ->
// if (isFocused) { // if (isFocused) {

View file

@ -56,6 +56,7 @@ class SeriesViewModel
api: ApiClient, api: ApiClient,
@param:ApplicationContext val context: Context, @param:ApplicationContext val context: Context,
@param:AuthOkHttpClient private val okHttpClient: OkHttpClient, @param:AuthOkHttpClient private val okHttpClient: OkHttpClient,
private val navigationManager: NavigationManager,
) : ItemViewModel<Video>(api) { ) : ItemViewModel<Video>(api) {
private var player: Player? = null private var player: Player? = null
private lateinit var seriesId: UUID private lateinit var seriesId: UUID
@ -275,7 +276,7 @@ class SeriesViewModel
} }
} }
fun playNextUp(nav: NavigationManager) { fun playNextUp() {
viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) { viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) {
val result by api.tvShowsApi.getNextUp(seriesId = seriesId) val result by api.tvShowsApi.getNextUp(seriesId = seriesId)
val nextUp = val nextUp =
@ -286,7 +287,7 @@ class SeriesViewModel
).content.items ).content.items
.firstOrNull() .firstOrNull()
if (nextUp != null) { if (nextUp != null) {
nav.navigateTo(Destination.Playback(nextUp.id, 0L)) navigateTo(Destination.Playback(nextUp.id, 0L))
} else { } else {
Toast Toast
.makeText(context, "Could not find an episode to play", Toast.LENGTH_SHORT) .makeText(context, "Could not find an episode to play", Toast.LENGTH_SHORT)
@ -294,6 +295,11 @@ class SeriesViewModel
} }
} }
} }
fun navigateTo(destination: Destination) {
release()
navigationManager.navigateTo(destination)
}
} }
data class ItemListAndMapping( data class ItemListAndMapping(

View file

@ -31,12 +31,12 @@ class VideoViewModel
@Inject @Inject
constructor( constructor(
api: ApiClient, api: ApiClient,
val navigationManager: NavigationManager,
) : LoadingItemViewModel<Video>(api) ) : LoadingItemViewModel<Video>(api)
@Composable @Composable
fun VideoDetails( fun VideoDetails(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.MediaItem, destination: Destination.MediaItem,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: MovieViewModel = hiltViewModel(), viewModel: MovieViewModel = hiltViewModel(),
@ -70,7 +70,7 @@ fun VideoDetails(
item { item {
Button( Button(
onClick = { onClick = {
navigationManager.navigateTo( viewModel.navigationManager.navigateTo(
Destination.Playback( Destination.Playback(
item.id, item.id,
it.inWholeMilliseconds, it.inWholeMilliseconds,
@ -87,7 +87,7 @@ fun VideoDetails(
item { item {
Button( Button(
onClick = { onClick = {
navigationManager.navigateTo( viewModel.navigationManager.navigateTo(
Destination.Playback( Destination.Playback(
item.id, item.id,
0L, 0L,

View file

@ -76,6 +76,7 @@ class MovieViewModel
@Inject @Inject
constructor( constructor(
api: ApiClient, api: ApiClient,
val navigationManager: NavigationManager,
) : LoadingItemViewModel<Video>(api) { ) : LoadingItemViewModel<Video>(api) {
private lateinit var itemId: UUID private lateinit var itemId: UUID
val people = MutableLiveData<List<Person>>(listOf()) val people = MutableLiveData<List<Person>>(listOf())
@ -113,7 +114,6 @@ class MovieViewModel
@Composable @Composable
fun MovieDetails( fun MovieDetails(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.MediaItem, destination: Destination.MediaItem,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: MovieViewModel = hiltViewModel(), viewModel: MovieViewModel = hiltViewModel(),
@ -136,12 +136,11 @@ fun MovieDetails(
item?.let { movie -> item?.let { movie ->
MovieDetailsContent( MovieDetailsContent(
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
movie = movie, movie = movie,
people = people, people = people,
chapters = chapters, chapters = chapters,
playOnClick = { playOnClick = {
navigationManager.navigateTo( viewModel.navigationManager.navigateTo(
Destination.Playback( Destination.Playback(
movie.id, movie.id,
it.inWholeMilliseconds, it.inWholeMilliseconds,
@ -172,12 +171,8 @@ fun MovieDetails(
Icons.Default.PlayArrow, Icons.Default.PlayArrow,
iconColor = Color.Green.copy(alpha = .8f), iconColor = Color.Green.copy(alpha = .8f),
) { ) {
navigationManager.navigateTo( viewModel.navigationManager.navigateTo(
Destination.Playback( Destination.Playback(movie),
movie.id,
movie.resumeMs ?: 0L,
movie,
),
) )
}, },
DialogItem( DialogItem(
@ -226,7 +221,6 @@ fun MovieDetails(
@Composable @Composable
fun MovieDetailsContent( fun MovieDetailsContent(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
movie: BaseItem, movie: BaseItem,
people: List<Person>, people: List<Person>,
chapters: List<Chapter>, chapters: List<Chapter>,

View file

@ -29,7 +29,6 @@ import com.github.damontecres.dolphin.ui.data.ItemDetailsDialogInfo
import com.github.damontecres.dolphin.ui.detail.ItemListAndMapping import com.github.damontecres.dolphin.ui.detail.ItemListAndMapping
import com.github.damontecres.dolphin.ui.detail.SeriesViewModel import com.github.damontecres.dolphin.ui.detail.SeriesViewModel
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.ui.tryRequestFocus import com.github.damontecres.dolphin.ui.tryRequestFocus
import com.github.damontecres.dolphin.util.LoadingState import com.github.damontecres.dolphin.util.LoadingState
import com.github.damontecres.dolphin.util.seasonEpisode import com.github.damontecres.dolphin.util.seasonEpisode
@ -55,7 +54,6 @@ data class SeriesOverviewPosition(
@Composable @Composable
fun SeriesOverview( fun SeriesOverview(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
destination: Destination.SeriesOverview, destination: Destination.SeriesOverview,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: SeriesViewModel = hiltViewModel(), viewModel: SeriesViewModel = hiltViewModel(),
@ -146,7 +144,7 @@ fun SeriesOverview(
it.data.userData it.data.userData
?.playbackPositionTicks ?.playbackPositionTicks
?.ticks ?: Duration.ZERO ?.ticks ?: Duration.ZERO
navigationManager.navigateTo( viewModel.navigateTo(
Destination.Playback( Destination.Playback(
it.id, it.id,
resumePosition.inWholeMilliseconds, resumePosition.inWholeMilliseconds,
@ -160,7 +158,7 @@ fun SeriesOverview(
playOnClick = { resume -> playOnClick = { resume ->
episodes.items.getOrNull(position.episodeRowIndex)?.let { episodes.items.getOrNull(position.episodeRowIndex)?.let {
viewModel.release() viewModel.release()
navigationManager.navigateTo( viewModel.navigateTo(
Destination.Playback( Destination.Playback(
it.id, it.id,
resume.inWholeMilliseconds, resume.inWholeMilliseconds,
@ -189,7 +187,7 @@ fun SeriesOverview(
iconColor = Color.Green.copy(alpha = .8f), iconColor = Color.Green.copy(alpha = .8f),
) { ) {
viewModel.release() viewModel.release()
navigationManager.navigateTo( viewModel.navigateTo(
Destination.Playback( Destination.Playback(
ep.id, ep.id,
ep.resumeMs ?: 0L, ep.resumeMs ?: 0L,
@ -203,7 +201,7 @@ fun SeriesOverview(
// iconColor = Color.Green.copy(alpha = .8f), // iconColor = Color.Green.copy(alpha = .8f),
) { ) {
viewModel.release() viewModel.release()
navigationManager.navigateTo( viewModel.navigateTo(
Destination.MediaItem( Destination.MediaItem(
series.id, series.id,
BaseItemKind.SERIES, BaseItemKind.SERIES,

View file

@ -48,7 +48,6 @@ import com.github.damontecres.dolphin.ui.data.RowColumn
import com.github.damontecres.dolphin.ui.data.RowColumnSaver import com.github.damontecres.dolphin.ui.data.RowColumnSaver
import com.github.damontecres.dolphin.ui.ifElse import com.github.damontecres.dolphin.ui.ifElse
import com.github.damontecres.dolphin.ui.isNotNullOrBlank import com.github.damontecres.dolphin.ui.isNotNullOrBlank
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.ui.roundMinutes import com.github.damontecres.dolphin.ui.roundMinutes
import com.github.damontecres.dolphin.ui.timeRemaining import com.github.damontecres.dolphin.ui.timeRemaining
import com.github.damontecres.dolphin.ui.tryRequestFocus import com.github.damontecres.dolphin.ui.tryRequestFocus
@ -66,7 +65,6 @@ data class HomeRow(
@Composable @Composable
fun HomePage( fun HomePage(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: HomeViewModel = hiltViewModel(), viewModel: HomeViewModel = hiltViewModel(),
) { ) {
@ -81,15 +79,21 @@ fun HomePage(
LoadingState.Success -> { LoadingState.Success -> {
val homeRows by viewModel.homeRows.observeAsState(listOf()) val homeRows by viewModel.homeRows.observeAsState(listOf())
HomePageContent(navigationManager, homeRows, modifier) HomePageContent(
homeRows,
onClickItem = {
viewModel.navigationManager.navigateTo(it.destination())
},
modifier,
)
} }
} }
} }
@Composable @Composable
fun HomePageContent( fun HomePageContent(
navigationManager: NavigationManager,
homeRows: List<HomeRow>, homeRows: List<HomeRow>,
onClickItem: (BaseItem) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
var position by rememberSaveable(stateSaver = RowColumnSaver) { var position by rememberSaveable(stateSaver = RowColumnSaver) {
@ -160,9 +164,7 @@ fun HomePageContent(
ItemRow( ItemRow(
title = row.title ?: stringResource(row.section.nameRes), title = row.title ?: stringResource(row.section.nameRes),
items = row.items, items = row.items,
onClickItem = { onClickItem = onClickItem,
navigationManager.navigateTo(it.destination())
},
cardOnFocus = { isFocused, index -> cardOnFocus = { isFocused, index ->
if (isFocused) { if (isFocused) {
focusedItem = row.items.getOrNull(index) focusedItem = row.items.getOrNull(index)

View file

@ -6,6 +6,7 @@ import androidx.lifecycle.viewModelScope
import com.github.damontecres.dolphin.data.model.BaseItem import com.github.damontecres.dolphin.data.model.BaseItem
import com.github.damontecres.dolphin.preferences.UserPreferences import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.ui.DefaultItemFields import com.github.damontecres.dolphin.ui.DefaultItemFields
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.util.LoadingExceptionHandler import com.github.damontecres.dolphin.util.LoadingExceptionHandler
import com.github.damontecres.dolphin.util.LoadingState import com.github.damontecres.dolphin.util.LoadingState
import com.github.damontecres.dolphin.util.supportItemKinds import com.github.damontecres.dolphin.util.supportItemKinds
@ -33,6 +34,7 @@ class HomeViewModel
@Inject @Inject
constructor( constructor(
val api: ApiClient, val api: ApiClient,
val navigationManager: NavigationManager,
) : ViewModel() { ) : ViewModel() {
val loadingState = MutableLiveData<LoadingState>(LoadingState.Loading) val loadingState = MutableLiveData<LoadingState>(LoadingState.Loading)
val homeRows = MutableLiveData<List<HomeRow>>() val homeRows = MutableLiveData<List<HomeRow>>()

View file

@ -48,6 +48,7 @@ class SearchViewModel
@Inject @Inject
constructor( constructor(
val api: ApiClient, val api: ApiClient,
val navigationManager: NavigationManager,
) : ViewModel() { ) : ViewModel() {
val movies = MutableLiveData<List<BaseItem?>>(listOf()) val movies = MutableLiveData<List<BaseItem?>>(listOf())
val series = MutableLiveData<List<BaseItem?>>(listOf()) val series = MutableLiveData<List<BaseItem?>>(listOf())
@ -111,7 +112,6 @@ class SearchViewModel
@Composable @Composable
fun SearchPage( fun SearchPage(
navigationManager: NavigationManager,
userPreferences: UserPreferences, userPreferences: UserPreferences,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: SearchViewModel = hiltViewModel(), viewModel: SearchViewModel = hiltViewModel(),
@ -170,7 +170,7 @@ fun SearchPage(
}, },
items = items, items = items,
onClickItem = { onClickItem = {
navigationManager.navigateTo(it.destination()) viewModel.navigationManager.navigateTo(it.destination())
}, },
onLongClickItem = {}, onLongClickItem = {},
modifier = Modifier.focusRequester(resultsFocusRequester), modifier = Modifier.focusRequester(resultsFocusRequester),

View file

@ -41,7 +41,6 @@ fun ApplicationContent(
DestinationContent( DestinationContent(
destination = key, destination = key,
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
deviceProfile = deviceProfile, deviceProfile = deviceProfile,
modifier = modifier.fillMaxSize(), modifier = modifier.fillMaxSize(),
) )
@ -49,7 +48,6 @@ fun ApplicationContent(
NavDrawer( NavDrawer(
destination = key, destination = key,
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
deviceProfile = deviceProfile, deviceProfile = deviceProfile,
user = user, user = user,
server = server, server = server,

View file

@ -61,6 +61,8 @@ sealed class Destination(
@Transient val item: BaseItem? = null, @Transient val item: BaseItem? = null,
) : Destination(true) { ) : Destination(true) {
override fun toString(): String = "Playback(itemId=$itemId, positionMs=$positionMs)" override fun toString(): String = "Playback(itemId=$itemId, positionMs=$positionMs)"
constructor(item: BaseItem) : this(item.id, item.resumeMs ?: 0, item)
} }
@Serializable @Serializable

View file

@ -5,7 +5,7 @@ import androidx.compose.ui.Modifier
import androidx.tv.material3.Text import androidx.tv.material3.Text
import com.github.damontecres.dolphin.preferences.UserPreferences import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.ui.components.LicenseInfo import com.github.damontecres.dolphin.ui.components.LicenseInfo
import com.github.damontecres.dolphin.ui.detail.CollectionFolderDetails import com.github.damontecres.dolphin.ui.detail.CollectionFolderGeneric
import com.github.damontecres.dolphin.ui.detail.CollectionFolderMovie import com.github.damontecres.dolphin.ui.detail.CollectionFolderMovie
import com.github.damontecres.dolphin.ui.detail.CollectionFolderTv import com.github.damontecres.dolphin.ui.detail.CollectionFolderTv
import com.github.damontecres.dolphin.ui.detail.EpisodeDetails import com.github.damontecres.dolphin.ui.detail.EpisodeDetails
@ -28,7 +28,6 @@ import org.jellyfin.sdk.model.api.DeviceProfile
fun DestinationContent( fun DestinationContent(
destination: Destination, destination: Destination,
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
deviceProfile: DeviceProfile, deviceProfile: DeviceProfile,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
@ -36,25 +35,22 @@ fun DestinationContent(
is Destination.Main -> is Destination.Main ->
HomePage( HomePage(
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
modifier = modifier, modifier = modifier,
) )
is Destination.Playback -> is Destination.Playback ->
PlaybackContent( PlaybackContent(
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
deviceProfile = deviceProfile, deviceProfile = deviceProfile,
destination = destination, destination = destination,
modifier = modifier, modifier = modifier,
) )
Destination.ServerList -> SwitchServerContent(navigationManager, modifier) Destination.ServerList -> SwitchServerContent(modifier)
Destination.UserList -> SwitchUserContent(navigationManager, modifier) Destination.UserList -> SwitchUserContent(modifier)
Destination.Settings -> Destination.Settings ->
PreferencesPage( PreferencesPage(
navigationManager,
preferences.appPreferences, preferences.appPreferences,
PreferenceScreenOption.BASIC, PreferenceScreenOption.BASIC,
modifier, modifier,
@ -63,7 +59,6 @@ fun DestinationContent(
is Destination.SeriesOverview -> is Destination.SeriesOverview ->
SeriesOverview( SeriesOverview(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
initialSeasonEpisode = destination.seasonEpisode, initialSeasonEpisode = destination.seasonEpisode,
@ -74,7 +69,6 @@ fun DestinationContent(
BaseItemKind.SERIES -> BaseItemKind.SERIES ->
SeriesDetails( SeriesDetails(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
) )
@ -82,7 +76,6 @@ fun DestinationContent(
BaseItemKind.SEASON -> BaseItemKind.SEASON ->
SeasonDetails( SeasonDetails(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
) )
@ -90,7 +83,6 @@ fun DestinationContent(
BaseItemKind.EPISODE -> BaseItemKind.EPISODE ->
EpisodeDetails( EpisodeDetails(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
) )
@ -98,7 +90,6 @@ fun DestinationContent(
BaseItemKind.MOVIE -> BaseItemKind.MOVIE ->
MovieDetails( MovieDetails(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
) )
@ -107,7 +98,6 @@ fun DestinationContent(
// TODO Use VideoDetails // TODO Use VideoDetails
MovieDetails( MovieDetails(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
) )
@ -117,7 +107,6 @@ fun DestinationContent(
CollectionType.TVSHOWS -> CollectionType.TVSHOWS ->
CollectionFolderTv( CollectionFolderTv(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
) )
@ -125,15 +114,13 @@ fun DestinationContent(
CollectionType.MOVIES -> CollectionType.MOVIES ->
CollectionFolderMovie( CollectionFolderMovie(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
) )
else -> else ->
CollectionFolderDetails( CollectionFolderGeneric(
preferences, preferences,
navigationManager,
destination, destination,
modifier, modifier,
) )
@ -149,7 +136,6 @@ fun DestinationContent(
Destination.Search -> Destination.Search ->
SearchPage( SearchPage(
navigationManager = navigationManager,
userPreferences = preferences, userPreferences = preferences,
modifier = modifier, modifier = modifier,
) )

View file

@ -78,6 +78,7 @@ class NavDrawerViewModel
constructor( constructor(
val serverRepository: ServerRepository, val serverRepository: ServerRepository,
val api: ApiClient, val api: ApiClient,
val navigationManager: NavigationManager,
) : ViewModel() { ) : ViewModel() {
val libraries = MutableLiveData<List<BaseItem>>(listOf()) val libraries = MutableLiveData<List<BaseItem>>(listOf())
val selectedIndex = MutableLiveData<Int>(-1) val selectedIndex = MutableLiveData<Int>(-1)
@ -104,7 +105,6 @@ class NavDrawerViewModel
fun NavDrawer( fun NavDrawer(
destination: Destination, destination: Destination,
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
user: JellyfinUser?, user: JellyfinUser?,
server: JellyfinServer?, server: JellyfinServer?,
deviceProfile: DeviceProfile, deviceProfile: DeviceProfile,
@ -157,7 +157,7 @@ fun NavDrawer(
icon = Icons.Default.AccountCircle, icon = Icons.Default.AccountCircle,
selected = false, selected = false,
onClick = { onClick = {
navigationManager.navigateTo(Destination.UserList) viewModel.navigationManager.navigateTo(Destination.UserList)
}, },
) )
} }
@ -168,7 +168,7 @@ fun NavDrawer(
selected = selectedIndex == -2, selected = selectedIndex == -2,
onClick = { onClick = {
viewModel.setIndex(-2) viewModel.setIndex(-2)
navigationManager.navigateToFromDrawer(Destination.Search) viewModel.navigationManager.navigateToFromDrawer(Destination.Search)
}, },
modifier = modifier =
Modifier.ifElse( Modifier.ifElse(
@ -185,9 +185,9 @@ fun NavDrawer(
onClick = { onClick = {
viewModel.setIndex(-1) viewModel.setIndex(-1)
if (destination is Destination.Main) { if (destination is Destination.Main) {
navigationManager.reloadHome() viewModel.navigationManager.reloadHome()
} else { } else {
navigationManager.goToHome() viewModel.navigationManager.goToHome()
} }
}, },
modifier = modifier =
@ -203,7 +203,7 @@ fun NavDrawer(
selected = selectedIndex == index, selected = selectedIndex == index,
onClick = { onClick = {
viewModel.setIndex(index) viewModel.setIndex(index)
navigationManager.navigateToFromDrawer(it.destination()) viewModel.navigationManager.navigateToFromDrawer(it.destination())
}, },
modifier = modifier =
Modifier.ifElse( Modifier.ifElse(
@ -218,7 +218,7 @@ fun NavDrawer(
icon = Icons.Default.Settings, icon = Icons.Default.Settings,
selected = false, selected = false,
onClick = { onClick = {
navigationManager.navigateTo(Destination.Settings) viewModel.navigationManager.navigateTo(Destination.Settings)
}, },
modifier = Modifier, modifier = Modifier,
) )
@ -231,7 +231,6 @@ fun NavDrawer(
DestinationContent( DestinationContent(
destination = destination, destination = destination,
preferences = preferences, preferences = preferences,
navigationManager = navigationManager,
deviceProfile = deviceProfile, deviceProfile = deviceProfile,
modifier = Modifier.fillMaxSize(), modifier = Modifier.fillMaxSize(),
) )

View file

@ -1,33 +1,37 @@
package com.github.damontecres.dolphin.ui.nav package com.github.damontecres.dolphin.ui.nav
import androidx.navigation3.runtime.NavBackStack
import androidx.navigation3.runtime.NavKey import androidx.navigation3.runtime.NavKey
import javax.inject.Inject
import javax.inject.Singleton
class NavigationManager( @Singleton
val backStack: NavBackStack<NavKey>, class NavigationManager
) { @Inject
fun navigateTo(destination: Destination) { constructor() {
backStack.add(destination) var backStack: MutableList<NavKey> = mutableListOf()
}
fun navigateToFromDrawer(destination: Destination) { fun navigateTo(destination: Destination) {
goToHome() backStack.add(destination)
backStack.add(destination) }
}
fun goBack() { fun navigateToFromDrawer(destination: Destination) {
backStack.removeLastOrNull() goToHome()
} backStack.add(destination)
}
fun goToHome() { fun goBack() {
while (backStack.size > 1) {
backStack.removeLastOrNull() backStack.removeLastOrNull()
} }
}
fun reloadHome() { fun goToHome() {
goToHome() while (backStack.size > 1) {
val id = (backStack[0] as Destination.Main).id + 1 backStack.removeLastOrNull()
backStack[0] = Destination.Main(id) }
}
fun reloadHome() {
goToHome()
val id = (backStack[0] as Destination.Main).id + 1
backStack[0] = Destination.Main(id)
}
} }
}

View file

@ -61,7 +61,6 @@ import com.github.damontecres.dolphin.preferences.skipBackOnResume
import com.github.damontecres.dolphin.ui.OneTimeLaunchedEffect import com.github.damontecres.dolphin.ui.OneTimeLaunchedEffect
import com.github.damontecres.dolphin.ui.components.LoadingPage import com.github.damontecres.dolphin.ui.components.LoadingPage
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.ui.tryRequestFocus import com.github.damontecres.dolphin.ui.tryRequestFocus
import com.github.damontecres.dolphin.util.seasonEpisode import com.github.damontecres.dolphin.util.seasonEpisode
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@ -73,7 +72,6 @@ import kotlin.time.Duration.Companion.seconds
@Composable @Composable
fun PlaybackContent( fun PlaybackContent(
preferences: UserPreferences, preferences: UserPreferences,
navigationManager: NavigationManager,
deviceProfile: DeviceProfile, deviceProfile: DeviceProfile,
destination: Destination.Playback, destination: Destination.Playback,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,

View file

@ -50,17 +50,17 @@ import com.github.damontecres.dolphin.ui.components.DialogItem
import com.github.damontecres.dolphin.ui.components.DialogParams import com.github.damontecres.dolphin.ui.components.DialogParams
import com.github.damontecres.dolphin.ui.components.DialogPopup import com.github.damontecres.dolphin.ui.components.DialogPopup
import com.github.damontecres.dolphin.ui.components.EditTextBox import com.github.damontecres.dolphin.ui.components.EditTextBox
import com.github.damontecres.dolphin.ui.nav.NavigationManager import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.util.ExceptionHandler import com.github.damontecres.dolphin.util.ExceptionHandler
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@Composable @Composable
fun <T> ComposablePreference( fun <T> ComposablePreference(
navigationManager: NavigationManager,
preference: AppPreference<T>, preference: AppPreference<T>,
value: T?, value: T?,
onValueChange: (T) -> Unit, onValueChange: (T) -> Unit,
onNavigate: (Destination) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) { ) {
@ -92,7 +92,7 @@ fun <T> ComposablePreference(
ClickPreference( ClickPreference(
title = title, title = title,
onClick = { onClick = {
navigationManager.navigateTo(preference.destination) onNavigate.invoke(preference.destination)
}, },
summary = preference.summary(context, value), summary = preference.summary(context, value),
interactionSource = interactionSource, interactionSource = interactionSource,

View file

@ -45,7 +45,6 @@ import com.github.damontecres.dolphin.preferences.advancedPreferences
import com.github.damontecres.dolphin.preferences.basicPreferences import com.github.damontecres.dolphin.preferences.basicPreferences
import com.github.damontecres.dolphin.preferences.uiPreferences import com.github.damontecres.dolphin.preferences.uiPreferences
import com.github.damontecres.dolphin.ui.ifElse import com.github.damontecres.dolphin.ui.ifElse
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.ui.playOnClickSound import com.github.damontecres.dolphin.ui.playOnClickSound
import com.github.damontecres.dolphin.ui.playSoundOnFocus import com.github.damontecres.dolphin.ui.playSoundOnFocus
import com.github.damontecres.dolphin.ui.tryRequestFocus import com.github.damontecres.dolphin.ui.tryRequestFocus
@ -58,7 +57,6 @@ data class Release(
@Composable @Composable
fun PreferencesContent( fun PreferencesContent(
navigationManager: NavigationManager,
initialPreferences: AppPreferences, initialPreferences: AppPreferences,
preferenceScreenOption: PreferenceScreenOption, preferenceScreenOption: PreferenceScreenOption,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -267,9 +265,9 @@ fun PreferencesContent(
else -> { else -> {
val value = pref.getter.invoke(preferences) val value = pref.getter.invoke(preferences)
ComposablePreference( ComposablePreference(
navigationManager = navigationManager,
preference = pref, preference = pref,
value = value, value = value,
onNavigate = viewModel.navigationManager::navigateTo,
onValueChange = { newValue -> onValueChange = { newValue ->
val validation = pref.validate(newValue) val validation = pref.validate(newValue)
when (validation) { when (validation) {
@ -312,7 +310,6 @@ fun PreferencesContent(
@Composable @Composable
fun PreferencesPage( fun PreferencesPage(
navigationManager: NavigationManager,
initialPreferences: AppPreferences, initialPreferences: AppPreferences,
preferenceScreenOption: PreferenceScreenOption, preferenceScreenOption: PreferenceScreenOption,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -321,7 +318,6 @@ fun PreferencesPage(
modifier = modifier.background(MaterialTheme.colorScheme.background), modifier = modifier.background(MaterialTheme.colorScheme.background),
) { ) {
PreferencesContent( PreferencesContent(
navigationManager,
initialPreferences, initialPreferences,
preferenceScreenOption, preferenceScreenOption,
Modifier Modifier

View file

@ -3,6 +3,7 @@ package com.github.damontecres.dolphin.ui.preferences
import androidx.datastore.core.DataStore import androidx.datastore.core.DataStore
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import com.github.damontecres.dolphin.preferences.AppPreferences import com.github.damontecres.dolphin.preferences.AppPreferences
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@ -11,4 +12,5 @@ class PreferencesViewModel
@Inject @Inject
constructor( constructor(
val preferenceDataStore: DataStore<AppPreferences>, val preferenceDataStore: DataStore<AppPreferences>,
val navigationManager: NavigationManager,
) : ViewModel() ) : ViewModel()

View file

@ -28,11 +28,9 @@ import androidx.tv.material3.surfaceColorAtElevation
import com.github.damontecres.dolphin.ui.components.BasicDialog import com.github.damontecres.dolphin.ui.components.BasicDialog
import com.github.damontecres.dolphin.ui.components.EditTextBox import com.github.damontecres.dolphin.ui.components.EditTextBox
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
@Composable @Composable
fun SwitchServerContent( fun SwitchServerContent(
navigationManager: NavigationManager,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: SwitchUserViewModel = hiltViewModel(), viewModel: SwitchUserViewModel = hiltViewModel(),
) { ) {
@ -68,7 +66,7 @@ fun SwitchServerContent(
connectionStatus = serverStatus, connectionStatus = serverStatus,
onSwitchServer = { onSwitchServer = {
viewModel.addServer(it.url) { viewModel.addServer(it.url) {
navigationManager.navigateTo(Destination.UserList) viewModel.navigationManager.navigateTo(Destination.UserList)
} }
}, },
onAddServer = { onAddServer = {
@ -92,7 +90,7 @@ fun SwitchServerContent(
val submit = { val submit = {
showAddServer = false showAddServer = false
viewModel.addServer(url) { viewModel.addServer(url) {
navigationManager.navigateTo(Destination.UserList) viewModel.navigationManager.navigateTo(Destination.UserList)
} }
} }
BasicDialog( BasicDialog(

View file

@ -31,11 +31,9 @@ import com.github.damontecres.dolphin.ui.components.BasicDialog
import com.github.damontecres.dolphin.ui.components.EditTextBox import com.github.damontecres.dolphin.ui.components.EditTextBox
import com.github.damontecres.dolphin.ui.isNotNullOrBlank import com.github.damontecres.dolphin.ui.isNotNullOrBlank
import com.github.damontecres.dolphin.ui.nav.Destination import com.github.damontecres.dolphin.ui.nav.Destination
import com.github.damontecres.dolphin.ui.nav.NavigationManager
@Composable @Composable
fun SwitchUserContent( fun SwitchUserContent(
navigationManager: NavigationManager,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
viewModel: SwitchUserViewModel = hiltViewModel(), viewModel: SwitchUserViewModel = hiltViewModel(),
) { ) {
@ -80,7 +78,7 @@ fun SwitchUserContent(
currentUser = currentUser, currentUser = currentUser,
onSwitchUser = { user -> onSwitchUser = { user ->
viewModel.switchUser(server, user) { viewModel.switchUser(server, user) {
navigationManager.goToHome() viewModel.navigationManager.goToHome()
} }
}, },
onAddUser = { showAddUser = true }, onAddUser = { showAddUser = true },
@ -88,7 +86,7 @@ fun SwitchUserContent(
viewModel.removeUser(user) viewModel.removeUser(user)
}, },
onSwitchServer = { onSwitchServer = {
navigationManager.navigateTo(Destination.ServerList) viewModel.navigationManager.navigateTo(Destination.ServerList)
}, },
modifier = modifier =
Modifier Modifier
@ -106,7 +104,7 @@ fun SwitchUserContent(
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
if (useQuickConnect) { if (useQuickConnect) {
viewModel.initiateQuickConnect(server) { viewModel.initiateQuickConnect(server) {
navigationManager.goToHome() viewModel.navigationManager.goToHome()
} }
} }
} }
@ -151,7 +149,7 @@ fun SwitchUserContent(
val onSubmit = { val onSubmit = {
viewModel.login(server, username, password) { viewModel.login(server, username, password) {
showAddUser = false showAddUser = false
navigationManager.goToHome() viewModel.navigationManager.goToHome()
} }
} }
Row( Row(

View file

@ -7,6 +7,7 @@ import com.github.damontecres.dolphin.data.JellyfinServer
import com.github.damontecres.dolphin.data.JellyfinServerDao import com.github.damontecres.dolphin.data.JellyfinServerDao
import com.github.damontecres.dolphin.data.JellyfinUser import com.github.damontecres.dolphin.data.JellyfinUser
import com.github.damontecres.dolphin.data.ServerRepository import com.github.damontecres.dolphin.data.ServerRepository
import com.github.damontecres.dolphin.ui.nav.NavigationManager
import com.github.damontecres.dolphin.util.ExceptionHandler import com.github.damontecres.dolphin.util.ExceptionHandler
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -32,6 +33,7 @@ class SwitchUserViewModel
val jellyfin: Jellyfin, val jellyfin: Jellyfin,
val serverRepository: ServerRepository, val serverRepository: ServerRepository,
val serverDao: JellyfinServerDao, val serverDao: JellyfinServerDao,
val navigationManager: NavigationManager,
) : ViewModel() { ) : ViewModel() {
val servers = MutableLiveData<List<JellyfinServer>>(listOf()) val servers = MutableLiveData<List<JellyfinServer>>(listOf())
val serverStatus = MutableLiveData<Map<String, ServerConnectionStatus>>(mapOf()) val serverStatus = MutableLiveData<Map<String, ServerConnectionStatus>>(mapOf())