diff --git a/android/src/main/java/com/brentvatne/common/api/ControlsConfig.kt b/android/src/main/java/com/brentvatne/common/api/ControlsConfig.kt
new file mode 100644
index 0000000000..cdc282f76e
--- /dev/null
+++ b/android/src/main/java/com/brentvatne/common/api/ControlsConfig.kt
@@ -0,0 +1,21 @@
+package com.brentvatne.common.api
+
+import com.brentvatne.common.toolbox.ReactBridgeUtils
+import com.facebook.react.bridge.ReadableMap
+
+class ControlsConfig {
+ var hideSeekBar: Boolean = false
+
+ companion object {
+ @JvmStatic
+ fun parse(src: ReadableMap?): ControlsConfig {
+ val config = ControlsConfig()
+
+ if (src != null) {
+ config.hideSeekBar = ReactBridgeUtils.safeGetBool(src, "hideSeekBar", false)
+ }
+
+ return config
+ }
+ }
+}
diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
index 9bd900f4f9..2d505e139d 100644
--- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
+++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
@@ -29,6 +29,8 @@
import android.view.accessibility.CaptioningManager;
import android.widget.FrameLayout;
import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
import androidx.activity.OnBackPressedCallback;
import androidx.annotation.NonNull;
@@ -102,10 +104,12 @@
import androidx.media3.extractor.metadata.id3.Id3Frame;
import androidx.media3.extractor.metadata.id3.TextInformationFrame;
import androidx.media3.session.MediaSessionService;
+import androidx.media3.ui.DefaultTimeBar;
import androidx.media3.ui.LegacyPlayerControlView;
import com.brentvatne.common.api.BufferConfig;
import com.brentvatne.common.api.BufferingStrategy;
+import com.brentvatne.common.api.ControlsConfig;
import com.brentvatne.common.api.ResizeMode;
import com.brentvatne.common.api.SideLoadedTextTrack;
import com.brentvatne.common.api.SideLoadedTextTrackList;
@@ -120,6 +124,7 @@
import com.brentvatne.receiver.AudioBecomingNoisyReceiver;
import com.brentvatne.receiver.BecomingNoisyListener;
import com.facebook.react.bridge.LifecycleEventListener;
+import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.UiThreadUtil;
import com.facebook.react.uimanager.ThemedReactContext;
import com.google.ads.interactivemedia.v3.api.AdError;
@@ -212,6 +217,7 @@ public class ReactExoplayerView extends FrameLayout implements
private Handler mainHandler;
private Runnable mainRunnable;
private DataSource.Factory cacheDataSourceFactory;
+ private ControlsConfig controlsConfig = new ControlsConfig();
// Props from React
private Uri srcUri;
@@ -451,6 +457,7 @@ public void handleOnBackPressed() {
final ImageButton fullScreenButton = playerControlView.findViewById(R.id.exo_fullscreen);
fullScreenButton.setOnClickListener(v -> setFullscreen(!isFullscreen));
updateFullScreenButtonVisbility();
+ refreshProgressBarVisibility();
// Invoking onPlaybackStateChanged and onPlayWhenReadyChanged events for Player
eventListener = new Player.Listener() {
@@ -509,6 +516,35 @@ 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);
+ exoDuration.setVisibility(VISIBLE);
+ // 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);
+ }
+ }
+
private void reLayoutControls() {
reLayout(exoPlayerView);
reLayout(playerControlView);
@@ -2296,4 +2332,9 @@ public void onAdError(AdErrorEvent adErrorEvent) {
AdError error = adErrorEvent.getError();
eventEmitter.receiveAdErrorEvent(error.getMessage(), String.valueOf(error.getErrorCode()), String.valueOf(error.getErrorType()));
}
+
+ public void setControlsStyles(ControlsConfig controlsStyles) {
+ controlsConfig = controlsStyles;
+ refreshProgressBarVisibility();
+ }
}
diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java
index 74f818f5c0..fd4efd85f2 100644
--- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java
+++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java
@@ -13,6 +13,7 @@
import com.brentvatne.common.api.BufferConfig;
import com.brentvatne.common.api.BufferingStrategy;
+import com.brentvatne.common.api.ControlsConfig;
import com.brentvatne.common.api.ResizeMode;
import com.brentvatne.common.api.SideLoadedTextTrackList;
import com.brentvatne.common.api.SubtitleStyle;
@@ -88,6 +89,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager
+
+Adjust the control styles. This prop is need only if `controls={true}` and is an object. See the list of prop supported below.
+
+| Property | Type | Description |
+|-------------|---------|--------------------------------------------------------------------------------------|
+| hideSeekBar | boolean | The default value is `false`, allowing you to hide the seek bar for live broadcasts. |
+
+Example with default values:
+
+```javascript
+controlsStyles={{
+ hideSeekBar: false,
+}}
+```
+
+
### `bufferConfig`
@@ -797,7 +816,7 @@ textTracks={[
-Controls whether to show media controls in the notification area.
+Controls whether to show media controls in the notification area.
For Android each Video component will have its own notification controls and for iOS only one notification control will be shown for the last Active Video component.
You propably want also set `playInBackground` to `true` to keep the video playing when the app is in the background or `playWhenInactive` to `true` to keep the video playing when notifications or the Control Center are in front of the video.
diff --git a/src/specs/VideoNativeComponent.ts b/src/specs/VideoNativeComponent.ts
index 4f1c738fb7..53cec03b46 100644
--- a/src/specs/VideoNativeComponent.ts
+++ b/src/specs/VideoNativeComponent.ts
@@ -273,6 +273,10 @@ export type OnAudioFocusChangedData = Readonly<{
hasAudioFocus: boolean;
}>;
+type ControlsStyles = Readonly<{
+ hideSeekBar?: boolean;
+}>;
+
export interface VideoNativeProps extends ViewProps {
src?: VideoSrc;
drm?: Drm;
@@ -320,6 +324,7 @@ export interface VideoNativeProps extends ViewProps {
useTextureView?: boolean; // Android
useSecureView?: boolean; // Android
bufferingStrategy?: BufferingStrategyType; // Android
+ controlsStyles?: ControlsStyles; // Android
onVideoLoad?: DirectEventHandler;
onVideoLoadStart?: DirectEventHandler;
onVideoAspectRatio?: DirectEventHandler;
diff --git a/src/types/video.ts b/src/types/video.ts
index e174bbbf75..56694ecd24 100644
--- a/src/types/video.ts
+++ b/src/types/video.ts
@@ -193,6 +193,10 @@ export enum PosterResizeModeType {
export type AudioOutput = 'speaker' | 'earpiece';
+export type ControlsStyles = {
+ hideSeekBar?: boolean;
+};
+
export interface ReactVideoProps extends ReactVideoEvents, ViewProps {
source?: ReactVideoSource;
drm?: Drm;
@@ -247,4 +251,5 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps {
localSourceEncryptionKeyScheme?: string;
debug?: DebugConfig;
allowsExternalPlayback?: boolean; // iOS
+ controlsStyles?: ControlsStyles; // Android
}