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:
		
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							3cd7ab60b2
						
					
				
				
					commit
					95e6140eea
				
			| @@ -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 | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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(); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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://") | ||||
|   | ||||
| @@ -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']} /> | ||||
|   | ||||
| @@ -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>; | ||||
|   | ||||
| @@ -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 | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user