ref: adding attributes

This commit is contained in:
tapframe 2026-05-22 20:29:51 +05:30
parent 9d41785887
commit 4b45d4dd25
5 changed files with 121 additions and 20 deletions

View file

@ -425,6 +425,10 @@
<string name="settings_licenses_attributions_imdb_body">Nuvio uses IMDb Non-Commercial Datasets, including title.ratings.tsv.gz, for IMDb ratings and vote counts. Information courtesy of IMDb (https://www.imdb.com). Used with permission. IMDb data is for personal and non-commercial use under IMDb&apos;s terms.</string>
<string name="settings_licenses_attributions_trakt_title">Trakt</string>
<string name="settings_licenses_attributions_trakt_body">Nuvio connects to Trakt for account authentication, watched history, progress sync, library data, ratings, lists, and comments. Nuvio is not affiliated with or endorsed by Trakt.</string>
<string name="settings_licenses_attributions_premiumize_title">Premiumize</string>
<string name="settings_licenses_attributions_premiumize_body">Nuvio connects to Premiumize for account authentication, cloud library access, cache checks, and cloud playback features. Nuvio is not affiliated with or endorsed by Premiumize.</string>
<string name="settings_licenses_attributions_torbox_title">TorBox</string>
<string name="settings_licenses_attributions_torbox_body">Nuvio connects to TorBox for account authentication, cloud library access, cache checks, and cloud playback features. Nuvio is not affiliated with or endorsed by TorBox.</string>
<string name="settings_licenses_attributions_mdblist_title">MDBList</string>
<string name="settings_licenses_attributions_mdblist_body">Nuvio uses MDBList for ratings and external score provider data. Nuvio is not affiliated with or endorsed by MDBList.</string>
<string name="settings_licenses_attributions_introdb_title">IntroDB</string>

View file

@ -104,6 +104,27 @@ private fun ContinueWatchingItem.continueWatchingArtworkUrl(
)
}
private fun ContinueWatchingItem.continueWatchingPosterArtworkUrl(
useEpisodeThumbnails: Boolean,
): String? {
if (seasonNumber == null || episodeNumber == null) {
return continueWatchingArtworkUrl(useEpisodeThumbnails)
}
val normalizedEpisodeThumbnail = episodeThumbnail?.trim()?.takeIf { it.isNotBlank() }
val nonEpisodeImageUrl = imageUrl
?.trim()
?.takeIf { it.isNotBlank() && it != normalizedEpisodeThumbnail }
return firstNonBlank(
poster,
background,
nonEpisodeImageUrl,
if (useEpisodeThumbnails) episodeThumbnail else null,
imageUrl,
)
}
private fun firstNonBlank(vararg values: String?): String? =
values.firstOrNull { value -> !value.isNullOrBlank() }?.trim()
@ -508,8 +529,11 @@ private fun ContinueWatchingPosterCard(
)
.posterCardClickable(onClick = onClick, onLongClick = onLongClick),
) {
val shouldBlurArtwork = blurNextUp && useEpisodeThumbnails && item.isNextUp
val imageUrl = item.continueWatchingArtworkUrl(useEpisodeThumbnails)
val imageUrl = item.continueWatchingPosterArtworkUrl(useEpisodeThumbnails)
val shouldBlurArtwork = blurNextUp &&
useEpisodeThumbnails &&
item.isNextUp &&
imageUrl == firstNonBlank(item.episodeThumbnail)
if (imageUrl != null) {
AsyncImage(
model = cloudLibraryDisplayArtworkUrl(imageUrl),

View file

@ -131,7 +131,6 @@ internal fun LazyListScope.debridSettingsContent(
) {
item {
var showResolverProviderDialog by rememberSaveable { mutableStateOf(false) }
val uriHandler = LocalUriHandler.current
val resolverProviders = settings.resolverServices.map { it.provider }
val activeResolverProvider = settings.activeResolverCredential?.provider
SettingsSection(
@ -144,15 +143,6 @@ internal fun LazyListScope.debridSettingsContent(
text = stringResource(Res.string.settings_debrid_experimental_notice),
)
SettingsGroupDivider(isTablet = isTablet)
DebridPreferenceRow(
isTablet = isTablet,
title = "Learn more",
description = "Cloud Library, connected accounts, and playable-link preparation.",
value = "Open",
enabled = true,
onClick = { runCatching { uriHandler.openUri(CLOUD_SERVICES_FAQ_URL) } },
)
SettingsGroupDivider(isTablet = isTablet)
SettingsSwitchRow(
title = stringResource(Res.string.settings_debrid_cloud_library),
description = stringResource(Res.string.settings_debrid_cloud_library_description),
@ -272,7 +262,10 @@ internal fun LazyListScope.debridSettingsContent(
}
}
if (!settings.canResolvePlayableLinks) return
if (!settings.canResolvePlayableLinks) {
debridLearnMoreFooterItem(isTablet)
return
}
item {
var showPrepareCountDialog by rememberSaveable { mutableStateOf(false) }
@ -461,6 +454,35 @@ internal fun LazyListScope.debridSettingsContent(
null -> Unit
}
}
debridLearnMoreFooterItem(isTablet)
}
private fun LazyListScope.debridLearnMoreFooterItem(isTablet: Boolean) {
item {
val uriHandler = LocalUriHandler.current
DebridLearnMoreFooter(
isTablet = isTablet,
onClick = { runCatching { uriHandler.openUri(CLOUD_SERVICES_FAQ_URL) } },
)
}
}
@Composable
private fun DebridLearnMoreFooter(
isTablet: Boolean,
onClick: () -> Unit,
) {
Box(
modifier = Modifier
.fillMaxWidth()
.padding(top = if (isTablet) 4.dp else 0.dp, bottom = if (isTablet) 10.dp else 6.dp),
contentAlignment = Alignment.Center,
) {
TextButton(onClick = onClick) {
Text("Learn more")
}
}
}
private enum class DebridTemplateField {

View file

@ -28,8 +28,12 @@ import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import coil3.compose.AsyncImage
import com.nuvio.app.core.ui.NuvioScreen
import com.nuvio.app.core.ui.NuvioScreenHeader
import com.nuvio.app.features.cloud.PremiumizeCloudLibraryPosterUrl
import com.nuvio.app.features.cloud.TorboxCloudLibraryPosterUrl
import com.nuvio.app.features.cloud.cloudLibraryDisplayArtworkUrl
import com.nuvio.app.isIos
import nuvio.composeapp.generated.resources.*
import org.jetbrains.compose.resources.StringResource
@ -38,6 +42,8 @@ import org.jetbrains.compose.resources.stringResource
private const val TmdbUrl = "https://www.themoviedb.org"
private const val ImdbDatasetsUrl = "https://developer.imdb.com/non-commercial-datasets/"
private const val TraktUrl = "https://trakt.tv"
private const val PremiumizeUrl = "https://www.premiumize.me"
private const val TorboxUrl = "https://torbox.app"
private const val MdbListUrl = "https://mdblist.com"
private const val IntroDbUrl = "https://introdb.app/"
private const val NuvioRepositoryUrl = "https://github.com/NuvioMedia/NuvioMobile"
@ -48,6 +54,7 @@ private data class AttributionItem(
val titleRes: StringResource,
val bodyRes: StringResource,
val logo: IntegrationLogo?,
val logoUrl: String? = null,
val link: String,
)
@ -165,14 +172,26 @@ private fun AttributionRow(
body = stringResource(item.bodyRes),
link = item.link,
isTablet = isTablet,
leading = item.logo?.let { logo ->
{
IntegrationLogoImage(
painter = integrationLogoPainter(logo),
contentDescription = title,
isTablet = isTablet,
)
leading = when {
item.logo != null -> item.logo.let { logo ->
{
IntegrationLogoImage(
painter = integrationLogoPainter(logo),
contentDescription = title,
isTablet = isTablet,
)
}
}
item.logoUrl != null -> item.logoUrl.let { logoUrl ->
{
ProviderLogoImage(
url = logoUrl,
contentDescription = title,
isTablet = isTablet,
)
}
}
else -> null
},
onOpen = { uriHandler.openUri(item.link) },
)
@ -274,6 +293,22 @@ private fun IntegrationLogoImage(
)
}
@Composable
private fun ProviderLogoImage(
url: String,
contentDescription: String,
isTablet: Boolean,
) {
AsyncImage(
model = url,
contentDescription = contentDescription,
modifier = Modifier
.padding(top = 2.dp)
.size(if (isTablet) 46.dp else 40.dp),
contentScale = ContentScale.Fit,
)
}
@Composable
private fun PlainStackDivider() {
HorizontalDivider(
@ -295,6 +330,20 @@ private fun attributionItems(): List<AttributionItem> = listOf(
logo = IntegrationLogo.Trakt,
link = TraktUrl,
),
AttributionItem(
titleRes = Res.string.settings_licenses_attributions_premiumize_title,
bodyRes = Res.string.settings_licenses_attributions_premiumize_body,
logo = null,
logoUrl = PremiumizeCloudLibraryPosterUrl,
link = PremiumizeUrl,
),
AttributionItem(
titleRes = Res.string.settings_licenses_attributions_torbox_title,
bodyRes = Res.string.settings_licenses_attributions_torbox_body,
logo = null,
logoUrl = cloudLibraryDisplayArtworkUrl(TorboxCloudLibraryPosterUrl),
link = TorboxUrl,
),
AttributionItem(
titleRes = Res.string.settings_licenses_attributions_mdblist_title,
bodyRes = Res.string.settings_licenses_attributions_mdblist_body,

View file

@ -262,6 +262,8 @@ internal fun settingsSearchEntries(
PlaybackSearchRow("nuvio-license", stringResource(Res.string.settings_licenses_attributions_nuvio_title), stringResource(Res.string.settings_licenses_attributions_nuvio_license)),
PlaybackSearchRow("tmdb-attribution", stringResource(Res.string.settings_licenses_attributions_tmdb_title), stringResource(Res.string.settings_licenses_attributions_tmdb_body)),
PlaybackSearchRow("trakt-attribution", stringResource(Res.string.settings_licenses_attributions_trakt_title), stringResource(Res.string.settings_licenses_attributions_trakt_body)),
PlaybackSearchRow("premiumize-attribution", stringResource(Res.string.settings_licenses_attributions_premiumize_title), stringResource(Res.string.settings_licenses_attributions_premiumize_body)),
PlaybackSearchRow("torbox-attribution", stringResource(Res.string.settings_licenses_attributions_torbox_title), stringResource(Res.string.settings_licenses_attributions_torbox_body)),
PlaybackSearchRow("mdblist-attribution", stringResource(Res.string.settings_licenses_attributions_mdblist_title), stringResource(Res.string.settings_licenses_attributions_mdblist_body)),
PlaybackSearchRow("introdb-attribution", stringResource(Res.string.settings_licenses_attributions_introdb_title), stringResource(Res.string.settings_licenses_attributions_introdb_body)),
PlaybackSearchRow("imdb-datasets", stringResource(Res.string.settings_licenses_attributions_imdb_title), stringResource(Res.string.settings_licenses_attributions_imdb_body)),