mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-07-26 22:42:17 +00:00
Merge branch 'appstorepolicy' into cmp-rewrite
This commit is contained in:
commit
e921e28141
14 changed files with 289 additions and 41 deletions
|
|
@ -2,6 +2,9 @@ package com.nuvio.app.core.build
|
|||
|
||||
actual object AppFeaturePolicy {
|
||||
actual val pluginsEnabled: Boolean = true
|
||||
actual val supportersContributorsPageEnabled: Boolean = true
|
||||
actual val accountDeletionEnabled: Boolean = false
|
||||
actual val personalMediaAddonCopyEnabled: Boolean = false
|
||||
actual val p2pEnabled: Boolean = true
|
||||
actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.IN_APP
|
||||
actual val heroTrailerPlaybackSupported: Boolean = true
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package com.nuvio.app.core.build
|
|||
|
||||
actual object AppFeaturePolicy {
|
||||
actual val pluginsEnabled: Boolean = false
|
||||
actual val supportersContributorsPageEnabled: Boolean = true
|
||||
actual val accountDeletionEnabled: Boolean = false
|
||||
actual val personalMediaAddonCopyEnabled: Boolean = false
|
||||
actual val p2pEnabled: Boolean = true
|
||||
actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.EXTERNAL
|
||||
actual val heroTrailerPlaybackSupported: Boolean = false
|
||||
|
|
|
|||
|
|
@ -32,6 +32,11 @@
|
|||
<string name="addons_badge_unavailable">Unavailable</string>
|
||||
<string name="addons_configure">Configure addon</string>
|
||||
<string name="addons_delete">Delete addon</string>
|
||||
<string name="addons_appstore_add_description">Connect your own media server to browse and play from your personal library.</string>
|
||||
<string name="addons_appstore_empty_subtitle">Add a server URL above when you want Nuvio to show your private library.</string>
|
||||
<string name="addons_appstore_empty_title">No personal libraries connected.</string>
|
||||
<string name="addons_appstore_input_placeholder">Server URL</string>
|
||||
<string name="addons_appstore_install_button">Add</string>
|
||||
<string name="addons_empty_subtitle">Add a manifest URL to start loading catalogs, metadata, streams or subtitles into Nuvio.</string>
|
||||
<string name="addons_empty_title">No addons installed yet.</string>
|
||||
<string name="addons_error_enter_url">Enter an addon URL.</string>
|
||||
|
|
@ -634,6 +639,7 @@
|
|||
<string name="settings_content_discovery_section_home">HOME</string>
|
||||
<string name="settings_content_discovery_section_sources">SOURCES</string>
|
||||
<string name="settings_content_discovery_addons_description">Install, remove, refresh, and sort your content sources.</string>
|
||||
<string name="settings_content_discovery_addons_description_appstore">Connect personal media sources and manage access to your own library.</string>
|
||||
<string name="settings_content_discovery_plugins_description">Install JavaScript scraper repositories and test providers internally.</string>
|
||||
<string name="settings_content_discovery_homescreen_description">Adjust home layout, content visibility, and poster behavior</string>
|
||||
<string name="settings_content_discovery_meta_screen_description">Settings for the detail and episode screens.</string>
|
||||
|
|
|
|||
|
|
@ -1582,7 +1582,9 @@ private fun MainAppContent(
|
|||
},
|
||||
onAccountSettingsClick = { navController.navigate(AccountSettingsRoute) },
|
||||
onSupportersContributorsSettingsClick = {
|
||||
navController.navigate(SupportersContributorsSettingsRoute)
|
||||
if (AppFeaturePolicy.supportersContributorsPageEnabled) {
|
||||
navController.navigate(SupportersContributorsSettingsRoute)
|
||||
}
|
||||
},
|
||||
onLicensesAttributionsSettingsClick = {
|
||||
navController.navigate(LicensesAttributionsSettingsRoute)
|
||||
|
|
@ -2681,9 +2683,15 @@ private fun MainAppContent(
|
|||
navController = navController,
|
||||
backStackEntry = backStackEntry,
|
||||
)
|
||||
SupportersContributorsSettingsScreen(
|
||||
onBack = onBack,
|
||||
)
|
||||
if (AppFeaturePolicy.supportersContributorsPageEnabled) {
|
||||
SupportersContributorsSettingsScreen(
|
||||
onBack = onBack,
|
||||
)
|
||||
} else {
|
||||
LaunchedEffect(Unit) {
|
||||
onBack()
|
||||
}
|
||||
}
|
||||
}
|
||||
composable<LicensesAttributionsSettingsRoute> { backStackEntry ->
|
||||
val onBack = rememberGuardedPopBackStack(
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@ enum class TrailerPlaybackMode {
|
|||
|
||||
expect object AppFeaturePolicy {
|
||||
val pluginsEnabled: Boolean
|
||||
val supportersContributorsPageEnabled: Boolean
|
||||
val accountDeletionEnabled: Boolean
|
||||
val personalMediaAddonCopyEnabled: Boolean
|
||||
val p2pEnabled: Boolean
|
||||
val trailerPlaybackMode: TrailerPlaybackMode
|
||||
val heroTrailerPlaybackSupported: Boolean
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import androidx.compose.ui.platform.LocalUriHandler
|
|||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.nuvio.app.core.build.AppFeaturePolicy
|
||||
import coil3.compose.AsyncImage
|
||||
import com.nuvio.app.core.ui.NuvioIconActionButton
|
||||
import com.nuvio.app.core.ui.NuvioInfoBadge
|
||||
|
|
@ -93,6 +94,7 @@ internal fun AddonsSettingsPageContent(
|
|||
var formMessage by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
var installModalState by remember { mutableStateOf<AddonInstallModalState?>(null) }
|
||||
val enterAddonUrlMessage = stringResource(Res.string.addons_error_enter_url)
|
||||
val usePersonalMediaCopy = AppFeaturePolicy.personalMediaAddonCopyEnabled
|
||||
|
||||
val overview = remember(uiState.addons) { uiState.addons.toOverview() }
|
||||
|
||||
|
|
@ -107,6 +109,7 @@ internal fun AddonsSettingsPageContent(
|
|||
AddAddonCard(
|
||||
addonUrl = addonUrl,
|
||||
formMessage = formMessage,
|
||||
usePersonalMediaCopy = usePersonalMediaCopy,
|
||||
onAddonUrlChange = {
|
||||
addonUrl = it
|
||||
formMessage = null
|
||||
|
|
@ -138,7 +141,7 @@ internal fun AddonsSettingsPageContent(
|
|||
|
||||
SectionHeader(stringResource(Res.string.addons_section_installed))
|
||||
if (uiState.addons.isEmpty()) {
|
||||
EmptyStateCard()
|
||||
EmptyStateCard(usePersonalMediaCopy = usePersonalMediaCopy)
|
||||
} else {
|
||||
val lastIndex = uiState.addons.lastIndex
|
||||
uiState.addons.forEachIndexed { index, addon ->
|
||||
|
|
@ -283,6 +286,7 @@ private fun VerticalSeparator() {
|
|||
private fun AddAddonCard(
|
||||
addonUrl: String,
|
||||
formMessage: String?,
|
||||
usePersonalMediaCopy: Boolean,
|
||||
onAddonUrlChange: (String) -> Unit,
|
||||
onAddClick: () -> Unit,
|
||||
) {
|
||||
|
|
@ -290,14 +294,34 @@ private fun AddAddonCard(
|
|||
NuvioInputField(
|
||||
value = addonUrl,
|
||||
onValueChange = onAddonUrlChange,
|
||||
placeholder = stringResource(Res.string.addons_input_placeholder),
|
||||
placeholder = stringResource(
|
||||
if (usePersonalMediaCopy) {
|
||||
Res.string.addons_appstore_input_placeholder
|
||||
} else {
|
||||
Res.string.addons_input_placeholder
|
||||
},
|
||||
),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(18.dp))
|
||||
NuvioPrimaryButton(
|
||||
text = stringResource(Res.string.addons_install_button),
|
||||
text = stringResource(
|
||||
if (usePersonalMediaCopy) {
|
||||
Res.string.addons_appstore_install_button
|
||||
} else {
|
||||
Res.string.addons_install_button
|
||||
},
|
||||
),
|
||||
enabled = addonUrl.isNotBlank(),
|
||||
onClick = onAddClick,
|
||||
)
|
||||
if (usePersonalMediaCopy) {
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
Text(
|
||||
text = stringResource(Res.string.addons_appstore_add_description),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
formMessage?.let { message ->
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
Text(
|
||||
|
|
@ -330,16 +354,30 @@ private sealed interface AddonInstallModalState {
|
|||
}
|
||||
|
||||
@Composable
|
||||
private fun EmptyStateCard() {
|
||||
private fun EmptyStateCard(
|
||||
usePersonalMediaCopy: Boolean,
|
||||
) {
|
||||
NuvioSurfaceCard {
|
||||
Text(
|
||||
text = stringResource(Res.string.addons_empty_title),
|
||||
text = stringResource(
|
||||
if (usePersonalMediaCopy) {
|
||||
Res.string.addons_appstore_empty_title
|
||||
} else {
|
||||
Res.string.addons_empty_title
|
||||
},
|
||||
),
|
||||
style = MaterialTheme.typography.titleLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = stringResource(Res.string.addons_empty_subtitle),
|
||||
text = stringResource(
|
||||
if (usePersonalMediaCopy) {
|
||||
Res.string.addons_appstore_empty_subtitle
|
||||
} else {
|
||||
Res.string.addons_empty_subtitle
|
||||
},
|
||||
),
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import androidx.compose.foundation.layout.Spacer
|
|||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.lazy.LazyListScope
|
||||
import androidx.compose.material3.Button
|
||||
import androidx.compose.material3.ButtonDefaults
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
|
|
@ -25,16 +27,24 @@ import androidx.compose.ui.unit.dp
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.nuvio.app.core.auth.AuthRepository
|
||||
import com.nuvio.app.core.auth.AuthState
|
||||
import com.nuvio.app.core.build.AppFeaturePolicy
|
||||
import com.nuvio.app.core.network.SyncBackendRepository
|
||||
import com.nuvio.app.core.ui.NuvioPrimaryButton
|
||||
import com.nuvio.app.core.ui.NuvioStatusModal
|
||||
import com.nuvio.app.core.ui.NuvioSurfaceCard
|
||||
import com.nuvio.app.core.ui.NuvioTokens
|
||||
import com.nuvio.app.core.ui.nuvio
|
||||
import com.nuvio.app.features.dev.DebugSyncBackendSwitch
|
||||
import com.nuvio.app.features.dev.shouldShowDebugSyncBackendSwitch
|
||||
import kotlinx.coroutines.launch
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.action_cancel
|
||||
import nuvio.composeapp.generated.resources.compose_settings_page_account
|
||||
import nuvio.composeapp.generated.resources.auth_account_deletion_failed
|
||||
import nuvio.composeapp.generated.resources.settings_account_delete_account
|
||||
import nuvio.composeapp.generated.resources.settings_account_delete_account_description
|
||||
import nuvio.composeapp.generated.resources.settings_account_delete_confirm_message
|
||||
import nuvio.composeapp.generated.resources.settings_account_delete_confirm_title
|
||||
import nuvio.composeapp.generated.resources.settings_account_email
|
||||
import nuvio.composeapp.generated.resources.settings_account_not_signed_in
|
||||
import nuvio.composeapp.generated.resources.settings_account_sign_out
|
||||
|
|
@ -62,7 +72,12 @@ private fun AccountSettingsBody(
|
|||
val syncBackendState by SyncBackendRepository.state.collectAsStateWithLifecycle()
|
||||
val scope = rememberCoroutineScope()
|
||||
var showSignOutConfirm by remember { mutableStateOf(false) }
|
||||
var showDeleteConfirm by remember { mutableStateOf(false) }
|
||||
var isDeletingAccount by remember { mutableStateOf(false) }
|
||||
var deleteErrorMessage by remember { mutableStateOf<String?>(null) }
|
||||
val syncBackendLabel = syncBackendState.selectedBackend.displayName
|
||||
val deleteAccountFallbackMessage = stringResource(Res.string.auth_account_deletion_failed)
|
||||
val canDeleteAccount = AppFeaturePolicy.accountDeletionEnabled && authState is AuthState.Authenticated
|
||||
|
||||
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
|
||||
NuvioSurfaceCard {
|
||||
|
|
@ -121,6 +136,16 @@ private fun AccountSettingsBody(
|
|||
text = stringResource(Res.string.settings_account_sign_out),
|
||||
onClick = { showSignOutConfirm = true },
|
||||
)
|
||||
|
||||
if (canDeleteAccount) {
|
||||
DeleteAccountCard(
|
||||
errorMessage = deleteErrorMessage,
|
||||
onDeleteClick = {
|
||||
deleteErrorMessage = null
|
||||
showDeleteConfirm = true
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NuvioStatusModal(
|
||||
|
|
@ -135,6 +160,85 @@ private fun AccountSettingsBody(
|
|||
},
|
||||
onDismiss = { showSignOutConfirm = false },
|
||||
)
|
||||
|
||||
NuvioStatusModal(
|
||||
title = stringResource(Res.string.settings_account_delete_confirm_title),
|
||||
message = stringResource(Res.string.settings_account_delete_confirm_message),
|
||||
isVisible = showDeleteConfirm,
|
||||
isBusy = isDeletingAccount,
|
||||
confirmText = stringResource(Res.string.settings_account_delete_account),
|
||||
dismissText = stringResource(Res.string.action_cancel),
|
||||
onConfirm = {
|
||||
if (isDeletingAccount) return@NuvioStatusModal
|
||||
isDeletingAccount = true
|
||||
scope.launch {
|
||||
val result = AuthRepository.deleteAccount()
|
||||
isDeletingAccount = false
|
||||
showDeleteConfirm = false
|
||||
deleteErrorMessage = if (result.isSuccess) {
|
||||
null
|
||||
} else {
|
||||
AuthRepository.error.value
|
||||
?: result.exceptionOrNull()?.message
|
||||
?: deleteAccountFallbackMessage
|
||||
}
|
||||
}
|
||||
},
|
||||
onDismiss = {
|
||||
if (!isDeletingAccount) {
|
||||
showDeleteConfirm = false
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun DeleteAccountCard(
|
||||
errorMessage: String?,
|
||||
onDeleteClick: () -> Unit,
|
||||
) {
|
||||
val tokens = MaterialTheme.nuvio
|
||||
|
||||
NuvioSurfaceCard {
|
||||
Text(
|
||||
text = stringResource(Res.string.settings_account_delete_account),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
color = tokens.colors.textPrimary,
|
||||
fontWeight = FontWeight.SemiBold,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = stringResource(Res.string.settings_account_delete_account_description),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = tokens.colors.textMuted,
|
||||
)
|
||||
errorMessage?.let { message ->
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
Text(
|
||||
text = message,
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = tokens.colors.danger,
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(14.dp))
|
||||
Button(
|
||||
onClick = onDeleteClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(NuvioTokens.Space.s48 + NuvioTokens.Space.s4),
|
||||
shape = tokens.shapes.button,
|
||||
colors = ButtonDefaults.buttonColors(
|
||||
containerColor = tokens.colors.danger,
|
||||
contentColor = tokens.colors.textInverse,
|
||||
),
|
||||
) {
|
||||
Text(
|
||||
text = stringResource(Res.string.settings_account_delete_account),
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import androidx.compose.material.icons.rounded.Extension
|
|||
import androidx.compose.material.icons.rounded.Home
|
||||
import androidx.compose.material.icons.rounded.Hub
|
||||
import androidx.compose.material.icons.rounded.Tune
|
||||
import com.nuvio.app.core.build.AppFeaturePolicy
|
||||
import nuvio.composeapp.generated.resources.Res
|
||||
import nuvio.composeapp.generated.resources.compose_settings_page_addons
|
||||
import nuvio.composeapp.generated.resources.compose_settings_page_homescreen
|
||||
|
|
@ -14,6 +15,7 @@ import nuvio.composeapp.generated.resources.compose_settings_page_meta_screen
|
|||
import nuvio.composeapp.generated.resources.compose_settings_page_plugins
|
||||
import nuvio.composeapp.generated.resources.collections_header
|
||||
import nuvio.composeapp.generated.resources.settings_content_discovery_addons_description
|
||||
import nuvio.composeapp.generated.resources.settings_content_discovery_addons_description_appstore
|
||||
import nuvio.composeapp.generated.resources.settings_content_discovery_collections_description
|
||||
import nuvio.composeapp.generated.resources.settings_content_discovery_homescreen_description
|
||||
import nuvio.composeapp.generated.resources.settings_content_discovery_meta_screen_description
|
||||
|
|
@ -39,7 +41,13 @@ internal fun LazyListScope.contentDiscoveryContent(
|
|||
SettingsGroup(isTablet = isTablet) {
|
||||
SettingsNavigationRow(
|
||||
title = stringResource(Res.string.compose_settings_page_addons),
|
||||
description = stringResource(Res.string.settings_content_discovery_addons_description),
|
||||
description = stringResource(
|
||||
if (AppFeaturePolicy.personalMediaAddonCopyEnabled) {
|
||||
Res.string.settings_content_discovery_addons_description_appstore
|
||||
} else {
|
||||
Res.string.settings_content_discovery_addons_description
|
||||
},
|
||||
),
|
||||
icon = Icons.Rounded.Extension,
|
||||
isTablet = isTablet,
|
||||
onClick = onAddonsClick,
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ internal fun LazyListScope.settingsRootContent(
|
|||
showGeneralSection: Boolean = true,
|
||||
showAboutSection: Boolean = true,
|
||||
showAdvancedSection: Boolean = true,
|
||||
showSupportersContributorsPage: Boolean = true,
|
||||
) {
|
||||
if (showAccountSection) {
|
||||
item {
|
||||
|
|
@ -189,14 +190,16 @@ internal fun LazyListScope.settingsRootContent(
|
|||
isTablet = isTablet,
|
||||
) {
|
||||
SettingsGroup(isTablet = isTablet) {
|
||||
SettingsNavigationRow(
|
||||
title = stringResource(Res.string.compose_settings_page_supporters_contributors),
|
||||
description = stringResource(Res.string.about_supporters_contributors_subtitle),
|
||||
icon = Icons.Rounded.Favorite,
|
||||
isTablet = isTablet,
|
||||
onClick = onSupportersContributorsClick,
|
||||
)
|
||||
SettingsGroupDivider(isTablet = isTablet)
|
||||
if (showSupportersContributorsPage) {
|
||||
SettingsNavigationRow(
|
||||
title = stringResource(Res.string.compose_settings_page_supporters_contributors),
|
||||
description = stringResource(Res.string.about_supporters_contributors_subtitle),
|
||||
icon = Icons.Rounded.Favorite,
|
||||
isTablet = isTablet,
|
||||
onClick = onSupportersContributorsClick,
|
||||
)
|
||||
SettingsGroupDivider(isTablet = isTablet)
|
||||
}
|
||||
SettingsNavigationRow(
|
||||
title = stringResource(Res.string.compose_settings_page_licenses_attributions),
|
||||
description = stringResource(Res.string.about_licenses_attributions_subtitle),
|
||||
|
|
|
|||
|
|
@ -94,6 +94,12 @@ private val SettingsSearchRevealThreshold = 28.dp
|
|||
private const val SettingsSearchRevealAnimationMillis = 240L
|
||||
private const val SettingsSearchRevealHapticDelayMillis = 90L
|
||||
|
||||
private fun SettingsPage.isEnabledByPolicy(): Boolean =
|
||||
when (this) {
|
||||
SettingsPage.SupportersContributors -> AppFeaturePolicy.supportersContributorsPageEnabled
|
||||
else -> true
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SettingsScreen(
|
||||
modifier: Modifier = Modifier,
|
||||
|
|
@ -216,9 +222,20 @@ fun SettingsScreen(
|
|||
|
||||
var currentPage by rememberSaveable { mutableStateOf(SettingsPage.Root.name) }
|
||||
val scrollToTopRequests = remember { MutableSharedFlow<Unit>(extraBufferCapacity = 1) }
|
||||
val page = remember(currentPage) { SettingsPage.valueOf(currentPage) }
|
||||
val page = remember(currentPage) {
|
||||
runCatching { SettingsPage.valueOf(currentPage) }
|
||||
.getOrDefault(SettingsPage.Root)
|
||||
.takeIf { it.isEnabledByPolicy() }
|
||||
?: SettingsPage.Root
|
||||
}
|
||||
val previousPage = page.previousPage()
|
||||
|
||||
LaunchedEffect(page, currentPage) {
|
||||
if (page.name != currentPage) {
|
||||
currentPage = page.name
|
||||
}
|
||||
}
|
||||
|
||||
LaunchedEffect(rootActionRequests, rootActionsEnabled, page) {
|
||||
rootActionRequests.collect {
|
||||
if (!rootActionsEnabled) return@collect
|
||||
|
|
@ -232,9 +249,12 @@ fun SettingsScreen(
|
|||
}
|
||||
|
||||
LaunchedEffect(requestedPageName, rootActionsEnabled) {
|
||||
val targetPage = requestedPageName
|
||||
?.let { runCatching { SettingsPage.valueOf(it) }.getOrNull() }
|
||||
?: return@LaunchedEffect
|
||||
val requestedPage = requestedPageName ?: return@LaunchedEffect
|
||||
val targetPage = runCatching { SettingsPage.valueOf(requestedPage) }.getOrNull()
|
||||
if (targetPage == null || !targetPage.isEnabledByPolicy()) {
|
||||
onRequestedPageConsumed()
|
||||
return@LaunchedEffect
|
||||
}
|
||||
if (!rootActionsEnabled) return@LaunchedEffect
|
||||
currentPage = targetPage.name
|
||||
onRequestedPageConsumed()
|
||||
|
|
@ -449,6 +469,9 @@ private fun MobileSettingsScreen(
|
|||
}
|
||||
val searchEntries = settingsSearchEntries(
|
||||
pluginsEnabled = AppFeaturePolicy.pluginsEnabled,
|
||||
supportersContributorsPageEnabled = AppFeaturePolicy.supportersContributorsPageEnabled,
|
||||
accountDeletionEnabled = AppFeaturePolicy.accountDeletionEnabled,
|
||||
personalMediaAddonCopyEnabled = AppFeaturePolicy.personalMediaAddonCopyEnabled,
|
||||
liquidGlassNativeTabBarSupported = liquidGlassNativeTabBarSupported,
|
||||
switchProfileAvailable = onSwitchProfile != null,
|
||||
checkForUpdatesAvailable = onCheckForUpdatesClick != null,
|
||||
|
|
@ -458,7 +481,11 @@ private fun MobileSettingsScreen(
|
|||
when (target) {
|
||||
is SettingsSearchTarget.Page -> when (target.page) {
|
||||
SettingsPage.Account -> onAccountClick()
|
||||
SettingsPage.SupportersContributors -> onSupportersContributorsClick()
|
||||
SettingsPage.SupportersContributors -> {
|
||||
if (AppFeaturePolicy.supportersContributorsPageEnabled) {
|
||||
onSupportersContributorsClick()
|
||||
}
|
||||
}
|
||||
SettingsPage.LicensesAttributions -> onLicensesAttributionsClick()
|
||||
SettingsPage.ContinueWatching -> onContinueWatchingClick()
|
||||
SettingsPage.Addons -> onAddonsClick()
|
||||
|
|
@ -531,15 +558,18 @@ private fun MobileSettingsScreen(
|
|||
onDownloadsClick = onDownloadsClick,
|
||||
onAccountClick = onAccountClick,
|
||||
onSwitchProfileClick = onSwitchProfile,
|
||||
showSupportersContributorsPage = AppFeaturePolicy.supportersContributorsPageEnabled,
|
||||
)
|
||||
}
|
||||
}
|
||||
SettingsPage.Account -> accountSettingsContent(
|
||||
isTablet = false,
|
||||
)
|
||||
SettingsPage.SupportersContributors -> supportersContributorsContent(
|
||||
isTablet = false,
|
||||
)
|
||||
SettingsPage.SupportersContributors -> {
|
||||
if (AppFeaturePolicy.supportersContributorsPageEnabled) {
|
||||
supportersContributorsContent(isTablet = false)
|
||||
}
|
||||
}
|
||||
SettingsPage.LicensesAttributions -> licensesAttributionsContent(
|
||||
isTablet = false,
|
||||
)
|
||||
|
|
@ -822,6 +852,9 @@ private fun TabletSettingsScreen(
|
|||
val hapticScope = rememberCoroutineScope()
|
||||
val searchEntries = settingsSearchEntries(
|
||||
pluginsEnabled = AppFeaturePolicy.pluginsEnabled,
|
||||
supportersContributorsPageEnabled = AppFeaturePolicy.supportersContributorsPageEnabled,
|
||||
accountDeletionEnabled = AppFeaturePolicy.accountDeletionEnabled,
|
||||
personalMediaAddonCopyEnabled = AppFeaturePolicy.personalMediaAddonCopyEnabled,
|
||||
liquidGlassNativeTabBarSupported = liquidGlassNativeTabBarSupported,
|
||||
switchProfileAvailable = onSwitchProfile != null,
|
||||
checkForUpdatesAvailable = onCheckForUpdatesClick != null,
|
||||
|
|
@ -829,7 +862,11 @@ private fun TabletSettingsScreen(
|
|||
|
||||
fun openSearchTarget(target: SettingsSearchTarget) {
|
||||
when (target) {
|
||||
is SettingsSearchTarget.Page -> openInlinePage(target.page)
|
||||
is SettingsSearchTarget.Page -> {
|
||||
if (target.page.isEnabledByPolicy()) {
|
||||
openInlinePage(target.page)
|
||||
}
|
||||
}
|
||||
SettingsSearchTarget.Downloads -> onDownloadsClick()
|
||||
SettingsSearchTarget.Collections -> onCollectionsClick()
|
||||
SettingsSearchTarget.SwitchProfile -> onSwitchProfile?.invoke()
|
||||
|
|
@ -924,15 +961,18 @@ private fun TabletSettingsScreen(
|
|||
showGeneralSection = activeCategory == SettingsCategory.General,
|
||||
showAboutSection = activeCategory == SettingsCategory.About,
|
||||
showAdvancedSection = activeCategory == SettingsCategory.Advanced,
|
||||
showSupportersContributorsPage = AppFeaturePolicy.supportersContributorsPageEnabled,
|
||||
)
|
||||
}
|
||||
}
|
||||
SettingsPage.Account -> accountSettingsContent(
|
||||
isTablet = true,
|
||||
)
|
||||
SettingsPage.SupportersContributors -> supportersContributorsContent(
|
||||
isTablet = true,
|
||||
)
|
||||
SettingsPage.SupportersContributors -> {
|
||||
if (AppFeaturePolicy.supportersContributorsPageEnabled) {
|
||||
supportersContributorsContent(isTablet = true)
|
||||
}
|
||||
}
|
||||
SettingsPage.LicensesAttributions -> licensesAttributionsContent(
|
||||
isTablet = true,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -79,6 +79,9 @@ internal data class SettingsSearchEntry(
|
|||
@Composable
|
||||
internal fun settingsSearchEntries(
|
||||
pluginsEnabled: Boolean,
|
||||
supportersContributorsPageEnabled: Boolean,
|
||||
accountDeletionEnabled: Boolean,
|
||||
personalMediaAddonCopyEnabled: Boolean,
|
||||
liquidGlassNativeTabBarSupported: Boolean,
|
||||
switchProfileAvailable: Boolean,
|
||||
checkForUpdatesAvailable: Boolean,
|
||||
|
|
@ -261,14 +264,16 @@ internal fun settingsSearchEntries(
|
|||
description = stringResource(Res.string.compose_settings_root_notifications_description),
|
||||
icon = Icons.Rounded.Notifications,
|
||||
)
|
||||
addPage(
|
||||
page = SettingsPage.SupportersContributors,
|
||||
key = "supporters",
|
||||
title = supportersPage,
|
||||
description = stringResource(Res.string.about_supporters_contributors_subtitle),
|
||||
category = aboutCategory,
|
||||
icon = Icons.Rounded.Favorite,
|
||||
)
|
||||
if (supportersContributorsPageEnabled) {
|
||||
addPage(
|
||||
page = SettingsPage.SupportersContributors,
|
||||
key = "supporters",
|
||||
title = supportersPage,
|
||||
description = stringResource(Res.string.about_supporters_contributors_subtitle),
|
||||
category = aboutCategory,
|
||||
icon = Icons.Rounded.Favorite,
|
||||
)
|
||||
}
|
||||
addPage(
|
||||
page = SettingsPage.LicensesAttributions,
|
||||
key = "licenses-attributions",
|
||||
|
|
@ -316,7 +321,7 @@ internal fun settingsSearchEntries(
|
|||
key = "check-updates",
|
||||
title = stringResource(Res.string.compose_settings_root_check_updates_title),
|
||||
description = stringResource(Res.string.compose_settings_root_check_updates_description),
|
||||
page = supportersPage,
|
||||
page = if (supportersContributorsPageEnabled) supportersPage else licensesPage,
|
||||
section = stringResource(Res.string.compose_settings_root_about_section),
|
||||
category = aboutCategory,
|
||||
icon = Icons.Rounded.CloudDownload,
|
||||
|
|
@ -342,6 +347,18 @@ internal fun settingsSearchEntries(
|
|||
category = accountCategory,
|
||||
icon = Icons.Rounded.AccountCircle,
|
||||
)
|
||||
if (accountDeletionEnabled) {
|
||||
addRow(
|
||||
page = SettingsPage.Account,
|
||||
key = "account-delete",
|
||||
title = stringResource(Res.string.settings_account_delete_account),
|
||||
description = stringResource(Res.string.settings_account_delete_account_description),
|
||||
pageLabel = accountPage,
|
||||
section = accountPage,
|
||||
category = accountCategory,
|
||||
icon = Icons.Rounded.AccountCircle,
|
||||
)
|
||||
}
|
||||
|
||||
addRow(
|
||||
page = SettingsPage.Appearance,
|
||||
|
|
@ -418,7 +435,13 @@ internal fun settingsSearchEntries(
|
|||
page = SettingsPage.Addons,
|
||||
key = "addons",
|
||||
title = addonsPage,
|
||||
description = stringResource(Res.string.settings_content_discovery_addons_description),
|
||||
description = stringResource(
|
||||
if (personalMediaAddonCopyEnabled) {
|
||||
Res.string.settings_content_discovery_addons_description_appstore
|
||||
} else {
|
||||
Res.string.settings_content_discovery_addons_description
|
||||
},
|
||||
),
|
||||
icon = Icons.Rounded.Extension,
|
||||
)
|
||||
if (pluginsEnabled) {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package com.nuvio.app.core.build
|
|||
|
||||
actual object AppFeaturePolicy {
|
||||
actual val pluginsEnabled: Boolean = false
|
||||
actual val supportersContributorsPageEnabled: Boolean = true
|
||||
actual val accountDeletionEnabled: Boolean = false
|
||||
actual val personalMediaAddonCopyEnabled: Boolean = false
|
||||
actual val p2pEnabled: Boolean = false
|
||||
actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.EXTERNAL
|
||||
actual val heroTrailerPlaybackSupported: Boolean = false
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package com.nuvio.app.core.build
|
|||
|
||||
actual object AppFeaturePolicy {
|
||||
actual val pluginsEnabled: Boolean = false
|
||||
actual val supportersContributorsPageEnabled: Boolean = false
|
||||
actual val accountDeletionEnabled: Boolean = true
|
||||
actual val personalMediaAddonCopyEnabled: Boolean = true
|
||||
actual val p2pEnabled: Boolean = false
|
||||
actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.EXTERNAL
|
||||
actual val heroTrailerPlaybackSupported: Boolean = false
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package com.nuvio.app.core.build
|
|||
|
||||
actual object AppFeaturePolicy {
|
||||
actual val pluginsEnabled: Boolean = true
|
||||
actual val supportersContributorsPageEnabled: Boolean = true
|
||||
actual val accountDeletionEnabled: Boolean = false
|
||||
actual val personalMediaAddonCopyEnabled: Boolean = false
|
||||
actual val p2pEnabled: Boolean = false
|
||||
actual val trailerPlaybackMode: TrailerPlaybackMode = TrailerPlaybackMode.IN_APP
|
||||
actual val heroTrailerPlaybackSupported: Boolean = false
|
||||
|
|
|
|||
Loading…
Reference in a new issue