From 83730188eb37e4489cef7755273a60161376debd Mon Sep 17 00:00:00 2001 From: Barnabas Balogh Date: Thu, 14 May 2026 12:39:20 +0200 Subject: [PATCH] feat: add online status handling to navigation and UI components --- .../bbara/purefin/ui/screen/AppBottomBar.kt | 29 ++++++++++--------- .../hu/bbara/purefin/ui/screen/AppScreen.kt | 15 ++++++++-- .../ui/screen/download/DownloadsScreen.kt | 2 ++ .../purefin/ui/screen/home/HomeScreen.kt | 2 ++ .../ui/screen/libraries/LibrariesScreen.kt | 2 ++ .../core/feature/browse/home/AppViewModel.kt | 9 ++++++ 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/AppBottomBar.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/AppBottomBar.kt index f93b74f3..724fa3b9 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/AppBottomBar.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/AppBottomBar.kt @@ -13,23 +13,26 @@ import androidx.compose.runtime.Composable @Composable fun AppBottomBar( selectedTab: Int, + isOnline: Boolean, onTabSelected: (Int) -> Unit ) { 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( - 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, + selected = !isOnline || selectedTab == 2, onClick = { onTabSelected(2) }, icon = { Icon(Icons.Outlined.Download, contentDescription = "Downloads") }, label = { Text("Downloads") } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/AppScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/AppScreen.kt index 841f3e8b..4d77fda1 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/AppScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/AppScreen.kt @@ -44,6 +44,7 @@ fun AppScreen( val continueWatching by viewModel.continueWatching.collectAsState() val nextUp by viewModel.nextUp.collectAsState() val isRefreshing by viewModel.isRefreshing.collectAsState() + val isOnline by viewModel.isOnline.collectAsState() val isCheckingForUpdates by updateViewModel.isCheckingForUpdates.collectAsState() val availableUpdate by updateViewModel.availableUpdate.collectAsState() val navigationManager = LocalNavigationManager.current @@ -54,6 +55,13 @@ fun AppScreen( val currentRoute = backStack.lastOrNull() ?: AppTabRoute.Home val selectedTab = currentRoute.toTabIndex() + LaunchedEffect(isOnline, currentRoute, backStack) { + if (!isOnline && currentRoute != AppTabRoute.Downloads) { + backStack.clear() + backStack.add(AppTabRoute.Downloads) + } + } + LifecycleResumeEffect(Unit) { viewModel.onResumed() onPauseOrDispose { } @@ -69,9 +77,9 @@ fun AppScreen( } } - val onTabSelected = remember(backStack) { + val onTabSelected = remember(backStack, isOnline) { { selectedIndex: Int -> - val route = selectedIndex.toAppTabRoute() + val route = if (isOnline) selectedIndex.toAppTabRoute() else AppTabRoute.Downloads if (backStack.lastOrNull() != route) { backStack.add(route) } @@ -104,6 +112,7 @@ fun AppScreen( onSearchClick = viewModel::openSearch, snackbarHostState = snackbarHostState, selectedTab = selectedTab, + isOnline = isOnline, onTabSelected = onTabSelected, modifier = Modifier.fillMaxSize() ) @@ -114,6 +123,7 @@ fun AppScreen( onLibrarySelected = { item -> viewModel.onLibrarySelected(item.id, item.name) }, onSearchClick = viewModel::openSearch, selectedTab = selectedTab, + isOnline = isOnline, onTabSelected = onTabSelected, modifier = Modifier.fillMaxSize() ) @@ -121,6 +131,7 @@ fun AppScreen( entry(metadata = appTabMetadata(AppTabRoute.Downloads)) { DownloadsScreen( selectedTab = selectedTab, + isOnline = isOnline, onTabSelected = onTabSelected, modifier = Modifier.fillMaxSize() ) diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/download/DownloadsScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/download/DownloadsScreen.kt index 942195d5..7470147c 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/download/DownloadsScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/download/DownloadsScreen.kt @@ -12,6 +12,7 @@ import hu.bbara.purefin.ui.screen.AppBottomBar @Composable fun DownloadsScreen( selectedTab: Int, + isOnline: Boolean, onTabSelected: (Int) -> Unit, modifier: Modifier = Modifier ) { @@ -22,6 +23,7 @@ fun DownloadsScreen( bottomBar = { AppBottomBar( selectedTab = selectedTab, + isOnline = isOnline, onTabSelected = onTabSelected ) } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/home/HomeScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/home/HomeScreen.kt index dd28acc7..19ddf546 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/home/HomeScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/home/HomeScreen.kt @@ -35,6 +35,7 @@ fun HomeScreen( onSearchClick: () -> Unit, snackbarHostState: SnackbarHostState, selectedTab: Int, + isOnline: Boolean, onTabSelected: (Int) -> Unit, modifier: Modifier = Modifier ) { @@ -57,6 +58,7 @@ fun HomeScreen( bottomBar = { AppBottomBar( selectedTab = selectedTab, + isOnline = isOnline, onTabSelected = onTabSelected ) } diff --git a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/LibrariesScreen.kt b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/LibrariesScreen.kt index 80c161df..69bac55f 100644 --- a/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/LibrariesScreen.kt +++ b/app/src/main/java/hu/bbara/purefin/ui/screen/libraries/LibrariesScreen.kt @@ -17,6 +17,7 @@ fun LibrariesScreen( onLibrarySelected: (LibraryUiModel) -> Unit, onSearchClick: () -> Unit, selectedTab: Int, + isOnline: Boolean, onTabSelected: (Int) -> Unit, modifier: Modifier = Modifier ) { @@ -32,6 +33,7 @@ fun LibrariesScreen( bottomBar = { AppBottomBar( selectedTab = selectedTab, + isOnline = isOnline, onTabSelected = onTabSelected ) } diff --git a/core/src/main/java/hu/bbara/purefin/core/feature/browse/home/AppViewModel.kt b/core/src/main/java/hu/bbara/purefin/core/feature/browse/home/AppViewModel.kt index 9ffbb429..94d198f6 100644 --- a/core/src/main/java/hu/bbara/purefin/core/feature/browse/home/AppViewModel.kt +++ b/core/src/main/java/hu/bbara/purefin/core/feature/browse/home/AppViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope import dagger.hilt.android.lifecycle.HiltViewModel import hu.bbara.purefin.core.data.HomeRepository 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.download.MediaDownloadController import hu.bbara.purefin.core.jellyfin.JellyfinMediaMetadataUpdater @@ -40,11 +41,19 @@ class AppViewModel @Inject constructor( private val jellyfinMediaMetadataUpdater: JellyfinMediaMetadataUpdater, private val navigationManager: NavigationManager, private val mediaDownloadManager: MediaDownloadController, + networkMonitor: NetworkMonitor, ) : ViewModel() { private val _isRefreshing = MutableStateFlow(false) val isRefreshing: StateFlow = _isRefreshing.asStateFlow() + val isOnline: StateFlow = networkMonitor.isOnline + .stateIn( + viewModelScope, + SharingStarted.Eagerly, + false + ) + val serverUrl: StateFlow = userSessionRepository.serverUrl .stateIn( viewModelScope,