1- import React , { useState , useEffect } from 'react' ;
2- import { View , Text , StyleSheet } from 'react-native' ;
1+ import React , { useState , useEffect , useMemo } from 'react' ;
2+ import { View , Text , StyleSheet , ViewStyle , TextStyle } from 'react-native' ;
3+ import { SubtitleStyle , DEFAULT_SUBTITLE_STYLE } from '../../types' ;
34
45interface SubtitleCue {
56 start : number ;
@@ -11,6 +12,8 @@ interface SubtitleOverlayProps {
1112 subtitleContent : string | null ;
1213 currentTime : number ;
1314 isVideoFullscreen : boolean ;
15+ delay ?: number ; // Delay in seconds (positive = subtitles later, negative = subtitles earlier)
16+ style ?: SubtitleStyle ; // Custom subtitle style from settings
1417}
1518
1619const parseSRT = ( srtContent : string ) : SubtitleCue [ ] => {
@@ -62,10 +65,63 @@ export const SubtitleOverlay: React.FC<SubtitleOverlayProps> = ({
6265 subtitleContent,
6366 currentTime,
6467 isVideoFullscreen,
68+ delay = 0 ,
69+ style = DEFAULT_SUBTITLE_STYLE ,
6570} ) => {
6671 const [ cues , setCues ] = useState < SubtitleCue [ ] > ( [ ] ) ;
6772 const [ currentCue , setCurrentCue ] = useState < string | null > ( null ) ;
6873
74+ // Compute font size based on style setting and fullscreen mode
75+ const computedFontSize = useMemo ( ( ) => {
76+ const baseSizes = {
77+ small : isVideoFullscreen ? 14 : 10 ,
78+ medium : isVideoFullscreen ? 18 : 14 ,
79+ large : isVideoFullscreen ? 22 : 18 ,
80+ xlarge : isVideoFullscreen ? 26 : 22 ,
81+ } ;
82+ return baseSizes [ style . fontSize ] || baseSizes . medium ;
83+ } , [ style . fontSize , isVideoFullscreen ] ) ;
84+
85+ // Compute background color with opacity
86+ const computedBackgroundColor = useMemo ( ( ) => {
87+ if ( style . backgroundOpacity === 0 ) return 'transparent' ;
88+ const hex = style . backgroundColor . replace ( '#' , '' ) ;
89+ const r = parseInt ( hex . substring ( 0 , 2 ) , 16 ) ;
90+ const g = parseInt ( hex . substring ( 2 , 4 ) , 16 ) ;
91+ const b = parseInt ( hex . substring ( 4 , 6 ) , 16 ) ;
92+ return `rgba(${ r } , ${ g } , ${ b } , ${ style . backgroundOpacity } )` ;
93+ } , [ style . backgroundColor , style . backgroundOpacity ] ) ;
94+
95+ // Dynamic container style based on position
96+ const containerStyle : ViewStyle = useMemo ( ( ) => ( {
97+ position : 'absolute' ,
98+ left : 0 ,
99+ right : 0 ,
100+ alignItems : 'center' ,
101+ paddingHorizontal : 20 ,
102+ ...( style . position === 'top' ? { top : 50 } : { bottom : 20 } ) ,
103+ } ) , [ style . position ] ) ;
104+
105+ // Dynamic text style
106+ const textStyle : TextStyle = useMemo ( ( ) => ( {
107+ color : style . fontColor ,
108+ textAlign : 'center' ,
109+ fontSize : computedFontSize ,
110+ fontWeight : style . fontWeight === 'bold' ? '700' : '400' ,
111+ textShadowColor : style . textShadow ? 'rgba(0, 0, 0, 1)' : 'transparent' ,
112+ textShadowOffset : style . textShadow ? { width : 1 , height : 1 } : { width : 0 , height : 0 } ,
113+ textShadowRadius : style . textShadow ? 2 : 0 ,
114+ } ) , [ style . fontColor , style . fontWeight , style . textShadow , computedFontSize ] ) ;
115+
116+ // Dynamic text container style
117+ const textContainerStyle : ViewStyle = useMemo ( ( ) => ( {
118+ backgroundColor : computedBackgroundColor ,
119+ paddingVertical : 8 ,
120+ paddingHorizontal : 16 ,
121+ borderRadius : 4 ,
122+ maxWidth : '100%' ,
123+ } ) , [ computedBackgroundColor ] ) ;
124+
69125 useEffect ( ( ) => {
70126 if ( subtitleContent ) {
71127 try {
@@ -87,50 +143,27 @@ export const SubtitleOverlay: React.FC<SubtitleOverlayProps> = ({
87143 return ;
88144 }
89145
90- const adjustedTime = currentTime + 0.5 ;
146+ // Apply delay: positive delay means subtitles appear later (subtract from currentTime)
147+ // negative delay means subtitles appear earlier (add to currentTime)
148+ const adjustedTime = currentTime - delay + 0.5 ;
91149 const activeCue = cues . find (
92150 cue => adjustedTime >= cue . start && adjustedTime <= cue . end
93151 ) ;
94152
95153 setCurrentCue ( activeCue ? activeCue . text : null ) ;
96- } , [ currentTime , cues ] ) ;
154+ } , [ currentTime , cues , delay ] ) ;
97155
98156 if ( ! currentCue ) {
99157 return null ;
100158 }
101159
102160 return (
103- < View style = { styles . container } >
104- < View style = { styles . textContainer } >
105- < Text style = { [ styles . text , isVideoFullscreen && { fontSize : 18 } ] } > { currentCue } </ Text >
161+ < View style = { containerStyle } >
162+ < View style = { textContainerStyle } >
163+ < Text style = { textStyle } > { currentCue } </ Text >
106164 </ View >
107165 </ View >
108166 ) ;
109167} ;
110168
111- const styles = StyleSheet . create ( {
112- container : {
113- position : 'absolute' ,
114- bottom : 20 ,
115- left : 0 ,
116- right : 0 ,
117- alignItems : 'center' ,
118- paddingHorizontal : 20 ,
119- } ,
120- textContainer : {
121- backgroundColor : 'rgba(0, 0, 0, 0)' ,
122- paddingVertical : 8 ,
123- paddingHorizontal : 16 ,
124- borderRadius : 4 ,
125- maxWidth : '100%' ,
126- } ,
127- text : {
128- color : '#FFFFFF' ,
129- textAlign : 'center' ,
130- fontSize : 12 ,
131- fontWeight : '600' ,
132- textShadowColor : 'rgba(0, 0, 0, 1)' ,
133- textShadowOffset : { width : 1 , height : 1 } ,
134- textShadowRadius : 2 ,
135- } ,
136- } ) ;
169+ export default SubtitleOverlay ;
0 commit comments