feat: enhance subtitle styling with adjustable font size and improved iOS bridge integration

This commit is contained in:
tapframe 2026-03-30 17:16:11 +05:30
parent 0ab26a1ac2
commit ead49a200b
6 changed files with 43 additions and 75 deletions

View file

@ -2,6 +2,7 @@ package com.nuvio.app.features.player
import android.net.Uri
import android.util.Log
import android.util.TypedValue
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
@ -379,7 +380,7 @@ private fun PlayerView.applySubtitleStyle(style: SubtitleStyleState) {
null,
)
)
setFractionalTextSize(SubtitleView.DEFAULT_TEXT_SIZE_FRACTION)
setFixedTextSize(TypedValue.COMPLEX_UNIT_SP, style.fontSizeSp.toFloat())
}
}

View file

@ -36,7 +36,8 @@ enum class SubtitleTab {
data class SubtitleStyleState(
val textColor: Color = Color.White,
val outlineEnabled: Boolean = false,
val bottomOffset: Int = 50,
val fontSizeSp: Int = 18,
val bottomOffset: Int = 20,
) {
companion object {
val DEFAULT = SubtitleStyleState()

View file

@ -8,7 +8,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.widthIn
@ -19,7 +18,7 @@ import androidx.compose.material.icons.rounded.KeyboardArrowDown
import androidx.compose.material.icons.rounded.KeyboardArrowUp
import androidx.compose.material.icons.rounded.Remove
import androidx.compose.material.icons.rounded.Tune
import androidx.compose.material.icons.rounded.Visibility
import androidx.compose.material.icons.rounded.FormatSize
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@ -27,13 +26,9 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import kotlin.math.min
@Composable
fun SubtitleStylePanel(
@ -48,13 +43,6 @@ fun SubtitleStylePanel(
Column(
verticalArrangement = Arrangement.spacedBy(gap),
) {
LivePreviewCard(
style = style,
isCompact = isCompact,
sectionPadding = sectionPadding,
colorScheme = colorScheme,
)
StyleControlsCard(
style = style,
isCompact = isCompact,
@ -65,64 +53,6 @@ fun SubtitleStylePanel(
}
}
@Composable
private fun LivePreviewCard(
style: SubtitleStyleState,
isCompact: Boolean,
sectionPadding: androidx.compose.ui.unit.Dp,
colorScheme: androidx.compose.material3.ColorScheme,
) {
val previewHeight = if (isCompact) 90.dp else 120.dp
val previewFontSize = if (isCompact) 18.sp else 22.sp
Column(
modifier = Modifier
.fillMaxWidth()
.clip(RoundedCornerShape(16.dp))
.background(colorScheme.surfaceVariant.copy(alpha = 0.45f))
.padding(sectionPadding),
) {
SectionHeader(
icon = Icons.Rounded.Visibility,
label = "Preview",
)
Box(
modifier = Modifier
.fillMaxWidth()
.height(previewHeight)
.clip(RoundedCornerShape(8.dp))
.background(Color.Black),
contentAlignment = Alignment.BottomCenter,
) {
Box(
modifier = Modifier
.padding(bottom = min(80, style.bottomOffset).dp, start = 10.dp, end = 10.dp),
) {
if (style.outlineEnabled) {
Text(
text = "The quick brown fox jumps over the lazy dog.",
color = Color.Black,
fontSize = previewFontSize,
style = TextStyle(
shadow = Shadow(
color = Color.Black,
blurRadius = 6f,
),
),
)
}
Text(
text = "The quick brown fox jumps over the lazy dog.",
color = style.textColor,
fontSize = previewFontSize,
)
}
}
}
}
@Composable
private fun StyleControlsCard(
style: SubtitleStyleState,
@ -147,6 +77,33 @@ private fun StyleControlsCard(
label = "Style",
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = "Font Size",
color = colorScheme.onSurfaceVariant,
fontSize = 14.sp,
fontWeight = FontWeight.Medium,
)
StepperControl(
value = "${style.fontSizeSp}sp",
onMinus = {
onStyleChanged(style.copy(fontSizeSp = (style.fontSizeSp - 2).coerceAtLeast(12)))
},
onPlus = {
onStyleChanged(style.copy(fontSizeSp = (style.fontSizeSp + 2).coerceAtMost(40)))
},
buttonSize = btnSize,
buttonRadius = btnRadius,
minWidth = 58.dp,
minusIcon = Icons.Rounded.Remove,
plusIcon = Icons.Rounded.FormatSize,
)
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,

View file

@ -36,6 +36,7 @@ interface NuvioPlayerBridge {
fun applySubtitleStyle(
textColor: String,
outlineSize: Float,
fontSize: Float,
subPos: Int,
)
fun getIsLoading(): Boolean

View file

@ -194,6 +194,7 @@ actual fun PlatformPlayerSurface(
bridge.applySubtitleStyle(
textColor = style.textColor.toMpvColorString(),
outlineSize = if (style.outlineEnabled) 1.65f else 0f,
fontSize = style.toMpvSubtitleFontSize(),
subPos = style.toMpvSubtitlePosition(),
)
}
@ -280,6 +281,9 @@ private fun Color.toMpvColorString(): String {
private fun SubtitleStyleState.toMpvSubtitlePosition(): Int =
(100 - (bottomOffset / 2)).coerceIn(0, 150)
private fun SubtitleStyleState.toMpvSubtitleFontSize(): Float =
(fontSizeSp * 3f).coerceIn(24f, 96f)
private fun Int.toHexByte(): String {
val digits = "0123456789ABCDEF"
val value = coerceIn(0, 255)

View file

@ -75,10 +75,11 @@ final class MPVPlayerBridgeImpl: NSObject, NuvioPlayerBridge {
func setSubtitleUrl(url: String) { playerVC?.addSubtitleUrl(url) }
func clearExternalSubtitle() { playerVC?.removeExternalSubtitles() }
func clearExternalSubtitleAndSelect(trackId: Int32) { playerVC?.removeExternalSubtitlesAndSelect(Int(trackId)) }
func applySubtitleStyle(textColor: String, outlineSize: Float, subPos: Int32) {
func applySubtitleStyle(textColor: String, outlineSize: Float, fontSize: Float, subPos: Int32) {
playerVC?.applySubtitleStyle(
textColor: textColor,
outlineSize: outlineSize,
fontSize: fontSize,
subPos: Int(subPos)
)
}
@ -337,7 +338,7 @@ final class MPVPlayerViewController: UIViewController {
}
}
func applySubtitleStyle(textColor: String, outlineSize: Float, subPos: Int) {
func applySubtitleStyle(textColor: String, outlineSize: Float, fontSize: Float, subPos: Int) {
guard mpv != nil else { return }
checkError(mpv_set_property_string(mpv, "sub-ass-override", "force"))
@ -347,6 +348,9 @@ final class MPVPlayerViewController: UIViewController {
var outline = Double(outlineSize)
checkError(mpv_set_property(mpv, "sub-outline-size", MPV_FORMAT_DOUBLE, &outline))
var size = Double(fontSize)
checkError(mpv_set_property(mpv, "sub-font-size", MPV_FORMAT_DOUBLE, &size))
var position = Int64(subPos)
checkError(mpv_set_property(mpv, "sub-pos", MPV_FORMAT_INT64, &position))
}