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(android): add live video label #4190

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class ControlsConfig {
var hideDuration: Boolean = false
var hideNavigationBarOnFullScreenMode: Boolean = true
var hideNotificationBarOnFullScreenMode: Boolean = true
var liveLabel: String? = ""
seyedmostafahasani marked this conversation as resolved.
Show resolved Hide resolved

companion object {
@JvmStatic
Expand All @@ -21,6 +22,7 @@ class ControlsConfig {
config.hideDuration = ReactBridgeUtils.safeGetBool(src, "hideDuration", false)
config.hideNavigationBarOnFullScreenMode = ReactBridgeUtils.safeGetBool(src, "hideNavigationBarOnFullScreenMode", true)
config.hideNotificationBarOnFullScreenMode = ReactBridgeUtils.safeGetBool(src, "hideNotificationBarOnFullScreenMode", true)
config.liveLabel = ReactBridgeUtils.safeGetString(src, "liveLabel", "")
seyedmostafahasani marked this conversation as resolved.
Show resolved Hide resolved
}
return config
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import android.view.Window
import android.view.WindowManager
import android.widget.FrameLayout
import android.widget.ImageButton
import android.widget.LinearLayout
import androidx.activity.OnBackPressedCallback
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
Expand Down Expand Up @@ -216,5 +217,13 @@ class FullScreenPlayerView(
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
)
}
if (controlsConfig.hideNotificationBarOnFullScreenMode) {
val liveContainer = playerControlView?.findViewById<LinearLayout?>(com.brentvatne.react.R.id.exo_live_container)
liveContainer?.let {
val layoutParams = it.layoutParams as LinearLayout.LayoutParams
layoutParams.topMargin = 40
it.layoutParams = layoutParams
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
Expand Down Expand Up @@ -466,7 +467,6 @@ public void onVisibilityChange(int visibility) {
final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
fullScreenButton.setOnClickListener(v -> setFullscreen(!isFullscreen));
updateFullScreenButtonVisibility();
refreshProgressBarVisibility();

// Invoking onPlaybackStateChanged and onPlayWhenReadyChanged events for Player
eventListener = new Player.Listener() {
Expand Down Expand Up @@ -525,41 +525,42 @@ private void reLayout(View view) {
view.layout(view.getLeft(), view.getTop(), view.getMeasuredWidth(), view.getMeasuredHeight());
}

private void refreshProgressBarVisibility (){
if(playerControlView == null) return;
DefaultTimeBar exoProgress;
TextView exoDuration;
TextView exoPosition;
exoProgress = playerControlView.findViewById(R.id.exo_progress);
exoDuration = playerControlView.findViewById(R.id.exo_duration);
exoPosition = playerControlView.findViewById(R.id.exo_position);
if(controlsConfig.getHideSeekBar()){
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT,
1.0f
);
exoProgress.setVisibility(GONE);
exoDuration.setVisibility(GONE);
exoPosition.setLayoutParams(param);
}else{
exoProgress.setVisibility(VISIBLE);
private void refreshControlsStyles() {
if (playerControlView == null || player == null) return;

if(controlsConfig.getHideDuration()){
exoDuration.setVisibility(GONE);
}else{
exoDuration.setVisibility(VISIBLE);
}
DefaultTimeBar exoProgress = playerControlView.findViewById(R.id.exo_progress);
TextView exoDuration = playerControlView.findViewById(R.id.exo_duration);
LinearLayout exoLiveContainer = playerControlView.findViewById(R.id.exo_live_container);
TextView exoLiveLabel = playerControlView.findViewById(R.id.exo_live_label);

// Reset the layout parameters of exoPosition to their default state
LinearLayout.LayoutParams defaultParam = new LinearLayout.LayoutParams(
LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT
);
exoPosition.setLayoutParams(defaultParam);
boolean isLive = false;
Timeline timeline = player.getCurrentTimeline();

// Determine if the content is live
if (!timeline.isEmpty()) {
Timeline.Window window = new Timeline.Window();
timeline.getWindow(player.getCurrentMediaItemIndex(), window);
isLive = window.isLive();
}

if(isLive && !Objects.equals(controlsConfig.getLiveLabel(), "")){
seyedmostafahasani marked this conversation as resolved.
Show resolved Hide resolved
exoLiveLabel.setText(controlsConfig.getLiveLabel());
exoLiveContainer.setVisibility(View.VISIBLE);
}else{
exoLiveContainer.setVisibility(View.GONE);
}

if (controlsConfig.getHideSeekBar()) {
exoProgress.setVisibility(View.INVISIBLE);
}else{
exoProgress.setVisibility(View.VISIBLE);
}

// Handle duration visibility based on configuration or live video
exoDuration.setVisibility(controlsConfig.getHideDuration() || isLive ? View.INVISIBLE : View.VISIBLE);
}


private void reLayoutControls() {
reLayout(exoPlayerView);
reLayout(playerControlView);
Expand Down Expand Up @@ -1459,6 +1460,7 @@ private void videoLoaded() {

eventEmitter.onVideoLoad.invoke(duration, currentPosition, width, height,
audioTracks, textTracks, videoTracks, trackId);
refreshControlsStyles();
}
}

Expand Down Expand Up @@ -2357,6 +2359,7 @@ public void setControls(boolean controls) {
removeViewAt(indexOfPC);
}
}
refreshControlsStyles();
}

public void setSubtitleStyle(SubtitleStyle style) {
Expand Down Expand Up @@ -2389,6 +2392,6 @@ public void onAdError(AdErrorEvent adErrorEvent) {

public void setControlsStyles(ControlsConfig controlsStyles) {
controlsConfig = controlsStyles;
refreshProgressBarVisibility();
refreshControlsStyles();
}
}
6 changes: 6 additions & 0 deletions android/src/main/res/drawable/circle.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/red"/>
<size android:width="10dp" android:height="10dp"/>
</shape>
35 changes: 33 additions & 2 deletions android/src/main/res/layout/exo_legacy_player_control_view.xml
Original file line number Diff line number Diff line change
@@ -1,17 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_height="match_parent"
android:layoutDirection="ltr"
android:background="@color/midnight_black"
android:orientation="vertical">

<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone"
android:gravity="center_vertical"
android:layout_marginTop="@dimen/live_wrapper_margin_top"
android:id="@+id/exo_live_container">

<ImageView
android:id="@+id/exo_live_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingHorizontal="@dimen/position_duration_horizontal_padding"
android:src="@drawable/circle" />

<TextView android:id="@+id/exo_live_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="@dimen/position_duration_text_size"
android:textStyle="bold"
android:includeFontPadding="false"
android:textColor="@color/white"/>
</LinearLayout>

<View
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="1"
/>

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:paddingTop="@dimen/controller_wrapper_padding_top"
android:layout_gravity="bottom"
android:orientation="horizontal">

<ImageButton android:id="@+id/exo_prev"
Expand Down
2 changes: 2 additions & 0 deletions android/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
<resources>
<color name="silver_gray">#FFBEBEBE</color>
<color name="midnight_black">#CC000000</color>
<color name="white">#FFFFFF</color>
<color name="red">#FF0000</color>
</resources>
1 change: 1 addition & 0 deletions android/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
<!-- margin & padding-->
<dimen name="controller_wrapper_padding_top">4dp</dimen>
<dimen name="seekBar_wrapper_margin_top">4dp</dimen>
<dimen name="live_wrapper_margin_top">12dp</dimen>
<dimen name="position_duration_horizontal_padding">4dp</dimen>
<dimen name="full_screen_margin">4dp</dimen>

Expand Down
4 changes: 3 additions & 1 deletion examples/basic/src/VideoPlayer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import Video, {
type SelectedVideoTrack,
type EnumValues,
OnBandwidthUpdateData,
ControlsStyles,
} from 'react-native-video';
import styles from './styles';
import {type AdditionalSourceInfo} from './types';
Expand Down Expand Up @@ -239,9 +240,10 @@ const VideoPlayer: FC<Props> = ({}) => {
const _renderLoader = showPoster ? () => <VideoLoader /> : undefined;

const _subtitleStyle = {subtitlesFollowVideo: true};
const _controlsStyles = {
const _controlsStyles : ControlsStyles = {
hideNavigationBarOnFullScreenMode: true,
hideNotificationBarOnFullScreenMode: true,
liveLabel: "LIVE"
};
const _bufferConfig = {
...bufferConfig,
Expand Down
1 change: 1 addition & 0 deletions src/specs/VideoNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,7 @@ type ControlsStyles = Readonly<{
seekIncrementMS?: Int32;
hideNavigationBarOnFullScreenMode?: WithDefault<boolean, true>;
hideNotificationBarOnFullScreenMode?: WithDefault<boolean, true>;
liveLabel?: string;
}>;

export type OnControlsVisibilityChange = 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 @@ -253,6 +253,7 @@ export type ControlsStyles = {
seekIncrementMS?: number;
hideNavigationBarOnFullScreenMode?: boolean;
hideNotificationBarOnFullScreenMode?: boolean;
liveLabel?: string;
};

export interface ReactVideoRenderLoaderProps {
Expand Down
Loading