feat(android): add possibility to hide seekBar (#3789)

* 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 <62574056+freeboub@users.noreply.github.com>
This commit is contained in:
Seyed Mostafa Hasani 2024-05-20 14:15:18 +03:30 committed by GitHub
parent 3cd7ab60b2
commit 95e6140eea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 101 additions and 2 deletions

View File

@ -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
}
}
}

View File

@ -29,6 +29,8 @@ import android.view.Window;
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.emsg.EventMessage;
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.react.R;
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 class ReactExoplayerView extends FrameLayout implements
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 @@ public class ReactExoplayerView extends FrameLayout implements
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 class ReactExoplayerView extends FrameLayout implements
AdError error = adErrorEvent.getError();
eventEmitter.receiveAdErrorEvent(error.getMessage(), String.valueOf(error.getErrorCode()), String.valueOf(error.getErrorType()));
}
public void setControlsStyles(ControlsConfig controlsStyles) {
controlsConfig = controlsStyles;
refreshProgressBarVisibility();
}
}

View File

@ -13,6 +13,7 @@ import androidx.media3.datasource.RawResourceDataSource;
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<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;
@ -451,6 +453,12 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
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://")

View File

@ -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']} />

View File

@ -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<OnLoadData>;
onVideoLoadStart?: DirectEventHandler<OnLoadStartData>;
onVideoAspectRatio?: DirectEventHandler<OnVideoAspectRatioData>;

View File

@ -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
}