Refactor navigation logic into separate container AppScreen

This commit is contained in:
2026-03-26 20:12:19 +01:00
parent 6c07878d02
commit 3aa8b2cce4
8 changed files with 243 additions and 113 deletions

View File

@@ -0,0 +1,38 @@
package hu.bbara.purefin.app.home
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Collections
import androidx.compose.material.icons.outlined.Download
import androidx.compose.material.icons.outlined.Home
import androidx.compose.material3.Icon
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@Composable
fun AppBottomBar(
selectedTab: Int,
onTabSelected: (Int) -> Unit
) {
NavigationBar {
NavigationBarItem(
selected = selectedTab == 0,
onClick = { onTabSelected(0) },
icon = { Icon(Icons.Outlined.Home, contentDescription = "Home") },
label = { Text("Home") }
)
NavigationBarItem(
selected = selectedTab == 1,
onClick = { onTabSelected(1) },
icon = { Icon(Icons.Outlined.Collections, contentDescription = "Libraries") },
label = { Text("Libraries") }
)
NavigationBarItem(
selected = selectedTab == 2,
onClick = { onTabSelected(2) },
icon = { Icon(Icons.Outlined.Download, contentDescription = "Downloads") },
label = { Text("Downloads") }
)
}
}

View File

@@ -0,0 +1,70 @@
package hu.bbara.purefin.app.home
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import hu.bbara.purefin.app.home.ui.HomeNavItem
import hu.bbara.purefin.feature.shared.home.HomePageViewModel
@Composable
fun AppScreen(
viewModel: HomePageViewModel = hiltViewModel(),
modifier: Modifier = Modifier
) {
var selectedTab by remember { mutableIntStateOf(0) }
val libraries by viewModel.libraries.collectAsState()
val libraryContent by viewModel.latestLibraryContent.collectAsState()
val continueWatching by viewModel.continueWatching.collectAsState()
val nextUp by viewModel.nextUp.collectAsState()
val isRefreshing by viewModel.isRefreshing.collectAsState()
val libraryNavItems = libraries.map {
HomeNavItem(
id = it.id,
label = it.name,
posterUrl = it.posterUrl
)
}
LifecycleResumeEffect(Unit) {
viewModel.onResumed()
onPauseOrDispose { }
}
when (selectedTab) {
0 -> HomeScreen(
libraries = libraries,
libraryContent = libraryContent,
continueWatching = continueWatching,
nextUp = nextUp,
isRefreshing = isRefreshing,
onRefresh = viewModel::onRefresh,
onMovieSelected = viewModel::onMovieSelected,
onSeriesSelected = viewModel::onSeriesSelected,
onEpisodeSelected = viewModel::onEpisodeSelected,
selectedTab = selectedTab,
onTabSelected = { selectedTab = it },
modifier = modifier.fillMaxSize()
)
1 -> LibrariesScreen(
items = libraryNavItems,
onLibrarySelected = { item -> viewModel.onLibrarySelected(item.id, item.label) },
selectedTab = selectedTab,
onTabSelected = { selectedTab = it },
modifier = modifier.fillMaxSize()
)
2 -> DownloadsScreen(
selectedTab = selectedTab,
onTabSelected = { selectedTab = it },
modifier = modifier.fillMaxSize()
)
}
}

View File

@@ -0,0 +1,32 @@
package hu.bbara.purefin.app.home
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import hu.bbara.purefin.app.home.ui.DownloadsContent
@Composable
fun DownloadsScreen(
selectedTab: Int,
onTabSelected: (Int) -> Unit,
modifier: Modifier = Modifier
) {
Scaffold(
modifier = modifier.fillMaxSize(),
containerColor = MaterialTheme.colorScheme.background,
contentColor = MaterialTheme.colorScheme.onBackground,
bottomBar = {
AppBottomBar(
selectedTab = selectedTab,
onTabSelected = onTabSelected
)
}
) { innerPadding ->
DownloadsContent(
modifier = Modifier.padding(innerPadding)
)
}
}

View File

@@ -8,6 +8,6 @@ import hu.bbara.purefin.core.data.navigation.Route
*/ */
fun EntryProviderScope<Route>.homeSection() { fun EntryProviderScope<Route>.homeSection() {
entry<Route.Home> { entry<Route.Home> {
HomePage() AppScreen()
} }
} }

View File

