diff --git a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerEngine.android.kt b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerEngine.android.kt index bc5cc2c9a..2d916aacc 100644 --- a/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerEngine.android.kt +++ b/composeApp/src/androidMain/kotlin/com/nuvio/app/features/player/PlayerEngine.android.kt @@ -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()) } } diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/SubtitleAudioModels.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/SubtitleAudioModels.kt index 0dd0bf651..cab3dcd9e 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/SubtitleAudioModels.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/SubtitleAudioModels.kt @@ -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() diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/SubtitleStylePanel.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/SubtitleStylePanel.kt index bae3c26c3..fa43469d0 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/SubtitleStylePanel.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/player/SubtitleStylePanel.kt @@ -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, diff --git a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/NuvioPlayerBridge.kt b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/NuvioPlayerBridge.kt index 90701fae1..8259f7214 100644 --- a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/NuvioPlayerBridge.kt +++ b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/NuvioPlayerBridge.kt @@ -36,6 +36,7 @@ interface NuvioPlayerBridge { fun applySubtitleStyle( textColor: String, outlineSize: Float, + fontSize: Float, subPos: Int, ) fun getIsLoading(): Boolean diff --git a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerEngine.ios.kt b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerEngine.ios.kt index ac673b2ff..ad76ae8f2 100644 --- a/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerEngine.ios.kt +++ b/composeApp/src/iosMain/kotlin/com/nuvio/app/features/player/PlayerEngine.ios.kt @@ -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) diff --git a/iosApp/iosApp/Player/MPVPlayerBridge.swift b/iosApp/iosApp/Player/MPVPlayerBridge.swift index a75de839e..3fbf6d09e 100644 --- a/iosApp/iosApp/Player/MPVPlayerBridge.swift +++ b/iosApp/iosApp/Player/MPVPlayerBridge.swift @@ -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)) }