Skip to content

Commit

Permalink
feat(android): add possibility to hide seekBar (#3789)
Browse files Browse the repository at this point in the history
* feat: hide seekBar on Android when a video is a live broadcast

* refactor: prop name & code

* chore: update the document for a new prop (controlsStyles)

* refactor: code

* remove: additional variables

* fix: indent issues

* remove: duplicate function

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

revert change1

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

revert change2

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

chore: revert indent change

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

chore: revert indent change

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

chore: revert indent change

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

chore: revert indent change

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java

chore: revert indent change

* fix: eslint errors

* Update android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java

chore: revert indent change

---------

Co-authored-by: Olivier Bouillet <[email protected]>
  • Loading branch information
seyedmostafahasani and freeboub authored May 20, 2024
1 parent 3cd7ab6 commit 95e6140
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 2 deletions.
21 changes: 21 additions & 0 deletions android/src/main/java/com/brentvatne/common/api/ControlsConfig.kt
Original file line number Diff line number Diff line change
@@ -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
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -88,6 +89,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
private static final String PROP_SHUTTER_COLOR = "shutterColor";
private static final String PROP_SHOW_NOTIFICATION_CONTROLS = "showNotificationControls";
private static final String PROP_DEBUG = "debug";
private static final String PROP_CONTROLS_STYLES = "controlsStyles";

private final ReactExoplayerConfig config;

Expand Down Expand Up @@ -451,6 +453,12 @@ public void setDebug(final ReactExoplayerView videoView,
videoView.setDebug(enableDebug);
}

@ReactProp(name = PROP_CONTROLS_STYLES)
public void setControlsStyles(final ReactExoplayerView videoView, @Nullable ReadableMap controlsStyles) {
ControlsConfig controlsConfig = ControlsConfig.parse(controlsStyles);
videoView.setControlsStyles(controlsConfig);
}

private boolean startsWithValidScheme(String uriString) {
String lowerCaseUri = uriString.toLowerCase();
return lowerCaseUri.startsWith("http://")
Expand All @@ -460,4 +468,4 @@ private boolean startsWithValidScheme(String uriString) {
|| lowerCaseUri.startsWith("rtsp://")
|| lowerCaseUri.startsWith("asset://");
}
}
}
21 changes: 20 additions & 1 deletion docs/pages/component/props.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,25 @@ A Boolean value that indicates whether the player should automatically delay pla
- **false** - Immediately starts playback
- **true (default)** - Delays playback in order to minimize stalling

### `controlsStyles`

<PlatformsList types={['Android']} />

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`

<PlatformsList types={['Android']} />
Expand Down Expand Up @@ -797,7 +816,7 @@ textTracks={[

<PlatformsList types={['Android', 'iOS']}/>

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.
Expand Down
5 changes: 5 additions & 0 deletions src/specs/VideoNativeComponent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,10 @@ export type OnAudioFocusChangedData = Readonly<{
hasAudioFocus: boolean;
}>;

type ControlsStyles = Readonly<{
hideSeekBar?: boolean;
}>;

export interface VideoNativeProps extends ViewProps {
src?: VideoSrc;
drm?: Drm;
Expand Down Expand Up @@ -320,6 +324,7 @@ export interface VideoNativeProps extends ViewProps {
useTextureView?: boolean; // Android
useSecureView?: boolean; // Android
bufferingStrategy?: BufferingStrategyType; // Android
controlsStyles?: ControlsStyles; // Android
onVideoLoad?: DirectEventHandler<OnLoadData>;
onVideoLoadStart?: DirectEventHandler<OnLoadStartData>;
onVideoAspectRatio?: DirectEventHandler<OnVideoAspectRatioData>;
Expand Down
5 changes: 5 additions & 0 deletions src/types/video.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -247,4 +251,5 @@ export interface ReactVideoProps extends ReactVideoEvents, ViewProps {
localSourceEncryptionKeyScheme?: string;
debug?: DebugConfig;
allowsExternalPlayback?: boolean; // iOS
controlsStyles?: ControlsStyles; // Android
}

0 comments on commit 95e6140

Please sign in to comment.