@@ -1,110 +0,0 @@
package hu.bbara.purefin.app.home
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Collections
import androidx.compose.material.icons.outlined.Download
import androidx.compose.material.icons.outlined.Home
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.LifecycleResumeEffect
import hu.bbara.purefin.app.home.ui.DownloadsContent
import hu.bbara.purefin.app.home.ui.HomeContent
import hu.bbara.purefin.app.home.ui.HomeNavItem
import hu.bbara.purefin.app.home.ui.HomeTopBar
import hu.bbara.purefin.app.home.ui.LibrariesContent
import hu.bbara.purefin.feature.shared.home.HomePageViewModel
@Composable
fun HomePage(
viewModel: HomePageViewModel = hiltViewModel(),
modifier: Modifier = Modifier
) {
var selectedTab by remember { mutableIntStateOf(0) }
val libraries = viewModel.libraries.collectAsState().value
val isOfflineMode = viewModel.isOfflineMode.collectAsState().value
val libraryNavItems = libraries.map {
HomeNavItem(
id = it.id,
label = it.name,
posterUrl = it.posterUrl
)
}
val continueWatching = viewModel.continueWatching.collectAsState()
val nextUp = viewModel.nextUp.collectAsState()
val latestLibraryContent = viewModel.latestLibraryContent.collectAsState()
val isRefreshing = viewModel.isRefreshing.collectAsState()
LifecycleResumeEffect(Unit) {
viewModel.onResumed()
onPauseOrDispose { }
}
Scaffold(
modifier = modifier.fillMaxSize(),
containerColor = MaterialTheme.colorScheme.background,
contentColor = MaterialTheme.colorScheme.onBackground,
topBar = {
HomeTopBar()
},
bottomBar = {
NavigationBar {
NavigationBarItem(
selected = selectedTab == 0,
onClick = { selectedTab = 0 },
icon = { Icon(Icons.Outlined.Home, contentDescription = "Home") },
label = { Text("Home") }
)
NavigationBarItem(
selected = selectedTab == 1,
onClick = { selectedTab = 1 },
icon = { Icon(Icons.Outlined.Collections, contentDescription = "Libraries") },
label = { Text("Libraries") }
)
NavigationBarItem(
selected = selectedTab == 2,
onClick = { selectedTab = 2 },
icon = { Icon(Icons.Outlined.Download, contentDescription = "Downloads") },
label = { Text("Downloads") }
)
}
}
) { innerPadding ->
when (selectedTab) {
0 -> HomeContent(
libraries = libraries,
libraryContent = latestLibraryContent.value,
continueWatching = continueWatching.value,
nextUp = nextUp.value,
isRefreshing = isRefreshing.value,
onRefresh = viewModel::onRefresh,
onMovieSelected = viewModel::onMovieSelected,
onSeriesSelected = viewModel::onSeriesSelected,
onEpisodeSelected = viewModel::onEpisodeSelected,
modifier = Modifier.padding(innerPadding)
)
1 -> LibrariesContent(
items = libraryNavItems,
onLibrarySelected = { item -> viewModel.onLibrarySelected(item.id, item.label) },
modifier = Modifier.padding(innerPadding)
)
2 -> DownloadsContent(
modifier = Modifier.padding(innerPadding)
)
}
}
}

View File

@@ -0,0 +1,59 @@
package hu.bbara.purefin.app.home
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import hu.bbara.purefin.app.home.ui.HomeContent
import hu.bbara.purefin.app.home.ui.HomeTopBar
import hu.bbara.purefin.feature.shared.home.ContinueWatchingItem
import hu.bbara.purefin.feature.shared.home.LibraryItem
import hu.bbara.purefin.feature.shared.home.NextUpItem
import hu.bbara.purefin.feature.shared.home.PosterItem
import org.jellyfin.sdk.model.UUID
@Composable
fun HomeScreen(
libraries: List<LibraryItem>,
libraryContent: Map<UUID, List<PosterItem>>,
continueWatching: List<ContinueWatchingItem>,
nextUp: List<NextUpItem>,
isRefreshing: Boolean,
onRefresh: () -> Unit,
onMovieSelected: (UUID) -> Unit,
onSeriesSelected: (UUID) -> Unit,
onEpisodeSelected: (UUID, UUID, UUID) -> Unit,
selectedTab: Int,
onTabSelected: (Int) -> Unit,
modifier: Modifier = Modifier
) {
Scaffold(
modifier = modifier.fillMaxSize(),
containerColor = MaterialTheme.colorScheme.background,
contentColor = MaterialTheme.colorScheme.onBackground,
topBar = {
HomeTopBar()
},
bottomBar = {
AppBottomBar(
selectedTab = selectedTab,
onTabSelected = onTabSelected
)
}
) { innerPadding ->
HomeContent(
libraries = libraries,
libraryContent = libraryContent,
continueWatching = continueWatching,
nextUp = nextUp,
isRefreshing = isRefreshing,
onRefresh = onRefresh,
onMovieSelected = onMovieSelected,
onSeriesSelected = onSeriesSelected,
onEpisodeSelected = onEpisodeSelected,
modifier = Modifier.padding(innerPadding)
)
}
}

View File

@@ -0,0 +1,41 @@
package hu.bbara.purefin.app.home
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import hu.bbara.purefin.app.home.ui.HomeNavItem
import hu.bbara.purefin.app.home.ui.HomeTopBar
import hu.bbara.purefin.app.home.ui.LibrariesContent
@Composable
fun LibrariesScreen(
items: List<HomeNavItem>,
onLibrarySelected: (HomeNavItem) -> Unit,
selectedTab: Int,
onTabSelected: (Int) -> Unit,
modifier: Modifier = Modifier
) {
Scaffold(
modifier = modifier.fillMaxSize(),
containerColor = MaterialTheme.colorScheme.background,
contentColor = MaterialTheme.colorScheme.onBackground,
topBar = {
HomeTopBar()
},
bottomBar = {
AppBottomBar(
selectedTab = selectedTab,
onTabSelected = onTabSelected
)
}
) { innerPadding ->
LibrariesContent(
items = items,
onLibrarySelected = onLibrarySelected,
modifier = Modifier.padding(innerPadding)
)
}
}

View File

@@ -4,14 +4,14 @@ import androidx.navigation3.runtime.EntryProviderScope
import hu.bbara.purefin.app.content.episode.EpisodeScreen 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.AppScreen
import hu.bbara.purefin.app.library.ui.LibraryScreen import hu.bbara.purefin.app.library.ui.LibraryScreen
import hu.bbara.purefin.core.data.navigation.Route import hu.bbara.purefin.core.data.navigation.Route
import hu.bbara.purefin.login.ui.LoginScreen import hu.bbara.purefin.login.ui.LoginScreen
fun EntryProviderScope<Route>.appRouteEntryBuilder() { fun EntryProviderScope<Route>.appRouteEntryBuilder() {
entry<Route.Home> { entry<Route.Home> {
HomePage() AppScreen()
} }
entry<Route.MovieRoute> { entry<Route.MovieRoute> {
MovieScreen(movie = it.item) MovieScreen(movie = it.item)