From 5cdda5791345fa7de995602e3a41ba502ded9777 Mon Sep 17 00:00:00 2001
From: tapframe <85391825+tapframe@users.noreply.github.com>
Date: Sun, 10 May 2026 13:47:36 +0530
Subject: [PATCH] feat; option to hide catalog underline
---
.../composeResources/values/strings.xml | 2 ++
.../home/HomeCatalogSettingsRepository.kt | 23 +++++++++++++++++++
.../home/HomeCatalogSettingsSyncService.kt | 1 +
.../home/components/HomeCatalogSection.kt | 9 ++++++++
.../components/HomeCollectionRowSection.kt | 10 ++++++++
.../settings/HomescreenSettingsPage.kt | 11 +++++++++
.../settings/SettingsFullScreenPages.kt | 1 +
.../app/features/settings/SettingsScreen.kt | 6 +++++
.../app/features/settings/SettingsSearch.kt | 1 +
9 files changed, 64 insertions(+)
diff --git a/composeApp/src/commonMain/composeResources/values/strings.xml b/composeApp/src/commonMain/composeResources/values/strings.xml
index cd8a97e2..782a24e0 100644
--- a/composeApp/src/commonMain/composeResources/values/strings.xml
+++ b/composeApp/src/commonMain/composeResources/values/strings.xml
@@ -506,6 +506,8 @@
Display hero carousel at top of home.
Hide Unreleased Content
Hide movies and shows that haven't been released yet.
+ Hide Catalog Underline
+ Remove the accent line under catalog and collection titles throughout the app.
%1$d of %2$d catalogs visible • %3$d hero sources selected
Open a catalog only when you need to rename or reorder it.
Visible
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsRepository.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsRepository.kt
index e920de04..202af87a 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsRepository.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsRepository.kt
@@ -33,6 +33,7 @@ data class HomeCatalogSettingsItem(
data class HomeCatalogSettingsUiState(
val heroEnabled: Boolean = true,
val hideUnreleasedContent: Boolean = false,
+ val hideCatalogUnderline: Boolean = false,
val items: List = emptyList(),
) {
val signature: String
@@ -41,6 +42,8 @@ data class HomeCatalogSettingsUiState(
append('|')
append(hideUnreleasedContent)
append('|')
+ append(hideCatalogUnderline)
+ append('|')
append(
items.joinToString(separator = "|") { item ->
"${item.key}:${item.order}:${item.enabled}:${item.heroSourceEnabled}:${item.customTitle}"
@@ -59,6 +62,7 @@ internal data class HomeCatalogPreference(
internal data class HomeCatalogSettingsSnapshot(
val heroEnabled: Boolean,
val hideUnreleasedContent: Boolean,
+ val hideCatalogUnderline: Boolean,
val preferences: Map,
)
@@ -75,6 +79,7 @@ private data class StoredHomeCatalogPreference(
private data class StoredHomeCatalogSettingsPayload(
val heroEnabled: Boolean = true,
val hideUnreleasedContent: Boolean = false,
+ val hideCatalogUnderline: Boolean = false,
val items: List = emptyList(),
)
@@ -95,12 +100,14 @@ object HomeCatalogSettingsRepository {
private var preferences: MutableMap = mutableMapOf()
private var heroEnabled = true
private var hideUnreleasedContent = false
+ private var hideCatalogUnderline = false
fun onProfileChanged() {
hasLoaded = false
preferences.clear()
heroEnabled = true
hideUnreleasedContent = false
+ hideCatalogUnderline = false
definitions = emptyList()
collectionDefinitions = emptyList()
_uiState.value = HomeCatalogSettingsUiState()
@@ -113,6 +120,7 @@ object HomeCatalogSettingsRepository {
preferences.clear()
heroEnabled = true
hideUnreleasedContent = false
+ hideCatalogUnderline = false
_uiState.value = HomeCatalogSettingsUiState()
}
@@ -144,6 +152,7 @@ object HomeCatalogSettingsRepository {
return HomeCatalogSettingsSnapshot(
heroEnabled = heroEnabled,
hideUnreleasedContent = hideUnreleasedContent,
+ hideCatalogUnderline = hideCatalogUnderline,
preferences = preferences.mapValues { (_, value) ->
HomeCatalogPreference(
customTitle = value.customTitle,
@@ -172,6 +181,14 @@ object HomeCatalogSettingsRepository {
HomeRepository.applyCurrentSettings()
}
+ fun setHideCatalogUnderline(enabled: Boolean) {
+ ensureLoaded()
+ if (hideCatalogUnderline == enabled) return
+ hideCatalogUnderline = enabled
+ publish()
+ persist()
+ }
+
fun setHeroSourceEnabled(key: String, enabled: Boolean) {
updatePreference(key) { preference ->
if (!enabled) {
@@ -200,6 +217,7 @@ object HomeCatalogSettingsRepository {
ensureLoaded()
heroEnabled = true
hideUnreleasedContent = false
+ hideCatalogUnderline = false
preferences.clear()
normalizePreferences()
publish()
@@ -246,6 +264,7 @@ object HomeCatalogSettingsRepository {
if (parsedPayload != null) {
heroEnabled = parsedPayload.heroEnabled
hideUnreleasedContent = parsedPayload.hideUnreleasedContent
+ hideCatalogUnderline = parsedPayload.hideCatalogUnderline
preferences = parsedPayload.items.associateBy { it.key }.toMutableMap()
publish()
return
@@ -345,6 +364,7 @@ object HomeCatalogSettingsRepository {
_uiState.value = HomeCatalogSettingsUiState(
heroEnabled = heroEnabled,
hideUnreleasedContent = hideUnreleasedContent,
+ hideCatalogUnderline = hideCatalogUnderline,
items = items,
)
}
@@ -355,6 +375,7 @@ object HomeCatalogSettingsRepository {
StoredHomeCatalogSettingsPayload(
heroEnabled = heroEnabled,
hideUnreleasedContent = hideUnreleasedContent,
+ hideCatalogUnderline = hideCatalogUnderline,
items = preferences.values.sortedBy { it.order },
),
),
@@ -437,6 +458,7 @@ object HomeCatalogSettingsRepository {
}
return SyncHomeCatalogPayload(
hideUnreleasedContent = hideUnreleasedContent,
+ hideCatalogUnderline = hideCatalogUnderline,
items = items,
)
}
@@ -444,6 +466,7 @@ object HomeCatalogSettingsRepository {
fun applyFromRemote(payload: SyncHomeCatalogPayload) {
ensureLoaded()
hideUnreleasedContent = payload.hideUnreleasedContent
+ hideCatalogUnderline = payload.hideCatalogUnderline
if (payload.items.isNotEmpty()) {
val existingHeroState = preferences.mapValues { it.value.heroSourceEnabled }
preferences = payload.items.associate { item ->
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsSyncService.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsSyncService.kt
index 5fbf8f7c..bddc4c97 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsSyncService.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/HomeCatalogSettingsSyncService.kt
@@ -42,6 +42,7 @@ data class SyncCatalogItem(
@Serializable
data class SyncHomeCatalogPayload(
@SerialName("hide_unreleased_content") val hideUnreleasedContent: Boolean = false,
+ @SerialName("hide_catalog_underline") val hideCatalogUnderline: Boolean = false,
val items: List = emptyList(),
)
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCatalogSection.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCatalogSection.kt
index e7561e09..aecd6626 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCatalogSection.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCatalogSection.kt
@@ -4,11 +4,15 @@ import androidx.compose.foundation.layout.BoxWithConstraints
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.nuvio.app.core.ui.NuvioShelfSection
import com.nuvio.app.core.ui.NuvioViewAllPillSize
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
+import com.nuvio.app.features.home.HomeCatalogSettingsRepository
import com.nuvio.app.features.home.HomeCatalogSection
import com.nuvio.app.features.home.MetaPreview
import com.nuvio.app.features.home.stableKey
@@ -64,6 +68,10 @@ private fun HomeCatalogRowSectionContent(
onPosterLongClick: ((MetaPreview) -> Unit)?,
) {
val posterCardStyle = rememberPosterCardStyleUiState()
+ val homeCatalogSettings by remember {
+ HomeCatalogSettingsRepository.snapshot()
+ HomeCatalogSettingsRepository.uiState
+ }.collectAsStateWithLifecycle()
NuvioShelfSection(
title = section.title,
@@ -71,6 +79,7 @@ private fun HomeCatalogRowSectionContent(
modifier = modifier,
headerHorizontalPadding = sectionPadding,
rowContentPadding = PaddingValues(horizontal = sectionPadding),
+ showHeaderAccent = !homeCatalogSettings.hideCatalogUnderline,
onViewAllClick = onViewAllClick,
viewAllPillSize = NuvioViewAllPillSize.Compact,
key = { item -> item.stableKey() },
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCollectionRowSection.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCollectionRowSection.kt
index dd053375..da63fe5d 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCollectionRowSection.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/home/components/HomeCollectionRowSection.kt
@@ -15,6 +15,8 @@ import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.ContentScale
@@ -23,6 +25,7 @@ import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
+import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.nuvio.app.core.ui.NuvioShelfSection
import com.nuvio.app.core.ui.PosterLandscapeAspectRatio
import com.nuvio.app.core.ui.landscapePosterWidth
@@ -30,6 +33,7 @@ import com.nuvio.app.core.ui.posterCardClickable
import com.nuvio.app.core.ui.rememberPosterCardStyleUiState
import com.nuvio.app.features.collection.Collection
import com.nuvio.app.features.collection.CollectionFolder
+import com.nuvio.app.features.home.HomeCatalogSettingsRepository
import com.nuvio.app.features.home.PosterShape
@Composable
@@ -71,12 +75,18 @@ private fun HomeCollectionRowSectionContent(
animateGifs: Boolean,
onFolderClick: ((collectionId: String, folderId: String) -> Unit)?,
) {
+ val homeCatalogSettings by remember {
+ HomeCatalogSettingsRepository.snapshot()
+ HomeCatalogSettingsRepository.uiState
+ }.collectAsStateWithLifecycle()
+
NuvioShelfSection(
title = collection.title,
entries = collection.folders,
modifier = modifier,
headerHorizontalPadding = sectionPadding,
rowContentPadding = PaddingValues(horizontal = sectionPadding),
+ showHeaderAccent = !homeCatalogSettings.hideCatalogUnderline,
key = { folder -> "collection_${collection.id}_folder_${folder.id}" },
) { folder ->
CollectionFolderCard(
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/HomescreenSettingsPage.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/HomescreenSettingsPage.kt
index ee44ba7c..254d49e1 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/HomescreenSettingsPage.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/HomescreenSettingsPage.kt
@@ -42,6 +42,8 @@ import nuvio.composeapp.generated.resources.layout_hide_unreleased
import nuvio.composeapp.generated.resources.layout_hide_unreleased_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
+import nuvio.composeapp.generated.resources.settings_homescreen_hide_catalog_underline_description
import nuvio.composeapp.generated.resources.settings_homescreen_keep_home_focused
import nuvio.composeapp.generated.resources.settings_homescreen_limit_reached
import nuvio.composeapp.generated.resources.settings_homescreen_no_sources_selected
@@ -65,6 +67,7 @@ internal fun LazyListScope.homescreenSettingsContent(
isTablet: Boolean,
heroEnabled: Boolean,
hideUnreleasedContent: Boolean,
+ hideCatalogUnderline: Boolean,
items: List,
) {
val selectedHeroSourceCount = items.count { it.heroSourceEnabled }
@@ -98,6 +101,14 @@ internal fun LazyListScope.homescreenSettingsContent(
isTablet = isTablet,
onCheckedChange = HomeCatalogSettingsRepository::setHideUnreleasedContent,
)
+ SettingsGroupDivider(isTablet = isTablet)
+ SettingsSwitchRow(
+ title = stringResource(Res.string.settings_homescreen_hide_catalog_underline),
+ description = stringResource(Res.string.settings_homescreen_hide_catalog_underline_description),
+ checked = hideCatalogUnderline,
+ isTablet = isTablet,
+ onCheckedChange = HomeCatalogSettingsRepository::setHideCatalogUnderline,
+ )
}
}
}
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsFullScreenPages.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsFullScreenPages.kt
index cbb6bfa4..45c6edf3 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsFullScreenPages.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsFullScreenPages.kt
@@ -78,6 +78,7 @@ fun HomescreenSettingsScreen(
isTablet = false,
heroEnabled = homescreenSettingsUiState.heroEnabled,
hideUnreleasedContent = homescreenSettingsUiState.hideUnreleasedContent,
+ hideCatalogUnderline = homescreenSettingsUiState.hideCatalogUnderline,
items = homescreenSettingsUiState.items,
)
}
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsScreen.kt
index 668a3c2e..4cd95d64 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsScreen.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsScreen.kt
@@ -237,6 +237,7 @@ fun SettingsScreen(
traktSettingsUiState = traktSettingsUiState,
homescreenHeroEnabled = homescreenSettingsUiState.heroEnabled,
homescreenHideUnreleasedContent = homescreenSettingsUiState.hideUnreleasedContent,
+ homescreenHideCatalogUnderline = homescreenSettingsUiState.hideCatalogUnderline,
homescreenItems = homescreenSettingsUiState.items,
metaScreenSettingsUiState = metaScreenSettingsUiState,
continueWatchingPreferencesUiState = continueWatchingPreferencesUiState,
@@ -283,6 +284,7 @@ fun SettingsScreen(
traktSettingsUiState = traktSettingsUiState,
homescreenHeroEnabled = homescreenSettingsUiState.heroEnabled,
homescreenHideUnreleasedContent = homescreenSettingsUiState.hideUnreleasedContent,
+ homescreenHideCatalogUnderline = homescreenSettingsUiState.hideCatalogUnderline,
homescreenItems = homescreenSettingsUiState.items,
metaScreenSettingsUiState = metaScreenSettingsUiState,
continueWatchingPreferencesUiState = continueWatchingPreferencesUiState,
@@ -339,6 +341,7 @@ private fun MobileSettingsScreen(
traktSettingsUiState: TraktSettingsUiState,
homescreenHeroEnabled: Boolean,
homescreenHideUnreleasedContent: Boolean,
+ homescreenHideCatalogUnderline: Boolean,
homescreenItems: List,
metaScreenSettingsUiState: MetaScreenSettingsUiState,
continueWatchingPreferencesUiState: ContinueWatchingPreferencesUiState,
@@ -530,6 +533,7 @@ private fun MobileSettingsScreen(
isTablet = false,
heroEnabled = homescreenHeroEnabled,
hideUnreleasedContent = homescreenHideUnreleasedContent,
+ hideCatalogUnderline = homescreenHideCatalogUnderline,
items = homescreenItems,
)
SettingsPage.MetaScreen -> metaScreenSettingsContent(
@@ -638,6 +642,7 @@ private fun TabletSettingsScreen(
traktSettingsUiState: TraktSettingsUiState,
homescreenHeroEnabled: Boolean,
homescreenHideUnreleasedContent: Boolean,
+ homescreenHideCatalogUnderline: Boolean,
homescreenItems: List,
metaScreenSettingsUiState: MetaScreenSettingsUiState,
continueWatchingPreferencesUiState: ContinueWatchingPreferencesUiState,
@@ -888,6 +893,7 @@ private fun TabletSettingsScreen(
isTablet = true,
heroEnabled = homescreenHeroEnabled,
hideUnreleasedContent = homescreenHideUnreleasedContent,
+ hideCatalogUnderline = homescreenHideCatalogUnderline,
items = homescreenItems,
)
SettingsPage.MetaScreen -> metaScreenSettingsContent(
diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsSearch.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsSearch.kt
index 1f3bafee..381ba569 100644
--- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsSearch.kt
+++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/settings/SettingsSearch.kt
@@ -588,6 +588,7 @@ internal fun settingsSearchEntries(
listOf(
PlaybackSearchRow("home-hero", stringResource(Res.string.settings_homescreen_show_hero), stringResource(Res.string.settings_homescreen_show_hero_description)),
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)),
PlaybackSearchRow("home-catalogs", stringResource(Res.string.settings_homescreen_section_catalogs)),
).forEach { row ->