diff --git a/android/src/main/java/com/brentvatne/common/api/SubtitleStyle.kt b/android/src/main/java/com/brentvatne/common/api/SubtitleStyle.kt index 1e32c77a..efb4da0a 100644 --- a/android/src/main/java/com/brentvatne/common/api/SubtitleStyle.kt +++ b/android/src/main/java/com/brentvatne/common/api/SubtitleStyle.kt @@ -17,6 +17,8 @@ class SubtitleStyle private constructor() { private set var paddingBottom = 0 private set + var opacity = 1f + private set companion object { private const val PROP_FONT_SIZE_TRACK = "fontSize" @@ -24,6 +26,7 @@ class SubtitleStyle private constructor() { private const val PROP_PADDING_TOP = "paddingTop" private const val PROP_PADDING_LEFT = "paddingLeft" private const val PROP_PADDING_RIGHT = "paddingRight" + private const val PROP_OPACITY = "opacity" @JvmStatic fun parse(src: ReadableMap?): SubtitleStyle { @@ -33,6 +36,7 @@ class SubtitleStyle private constructor() { subtitleStyle.paddingTop = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_TOP, 0) subtitleStyle.paddingLeft = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_LEFT, 0) subtitleStyle.paddingRight = ReactBridgeUtils.safeGetInt(src, PROP_PADDING_RIGHT, 0) + subtitleStyle.opacity = ReactBridgeUtils.safeGetFloat(src, PROP_OPACITY, 1f) return subtitleStyle } } diff --git a/android/src/main/java/com/brentvatne/common/toolbox/ReactBridgeUtils.kt b/android/src/main/java/com/brentvatne/common/toolbox/ReactBridgeUtils.kt index 65dc57a5..c2ee2492 100644 --- a/android/src/main/java/com/brentvatne/common/toolbox/ReactBridgeUtils.kt +++ b/android/src/main/java/com/brentvatne/common/toolbox/ReactBridgeUtils.kt @@ -66,6 +66,14 @@ object ReactBridgeUtils { return safeGetDouble(map, key, 0.0) } + @JvmStatic fun safeGetFloat(map: ReadableMap?, key: String?, fallback: Float): Float { + return if (map != null && map.hasKey(key!!) && !map.isNull(key)) map.getDouble(key).toFloat() else fallback + } + + @JvmStatic fun safeGetFloat(map: ReadableMap?, key: String?): Float { + return safeGetFloat(map, key, 0.0f) + } + /** * toStringMap converts a [ReadableMap] into a HashMap. * diff --git a/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java index b00b4e95..ebe05d16 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java @@ -117,6 +117,13 @@ public final class ExoPlayerView extends FrameLayout implements AdViewProvider { subtitleLayout.setFixedTextSize(TypedValue.COMPLEX_UNIT_SP, style.getFontSize()); } subtitleLayout.setPadding(style.getPaddingLeft(), style.getPaddingTop(), style.getPaddingRight(), style.getPaddingBottom()); + if (style.getOpacity() != 0) { + subtitleLayout.setAlpha(style.getOpacity()); + subtitleLayout.setVisibility(View.VISIBLE); + } else { + subtitleLayout.setVisibility(View.GONE); + } + } public void setShutterColor(Integer color) { diff --git a/docs/pages/component/events.mdx b/docs/pages/component/events.mdx index fab327f8..09d50a29 100644 --- a/docs/pages/component/events.mdx +++ b/docs/pages/component/events.mdx @@ -534,6 +534,8 @@ Example: } ``` +For details on how to control the visibility of subtitles, see the [subtitleStyle](./props.mdx#subtitleStyle) section. + ### `onVideoTracks` diff --git a/docs/pages/component/props.mdx b/docs/pages/component/props.mdx index cb87d463..e3c7986d 100644 --- a/docs/pages/component/props.mdx +++ b/docs/pages/component/props.mdx @@ -748,11 +748,12 @@ source={{ | paddingBottom | Adjust the bottom padding of the subtitles. Default: 0 | Android | | paddingLeft | Adjust the left padding of the subtitles. Default: 0 | Android | | paddingRight | Adjust the right 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 | Example: ```javascript -subtitleStyle={{ paddingBottom: 50, fontSize: 20 }} +subtitleStyle={{ paddingBottom: 50, fontSize: 20, opacity: 0 }} ``` ### `textTracks` diff --git a/ios/Video/DataStructures/SubtitleStyle.swift b/ios/Video/DataStructures/SubtitleStyle.swift new file mode 100644 index 00000000..76bd8632 --- /dev/null +++ b/ios/Video/DataStructures/SubtitleStyle.swift @@ -0,0 +1,17 @@ +struct SubtitleStyle { + // Extend with more style properties as needed. + private(set) var opacity: CGFloat + + enum SubtitleStyleKeys { + static let opacity = "opacity" + } + + init(opacity: CGFloat = 1) { + self.opacity = opacity + } + + static func parse(from dictionary: [String: Any]?) -> SubtitleStyle { + let opacity = dictionary?[SubtitleStyleKeys.opacity] as? CGFloat ?? 1 + return SubtitleStyle(opacity: opacity) + } +} diff --git a/ios/Video/Features/RCTPlayerObserver.swift b/ios/Video/Features/RCTPlayerObserver.swift index c1c93262..22db23a8 100644 --- a/ios/Video/Features/RCTPlayerObserver.swift +++ b/ios/Video/Features/RCTPlayerObserver.swift @@ -47,6 +47,8 @@ class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate, AVPla } } + var subtitleStyle: SubtitleStyle? + var playerItem: AVPlayerItem? { willSet { removePlayerItemObservers() @@ -63,6 +65,7 @@ class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate, AVPla playerItem.add(legibleOutput) metadataOutput.setDelegate(self, queue: .main) legibleOutput.setDelegate(self, queue: .main) + legibleOutput.suppressesPlayerRendering = subtitleStyle?.opacity == 0 ? true : false } } diff --git a/ios/Video/RCTVideo.swift b/ios/Video/RCTVideo.swift index 2c051cf0..7ff053eb 100644 --- a/ios/Video/RCTVideo.swift +++ b/ios/Video/RCTVideo.swift @@ -953,6 +953,12 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH _playerObserver.playerLayer = nil } + @objc + func setSubtitleStyle(_ style: [String: Any]) { + let subtitleStyle = SubtitleStyle.parse(from: style) + _playerObserver.subtitleStyle = subtitleStyle + } + // MARK: - RCTVideoPlayerViewControllerDelegate func videoPlayerViewControllerWillDismiss(playerViewController: AVPlayerViewController) { diff --git a/ios/Video/RCTVideoManager.m b/ios/Video/RCTVideoManager.m index e30f6c9c..de1140ef 100644 --- a/ios/Video/RCTVideoManager.m +++ b/ios/Video/RCTVideoManager.m @@ -37,7 +37,7 @@ RCT_EXPORT_VIEW_PROPERTY(filterEnabled, BOOL); RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float); RCT_EXPORT_VIEW_PROPERTY(restoreUserInterfaceForPIPStopCompletionHandler, BOOL); RCT_EXPORT_VIEW_PROPERTY(localSourceEncryptionKeyScheme, NSString); - +RCT_EXPORT_VIEW_PROPERTY(subtitleStyle, NSDictionary); /* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */ RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTDirectEventBlock); RCT_EXPORT_VIEW_PROPERTY(onVideoLoad, RCTDirectEventBlock); diff --git a/src/specs/VideoNativeComponent.ts b/src/specs/VideoNativeComponent.ts index 718ffbfc..6d718b8d 100644 --- a/src/specs/VideoNativeComponent.ts +++ b/src/specs/VideoNativeComponent.ts @@ -118,6 +118,7 @@ type SubtitleStyle = Readonly<{ paddingBottom?: WithDefault; paddingLeft?: WithDefault; paddingRight?: WithDefault; + opacity?: WithDefault; }>; export type OnLoadData = Readonly<{ diff --git a/src/types/video.ts b/src/types/video.ts index 6fa2841e..5f505118 100644 --- a/src/types/video.ts +++ b/src/types/video.ts @@ -104,6 +104,7 @@ export type SubtitleStyle = { paddingBottom?: number; paddingLeft?: number; paddingRight?: number; + opacity?: number; }; export enum TextTracksType {