Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement opacity to control visibility of subtitles #3583

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ 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"
private const val PROP_PADDING_BOTTOM = "paddingBottom"
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 {
Expand All @@ -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
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,13 @@ public void setSubtitleStyle(SubtitleStyle style) {
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());
coofzilla marked this conversation as resolved.
Show resolved Hide resolved
subtitleLayout.setVisibility(View.VISIBLE);
} else {
subtitleLayout.setVisibility(View.GONE);
}

}

public void setShutterColor(Integer color) {
Expand Down
2 changes: 2 additions & 0 deletions docs/pages/component/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,8 @@ Example:
}
```

For details on how to control the visibility of subtitles, see the [subtitleStyle](./props.mdx#subtitleStyle) section.

### `onVideoTracks`

<PlatformsList types={['Android']} />
Expand Down
3 changes: 2 additions & 1 deletion docs/pages/component/props.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -739,11 +739,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`
Expand Down
17 changes: 17 additions & 0 deletions ios/Video/DataStructures/SubtitleStyle.swift
Original file line number Diff line number Diff line change
@@ -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)
}
}
3 changes: 3 additions & 0 deletions ios/Video/Features/RCTPlayerObserver.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class RCTPlayerObserver: NSObject, AVPlayerItemMetadataOutputPushDelegate, AVPla
}
}

var subtitleStyle: SubtitleStyle?

var playerItem: AVPlayerItem? {
willSet {
removePlayerItemObservers()
Expand All @@ -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
}
}

Expand Down
6 changes: 6 additions & 0 deletions ios/Video/RCTVideo.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion ios/Video/RCTVideoManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ @interface RCT_EXTERN_MODULE (RCTVideoManager, RCTViewManager)
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);
Expand Down
1 change: 1 addition & 0 deletions src/specs/VideoNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ type SubtitleStyle = Readonly<{
paddingBottom?: WithDefault<Float, 0>;
paddingLeft?: WithDefault<Float, 0>;
paddingRight?: WithDefault<Float, 0>;
opacity?: WithDefault<Float, 1>;
}>;

export type OnLoadData = Readonly<{
Expand Down
1 change: 1 addition & 0 deletions src/types/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ export type SubtitleStyle = {
paddingBottom?: number;
paddingLeft?: number;
paddingRight?: number;
opacity?: number;
};

export enum TextTracksType {
Expand Down
Loading