Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ class CloudSyncRepository @Inject constructor(
val frameRateMatchingMode: String = "Off",
val autoPlayNext: Boolean = true,
val autoPlaySingleSource: Boolean = true,
val autoPlayMinQuality: String = "Any",
val autoPlayMinQuality: String = "Any", // Ensure this name is exact
val trailerAutoPlay: Boolean = false,
val trailerAudioEnabled: Boolean = false,
val includeSpecials: Boolean = false,
val iptvHiddenGroups: String = "",
val iptvGroupOrder: String = ""
Expand All @@ -70,6 +71,8 @@ class CloudSyncRepository @Inject constructor(
profileManager.profileStringKeyFor(profileId, "content_language")
private fun trailerAutoPlayKeyFor(profileId: String) =
profileManager.profileBooleanKeyFor(profileId, "trailer_auto_play")
private fun trailerAudioEnabledKeyFor(profileId: String) =
profileManager.profileBooleanKeyFor(profileId, "trailer_audio_enabled")

private fun subtitleSizeKeyFor(profileId: String) =
profileManager.profileStringKeyFor(profileId, "subtitle_size")
Expand Down Expand Up @@ -149,8 +152,8 @@ class CloudSyncRepository @Inject constructor(
defaultSubtitle = prefs[defaultSubtitleKeyFor(profile.id)] ?: "Off",
defaultAudioLanguage = prefs[defaultAudioLanguageKeyFor(profile.id)] ?: "Auto (Original)",
contentLanguage = prefs[contentLanguageKeyFor(profile.id)] ?: "en-US",

trailerAutoPlay = prefs[trailerAutoPlayKeyFor(profile.id)] ?: false,
trailerAudioEnabled = prefs[trailerAudioEnabledKeyFor(profile.id)] ?: false,
subtitleSize = prefs[subtitleSizeKeyFor(profile.id)] ?: "Medium",
subtitleColor = prefs[subtitleColorKeyFor(profile.id)] ?: "White",
iptvHiddenGroups = prefs[iptvHiddenGroupsKeyFor(profile.id)] ?: "",
Expand Down Expand Up @@ -368,8 +371,8 @@ class CloudSyncRepository @Inject constructor(
prefs[defaultSubtitleKeyFor(profileId)] = state.defaultSubtitle
prefs[defaultAudioLanguageKeyFor(profileId)] = state.defaultAudioLanguage
prefs[contentLanguageKeyFor(profileId)] = state.contentLanguage

prefs[trailerAutoPlayKeyFor(profileId)] = state.trailerAutoPlay
prefs[trailerAudioEnabledKeyFor(profileId)] = state.trailerAudioEnabled
prefs[subtitleSizeKeyFor(profileId)] = state.subtitleSize
prefs[subtitleColorKeyFor(profileId)] = state.subtitleColor
if (state.iptvHiddenGroups.isNotBlank()) prefs[iptvHiddenGroupsKeyFor(profileId)] = state.iptvHiddenGroups
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ import kotlinx.coroutines.withContext
fun TrailerPlayer(
youtubeKey: String,
modifier: Modifier = Modifier,
delayMs: Long = 3000L
delayMs: Long = 3000L,
isMuted: Boolean = true
) {
val context = LocalContext.current
var shouldPlay by remember { mutableStateOf(false) }
Expand Down Expand Up @@ -72,7 +73,7 @@ fun TrailerPlayer(
) {
val player = remember(youtubeKey) {
ExoPlayer.Builder(context).build().apply {
volume = 0.5f // Half volume for background trailer
volume = if (isMuted) 0f else 0.5f // Muted or half volume for background trailer
repeatMode = Player.REPEAT_MODE_ONE
playWhenReady = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ fun HomeScreen(
if (heroVideoUrl == null && uiState.trailerAutoPlay && uiState.heroTrailerKey != null) {
TrailerPlayer(
youtubeKey = uiState.heroTrailerKey!!,
isMuted = !uiState.trailerAudioEnabled,
modifier = Modifier.fillMaxSize()
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.arflix.tv.ui.screens.home

import com.arflix.tv.data.repository.ProfileManager
import android.app.ActivityManager
import android.content.Context
import com.arflix.tv.util.settingsDataStore
Expand Down Expand Up @@ -66,6 +67,7 @@ data class HomeUiState(
val heroLogoUrl: String? = null,
val heroTrailerKey: String? = null,
val trailerAutoPlay: Boolean = false,
val trailerAudioEnabled: Boolean = false,
val heroOverviewOverride: String? = null,
val cardLogoUrls: Map<String, String> = emptyMap(),
// Previous hero for crossfade (Phase 2.1)
Expand Down Expand Up @@ -96,6 +98,7 @@ class HomeViewModel @Inject constructor(
private val watchlistRepository: WatchlistRepository,
private val cloudSyncRepository: CloudSyncRepository,
private val launcherContinueWatchingRepository: LauncherContinueWatchingRepository,
private val profileManager: ProfileManager,
@ApplicationContext private val context: Context
) : ViewModel() {
private val imageLoader: ImageLoader by lazy(LazyThreadSafetyMode.NONE) {
Expand Down Expand Up @@ -648,7 +651,14 @@ class HomeViewModel @Inject constructor(
val trailerEnabled = prefs.asMap().any { (key, value) ->
key.name.endsWith("_trailer_auto_play") && value == true
}
_uiState.value = _uiState.value.copy(trailerAutoPlay = trailerEnabled)

// Scope trailer audio strictly to the active profile
val trailerAudio = prefs[profileManager.profileBooleanKey("trailer_audio_enabled")] ?: false

_uiState.value = _uiState.value.copy(
trailerAutoPlay = trailerEnabled,
trailerAudioEnabled = trailerAudio
)
} catch (_: Exception) {}
}
// Restore logo URL cache from disk for instant clearlogos on cold start
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ fun SettingsScreen(
if (scrollState.maxValue <= 0) return@LaunchedEffect

val maxIndex = when (sectionIndex) {
0 -> 13 // General: 14 items
0 -> 14 // General: 15 items
1 -> 3 // IPTV: Configure + Refresh + Delete + Stalker
2 -> uiState.catalogs.size // Catalogs
3 -> uiState.addons.size // Addons
Expand Down Expand Up @@ -433,7 +433,7 @@ fun SettingsScreen(
Zone.CONTENT -> {
// Dynamic max based on current section
val maxIndex = when (sectionIndex) {
0 -> 13 // General: 14 items
0 -> 14 // General: 15 items
1 -> 3 // IPTV: Configure + Refresh + Delete + Stalker
2 -> uiState.catalogs.size // Catalogs: Add + N catalogs
3 -> uiState.addons.size // Addons: N addons + "Add Custom" button
Expand Down Expand Up @@ -482,11 +482,12 @@ fun SettingsScreen(
6 -> viewModel.setAutoPlaySingleSource(!uiState.autoPlaySingleSource)
7 -> viewModel.cycleAutoPlayMinQuality()
8 -> viewModel.setTrailerAutoPlay(!uiState.trailerAutoPlay)
9 -> viewModel.cycleFrameRateMatchingMode()
10 -> viewModel.toggleCardLayoutMode()
11 -> { val next = when (uiState.deviceModeOverride) { "auto" -> "tv"; "tv" -> "tablet"; "tablet" -> "phone"; else -> "auto" }; viewModel.setDeviceModeOverride(next) }
12 -> viewModel.setSkipProfileSelection(!uiState.skipProfileSelection)
13 -> openDnsProviderPicker()
9 -> viewModel.setTrailerAudioEnabled(!uiState.trailerAudioEnabled)
10 -> viewModel.cycleFrameRateMatchingMode()
11 -> viewModel.toggleCardLayoutMode()
12 -> { val next = when (uiState.deviceModeOverride) { "auto" -> "tv"; "tv" -> "tablet"; "tablet" -> "phone"; else -> "auto" }; viewModel.setDeviceModeOverride(next) }
13 -> viewModel.setSkipProfileSelection(!uiState.skipProfileSelection)
14 -> openDnsProviderPicker()
}
}
1 -> { // IPTV
Expand Down Expand Up @@ -625,7 +626,9 @@ fun SettingsScreen(
onAutoPlaySingleSourceToggle = { viewModel.setAutoPlaySingleSource(it) },
onAutoPlayMinQualityClick = { viewModel.cycleAutoPlayMinQuality() },
trailerAutoPlay = uiState.trailerAutoPlay,
trailerAudioEnabled = uiState.trailerAudioEnabled,
onTrailerAutoPlayToggle = { viewModel.setTrailerAutoPlay(it) },
onTrailerAudioToggle = { viewModel.setTrailerAudioEnabled(it) },
onDeviceModeClick = {
val next = when (uiState.deviceModeOverride) { "auto" -> "tv"; "tv" -> "tablet"; "tablet" -> "phone"; else -> "auto" }
viewModel.setDeviceModeOverride(next)
Expand Down Expand Up @@ -797,7 +800,9 @@ fun SettingsScreen(
onAutoPlaySingleSourceToggle = { viewModel.setAutoPlaySingleSource(it) },
onAutoPlayMinQualityClick = { viewModel.cycleAutoPlayMinQuality() },
trailerAutoPlay = uiState.trailerAutoPlay,
trailerAudioEnabled = uiState.trailerAudioEnabled,
onTrailerAutoPlayToggle = { viewModel.setTrailerAutoPlay(it) },
onTrailerAudioToggle = { viewModel.setTrailerAudioEnabled(it) },
onDeviceModeClick = {
val next = when (uiState.deviceModeOverride) { "auto" -> "tv"; "tv" -> "tablet"; "tablet" -> "phone"; else -> "auto" }
viewModel.setDeviceModeOverride(next)
Expand Down Expand Up @@ -2127,9 +2132,11 @@ private fun GeneralSettings(
onContentLanguageClick: () -> Unit = {},
onSkipProfileSelectionToggle: (Boolean) -> Unit = {},
trailerAutoPlay: Boolean = false,
trailerAudioEnabled: Boolean = false,
onSubtitleSizeClick: () -> Unit = {},
onSubtitleColorClick: () -> Unit = {},
onTrailerAutoPlayToggle: (Boolean) -> Unit = {}
onTrailerAutoPlayToggle: (Boolean) -> Unit = {},
onTrailerAudioToggle: (Boolean) -> Unit = {}
) {
Column {
// ── Language & Subtitles ──
Expand Down Expand Up @@ -2227,12 +2234,20 @@ private fun GeneralSettings(
onToggle = onTrailerAutoPlayToggle
)
Spacer(modifier = Modifier.height(10.dp))
SettingsToggleRow(
title = "Trailer Audio",
subtitle = "Enable sound for banners",
isEnabled = trailerAudioEnabled,
isFocused = focusedIndex == 9,
onToggle = onTrailerAudioToggle
)
Spacer(modifier = Modifier.height(10.dp))
SettingsRow(
icon = Icons.Default.Movie,
title = "Match Frame Rate",
subtitle = "Off, Seamless, or Always",
value = frameRateMatchingMode,
isFocused = focusedIndex == 9,
isFocused = focusedIndex == 10,
onClick = onFrameRateMatchingClick
)

Expand All @@ -2250,7 +2265,7 @@ private fun GeneralSettings(
title = "Card Layout",
subtitle = "Landscape or poster cards",
value = cardLayoutMode,
isFocused = focusedIndex == 10,
isFocused = focusedIndex == 11,
onClick = onCardLayoutToggle
)
Spacer(modifier = Modifier.height(10.dp))
Expand All @@ -2264,15 +2279,15 @@ private fun GeneralSettings(
"phone" -> "Phone"
else -> "Auto"
},
isFocused = focusedIndex == 11,
isFocused = focusedIndex == 12,
onClick = onDeviceModeClick
)
Spacer(modifier = Modifier.height(10.dp))
SettingsToggleRow(
title = "Skip Profile Selection",
subtitle = "Auto-load last used profile",
isEnabled = skipProfileSelection,
isFocused = focusedIndex == 12,
isFocused = focusedIndex == 13,
onToggle = onSkipProfileSelectionToggle
)

Expand All @@ -2290,7 +2305,7 @@ private fun GeneralSettings(
title = "DNS Provider",
subtitle = "Resolve API and stream requests",
value = dnsProvider,
isFocused = focusedIndex == 13,
isFocused = focusedIndex == 14,
onClick = onDnsProviderClick
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ data class SettingsUiState(
val subtitleSize: String = "Medium",
val subtitleColor: String = "White",
val trailerAutoPlay: Boolean = false,
val trailerAudioEnabled: Boolean = false,
val includeSpecials: Boolean = false,
val isLoggedIn: Boolean = false,
val accountEmail: String? = null,
Expand Down Expand Up @@ -177,6 +178,7 @@ class SettingsViewModel @Inject constructor(
private fun autoPlayMinQualityKey() = profileManager.profileStringKey("auto_play_min_quality")
private fun autoPlayMinQualityKeyFor(profileId: String) = profileManager.profileStringKeyFor(profileId, "auto_play_min_quality")
private fun trailerAutoPlayKey() = profileManager.profileBooleanKey("trailer_auto_play")
private fun trailerAudioEnabledKey() = profileManager.profileBooleanKey("trailer_audio_enabled")

private fun subtitleSizeKey() = profileManager.profileStringKey("subtitle_size")
private fun subtitleColorKey() = profileManager.profileStringKey("subtitle_color")
Expand Down Expand Up @@ -264,6 +266,7 @@ class SettingsViewModel @Inject constructor(
}
val autoPlayMinQuality = normalizeAutoPlayMinQuality(prefs[autoPlayMinQualityKey()])
val trailerAutoPlay = prefs[trailerAutoPlayKey()] ?: false
val trailerAudioEnabled = prefs[trailerAudioEnabledKey()] ?: false

val subtitleSize = prefs[subtitleSizeKey()] ?: "Medium"
val subtitleColor = prefs[subtitleColorKey()] ?: "White"
Expand Down Expand Up @@ -303,6 +306,7 @@ class SettingsViewModel @Inject constructor(
autoPlaySingleSource = autoPlaySingleSource,
autoPlayMinQuality = autoPlayMinQuality,
trailerAutoPlay = trailerAutoPlay,
trailerAudioEnabled = trailerAudioEnabled,

subtitleSize = subtitleSize,
subtitleColor = subtitleColor,
Expand Down Expand Up @@ -783,6 +787,10 @@ class SettingsViewModel @Inject constructor(
viewModelScope.launch { context.settingsDataStore.edit { it[trailerAutoPlayKey()] = enabled }; _uiState.value = _uiState.value.copy(trailerAutoPlay = enabled); syncLocalStateToCloud(silent = true) }
}

fun setTrailerAudioEnabled(enabled: Boolean) {
viewModelScope.launch { context.settingsDataStore.edit { it[trailerAudioEnabledKey()] = enabled }; _uiState.value = _uiState.value.copy(trailerAudioEnabled = enabled); syncLocalStateToCloud(silent = true) }
}

fun cycleSubtitleSize() {
val next = when (_uiState.value.subtitleSize) { "Small" -> "Medium"; "Medium" -> "Large"; "Large" -> "Extra Large"; else -> "Small" }
viewModelScope.launch { context.settingsDataStore.edit { it[subtitleSizeKey()] = next }; _uiState.value = _uiState.value.copy(subtitleSize = next); syncLocalStateToCloud(silent = true) }
Expand Down
Loading