Add settings rows for notifications, auto-updates, subtitle shadow, and home hero trailer autoplay

These profile fields (notificationsEnabled, automaticUpdates, subtitleShadow,
trailerOnHomeHeroEnabled/DelaySeconds) already drove real behavior but had no
visible Settings UI on TV or mobile. Also gates the background update-check
loop in MainActivity behind automaticUpdates, and wires a TV "Check for
updates" action mirroring the existing mobile flow.
This commit is contained in:
KhooLy 2026-07-09 23:00:59 +03:00
parent 3bbbcb206c
commit cffda2dad9
9 changed files with 111 additions and 5 deletions

View file

@ -346,6 +346,10 @@ class MainActivity : FragmentActivity() {
if (initialProfile == null) {
homeViewModel.loadInitialData(null)
}
}
LaunchedEffect(activeProfile?.safeAutomaticUpdates) {
if (activeProfile?.safeAutomaticUpdates == false) return@LaunchedEffect
while (isActive) {
val update = UpdateManager.checkUpdate()
if (update != null) {

View file

@ -214,7 +214,8 @@ fun SettingsScreen(
onBack = onBack,
onLogout = onLogout,
onManageAddons = onManageAddons,
onUpdateInfoChanged = onUpdateInfoChanged
onUpdateInfoChanged = onUpdateInfoChanged,
onUpdateProfile = onUpdateProfile
)
} else mobileCategory?.let { category ->
MobileCategoryDetail(

View file

@ -157,6 +157,21 @@ internal fun AppearanceSettings(profile: UserProfile, lang: String, previewMeta:
checked = profile.safeHomeSeasonPostersOnHero,
onToggle = { onUpdateProfile(profile.copy(homeSeasonPostersOnHero = it)) }
)
SettingsToggleTile(
title = AppStrings.t(lang, "settings.trailer_on_home_hero"),
subtitle = AppStrings.t(lang, "settings.trailer_on_home_hero_desc"),
checked = profile.safeTrailerOnHomeHeroEnabled,
onToggle = { onUpdateProfile(profile.copy(trailerOnHomeHeroEnabled = it)) }
)
if (profile.safeTrailerOnHomeHeroEnabled) {
SettingsSecondsSliderTile(
title = AppStrings.t(lang, "settings.trailer_on_home_hero_delay"),
subtitle = AppStrings.t(lang, "settings.trailer_on_home_hero_delay_desc"),
value = profile.safeTrailerOnHomeHeroDelaySeconds,
valueRange = 0..15,
onValueChange = { onUpdateProfile(profile.copy(trailerOnHomeHeroDelaySeconds = it)) }
)
}
SettingsToggleTile(
title = AppStrings.t(lang, "auto.continue_watching"),
subtitle = "",

View file

@ -113,7 +113,7 @@ internal fun SettingsContent(
}
"downloads" -> DownloadSettings(profileValue, lang, onUpdateProfile)
"addons" -> AddonSettings(profileValue, lang, onManageAddons, onUpdateProfile)
"system" -> SystemSettings(profileValue, lang, onReboot, onLogout)
"system" -> SystemSettings(profileValue, lang, onReboot, onLogout, onUpdateProfile)
"developer" -> DeveloperSettings(lang)
}
}

View file

@ -22,6 +22,7 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlinx.coroutines.launch
@Composable
internal fun DownloadSettings(profile: UserProfile, lang: String, onUpdateProfile: (UserProfile) -> Unit) {
@ -75,6 +76,12 @@ internal fun SubtitleSettings(profile: UserProfile, lang: String, onUpdateProfil
checked = profile.safeAutoEnableSubtitles,
onToggle = { onUpdateProfile(profile.copy(autoEnableSubtitles = it)) }
)
SettingsToggleTile(
title = AppStrings.t(lang, "settings.subtitle_shadow"),
subtitle = AppStrings.t(lang, "settings.subtitle_shadow_desc"),
checked = profile.safeSubtitleShadow,
onToggle = { onUpdateProfile(profile.copy(subtitleShadow = it)) }
)
SettingsChoiceTile(
title = AppStrings.t(lang, "auto.preferred_subtitle_language"),
subtitle = AppStrings.t(lang, "auto.default_subtitle_track_preference"),
@ -161,9 +168,41 @@ internal fun AddonSettings(profile: UserProfile, lang: String, onManageAddons: (
}
@Composable
internal fun SystemSettings(profile: UserProfile, lang: String, onReboot: () -> Unit, onLogout: () -> Unit) {
internal fun SystemSettings(profile: UserProfile, lang: String, onReboot: () -> Unit, onLogout: () -> Unit, onUpdateProfile: (UserProfile) -> Unit) {
val scope = rememberCoroutineScope()
var isCheckingUpdate by remember { mutableStateOf(false) }
var updateStatus by remember { mutableStateOf<String?>(null) }
SettingsSection(AppStrings.t(lang, "auto.system"), AppStrings.t(lang, "auto.app_and_device_actions")) {
SettingsInfoTile(AppStrings.t(lang, "auto.version"), "1.2.5", FluxaIcons.Settings)
SettingsInfoTile(
AppStrings.t(lang, "auto.version"),
"${com.fluxa.app.BuildConfig.VERSION_NAME} (${com.fluxa.app.BuildConfig.VERSION_CODE})",
FluxaIcons.Settings
)
SettingsToggleTile(
title = AppStrings.t(lang, "settings.automatic_updates"),
subtitle = AppStrings.t(lang, "settings.automatic_updates_desc"),
checked = profile.safeAutomaticUpdates,
onToggle = { onUpdateProfile(profile.copy(automaticUpdates = it)) }
)
SettingsActionTile(
title = AppStrings.t(lang, "settings.check_for_updates"),
subtitle = updateStatus ?: AppStrings.t(lang, "settings.check_for_updates_desc"),
icon = FluxaIcons.Settings,
onClick = {
if (!isCheckingUpdate) {
isCheckingUpdate = true
updateStatus = AppStrings.t(lang, "settings.checking_for_updates")
scope.launch {
val update = UpdateManager.checkUpdate()
isCheckingUpdate = false
updateStatus = if (update != null)
AppStrings.format(lang, "settings.update_available", update.versionName)
else
AppStrings.t(lang, "settings.up_to_date")
}
}
}
)
SettingsActionTile(
title = AppStrings.t(lang, "auto.restart_app"),
subtitle = AppStrings.t(lang, "auto.refresh_the_app_after_playback_or_network_ch"),

View file

@ -294,6 +294,12 @@ internal fun MobileCategoryDetail(
}
item {
MobileSettingsGroup(AppStrings.t(lang, "settings.notifications")) {
MobileToggleRow(
title = AppStrings.t(lang, "settings.enable_notifications"),
subtitle = AppStrings.t(lang, "settings.enable_notifications_desc"),
checked = profile.safeNotificationsEnabled,
onToggle = { onUpdateProfile(profile.sanitizedUpdate(notificationsEnabled = !profile.safeNotificationsEnabled)) }
)
MobileToggleRow(
title = AppStrings.t(lang, "settings.alert_new_episodes"),
subtitle = AppStrings.t(lang, "settings.alert_new_episodes_desc"),
@ -395,6 +401,21 @@ internal fun MobileCategoryDetail(
checked = profile.safeHomeSeasonPostersOnHero,
onToggle = { onUpdateProfile(profile.copy(homeSeasonPostersOnHero = !profile.safeHomeSeasonPostersOnHero)) }
)
MobileToggleRow(
title = AppStrings.t(lang, "settings.trailer_on_home_hero"),
subtitle = AppStrings.t(lang, "settings.trailer_on_home_hero_desc"),
checked = profile.safeTrailerOnHomeHeroEnabled,
onToggle = { onUpdateProfile(profile.copy(trailerOnHomeHeroEnabled = !profile.safeTrailerOnHomeHeroEnabled)) }
)
if (profile.safeTrailerOnHomeHeroEnabled) {
MobileStepperRow(
title = AppStrings.t(lang, "settings.trailer_on_home_hero_delay"),
value = "${profile.safeTrailerOnHomeHeroDelaySeconds}s",
subtitle = AppStrings.t(lang, "settings.trailer_on_home_hero_delay_desc"),
onDecrease = { onUpdateProfile(profile.copy(trailerOnHomeHeroDelaySeconds = (profile.safeTrailerOnHomeHeroDelaySeconds - 1).coerceIn(0, 15))) },
onIncrease = { onUpdateProfile(profile.copy(trailerOnHomeHeroDelaySeconds = (profile.safeTrailerOnHomeHeroDelaySeconds + 1).coerceIn(0, 15))) }
)
}
}
}
item {
@ -688,6 +709,12 @@ internal fun MobileCategoryDetail(
checked = profile.safeAutoEnableSubtitles,
onToggle = { onUpdateProfile(profile.copy(autoEnableSubtitles = !profile.safeAutoEnableSubtitles)) }
)
MobileToggleRow(
title = AppStrings.t(lang, "settings.subtitle_shadow"),
subtitle = AppStrings.t(lang, "settings.subtitle_shadow_desc"),
checked = profile.safeSubtitleShadow,
onToggle = { onUpdateProfile(profile.copy(subtitleShadow = !profile.safeSubtitleShadow)) }
)
MobileSubtitlePreview(profile = profile, lang = lang)
MobileStepperRow(
title = AppStrings.t(lang, "auto.subtitle_size_7fc78c82"),

View file

@ -132,7 +132,8 @@ internal fun MobileSettingsHub(
onBack: () -> Unit,
onLogout: () -> Unit,
onManageAddons: () -> Unit,
onUpdateInfoChanged: (UpdateManager.UpdateInfo?) -> Unit = {}
onUpdateInfoChanged: (UpdateManager.UpdateInfo?) -> Unit = {},
onUpdateProfile: (UserProfile) -> Unit
) {
val coroutineScope = rememberCoroutineScope()
var updateDialogMessage by remember { mutableStateOf<String?>(null) }
@ -275,6 +276,13 @@ internal fun MobileSettingsHub(
}
}
if (isSystemSection) {
MobileToggleRow(
title = AppStrings.t(lang, "settings.automatic_updates"),
subtitle = AppStrings.t(lang, "settings.automatic_updates_desc"),
checked = profile.safeAutomaticUpdates,
onToggle = { onUpdateProfile(profile.sanitizedUpdate(automaticUpdates = !profile.safeAutomaticUpdates)) }
)
MobileSettingsRowDivider()
MobileSettingsRow(
title = AppStrings.t(lang, "settings.check_for_updates"),
subtitle = if (availableUpdate != null)

View file

@ -575,6 +575,12 @@
"settings.picture_in_picture_desc": "Shows the player in a floating window when supported.",
"settings.notifications_desc": "Allows app status and playback notifications.",
"settings.notifications": "NOTIFICATIONS",
"settings.enable_notifications": "Enable Notifications",
"settings.enable_notifications_desc": "Master switch for all app notifications.",
"settings.automatic_updates": "Automatic Updates",
"settings.automatic_updates_desc": "Check for new app versions in the background.",
"settings.subtitle_shadow": "Subtitle Shadow",
"settings.subtitle_shadow_desc": "Adds a drop shadow behind subtitle text for readability.",
"settings.alert_new_episodes": "Alert me on new episodes",
"settings.alert_new_episodes_desc": "Notifies when upcoming episodes are released in your device timezone.",
"settings.default_player_desc": "Chooses which player opens streams by default.",

View file

@ -575,6 +575,12 @@
"settings.picture_in_picture_desc": "Destekleyen cihazlarda oynatıcıyı küçük pencerede gösterir.",
"settings.notifications_desc": "Uygulama durumu ve oynatma bildirimlerine izin verir.",
"settings.notifications": "BİLDİRİMLER",
"settings.enable_notifications": "Bildirimleri Etkinleştir",
"settings.enable_notifications_desc": "Tüm uygulama bildirimleri için ana anahtar.",
"settings.automatic_updates": "Otomatik Güncellemeler",
"settings.automatic_updates_desc": "Arka planda yeni uygulama sürümlerini kontrol eder.",
"settings.subtitle_shadow": "Altyazı Gölgesi",
"settings.subtitle_shadow_desc": "Okunabilirlik için altyazı metninin arkasına gölge ekler.",
"settings.alert_new_episodes": "Yeni bölümlerde uyar",
"settings.alert_new_episodes_desc": "Yaklaşan bölümler cihaz saat diliminde yayınlandığında bildirir.",
"settings.default_player_desc": "Yayınların varsayılan olarak hangi oynatıcıda açılacağını seçer.",