feat: add online status handling to navigation and UI components

This commit is contained in:
2026-05-14 12:39:20 +02:00
parent a92c10a07c
commit 83730188eb
6 changed files with 44 additions and 15 deletions

View File

@@ -13,23 +13,26 @@ import androidx.compose.runtime.Composable
@Composable @Composable
fun AppBottomBar( fun AppBottomBar(
selectedTab: Int, selectedTab: Int,
isOnline: Boolean,
onTabSelected: (Int) -> Unit onTabSelected: (Int) -> Unit
) { ) {
NavigationBar { NavigationBar {
if (isOnline) {
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( NavigationBarItem(
selected = selectedTab == 0, selected = !isOnline || selectedTab == 2,
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) }, onClick = { onTabSelected(2) },
icon = { Icon(Icons.Outlined.Download, contentDescription = "Downloads") }, icon = { Icon(Icons.Outlined.Download, contentDescription = "Downloads") },
label = { Text("Downloads") } label = { Text("Downloads") }

View File

@@ -44,6 +44,7 @@ fun AppScreen(
val continueWatching by viewModel.continueWatching.collectAsState() val continueWatching by viewModel.continueWatching.collectAsState()
val nextUp by viewModel.nextUp.collectAsState() val nextUp by viewModel.nextUp.collectAsState()
val isRefreshing by viewModel.isRefreshing.collectAsState() val isRefreshing by viewModel.isRefreshing.collectAsState()
val isOnline by viewModel.isOnline.collectAsState()
val isCheckingForUpdates by updateViewModel.isCheckingForUpdates.collectAsState() val isCheckingForUpdates by updateViewModel.isCheckingForUpdates.collectAsState()
val availableUpdate by updateViewModel.availableUpdate.collectAsState() val availableUpdate by updateViewModel.availableUpdate.collectAsState()
val navigationManager = LocalNavigationManager.current val navigationManager = LocalNavigationManager.current
@@ -54,6 +55,13 @@ fun AppScreen(
val currentRoute = backStack.lastOrNull() ?: AppTabRoute.Home val currentRoute = backStack.lastOrNull() ?: AppTabRoute.Home
val selectedTab = currentRoute.toTabIndex() val selectedTab = currentRoute.toTabIndex()
LaunchedEffect(isOnline, currentRoute, backStack) {
if (!isOnline && currentRoute != AppTabRoute.Downloads) {
backStack.clear()
backStack.add(AppTabRoute.Downloads)
}
}
LifecycleResumeEffect(Unit) { LifecycleResumeEffect(Unit) {
viewModel.onResumed() viewModel.onResumed()
onPauseOrDispose { } onPauseOrDispose { }
@@ -69,9 +77,9 @@ fun AppScreen(
} }
} }
val onTabSelected = remember(backStack) { val onTabSelected = remember(backStack, isOnline) {
{ selectedIndex: Int -> { selectedIndex: Int ->
val route = selectedIndex.toAppTabRoute() val route = if (isOnline) selectedIndex.toAppTabRoute() else AppTabRoute.Downloads
if (backStack.lastOrNull() != route) { if (backStack.lastOrNull() != route) {
backStack.add(route) backStack.add(route)
} }
@@ -104,6 +112,7 @@ fun AppScreen(
onSearchClick = viewModel::openSearch, onSearchClick = viewModel::openSearch,
snackbarHostState = snackbarHostState, snackbarHostState = snackbarHostState,
selectedTab = selectedTab, selectedTab = selectedTab,
isOnline = isOnline,
onTabSelected = onTabSelected, onTabSelected = onTabSelected,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )
@@ -114,6 +123,7 @@ fun AppScreen(
onLibrarySelected = { item -> viewModel.onLibrarySelected(item.id, item.name) }, onLibrarySelected = { item -> viewModel.onLibrarySelected(item.id, item.name) },
onSearchClick = viewModel::openSearch, onSearchClick = viewModel::openSearch,
selectedTab = selectedTab, selectedTab = selectedTab,
isOnline = isOnline,
onTabSelected = onTabSelected, onTabSelected = onTabSelected,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )
@@ -121,6 +131,7 @@ fun AppScreen(
entry<AppTabRoute.Downloads>(metadata = appTabMetadata(AppTabRoute.Downloads)) { entry<AppTabRoute.Downloads>(metadata = appTabMetadata(AppTabRoute.Downloads)) {
DownloadsScreen( DownloadsScreen(
selectedTab = selectedTab, selectedTab = selectedTab,
isOnline = isOnline,
onTabSelected = onTabSelected, onTabSelected = onTabSelected,
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) )

View File

@@ -12,6 +12,7 @@ import hu.bbara.purefin.ui.screen.AppBottomBar
@Composable @Composable
fun DownloadsScreen( fun DownloadsScreen(
selectedTab: Int, selectedTab: Int,
isOnline: Boolean,
onTabSelected: (Int) -> Unit, onTabSelected: (Int) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
@@ -22,6 +23,7 @@ fun DownloadsScreen(
bottomBar = { bottomBar = {
AppBottomBar( AppBottomBar(
selectedTab = selectedTab, selectedTab = selectedTab,
isOnline = isOnline,
onTabSelected = onTabSelected onTabSelected = onTabSelected
) )
} }

View File

@@ -35,6 +35,7 @@ fun HomeScreen(
onSearchClick: () -> Unit, onSearchClick: () -> Unit,
snackbarHostState: SnackbarHostState, snackbarHostState: SnackbarHostState,
selectedTab: Int, selectedTab: Int,
isOnline: Boolean,
onTabSelected: (Int) -> Unit, onTabSelected: (Int) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
@@ -57,6 +58,7 @@ fun HomeScreen(
bottomBar = { bottomBar = {
AppBottomBar( AppBottomBar(
selectedTab = selectedTab, selectedTab = selectedTab,
isOnline = isOnline,
onTabSelected = onTabSelected onTabSelected = onTabSelected
) )
} }

View File

@@ -17,6 +17,7 @@ fun LibrariesScreen(
onLibrarySelected: (LibraryUiModel) -> Unit, onLibrarySelected: (LibraryUiModel) -> Unit,
onSearchClick: () -> Unit, onSearchClick: () -> Unit,
selectedTab: Int, selectedTab: Int,
isOnline: Boolean,
onTabSelected: (Int) -> Unit, onTabSelected: (Int) -> Unit,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
@@ -32,6 +33,7 @@ fun LibrariesScreen(
bottomBar = { bottomBar = {
AppBottomBar( AppBottomBar(
selectedTab = selectedTab, selectedTab = selectedTab,
isOnline = isOnline,
onTabSelected = onTabSelected onTabSelected = onTabSelected
) )
} }

View File

@@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import hu.bbara.purefin.core.data.HomeRepository import hu.bbara.purefin.core.data.HomeRepository
import hu.bbara.purefin.core.data.LocalMediaRepository import hu.bbara.purefin.core.data.LocalMediaRepository
import hu.bbara.purefin.core.data.NetworkMonitor
import hu.bbara.purefin.core.data.UserSessionRepository import hu.bbara.purefin.core.data.UserSessionRepository
import hu.bbara.purefin.core.download.MediaDownloadController import hu.bbara.purefin.core.download.MediaDownloadController
import hu.bbara.purefin.core.jellyfin.JellyfinMediaMetadataUpdater import hu.bbara.purefin.core.jellyfin.JellyfinMediaMetadataUpdater
@@ -40,11 +41,19 @@ class AppViewModel @Inject constructor(
private val jellyfinMediaMetadataUpdater: JellyfinMediaMetadataUpdater, private val jellyfinMediaMetadataUpdater: JellyfinMediaMetadataUpdater,
private val navigationManager: NavigationManager, private val navigationManager: NavigationManager,
private val mediaDownloadManager: MediaDownloadController, private val mediaDownloadManager: MediaDownloadController,
networkMonitor: NetworkMonitor,
) : ViewModel() { ) : ViewModel() {
private val _isRefreshing = MutableStateFlow(false) private val _isRefreshing = MutableStateFlow(false)
val isRefreshing: StateFlow<Boolean> = _isRefreshing.asStateFlow() val isRefreshing: StateFlow<Boolean> = _isRefreshing.asStateFlow()
val isOnline: StateFlow<Boolean> = networkMonitor.isOnline
.stateIn(
viewModelScope,
SharingStarted.Eagerly,
false
)
val serverUrl: StateFlow<String> = userSessionRepository.serverUrl val serverUrl: StateFlow<String> = userSessionRepository.serverUrl
.stateIn( .stateIn(
viewModelScope, viewModelScope,