fix(android): add subtitleStyle.subtitlesFollowVideo prop to control subtitles positionning (#4133)
* fix(android): add subtitleStyle.subtitlesFollowVideo prop to control subtitles positionning * docs: add new prop description * docs: add supported platform for subtitleStyle * chore: use constructor instead of parse
This commit is contained in:
		@@ -6,7 +6,7 @@ import com.facebook.react.bridge.ReadableMap
 | 
				
			|||||||
/**
 | 
					/**
 | 
				
			||||||
 * Helper file to parse SubtitleStyle prop and build a dedicated class
 | 
					 * Helper file to parse SubtitleStyle prop and build a dedicated class
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
class SubtitleStyle private constructor() {
 | 
					class SubtitleStyle public constructor() {
 | 
				
			||||||
    var fontSize = -1
 | 
					    var fontSize = -1
 | 
				
			||||||
        private set
 | 
					        private set
 | 
				
			||||||
    var paddingLeft = 0
 | 
					    var paddingLeft = 0
 | 
				
			||||||
@@ -19,6 +19,8 @@ class SubtitleStyle private constructor() {
 | 
				
			|||||||
        private set
 | 
					        private set
 | 
				
			||||||
    var opacity = 1f
 | 
					    var opacity = 1f
 | 
				
			||||||
        private set
 | 
					        private set
 | 
				
			||||||
 | 
					    var subtitlesFollowVideo = true
 | 
				
			||||||
 | 
					        private set
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        private const val PROP_FONT_SIZE_TRACK = "fontSize"
 | 
					        private const val PROP_FONT_SIZE_TRACK = "fontSize"
 | 
				
			||||||
@@ -27,6 +29,7 @@ class SubtitleStyle private constructor() {
 | 
				
			|||||||
        private const val PROP_PADDING_LEFT = "paddingLeft"
 | 
					        private const val PROP_PADDING_LEFT = "paddingLeft"
 | 
				
			||||||
        private const val PROP_PADDING_RIGHT = "paddingRight"
 | 
					        private const val PROP_PADDING_RIGHT = "paddingRight"
 | 
				
			||||||
        private const val PROP_OPACITY = "opacity"
 | 
					        private const val PROP_OPACITY = "opacity"
 | 
				
			||||||
 | 
					        private const val PROP_SUBTITLES_FOLLOW_VIDEO = "subtitlesFollowVideo"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        @JvmStatic
 | 
					        @JvmStatic
 | 
				
			||||||
        fun parse(src: ReadableMap?): SubtitleStyle {
 | 
					        fun parse(src: ReadableMap?): SubtitleStyle {
 | 
				
			||||||
@@ -37,6 +40,7 @@ class SubtitleStyle private constructor() {
 | 
				
			|||||||
            subtitleStyle.paddingLeft = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_LEFT, 0)
 | 
					            subtitleStyle.paddingLeft = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_LEFT, 0)
 | 
				
			||||||
            subtitleStyle.paddingRight = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_RIGHT, 0)
 | 
					            subtitleStyle.paddingRight = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_RIGHT, 0)
 | 
				
			||||||
            subtitleStyle.opacity = ReactBridgeUtils.safeGetFloat(src, PROP_OPACITY, 1f)
 | 
					            subtitleStyle.opacity = ReactBridgeUtils.safeGetFloat(src, PROP_OPACITY, 1f)
 | 
				
			||||||
 | 
					            subtitleStyle.subtitlesFollowVideo = ReactBridgeUtils.safeGetBool(src, PROP_SUBTITLES_FOLLOW_VIDEO, true)
 | 
				
			||||||
            return subtitleStyle
 | 
					            return subtitleStyle
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -48,6 +48,8 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
 | 
				
			|||||||
    private @ViewType.ViewType int viewType = ViewType.VIEW_TYPE_SURFACE;
 | 
					    private @ViewType.ViewType int viewType = ViewType.VIEW_TYPE_SURFACE;
 | 
				
			||||||
    private boolean hideShutterView = false;
 | 
					    private boolean hideShutterView = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private SubtitleStyle localStyle = new SubtitleStyle();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public ExoPlayerView(Context context) {
 | 
					    public ExoPlayerView(Context context) {
 | 
				
			||||||
        super(context, null, 0);
 | 
					        super(context, null, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -80,11 +82,16 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
 | 
				
			|||||||
        adOverlayFrameLayout = new FrameLayout(context);
 | 
					        adOverlayFrameLayout = new FrameLayout(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        layout.addView(shutterView, 1, layoutParams);
 | 
					        layout.addView(shutterView, 1, layoutParams);
 | 
				
			||||||
        layout.addView(adOverlayFrameLayout, 2, layoutParams);
 | 
					        if (localStyle.getSubtitlesFollowVideo()) {
 | 
				
			||||||
 | 
					            layout.addView(subtitleLayout, layoutParams);
 | 
				
			||||||
 | 
					            layout.addView(adOverlayFrameLayout, layoutParams);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        addViewInLayout(layout, 0, aspectRatioParams);
 | 
					        addViewInLayout(layout, 0, aspectRatioParams);
 | 
				
			||||||
 | 
					        if (!localStyle.getSubtitlesFollowVideo()) {
 | 
				
			||||||
            addViewInLayout(subtitleLayout, 1, layoutParams);
 | 
					            addViewInLayout(subtitleLayout, 1, layoutParams);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private void clearVideoView() {
 | 
					    private void clearVideoView() {
 | 
				
			||||||
        if (surfaceView instanceof TextureView) {
 | 
					        if (surfaceView instanceof TextureView) {
 | 
				
			||||||
@@ -107,7 +114,7 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setSubtitleStyle(SubtitleStyle style) {
 | 
					    public void setSubtitleStyle(SubtitleStyle style) {
 | 
				
			||||||
        // ensure we reset subtile style before reapplying it
 | 
					        // ensure we reset subtitle style before reapplying it
 | 
				
			||||||
        subtitleLayout.setUserDefaultStyle();
 | 
					        subtitleLayout.setUserDefaultStyle();
 | 
				
			||||||
        subtitleLayout.setUserDefaultTextSize();
 | 
					        subtitleLayout.setUserDefaultTextSize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -121,7 +128,18 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider {
 | 
				
			|||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            subtitleLayout.setVisibility(View.GONE);
 | 
					            subtitleLayout.setVisibility(View.GONE);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        if (localStyle.getSubtitlesFollowVideo() != style.getSubtitlesFollowVideo()) {
 | 
				
			||||||
 | 
					            // No need to manipulate layout if value didn't change
 | 
				
			||||||
 | 
					            if (style.getSubtitlesFollowVideo()) {
 | 
				
			||||||
 | 
					                removeViewInLayout(subtitleLayout);
 | 
				
			||||||
 | 
					                layout.addView(subtitleLayout, layoutParams);
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                layout.removeViewInLayout(subtitleLayout);
 | 
				
			||||||
 | 
					                addViewInLayout(subtitleLayout, 1, layoutParams, false);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            requestLayout();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        localStyle = style;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public void setShutterColor(Integer color) {
 | 
					    public void setShutterColor(Integer color) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -846,14 +846,18 @@ source={{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
### `subtitleStyle`
 | 
					### `subtitleStyle`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| Property      | Description                                                                                                                                                                                        | Platforms    |
 | 
					<PlatformsList types={['Android', 'iOS']} />
 | 
				
			||||||
| ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
 | 
					
 | 
				
			||||||
| fontSize      | Adjust the font size of the subtitles. Default: font size of the device                                                                                                                            | Android      |
 | 
					| Property      | Platform | Description                                                                                                                                                                                        | Platforms    |
 | 
				
			||||||
| paddingTop    | Adjust the top padding of the subtitles. Default: 0                                                                                                                                                | Android      |
 | 
					| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ |
 | 
				
			||||||
| paddingBottom | Adjust the bottom padding of the subtitles. Default: 0                                                                                                                                             | Android      |
 | 
					| fontSize      | Android  | Adjust the font size of the subtitles. Default: font size of the device                                                                                                                            | Android      |
 | 
				
			||||||
| paddingLeft   | Adjust the left padding of the subtitles. Default: 0                                                                                                                                               | Android      |
 | 
					| paddingTop    | Android  | Adjust the top padding of the subtitles. Default: 0                                                                                                                                                | Android      |
 | 
				
			||||||
| paddingRight  | Adjust the right padding of the subtitles. Default: 0                                                                                                                                              | Android      |
 | 
					| paddingBottom | Android  | Adjust the bottom padding of the subtitles. Default: 0                                                                                                                                             | Android      |
 | 
				
			||||||
| opacity       | Adjust the visibility of subtitles with 0 hiding and 1 fully showing them. Android supports float values between 0 and 1 for varying opacity levels, whereas iOS supports only 0 or 1. Default: 1. | Android, iOS |
 | 
					| paddingLeft   | Android  | Adjust the left padding of the subtitles. Default: 0                                                                                                                                               | Android      |
 | 
				
			||||||
 | 
					| paddingRight  | Android  | Adjust the right padding of the subtitles. Default: 0                                                                                                                                              | Android      |
 | 
				
			||||||
 | 
					| opacity       | Android, iOS | Adjust the visibility of subtitles with 0 hiding and 1 fully showing them. Android supports float values between 0 and 1 for varying opacity levels, whereas iOS supports only 0 or 1. Default: 1. | Android, iOS |
 | 
				
			||||||
 | 
					| subtitlesFollowVideo | Android | Boolean to adjust position of subtitles. Default: true |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Example:
 | 
					Example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -861,6 +865,27 @@ Example:
 | 
				
			|||||||
subtitleStyle={{ paddingBottom: 50, fontSize: 20, opacity: 0 }}
 | 
					subtitleStyle={{ paddingBottom: 50, fontSize: 20, opacity: 0 }}
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note for `subtitlesFollowVideo`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`subtitlesFollowVideo` helps to determine how the subtitles are positionned.
 | 
				
			||||||
 | 
					To understand this prop you need to understand how views management works.
 | 
				
			||||||
 | 
					The main View style passed to react native video is the position reserved to display the video component.
 | 
				
			||||||
 | 
					It may not match exactly the real video size.
 | 
				
			||||||
 | 
					For exemple, you can pass a 4:3 video view and render a 16:9 video inside.
 | 
				
			||||||
 | 
					So there is a second view, the video view.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Subtitles are managed in a third view.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					First react-native-video resize the video to keep aspect ratio (depending on `resizeMode` property) and put it in main view.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* When putting subtitlesFollowVideo to true, the subtitle view will be adapt to the video view.
 | 
				
			||||||
 | 
					It means that if the video is displayed out of screen, the subtitles may also be displayed out of screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* When putting subtitlesFollowVideo to false, the subtitle view will keep adapting to the main view.
 | 
				
			||||||
 | 
					It means that if the video is displayed out of screen, the subtitles may also be displayed out of screen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This prop can be changed on runtime.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### `textTracks`
 | 
					### `textTracks`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<PlatformsList types={['Android', 'iOS', 'visionOS']} />
 | 
					<PlatformsList types={['Android', 'iOS', 'visionOS']} />
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -268,6 +268,7 @@ const VideoPlayer: FC<Props> = ({}) => {
 | 
				
			|||||||
            onPlaybackStateChanged={onPlaybackStateChanged}
 | 
					            onPlaybackStateChanged={onPlaybackStateChanged}
 | 
				
			||||||
            bufferingStrategy={BufferingStrategyType.DEFAULT}
 | 
					            bufferingStrategy={BufferingStrategyType.DEFAULT}
 | 
				
			||||||
            debug={{enable: true, thread: true}}
 | 
					            debug={{enable: true, thread: true}}
 | 
				
			||||||
 | 
					            subtitleStyle={{subtitlesFollowVideo: true}}
 | 
				
			||||||
          />
 | 
					          />
 | 
				
			||||||
        </TouchableOpacity>
 | 
					        </TouchableOpacity>
 | 
				
			||||||
      )}
 | 
					      )}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -131,6 +131,7 @@ type SubtitleStyle = Readonly<{
 | 
				
			|||||||
  paddingLeft?: WithDefault<Float, 0>;
 | 
					  paddingLeft?: WithDefault<Float, 0>;
 | 
				
			||||||
  paddingRight?: WithDefault<Float, 0>;
 | 
					  paddingRight?: WithDefault<Float, 0>;
 | 
				
			||||||
  opacity?: WithDefault<Float, 1>;
 | 
					  opacity?: WithDefault<Float, 1>;
 | 
				
			||||||
 | 
					  subtitlesFollowVideo?: WithDefault<boolean, true>;
 | 
				
			||||||
}>;
 | 
					}>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type OnLoadData = Readonly<{
 | 
					type OnLoadData = Readonly<{
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -168,6 +168,7 @@ export type SubtitleStyle = {
 | 
				
			|||||||
  paddingLeft?: number;
 | 
					  paddingLeft?: number;
 | 
				
			||||||
  paddingRight?: number;
 | 
					  paddingRight?: number;
 | 
				
			||||||
  opacity?: number;
 | 
					  opacity?: number;
 | 
				
			||||||
 | 
					  subtitlesFollowVideo?: boolean;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export enum TextTrackType {
 | 
					export enum TextTrackType {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user