Skip to content
Open
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 @@ -439,6 +439,8 @@ fun PlayerScreen(
}
var useVideoFrameSubtitleViewport by remember { mutableStateOf(false) }
val subtitleGroups = remember(uiState.subtitles, uiState.preferredSubtitleLang, uiState.secondarySubtitleLang, uiState.selectedStream, uiState.isAiAvailable, uiState.aiTargetLanguageName) {
val subtitlePrefsRepo = SubtitlePrefsRepository(requireContext())
val subtitlePrefs = subtitlePrefsRepo.load()
val streamSource = uiState.selectedStream?.source ?: ""
val primaryName = getFullLanguageName(uiState.preferredSubtitleLang)
val secondaryName = getFullLanguageName(uiState.secondarySubtitleLang)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

package com.arvio.tv.player.subtitle

import android.graphics.Color
import android.graphics.Typeface

enum class SubtitlePosition { BOTTOM, TOP }

enum class SubtitleFontSize(val sp: Float, val label: String) {
SMALL(14f, "Small"),
MEDIUM(18f, "Medium"),
LARGE(22f, "Large"),
EXTRA_LARGE(28f, "Extra Large")
}

data class SubtitlePreferences(
val fontSize: Float = SubtitleFontSize.MEDIUM.sp,
val textColor: Int = Color.WHITE,
val backgroundColor: Int = Color.parseColor("#80000000"),
val position: SubtitlePosition = SubtitlePosition.BOTTOM,
val fontStyle: Int = Typeface.BOLD,
val useSystemCaptions: Boolean = true // honour Android TV CaptionManager
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// app/src/main/java/com/arvio/tv/player/subtitle/SubtitlePrefsRepository.kt
package com.arvio.tv.player.subtitle

import android.content.Context
import android.graphics.Color
import androidx.core.content.edit

private const val PREFS_NAME = "subtitle_prefs"
private const val KEY_FONT_SIZE = "font_size"
private const val KEY_TEXT_COLOR = "text_color"
private const val KEY_BG_COLOR = "bg_color"
private const val KEY_USE_SYSTEM = "use_system_captions"

class SubtitlePrefsRepository(context: Context) {

private val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)

fun load(): SubtitlePreferences = SubtitlePreferences(
fontSize = prefs.getFloat(KEY_FONT_SIZE, SubtitleFontSize.MEDIUM.sp),
textColor = prefs.getInt(KEY_TEXT_COLOR, Color.WHITE),
backgroundColor = prefs.getInt(KEY_BG_COLOR, Color.parseColor("#80000000")),
useSystemCaptions = prefs.getBoolean(KEY_USE_SYSTEM, true)
)

fun save(prefs: SubtitlePreferences) {
this.prefs.edit {
putFloat(KEY_FONT_SIZE, prefs.fontSize)
putInt(KEY_TEXT_COLOR, prefs.textColor)
putInt(KEY_BG_COLOR, prefs.backgroundColor)
putBoolean(KEY_USE_SYSTEM, prefs.useSystemCaptions)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SubtitleSettingsFragment.kt — simplified example
class SubtitleSettingsFragment : BottomSheetDialogFragment() {

private val repo by lazy { SubtitlePrefsRepository(requireContext()) }

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, saved: Bundle?): View {
val view = inflater.inflate(R.layout.fragment_subtitle_settings, container, false)

val sizeOptions = SubtitleFontSize.values()
// bind RadioGroup / RecyclerView with size options
// on selection: repo.save(currentPrefs.copy(fontSize = selected.sp))

return view
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// app/src/main/java/com/arvio/tv/player/subtitle/SubtitleStyleManager.kt
package com.arvio.tv.player.subtitle

import android.content.Context
import android.util.TypedValue
import android.view.accessibility.CaptioningManager
import androidx.media3.ui.CaptionStyleCompat
import androidx.media3.ui.SubtitleView
import android.graphics.Color

object SubtitleStyleManager {

/**
* Reads Android TV system caption preferences (if enabled) and falls back
* to the app-level [SubtitlePreferences]. Applies the resolved style to
* the provided [SubtitleView].
*/
fun applyStyle(context: Context, subtitleView: SubtitleView, prefs: SubtitlePreferences) {
val captionManager =
context.getSystemService(Context.CAPTIONING_SERVICE) as? CaptioningManager

val systemEnabled = captionManager?.isEnabled == true
val systemStyle = if (prefs.useSystemCaptions && systemEnabled) {
captionManager?.userStyle
} else null

val textColor = systemStyle?.foregroundColor?.takeIf { it != CaptioningManager.CaptionStyle.COLOR_UNSPECIFIED }
?: prefs.textColor
val bgColor = systemStyle?.backgroundColor?.takeIf { it != CaptioningManager.CaptionStyle.COLOR_UNSPECIFIED }
?: prefs.backgroundColor
val edgeType = systemStyle?.edgeType
?: CaptionStyleCompat.EDGE_TYPE_OUTLINE

val captionStyle = CaptionStyleCompat(
textColor,
bgColor,
Color.TRANSPARENT,
edgeType,
Color.BLACK,
null // default typeface
)

subtitleView.setStyle(captionStyle)
subtitleView.setFixedTextSize(TypedValue.COMPLEX_UNIT_SP, prefs.fontSize)
}
}
Loading