mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-08-19 05:45:41 +00:00
parent
99d1cf345f
commit
65e38b0da6
10 changed files with 94 additions and 1 deletions
|
|
@ -605,6 +605,8 @@
|
|||
<string name="settings_homescreen_show_hero_description">Display hero carousel at top of home.</string>
|
||||
<string name="layout_hide_unreleased">Hide Unreleased Content</string>
|
||||
<string name="layout_hide_unreleased_sub">Hide movies and shows that haven't been released yet.</string>
|
||||
<string name="layout_catalog_type">Show Catalog Type</string>
|
||||
<string name="layout_catalog_type_sub">Show type suffix next to catalog name (Movie/Series).</string>
|
||||
<string name="settings_homescreen_hide_catalog_underline">Hide Catalog Underline</string>
|
||||
<string name="settings_homescreen_hide_catalog_underline_description">Remove the accent line under catalog and collection titles throughout the app.</string>
|
||||
<string name="settings_homescreen_summary">%1$d of %2$d catalogs visible • %3$d hero sources selected</string>
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import org.jetbrains.compose.resources.getString
|
|||
data class HomeCatalogDefinition(
|
||||
val key: String,
|
||||
val defaultTitle: String,
|
||||
val catalogName: String,
|
||||
val addonName: String,
|
||||
val manifestUrl: String,
|
||||
val type: String,
|
||||
|
|
@ -23,6 +24,9 @@ data class HomeCatalogDefinition(
|
|||
) {
|
||||
val cacheKey: String
|
||||
get() = "$key|$descriptorSignature"
|
||||
|
||||
fun titleFor(showCatalogType: Boolean): String =
|
||||
if (showCatalogType) defaultTitle else catalogName
|
||||
}
|
||||
|
||||
fun buildHomeCatalogRefreshSignature(addons: List<ManagedAddon>): List<String> =
|
||||
|
|
@ -52,6 +56,7 @@ fun buildHomeCatalogDefinitions(addons: List<ManagedAddon>): List<HomeCatalogDef
|
|||
localizedMediaTypeLabel(catalog.type),
|
||||
)
|
||||
},
|
||||
catalogName = catalog.name,
|
||||
addonName = addon.displayTitle,
|
||||
manifestUrl = addon.manifestUrl,
|
||||
type = catalog.type,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ data class HomeCatalogSettingsItem(
|
|||
|
||||
data class HomeCatalogSettingsUiState(
|
||||
val heroEnabled: Boolean = true,
|
||||
val showCatalogType: Boolean = true,
|
||||
val hideUnreleasedContent: Boolean = false,
|
||||
val hideCatalogUnderline: Boolean = false,
|
||||
val items: List<HomeCatalogSettingsItem> = emptyList(),
|
||||
|
|
@ -40,6 +41,8 @@ data class HomeCatalogSettingsUiState(
|
|||
get() = buildString {
|
||||
append(heroEnabled)
|
||||
append('|')
|
||||
append(showCatalogType)
|
||||
append('|')
|
||||
append(hideUnreleasedContent)
|
||||
append('|')
|
||||
append(hideCatalogUnderline)
|
||||
|
|
@ -61,6 +64,7 @@ internal data class HomeCatalogPreference(
|
|||
|
||||
internal data class HomeCatalogSettingsSnapshot(
|
||||
val heroEnabled: Boolean,
|
||||
val showCatalogType: Boolean,
|
||||
val hideUnreleasedContent: Boolean,
|
||||
val hideCatalogUnderline: Boolean,
|
||||
val preferences: Map<String, HomeCatalogPreference>,
|
||||
|
|
@ -78,6 +82,7 @@ private data class StoredHomeCatalogPreference(
|
|||
@Serializable
|
||||
private data class StoredHomeCatalogSettingsPayload(
|
||||
val heroEnabled: Boolean = true,
|
||||
val showCatalogType: Boolean = true,
|
||||
val hideUnreleasedContent: Boolean = false,
|
||||
val hideCatalogUnderline: Boolean = false,
|
||||
val items: List<StoredHomeCatalogPreference> = emptyList(),
|
||||
|
|
@ -99,6 +104,7 @@ object HomeCatalogSettingsRepository {
|
|||
private var collectionDefinitions: List<CollectionCatalogDefinition> = emptyList()
|
||||
private var preferences: MutableMap<String, StoredHomeCatalogPreference> = mutableMapOf()
|
||||
private var heroEnabled = true
|
||||
private var showCatalogType = true
|
||||
private var hideUnreleasedContent = false
|
||||
private var hideCatalogUnderline = false
|
||||
|
||||
|
|
@ -106,6 +112,7 @@ object HomeCatalogSettingsRepository {
|
|||
hasLoaded = false
|
||||
preferences.clear()
|
||||
heroEnabled = true
|
||||
showCatalogType = true
|
||||
hideUnreleasedContent = false
|
||||
hideCatalogUnderline = false
|
||||
definitions = emptyList()
|
||||
|
|
@ -119,6 +126,7 @@ object HomeCatalogSettingsRepository {
|
|||
collectionDefinitions = emptyList()
|
||||
preferences.clear()
|
||||
heroEnabled = true
|
||||
showCatalogType = true
|
||||
hideUnreleasedContent = false
|
||||
hideCatalogUnderline = false
|
||||
_uiState.value = HomeCatalogSettingsUiState()
|
||||
|
|
@ -152,6 +160,7 @@ object HomeCatalogSettingsRepository {
|
|||
ensureLoaded()
|
||||
return HomeCatalogSettingsSnapshot(
|
||||
heroEnabled = heroEnabled,
|
||||
showCatalogType = showCatalogType,
|
||||
hideUnreleasedContent = hideUnreleasedContent,
|
||||
hideCatalogUnderline = hideCatalogUnderline,
|
||||
preferences = preferences.mapValues { (_, value) ->
|
||||
|
|
@ -173,6 +182,16 @@ object HomeCatalogSettingsRepository {
|
|||
HomeRepository.applyCurrentSettings()
|
||||
}
|
||||
|
||||
fun setShowCatalogType(enabled: Boolean) {
|
||||
ensureLoaded()
|
||||
if (showCatalogType == enabled) return
|
||||
showCatalogType = enabled
|
||||
publish()
|
||||
persist()
|
||||
HomeRepository.applyCurrentSettings()
|
||||
HomeCatalogSettingsSyncService.triggerPush()
|
||||
}
|
||||
|
||||
fun setHideUnreleasedContent(enabled: Boolean) {
|
||||
ensureLoaded()
|
||||
if (hideUnreleasedContent == enabled) return
|
||||
|
|
@ -219,6 +238,7 @@ object HomeCatalogSettingsRepository {
|
|||
fun resetToDefaults() {
|
||||
ensureLoaded()
|
||||
heroEnabled = true
|
||||
showCatalogType = true
|
||||
hideUnreleasedContent = false
|
||||
hideCatalogUnderline = false
|
||||
preferences.clear()
|
||||
|
|
@ -268,6 +288,7 @@ object HomeCatalogSettingsRepository {
|
|||
|
||||
if (parsedPayload != null) {
|
||||
heroEnabled = parsedPayload.heroEnabled
|
||||
showCatalogType = parsedPayload.showCatalogType
|
||||
hideUnreleasedContent = parsedPayload.hideUnreleasedContent
|
||||
hideCatalogUnderline = parsedPayload.hideCatalogUnderline
|
||||
preferences = parsedPayload.items.associateBy { it.key }.toMutableMap()
|
||||
|
|
@ -368,6 +389,7 @@ object HomeCatalogSettingsRepository {
|
|||
|
||||
_uiState.value = HomeCatalogSettingsUiState(
|
||||
heroEnabled = heroEnabled,
|
||||
showCatalogType = showCatalogType,
|
||||
hideUnreleasedContent = hideUnreleasedContent,
|
||||
hideCatalogUnderline = hideCatalogUnderline,
|
||||
items = items,
|
||||
|
|
@ -379,6 +401,7 @@ object HomeCatalogSettingsRepository {
|
|||
json.encodeToString(
|
||||
StoredHomeCatalogSettingsPayload(
|
||||
heroEnabled = heroEnabled,
|
||||
showCatalogType = showCatalogType,
|
||||
hideUnreleasedContent = hideUnreleasedContent,
|
||||
hideCatalogUnderline = hideCatalogUnderline,
|
||||
items = preferences.values.sortedBy { it.order },
|
||||
|
|
@ -475,6 +498,7 @@ object HomeCatalogSettingsRepository {
|
|||
}
|
||||
}
|
||||
return SyncHomeCatalogPayload(
|
||||
showCatalogType = showCatalogType,
|
||||
hideUnreleasedContent = hideUnreleasedContent,
|
||||
hideCatalogUnderline = hideCatalogUnderline,
|
||||
items = items,
|
||||
|
|
@ -483,6 +507,7 @@ object HomeCatalogSettingsRepository {
|
|||
|
||||
fun applyFromRemote(payload: SyncHomeCatalogPayload) {
|
||||
ensureLoaded()
|
||||
showCatalogType = payload.showCatalogType
|
||||
hideUnreleasedContent = payload.hideUnreleasedContent
|
||||
hideCatalogUnderline = payload.hideCatalogUnderline
|
||||
if (payload.items.isNotEmpty()) {
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ data class SyncCatalogItem(
|
|||
|
||||
@Serializable
|
||||
data class SyncHomeCatalogPayload(
|
||||
@SerialName("show_catalog_type") val showCatalogType: Boolean = true,
|
||||
@SerialName("hide_unreleased_content") val hideUnreleasedContent: Boolean = false,
|
||||
@SerialName("hide_catalog_underline") val hideCatalogUnderline: Boolean = false,
|
||||
val items: List<SyncCatalogItem> = emptyList(),
|
||||
|
|
@ -56,6 +57,7 @@ private data class RemoteHomeCatalogSettings(
|
|||
val platform: String,
|
||||
val payload: SyncHomeCatalogPayload,
|
||||
val updatedAt: String?,
|
||||
val hasShowCatalogType: Boolean,
|
||||
val hasHideUnreleasedContent: Boolean,
|
||||
val hasHideCatalogUnderline: Boolean,
|
||||
)
|
||||
|
|
@ -74,6 +76,7 @@ object HomeCatalogSettingsSyncService {
|
|||
}
|
||||
|
||||
private const val HIDE_UNRELEASED_CONTENT_KEY = "hide_unreleased_content"
|
||||
private const val SHOW_CATALOG_TYPE_KEY = "show_catalog_type"
|
||||
private const val HIDE_CATALOG_UNDERLINE_KEY = "hide_catalog_underline"
|
||||
|
||||
@Volatile
|
||||
|
|
@ -216,6 +219,7 @@ object HomeCatalogSettingsSyncService {
|
|||
platform = platform,
|
||||
payload = payload,
|
||||
updatedAt = blob.updatedAt,
|
||||
hasShowCatalogType = blob.settingsJson.containsKey(SHOW_CATALOG_TYPE_KEY),
|
||||
hasHideUnreleasedContent = blob.settingsJson.containsKey(HIDE_UNRELEASED_CONTENT_KEY),
|
||||
hasHideCatalogUnderline = blob.settingsJson.containsKey(HIDE_CATALOG_UNDERLINE_KEY),
|
||||
)
|
||||
|
|
@ -227,12 +231,17 @@ object HomeCatalogSettingsSyncService {
|
|||
val hideUnreleasedSource = rows
|
||||
.filter { it.hasHideUnreleasedContent }
|
||||
.maxByOrNull { it.updatedAt.orEmpty() }
|
||||
val showCatalogTypeSource = rows
|
||||
.filter { it.hasShowCatalogType }
|
||||
.maxByOrNull { it.updatedAt.orEmpty() }
|
||||
val hideUnderlineSource = rows
|
||||
.filter { it.hasHideCatalogUnderline }
|
||||
.maxByOrNull { it.updatedAt.orEmpty() }
|
||||
|
||||
return copy(
|
||||
payload = payload.copy(
|
||||
showCatalogType = showCatalogTypeSource?.payload?.showCatalogType
|
||||
?: payload.showCatalogType,
|
||||
hideUnreleasedContent = hideUnreleasedSource?.payload?.hideUnreleasedContent
|
||||
?: payload.hideUnreleasedContent,
|
||||
hideCatalogUnderline = hideUnderlineSource?.payload?.hideCatalogUnderline
|
||||
|
|
@ -259,6 +268,11 @@ object HomeCatalogSettingsSyncService {
|
|||
): SyncHomeCatalogPayload? = runCatching {
|
||||
val decoded = json.decodeFromJsonElement(SyncHomeCatalogPayload.serializer(), settingsJson)
|
||||
decoded.copy(
|
||||
showCatalogType = if (settingsJson.containsKey(SHOW_CATALOG_TYPE_KEY)) {
|
||||
decoded.showCatalogType
|
||||
} else {
|
||||
localPayload.showCatalogType
|
||||
},
|
||||
hideUnreleasedContent = if (settingsJson.containsKey(HIDE_UNRELEASED_CONTENT_KEY)) {
|
||||
decoded.hideUnreleasedContent
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -208,7 +208,7 @@ object HomeRepository {
|
|||
if (section.items.isEmpty()) return@mapNotNull null
|
||||
val customTitle = preference?.customTitle.orEmpty()
|
||||
section.copy(
|
||||
title = customTitle.ifBlank { section.title },
|
||||
title = customTitle.ifBlank { definition.titleFor(snapshot.showCatalogType) },
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ import nuvio.composeapp.generated.resources.Res
|
|||
import nuvio.composeapp.generated.resources.action_reset
|
||||
import nuvio.composeapp.generated.resources.layout_hide_unreleased
|
||||
import nuvio.composeapp.generated.resources.layout_hide_unreleased_sub
|
||||
import nuvio.composeapp.generated.resources.layout_catalog_type
|
||||
import nuvio.composeapp.generated.resources.layout_catalog_type_sub
|
||||
import nuvio.composeapp.generated.resources.settings_homescreen_empty_message
|
||||
import nuvio.composeapp.generated.resources.settings_homescreen_empty_title
|
||||
import nuvio.composeapp.generated.resources.settings_homescreen_hide_catalog_underline
|
||||
|
|
@ -66,6 +68,7 @@ import sh.calvin.reorderable.rememberReorderableLazyListState
|
|||
internal fun LazyListScope.homescreenSettingsContent(
|
||||
isTablet: Boolean,
|
||||
heroEnabled: Boolean,
|
||||
showCatalogType: Boolean,
|
||||
hideUnreleasedContent: Boolean,
|
||||
hideCatalogUnderline: Boolean,
|
||||
items: List<HomeCatalogSettingsItem>,
|
||||
|
|
@ -94,6 +97,14 @@ internal fun LazyListScope.homescreenSettingsContent(
|
|||
onCheckedChange = HomeCatalogSettingsRepository::setHeroEnabled,
|
||||
)
|
||||
SettingsGroupDivider(isTablet = isTablet)
|
||||
SettingsSwitchRow(
|
||||
title = stringResource(Res.string.layout_catalog_type),
|
||||
description = stringResource(Res.string.layout_catalog_type_sub),
|
||||
checked = showCatalogType,
|
||||
isTablet = isTablet,
|
||||
onCheckedChange = HomeCatalogSettingsRepository::setShowCatalogType,
|
||||
)
|
||||
SettingsGroupDivider(isTablet = isTablet)
|
||||
SettingsSwitchRow(
|
||||
title = stringResource(Res.string.layout_hide_unreleased),
|
||||
description = stringResource(Res.string.layout_hide_unreleased_sub),
|
||||
|
|
|
|||
|
|
@ -79,6 +79,7 @@ fun HomescreenSettingsScreen(
|
|||
homescreenSettingsContent(
|
||||
isTablet = false,
|
||||
heroEnabled = homescreenSettingsUiState.heroEnabled,
|
||||
showCatalogType = homescreenSettingsUiState.showCatalogType,
|
||||
hideUnreleasedContent = homescreenSettingsUiState.hideUnreleasedContent,
|
||||
hideCatalogUnderline = homescreenSettingsUiState.hideCatalogUnderline,
|
||||
items = homescreenSettingsUiState.items,
|
||||
|
|
|
|||
|
|
@ -403,6 +403,7 @@ fun SettingsScreen(
|
|||
traktCommentsEnabled = traktCommentsEnabled,
|
||||
traktSettingsUiState = traktSettingsUiState,
|
||||
homescreenHeroEnabled = homescreenSettingsUiState.heroEnabled,
|
||||
homescreenShowCatalogType = homescreenSettingsUiState.showCatalogType,
|
||||
homescreenHideUnreleasedContent = homescreenSettingsUiState.hideUnreleasedContent,
|
||||
homescreenHideCatalogUnderline = homescreenSettingsUiState.hideCatalogUnderline,
|
||||
homescreenItems = homescreenSettingsUiState.items,
|
||||
|
|
@ -463,6 +464,7 @@ fun SettingsScreen(
|
|||
traktCommentsEnabled = traktCommentsEnabled,
|
||||
traktSettingsUiState = traktSettingsUiState,
|
||||
homescreenHeroEnabled = homescreenSettingsUiState.heroEnabled,
|
||||
homescreenShowCatalogType = homescreenSettingsUiState.showCatalogType,
|
||||
homescreenHideUnreleasedContent = homescreenSettingsUiState.hideUnreleasedContent,
|
||||
homescreenHideCatalogUnderline = homescreenSettingsUiState.hideCatalogUnderline,
|
||||
homescreenItems = homescreenSettingsUiState.items,
|
||||
|
|
@ -533,6 +535,7 @@ private fun MobileSettingsScreen(
|
|||
traktCommentsEnabled: Boolean,
|
||||
traktSettingsUiState: TraktSettingsUiState,
|
||||
homescreenHeroEnabled: Boolean,
|
||||
homescreenShowCatalogType: Boolean,
|
||||
homescreenHideUnreleasedContent: Boolean,
|
||||
homescreenHideCatalogUnderline: Boolean,
|
||||
homescreenItems: List<HomeCatalogSettingsItem>,
|
||||
|
|
@ -763,6 +766,7 @@ private fun MobileSettingsScreen(
|
|||
SettingsPage.Homescreen -> homescreenSettingsContent(
|
||||
isTablet = false,
|
||||
heroEnabled = homescreenHeroEnabled,
|
||||
showCatalogType = homescreenShowCatalogType,
|
||||
hideUnreleasedContent = homescreenHideUnreleasedContent,
|
||||
hideCatalogUnderline = homescreenHideCatalogUnderline,
|
||||
items = homescreenItems,
|
||||
|
|
@ -889,6 +893,7 @@ private fun TabletSettingsScreen(
|
|||
traktCommentsEnabled: Boolean,
|
||||
traktSettingsUiState: TraktSettingsUiState,
|
||||
homescreenHeroEnabled: Boolean,
|
||||
homescreenShowCatalogType: Boolean,
|
||||
homescreenHideUnreleasedContent: Boolean,
|
||||
homescreenHideCatalogUnderline: Boolean,
|
||||
homescreenItems: List<HomeCatalogSettingsItem>,
|
||||
|
|
@ -1175,6 +1180,7 @@ private fun TabletSettingsScreen(
|
|||
SettingsPage.Homescreen -> homescreenSettingsContent(
|
||||
isTablet = true,
|
||||
heroEnabled = homescreenHeroEnabled,
|
||||
showCatalogType = homescreenShowCatalogType,
|
||||
hideUnreleasedContent = homescreenHideUnreleasedContent,
|
||||
hideCatalogUnderline = homescreenHideCatalogUnderline,
|
||||
items = homescreenItems,
|
||||
|
|
|
|||
|
|
@ -730,6 +730,7 @@ internal fun settingsSearchEntries(
|
|||
val homeLayoutSection = stringResource(Res.string.settings_homescreen_section_hero)
|
||||
listOf(
|
||||
PlaybackSearchRow("home-hero", stringResource(Res.string.settings_homescreen_show_hero), stringResource(Res.string.settings_homescreen_show_hero_description)),
|
||||
PlaybackSearchRow("home-catalog-type", stringResource(Res.string.layout_catalog_type), stringResource(Res.string.layout_catalog_type_sub)),
|
||||
PlaybackSearchRow("home-hide-unreleased", stringResource(Res.string.layout_hide_unreleased), stringResource(Res.string.layout_hide_unreleased_sub)),
|
||||
PlaybackSearchRow("home-hide-catalog-underline", stringResource(Res.string.settings_homescreen_hide_catalog_underline), stringResource(Res.string.settings_homescreen_hide_catalog_underline_description)),
|
||||
PlaybackSearchRow("home-hero-sources", stringResource(Res.string.settings_homescreen_section_hero_sources)),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
package com.nuvio.app.features.home
|
||||
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class HomeCatalogDefinitionTest {
|
||||
private val definition = HomeCatalogDefinition(
|
||||
key = "addon:movie:popular",
|
||||
defaultTitle = "Popular - Movie",
|
||||
catalogName = "Popular",
|
||||
addonName = "Addon",
|
||||
manifestUrl = "https://example.com/manifest.json",
|
||||
type = "movie",
|
||||
catalogId = "popular",
|
||||
supportsPagination = true,
|
||||
descriptorSignature = "signature",
|
||||
)
|
||||
|
||||
@Test
|
||||
fun `shows the type suffix by default`() {
|
||||
assertEquals("Popular - Movie", definition.titleFor(showCatalogType = true))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `omits the type suffix when disabled`() {
|
||||
assertEquals("Popular", definition.titleFor(showCatalogType = false))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue