Update App.kt

This commit is contained in:
AdityasahuX07 2026-04-25 13:10:39 +05:30 committed by GitHub
parent 52ffd0c553
commit 8187f404c4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -92,6 +92,7 @@ import com.nuvio.app.core.ui.NuvioToastController
import com.nuvio.app.core.ui.NuvioFloatingPrompt import com.nuvio.app.core.ui.NuvioFloatingPrompt
import com.nuvio.app.core.ui.TraktListPickerDialog import com.nuvio.app.core.ui.TraktListPickerDialog
import com.nuvio.app.core.ui.NuvioTheme import com.nuvio.app.core.ui.NuvioTheme
import com.nuvio.app.core.ui.localizedContinueWatchingSubtitle
import com.nuvio.app.features.auth.AuthScreen import com.nuvio.app.features.auth.AuthScreen
import com.nuvio.app.features.addons.AddonRepository import com.nuvio.app.features.addons.AddonRepository
import com.nuvio.app.features.catalog.CatalogRepository import com.nuvio.app.features.catalog.CatalogRepository
@ -168,12 +169,20 @@ import com.nuvio.app.features.watching.application.WatchingState
import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import nuvio.composeapp.generated.resources.Res import nuvio.composeapp.generated.resources.*
import nuvio.composeapp.generated.resources.app_logo_wordmark import nuvio.composeapp.generated.resources.app_logo_wordmark
import nuvio.composeapp.generated.resources.compose_catalog_subtitle_library
import nuvio.composeapp.generated.resources.compose_catalog_subtitle_trakt_library
import nuvio.composeapp.generated.resources.compose_nav_home
import nuvio.composeapp.generated.resources.compose_nav_library
import nuvio.composeapp.generated.resources.compose_nav_profile
import nuvio.composeapp.generated.resources.compose_nav_search
import nuvio.composeapp.generated.resources.sidebar_library import nuvio.composeapp.generated.resources.sidebar_library
import nuvio.composeapp.generated.resources.sidebar_search import nuvio.composeapp.generated.resources.sidebar_search
import org.jetbrains.compose.resources.DrawableResource import org.jetbrains.compose.resources.DrawableResource
import org.jetbrains.compose.resources.getString
import org.jetbrains.compose.resources.painterResource import org.jetbrains.compose.resources.painterResource
import org.jetbrains.compose.resources.stringResource
@Serializable @Serializable
object TabsRoute object TabsRoute
@ -279,7 +288,6 @@ fun App() {
ThemeSettingsRepository.selectedTheme ThemeSettingsRepository.selectedTheme
}.collectAsStateWithLifecycle() }.collectAsStateWithLifecycle()
val amoledEnabled by remember { ThemeSettingsRepository.amoledEnabled }.collectAsStateWithLifecycle() val amoledEnabled by remember { ThemeSettingsRepository.amoledEnabled }.collectAsStateWithLifecycle()
NuvioTheme(appTheme = selectedTheme, amoled = amoledEnabled) { NuvioTheme(appTheme = selectedTheme, amoled = amoledEnabled) {
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
AuthRepository.initialize() AuthRepository.initialize()
@ -500,6 +508,7 @@ private fun MainAppContent(
val networkStatusUiState by remember { val networkStatusUiState by remember {
NetworkStatusRepository.uiState NetworkStatusRepository.uiState
}.collectAsStateWithLifecycle() }.collectAsStateWithLifecycle()
val downloadedProviderLabel = stringResource(Res.string.provider_downloaded)
val isTraktConnected = traktAuthUiState.mode == TraktConnectionMode.CONNECTED val isTraktConnected = traktAuthUiState.mode == TraktConnectionMode.CONNECTED
var initialHomeReady by rememberSaveable { mutableStateOf(false) } var initialHomeReady by rememberSaveable { mutableStateOf(false) }
var offlineLaunchRouteHandled by rememberSaveable { mutableStateOf(false) } var offlineLaunchRouteHandled by rememberSaveable { mutableStateOf(false) }
@ -543,11 +552,11 @@ private fun MainAppContent(
when (condition) { when (condition) {
NetworkCondition.NoInternet -> { NetworkCondition.NoInternet -> {
NuvioToastController.show("No internet connection") NuvioToastController.show(getString(Res.string.network_no_internet_connection))
} }
NetworkCondition.ServersUnreachable -> { NetworkCondition.ServersUnreachable -> {
NuvioToastController.show("Cannot reach servers") NuvioToastController.show(getString(Res.string.network_cannot_reach_servers))
} }
NetworkCondition.Online -> { NetworkCondition.Online -> {
@ -555,7 +564,7 @@ private fun MainAppContent(
previousConditionName == NetworkCondition.NoInternet.name || previousConditionName == NetworkCondition.NoInternet.name ||
previousConditionName == NetworkCondition.ServersUnreachable.name previousConditionName == NetworkCondition.ServersUnreachable.name
) { ) {
NuvioToastController.show("Back online") NuvioToastController.show(getString(Res.string.network_back_online))
} }
} }
@ -699,7 +708,7 @@ private fun MainAppContent(
streamTitle = downloadedItem.streamTitle.ifBlank { title }, streamTitle = downloadedItem.streamTitle.ifBlank { title },
streamSubtitle = downloadedItem.streamSubtitle, streamSubtitle = downloadedItem.streamSubtitle,
pauseDescription = pauseDescription, pauseDescription = pauseDescription,
providerName = downloadedItem.providerName.ifBlank { "Downloaded" }, providerName = downloadedItem.providerName.ifBlank { downloadedProviderLabel },
providerAddonId = downloadedItem.providerAddonId, providerAddonId = downloadedItem.providerAddonId,
contentType = type, contentType = type,
videoId = videoId, videoId = videoId,
@ -799,15 +808,17 @@ private fun MainAppContent(
) )
} }
val librarySectionSubtitle = if (libraryUiState.sourceMode == LibrarySourceMode.TRAKT) {
stringResource(Res.string.compose_catalog_subtitle_trakt_library)
} else {
stringResource(Res.string.compose_catalog_subtitle_library)
}
val onLibrarySectionViewAllClick: (LibrarySection) -> Unit = { section -> val onLibrarySectionViewAllClick: (LibrarySection) -> Unit = { section ->
navController.navigate( navController.navigate(
CatalogRoute( CatalogRoute(
title = section.displayTitle, title = section.displayTitle,
subtitle = if (libraryUiState.sourceMode == LibrarySourceMode.TRAKT) { subtitle = librarySectionSubtitle,
"Trakt Library"
} else {
"Library"
},
manifestUrl = INTERNAL_LIBRARY_MANIFEST_URL, manifestUrl = INTERNAL_LIBRARY_MANIFEST_URL,
type = section.items.firstOrNull()?.type ?: "movie", type = section.items.firstOrNull()?.type ?: "movie",
catalogId = section.type, catalogId = section.type,
@ -900,19 +911,19 @@ private fun MainAppContent(
selected = selectedTab == AppScreenTab.Home, selected = selectedTab == AppScreenTab.Home,
onClick = { selectedTab = AppScreenTab.Home }, onClick = { selectedTab = AppScreenTab.Home },
icon = Icons.Filled.Home, icon = Icons.Filled.Home,
contentDescription = "Home", contentDescription = stringResource(Res.string.compose_nav_home),
) )
NavItem( NavItem(
selected = selectedTab == AppScreenTab.Search, selected = selectedTab == AppScreenTab.Search,
onClick = { selectedTab = AppScreenTab.Search }, onClick = { selectedTab = AppScreenTab.Search },
icon = Res.drawable.sidebar_search, icon = Res.drawable.sidebar_search,
contentDescription = "Search", contentDescription = stringResource(Res.string.compose_nav_search),
) )
NavItem( NavItem(
selected = selectedTab == AppScreenTab.Library, selected = selectedTab == AppScreenTab.Library,
onClick = { selectedTab = AppScreenTab.Library }, onClick = { selectedTab = AppScreenTab.Library },
icon = Res.drawable.sidebar_library, icon = Res.drawable.sidebar_library,
contentDescription = "Library", contentDescription = stringResource(Res.string.compose_nav_library),
) )
NavItem( NavItem(
selected = selectedTab == AppScreenTab.Settings, selected = selectedTab == AppScreenTab.Settings,
@ -948,7 +959,7 @@ private fun MainAppContent(
}, },
onLibraryPosterLongClick = { item -> onLibraryPosterLongClick = { item ->
hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress) hapticFeedback.performHapticFeedback(HapticFeedbackType.LongPress)
selectedPosterForActions = item.toMetaPreview() // reuse existing sheet selectedPosterForActions = item.toMetaPreview()
}, },
onLibrarySectionViewAllClick = onLibrarySectionViewAllClick, onLibrarySectionViewAllClick = onLibrarySectionViewAllClick,
onContinueWatchingClick = onContinueWatchingClick, onContinueWatchingClick = onContinueWatchingClick,
@ -999,6 +1010,9 @@ private fun MainAppContent(
} }
composable<DetailRoute> { backStackEntry -> composable<DetailRoute> { backStackEntry ->
val route = backStackEntry.toRoute<DetailRoute>() val route = backStackEntry.toRoute<DetailRoute>()
val directorRole = stringResource(Res.string.person_role_director)
val writerRole = stringResource(Res.string.person_role_writer)
val creatorRole = stringResource(Res.string.person_role_creator)
MetaDetailsScreen( MetaDetailsScreen(
type = route.type, type = route.type,
id = route.id, id = route.id,
@ -1039,8 +1053,11 @@ private fun MainAppContent(
castAvatarTransitionKey = avatarTransitionKey, castAvatarTransitionKey = avatarTransitionKey,
preferCrew = person.role?.let { preferCrew = person.role?.let {
it.equals("Director", ignoreCase = true) || it.equals("Director", ignoreCase = true) ||
it.equals(directorRole, ignoreCase = true) ||
it.equals("Writer", ignoreCase = true) || it.equals("Writer", ignoreCase = true) ||
it.equals(writerRole, ignoreCase = true) ||
it.equals("Creator", ignoreCase = true) it.equals("Creator", ignoreCase = true)
|| it.equals(creatorRole, ignoreCase = true)
} ?: false, } ?: false,
), ),
) )
@ -1667,7 +1684,7 @@ private fun MainAppContent(
tab.key to (snapshot[tab.key] == true) tab.key to (snapshot[tab.key] == true)
} }
}.onFailure { error -> }.onFailure { error ->
pickerError = error.message ?: "Failed to load Trakt lists" pickerError = error.message ?: getString(Res.string.trakt_lists_load_failed)
} }
pickerPending = false pickerPending = false
} }
@ -1753,7 +1770,7 @@ private fun MainAppContent(
pickerItem = null pickerItem = null
pickerError = null pickerError = null
}.onFailure { error -> }.onFailure { error ->
pickerError = error.message ?: "Failed to update Trakt lists" pickerError = error.message ?: getString(Res.string.trakt_lists_update_failed)
} }
pickerPending = false pickerPending = false
} }
@ -1761,11 +1778,11 @@ private fun MainAppContent(
) )
NuvioStatusModal( NuvioStatusModal(
title = "Exit app", title = stringResource(Res.string.app_exit_title),
message = "Do you want to exit the app?", message = stringResource(Res.string.app_exit_message),
isVisible = showExitConfirmation, isVisible = showExitConfirmation,
confirmText = "Yes", confirmText = stringResource(Res.string.action_yes),
dismissText = "No", dismissText = stringResource(Res.string.action_no),
onConfirm = { onConfirm = {
showExitConfirmation = false showExitConfirmation = false
platformExitApp() platformExitApp()
@ -1796,9 +1813,9 @@ private fun MainAppContent(
visible = resumePromptItem != null, visible = resumePromptItem != null,
imageUrl = resumePromptItem?.poster ?: resumePromptItem?.imageUrl, imageUrl = resumePromptItem?.poster ?: resumePromptItem?.imageUrl,
title = resumePromptItem?.title.orEmpty(), title = resumePromptItem?.title.orEmpty(),
subtitle = resumePromptItem?.subtitle.orEmpty(), subtitle = resumePromptItem?.let { localizedContinueWatchingSubtitle(it) }.orEmpty(),
progressFraction = resumePromptItem?.progressFraction ?: 0f, progressFraction = resumePromptItem?.progressFraction ?: 0f,
actionLabel = "Resume", actionLabel = stringResource(Res.string.resume_prompt_action),
onAction = { onAction = {
val item = resumePromptItem ?: return@NuvioFloatingPrompt val item = resumePromptItem ?: return@NuvioFloatingPrompt
resumePromptItem = null resumePromptItem = null
@ -1853,6 +1870,7 @@ private fun AppTabHost(
onPosterClick: ((MetaPreview) -> Unit)? = null, onPosterClick: ((MetaPreview) -> Unit)? = null,
onPosterLongClick: ((MetaPreview) -> Unit)? = null, onPosterLongClick: ((MetaPreview) -> Unit)? = null,
onLibraryPosterClick: ((LibraryItem) -> Unit)? = null, onLibraryPosterClick: ((LibraryItem) -> Unit)? = null,
onLibraryPosterLongClick: ((LibraryItem) -> Unit)? = null,
onLibrarySectionViewAllClick: ((LibrarySection) -> Unit)? = null, onLibrarySectionViewAllClick: ((LibrarySection) -> Unit)? = null,
onContinueWatchingClick: ((ContinueWatchingItem) -> Unit)? = null, onContinueWatchingClick: ((ContinueWatchingItem) -> Unit)? = null,
onContinueWatchingLongPress: ((ContinueWatchingItem) -> Unit)? = null, onContinueWatchingLongPress: ((ContinueWatchingItem) -> Unit)? = null,
@ -1869,7 +1887,6 @@ private fun AppTabHost(
onCollectionsSettingsClick: () -> Unit = {}, onCollectionsSettingsClick: () -> Unit = {},
onFolderClick: ((collectionId: String, folderId: String) -> Unit)? = null, onFolderClick: ((collectionId: String, folderId: String) -> Unit)? = null,
onInitialHomeContentRendered: () -> Unit = {}, onInitialHomeContentRendered: () -> Unit = {},
onLibraryPosterLongClick: ((LibraryItem) -> Unit)? = null,
) { ) {
val tabStateHolder = rememberSaveableStateHolder() val tabStateHolder = rememberSaveableStateHolder()
@ -1955,13 +1972,13 @@ private fun TabletFloatingTopBar(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
TabletTopPillItem( TabletTopPillItem(
label = "Home", label = stringResource(Res.string.compose_nav_home),
selected = selectedTab == AppScreenTab.Home, selected = selectedTab == AppScreenTab.Home,
onClick = { onTabSelected(AppScreenTab.Home) }, onClick = { onTabSelected(AppScreenTab.Home) },
icon = { icon = {
Icon( Icon(
imageVector = Icons.Filled.Home, imageVector = Icons.Filled.Home,
contentDescription = "Home", contentDescription = stringResource(Res.string.compose_nav_home),
modifier = Modifier.size(18.dp), modifier = Modifier.size(18.dp),
tint = if (selectedTab == AppScreenTab.Home) { tint = if (selectedTab == AppScreenTab.Home) {
MaterialTheme.colorScheme.onPrimaryContainer MaterialTheme.colorScheme.onPrimaryContainer
@ -1972,13 +1989,13 @@ private fun TabletFloatingTopBar(
}, },
) )
TabletTopPillItem( TabletTopPillItem(
label = "Search", label = stringResource(Res.string.compose_nav_search),
selected = selectedTab == AppScreenTab.Search, selected = selectedTab == AppScreenTab.Search,
onClick = { onTabSelected(AppScreenTab.Search) }, onClick = { onTabSelected(AppScreenTab.Search) },
icon = { icon = {
Icon( Icon(
painter = painterResource(Res.drawable.sidebar_search), painter = painterResource(Res.drawable.sidebar_search),
contentDescription = "Search", contentDescription = stringResource(Res.string.compose_nav_search),
modifier = Modifier.size(18.dp), modifier = Modifier.size(18.dp),
tint = if (selectedTab == AppScreenTab.Search) { tint = if (selectedTab == AppScreenTab.Search) {
MaterialTheme.colorScheme.onPrimaryContainer MaterialTheme.colorScheme.onPrimaryContainer
@ -1989,13 +2006,13 @@ private fun TabletFloatingTopBar(
}, },
) )
TabletTopPillItem( TabletTopPillItem(
label = "Library", label = stringResource(Res.string.compose_nav_library),
selected = selectedTab == AppScreenTab.Library, selected = selectedTab == AppScreenTab.Library,
onClick = { onTabSelected(AppScreenTab.Library) }, onClick = { onTabSelected(AppScreenTab.Library) },
icon = { icon = {
Icon( Icon(
painter = painterResource(Res.drawable.sidebar_library), painter = painterResource(Res.drawable.sidebar_library),
contentDescription = "Library", contentDescription = stringResource(Res.string.compose_nav_library),
modifier = Modifier.size(18.dp), modifier = Modifier.size(18.dp),
tint = if (selectedTab == AppScreenTab.Library) { tint = if (selectedTab == AppScreenTab.Library) {
MaterialTheme.colorScheme.onPrimaryContainer MaterialTheme.colorScheme.onPrimaryContainer
@ -2025,7 +2042,7 @@ private fun TabletFloatingTopBar(
onAddProfileRequested = onAddProfileRequested, onAddProfileRequested = onAddProfileRequested,
) )
Text( Text(
text = "Profile", text = stringResource(Res.string.compose_nav_profile),
modifier = Modifier.clickable { onTabSelected(AppScreenTab.Settings) }, modifier = Modifier.clickable { onTabSelected(AppScreenTab.Settings) },
style = MaterialTheme.typography.labelLarge, style = MaterialTheme.typography.labelLarge,
color = if (selectedTab == AppScreenTab.Settings) { color = if (selectedTab == AppScreenTab.Settings) {
@ -2088,7 +2105,7 @@ private fun AppLaunchOverlay(
) { ) {
Image( Image(
painter = painterResource(Res.drawable.app_logo_wordmark), painter = painterResource(Res.drawable.app_logo_wordmark),
contentDescription = "Nuvio", contentDescription = stringResource(Res.string.app_brand_name),
modifier = Modifier modifier = Modifier
.fillMaxWidth(0.48f) .fillMaxWidth(0.48f)
.height(44.dp), .height(44.dp),