Skip to content
Merged
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 @@ -106,6 +106,7 @@ class CloudSyncRepository @Inject constructor(
val subtitleColor: String = "White",
val subtitleStyle: String = "Bold",
val subtitleOffset: String = "Low",
val subtitleStylized: Boolean = true,
val cardLayoutMode: String = CARD_LAYOUT_MODE_LANDSCAPE,
val frameRateMatchingMode: String = "Off",
val autoPlayNext: Boolean = true,
Expand Down Expand Up @@ -160,6 +161,8 @@ class CloudSyncRepository @Inject constructor(
profileManager.profileStringKeyFor(profileId, "subtitle_offset")
private fun subtitleStyleKeyFor(profileId: String) =
profileManager.profileStringKeyFor(profileId, "subtitle_style")
private fun subtitleStylizedKeyFor(profileId: String) =
profileManager.profileBooleanKeyFor(profileId, "subtitle_stylized")
private fun iptvHiddenGroupsKeyFor(profileId: String) =
profileManager.profileStringKeyFor(profileId, "iptv_hidden_groups")
private fun iptvGroupOrderKeyFor(profileId: String) =
Expand Down Expand Up @@ -279,6 +282,7 @@ class CloudSyncRepository @Inject constructor(
subtitleColor = prefs[subtitleColorKeyFor(profile.id)] ?: "White",
subtitleOffset = prefs[subtitleOffsetKeyFor(profile.id)] ?: "Low",
subtitleStyle = prefs[subtitleStyleKeyFor(profile.id)] ?: "Bold",
subtitleStylized = prefs[subtitleStylizedKeyFor(profile.id)] ?: true,
iptvHiddenGroups = prefs[iptvHiddenGroupsKeyFor(profile.id)] ?: "",
iptvGroupOrder = prefs[iptvGroupOrderKeyFor(profile.id)] ?: "",
secondarySubtitle = prefs[secondarySubtitleKeyFor(profile.id)] ?: "Off",
Expand Down Expand Up @@ -695,6 +699,7 @@ class CloudSyncRepository @Inject constructor(
prefs[subtitleColorKeyFor(profileId)] = state.subtitleColor
prefs[subtitleOffsetKeyFor(profileId)] = state.subtitleOffset
prefs[subtitleStyleKeyFor(profileId)] = state.subtitleStyle
prefs[subtitleStylizedKeyFor(profileId)] = state.subtitleStylized
if (state.iptvHiddenGroups.isNotBlank()) prefs[iptvHiddenGroupsKeyFor(profileId)] = state.iptvHiddenGroups
if (state.iptvGroupOrder.isNotBlank()) prefs[iptvGroupOrderKeyFor(profileId)] = state.iptvGroupOrder
prefs[secondarySubtitleKeyFor(profileId)] = state.secondarySubtitle.ifBlank { "Off" }
Expand Down
66 changes: 38 additions & 28 deletions app/src/main/kotlin/com/arflix/tv/ui/screens/player/PlayerScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -1566,6 +1566,7 @@ fun PlayerScreen(
val subtitleSizePref = uiState.subtitleSize
val subtitleColorPref = uiState.subtitleColor
val subtitleStylePref = uiState.subtitleStyle
val subtitleStylizedPref = uiState.subtitleStylized
val aspectModeLabel = when (playerResizeMode) {
AspectRatioFrameLayout.RESIZE_MODE_ZOOM -> "Zoom"
AspectRatioFrameLayout.RESIZE_MODE_FILL -> "Fill"
Expand Down Expand Up @@ -1998,9 +1999,8 @@ fun PlayerScreen(
setKeepContentOnPlayerReset(true)
resizeMode = playerResizeMode

// Enable subtitle view with Netflix-style: bold white text with black outline
// Enable subtitle view with styling based on user preference
subtitleView?.apply {
// Read subtitle appearance from user settings
val subSizeSp = when (subtitleSizePref) {
"Small" -> 18f; "Large" -> 30f; "Extra Large" -> 36f; else -> 24f
}
Expand All @@ -2009,35 +2009,45 @@ fun PlayerScreen(
"Green" -> android.graphics.Color.GREEN
"Cyan" -> android.graphics.Color.CYAN
else -> android.graphics.Color.WHITE
}
val subTypeface = when (subtitleStylePref) {
"Normal" -> android.graphics.Typeface.DEFAULT
"Background" -> android.graphics.Typeface.DEFAULT_BOLD
else -> android.graphics.Typeface.DEFAULT_BOLD
}
val subEdgeType = when (subtitleStylePref) {
"Normal" -> androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_NONE
"Background" -> androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_NONE
else -> androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_OUTLINE
}
val subBgColor = when (subtitleStylePref) {
"Background" -> android.graphics.Color.argb(180, 0, 0, 0)
else -> android.graphics.Color.TRANSPARENT
}
setStyle(
androidx.media3.ui.CaptionStyleCompat(
subFgColor,
android.graphics.Color.TRANSPARENT,
subBgColor,
subEdgeType,
android.graphics.Color.BLACK,
subTypeface
)
}
val subTypeface = when (subtitleStylePref) {
"Normal" -> android.graphics.Typeface.DEFAULT
"Background" -> android.graphics.Typeface.DEFAULT_BOLD
else -> android.graphics.Typeface.DEFAULT_BOLD
}
val subEdgeType = when (subtitleStylePref) {
"Normal" -> androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_NONE
"Background" -> androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_NONE
else -> androidx.media3.ui.CaptionStyleCompat.EDGE_TYPE_OUTLINE
}
val subBgColor = when (subtitleStylePref) {
"Background" -> android.graphics.Color.argb(180, 0, 0, 0)
else -> android.graphics.Color.TRANSPARENT
}
setStyle(
androidx.media3.ui.CaptionStyleCompat(
subFgColor,
android.graphics.Color.TRANSPARENT,
subBgColor,
subEdgeType,
android.graphics.Color.BLACK,
subTypeface
)
setApplyEmbeddedStyles(false)
setApplyEmbeddedFontSizes(false)
)
setFixedTextSize(android.util.TypedValue.COMPLEX_UNIT_SP, subSizeSp)
setBottomPaddingFraction(0.08f)

if (subtitleStylizedPref) {
// Stylized mode: let Media3 render embedded ASS/SSA styles
// (colors, fonts, positioning, z-order). User prefs are
// only used as a fallback CaptionStyle for plain SRT/VTT.
setApplyEmbeddedStyles(true)
setApplyEmbeddedFontSizes(true)
} else {
// Uniform mode: override everything with user preferences
setApplyEmbeddedStyles(false)
setApplyEmbeddedFontSizes(false)
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ data class PlayerUiState(
val subtitleSize: String = "Medium",
val subtitleColor: String = "White",
val subtitleStyle: String = "Bold",
val subtitleStylized: Boolean = true,
val error: String? = null,
val isSetupError: Boolean = false, // true when error is due to missing addons (shows friendly guide instead of red error)
// Auto-play next episode at end of current one. Mirrors the profile-scoped
Expand Down Expand Up @@ -347,6 +348,7 @@ class PlayerViewModel @Inject constructor(
val subSize = prefs[profileManager.profileStringKey("subtitle_size")] ?: "Medium"
val subColor = prefs[profileManager.profileStringKey("subtitle_color")] ?: "White"
val subStyle = prefs[profileManager.profileStringKey("subtitle_style")] ?: "Bold"
val subStylized = prefs[profileManager.profileBooleanKey("subtitle_stylized")] ?: true
val autoPlayNext = prefs[autoPlayNextKey()] ?: true
val showLoadingStats = prefs[showLoadingStatsKey()] ?: true
val volumeBoostDb = prefs[profileManager.profileStringKey("volume_boost_db")]
Expand Down Expand Up @@ -379,6 +381,7 @@ class PlayerViewModel @Inject constructor(
subtitleSize = subSize,
subtitleColor = subColor,
subtitleStyle = subStyle,
subtitleStylized = subStylized,
autoPlayNext = autoPlayNext,
showLoadingStats = showLoadingStats,
volumeBoostDb = volumeBoostDb
Expand Down
Loading
Loading