in example/src/screens/PlaygroundExample.tsx [64:469]
export default function PlaygroundExample() {
const { setOptions } = useNavigation<PlaygroundScreenNavigationProp>();
const mediaPlayerRef = React.useRef<IVSPlayerRef>(null);
const [isModalOpened, setIsModalOpened] = useState(false);
const [autoplay, setAutoplay] = useState(true);
const [paused, setPaused] = useState(false);
const [url, setUrl] = useState(URL);
const [origin, setOrigin] = useState('');
const [muted, setMuted] = useState(false);
const [pauseInBackground, setPauseInBackground] = useState(false);
const [manualQuality, setManualQuality] = useState<Quality | null>(null);
const [detectedQuality, setDetectedQuality] = useState<Quality | null>(null);
const [initialBufferDuration, setInitialBufferDuration] = useState(0.1);
const [autoMaxQuality, setAutoMaxQuality] = useState<Quality | null>(null);
const [qualities, setQualities] = useState<Quality[]>([]);
const [autoQualityMode, setAutoQualityMode] = useState(true);
const [buffering, setBuffering] = useState(false);
const [duration, setDuration] = useState<number | null>(null);
const [liveLowLatency, setLiveLowLatency] = useState(true);
const [rebufferToLive, setRebufferToLive] = useState(false);
const [playbackRate, setPlaybackRate] = useState(1);
const [logLevel, setLogLevel] = useState(LogLevel.IVSLogLevelError);
const [progressInterval, setProgressInterval] = useState(1);
const [volume, setVolume] = useState(1);
const [position, setPosition] = useState<number>();
const [lockPosition, setLockPosition] = useState(false);
const [positionSlider, setPositionSlider] = useState(0);
const [breakpoints, setBreakpoints] = useState<number[]>(INITIAL_BREAKPOINTS);
const [orientation, setOrientation] = useState(Position.PORTRAIT);
const [logs, setLogs] = useState<string[]>([]);
const [resizeMode, setResizeMode] = useState<ResizeModeOption | null>(
RESIZE_MODES[1]
);
useAppState({
onBackground: () => {
pauseInBackground && setPaused(true);
},
onForeground: () => {
pauseInBackground && setPaused(false);
},
});
const log = useCallback(
(text: string) => {
console.log(text);
setLogs((logs) => [text, ...logs.slice(0, 30)]);
},
[setLogs]
);
const onDimensionChange = useCallback(
({ window: { width, height } }) => {
if (width < height) {
setOrientation(Position.PORTRAIT);
setOptions({ headerShown: true, gestureEnabled: true });
} else {
setOrientation(Position.LANDSCAPE);
setOptions({ headerShown: false, gestureEnabled: false });
}
},
[setOptions]
);
useEffect(() => {
Dimensions.addEventListener('change', onDimensionChange);
return () => {
Dimensions.removeEventListener('change', onDimensionChange);
};
}, [onDimensionChange]);
const slidingCompleteHandler = (value: number) => {
mediaPlayerRef?.current?.seekTo(value);
};
return (
<View style={styles.container}>
<View style={styles.playerContainer}>
{/*
Note: A buffering indicator is included by default on Android. It's
styling is managed in /example/android/app/src/main/res/values/styles.xml
by adjusting the 'android:indeterminateTint'.
*/}
{buffering && Platform.OS === 'ios' ? (
<ActivityIndicator
animating={true}
size="large"
style={styles.loader}
/>
) : null}
<IVSPlayer
key={resizeMode?.value}
ref={mediaPlayerRef}
paused={paused}
resizeMode={resizeMode?.value}
muted={muted}
autoplay={autoplay}
liveLowLatency={liveLowLatency}
rebufferToLive={rebufferToLive}
streamUrl={url}
logLevel={logLevel}
initialBufferDuration={initialBufferDuration}
playbackRate={playbackRate}
progressInterval={progressInterval}
volume={volume}
autoQualityMode={autoQualityMode}
quality={manualQuality}
autoMaxQuality={autoMaxQuality}
breakpoints={breakpoints}
onSeek={(newPosition) => console.log('new position', newPosition)}
onPlayerStateChange={(state) => {
if (state === PlayerState.Buffering) {
log(`buffering at ${detectedQuality?.name}`);
}
if (state === PlayerState.Playing || state === PlayerState.Idle) {
setBuffering(false);
}
log(`state changed: ${state}`);
}}
onDurationChange={(duration) => {
setDuration(duration);
log(`duration changed: ${parseSecondsToString(duration || 0)}`);
}}
onQualityChange={(newQuality) => {
setDetectedQuality(newQuality);
log(`quality changed: ${newQuality?.name}`);
}}
onPipChange={(isActive) => {
log(`picture in picture changed - isActive: ${isActive}`);
}}
onRebuffering={() => setBuffering(true)}
onLoadStart={() => log(`load started`)}
onLoad={(loadedDuration) =>
log(
`loaded duration changed: ${parseSecondsToString(
loadedDuration || 0
)}`
)
}
onLiveLatencyChange={(liveLatency) =>
console.log(`live latency changed: ${liveLatency}`)
}
onTextCue={(textCue) => console.log('text cue', textCue)}
onTextMetadataCue={(textMetadataCue) =>
console.log('text metadata cue', textMetadataCue)
}
onProgress={(newPosition) => {
if (!lockPosition) {
setPosition(newPosition);
setPositionSlider(newPosition);
}
console.log(
`progress changed: ${parseSecondsToString(
position ? position : 0
)}`
);
}}
onData={(data) => setQualities(data.qualities)}
onVideoStatistics={(video) => console.log('onVideoStatistics', video)}
onError={(error) => console.log('error', error)}
onTimePoint={(timePoint) => console.log('time point', timePoint)}
>
{orientation === Position.PORTRAIT ? (
<>
<Button
testID="settingsIcon"
style={styles.icon}
icon="cog"
color="gray"
onPress={() => setIsModalOpened(true)}
>
Settings
</Button>
<View style={styles.playButtonContainer}>
<View style={styles.positionContainer}>
<View style={styles.durationsContainer}>
{duration && position !== null ? (
<Text style={styles.positionText} testID="videoPosition">
{parseSecondsToString(position ? position : 0)}
</Text>
) : (
<Text />
)}
{duration ? (
<Text style={styles.positionText} testID="durationLabel">
{parseSecondsToString(duration)}
</Text>
) : null}
</View>
{duration && !Number.isNaN(duration) ? (
<Slider
testID="durationSlider"
disabled={!duration || duration === Infinity}
minimumValue={0}
maximumValue={duration === Infinity ? 100 : duration}
value={duration === Infinity ? 100 : positionSlider}
onValueChange={setPosition}
onSlidingComplete={slidingCompleteHandler}
onTouchStart={() => setLockPosition(true)}
onTouchEnd={() => {
setLockPosition(false);
setPositionSlider(position ?? 0);
}}
/>
) : null}
</View>
<IconButton
testID="playPauseButton"
icon={paused ? 'play' : 'pause'}
size={40}
color="white"
onPress={() => {
setPaused((prev) => !prev);
}}
style={styles.playIcon}
/>
</View>
</>
) : null}
</IVSPlayer>
<View style={styles.logs}>
{logs.map((log, index) => (
<Text key={index} style={styles.log} accessibilityLabel={log}>
{log}
</Text>
))}
</View>
</View>
<Portal>
{isModalOpened && (
<View style={styles.modalContentContainer}>
<View style={styles.modalContent}>
<View style={styles.modalHeader}>
<Title>Settings</Title>
<Button
testID="closeIcon"
icon="close"
color="gray"
onPress={() => setIsModalOpened(false)}
>
Close
</Button>
</View>
<ScrollView testID="modalScrollView">
<View style={styles.settings}>
<SettingsInputItem
label="url"
onChangeText={setUrl}
value={url}
multiline
/>
<SettingsItem label="Quality" testID="qualitiesPicker">
<OptionPicker
option={manualQuality}
options={qualities}
autoOption
setOption={(quality) => {
setAutoQualityMode(!quality);
setManualQuality(quality);
}}
/>
</SettingsItem>
<SettingsItem label="Resize mode" testID="resizeModePicker">
<OptionPicker
option={resizeMode}
options={RESIZE_MODES}
setOption={(mode) => {
setResizeMode(mode);
log(`Resize mode changed: ${resizeMode?.value}`);
}}
/>
</SettingsItem>
<SettingsSliderItem
label={`Playback Rate: ${playbackRate}`}
minimumValue={0.5}
maximumValue={2}
step={0.1}
value={playbackRate || INITIAL_PLAYBACK_RATE}
onValueChange={(value) =>
setPlaybackRate(Number(value.toFixed(1)))
}
testID="playbackRate"
/>
<SettingsSliderItem
label={`Progress Interval: ${progressInterval}`}
minimumValue={1}
maximumValue={5}
step={1}
value={progressInterval || INITIAL_PROGRESS_INTERVAL}
onValueChange={(value) =>
setProgressInterval(Number(value))
}
testID="progressInterval"
/>
<SettingsSwitchItem
label="Muted"
value={muted}
onValueChange={setMuted}
testID="muted"
/>
<SettingsSwitchItem
label="Autoplay"
onValueChange={setAutoplay}
value={autoplay}
testID="autoplay"
/>
<SettingsSwitchItem
label="Paused"
onValueChange={setPaused}
value={paused}
testID="paused"
/>
<SettingsSliderItem
label={`Volume: ${volume.toFixed(1)}`}
minimumValue={0}
maximumValue={1}
step={0.1}
value={volume}
onValueChange={setVolume}
testID="volume"
/>
<SettingsSliderItem
label={`Initial buffer duration: ${initialBufferDuration.toFixed(
1
)}`}
minimumValue={0.1}
maximumValue={5}
step={0.1}
value={initialBufferDuration}
onValueChange={setInitialBufferDuration}
testID="initialBufferDuration"
/>
<SettingsSwitchItem
label="Live Low Latency"
onValueChange={setLiveLowLatency}
value={liveLowLatency}
testID="liveLowLatency"
/>
<SettingsSwitchItem
label="Rebuffer To Live"
onValueChange={setRebufferToLive}
value={rebufferToLive}
testID="rebufferToLive"
/>
<SettingsSwitchItem
label="Pause in background"
value={pauseInBackground}
onValueChange={setPauseInBackground}
testID="pauseInBackground"
/>
<SettingsItem label="Log Level" testID="logLevelPicker">
<LogLevelPicker
logLevel={logLevel}
setLogLevel={setLogLevel}
/>
</SettingsItem>
<SettingsSwitchItem
label="Auto Quality"
onValueChange={(value) => {
if (value) {
setManualQuality(null);
}
setAutoQualityMode(value);
}}
value={autoQualityMode}
testID="autoQuality"
/>
<SettingsItem
label="Auto Max Quality"
testID="autoMaxQualityPicker"
>
<OptionPicker
option={autoMaxQuality}
options={qualities}
autoOption
setOption={setAutoMaxQuality}
/>
</SettingsItem>
<SettingsItem label="Breakpoints">
<Button onPress={() => setBreakpoints(UPDATED_BREAKPOINTS)}>
Add
</Button>
</SettingsItem>
<SettingsInputItem
label="origin"
onChangeText={setOrigin}
value={origin}
/>
<SettingsItem label=" ">
<Button
onPress={() => {
mediaPlayerRef.current?.setOrigin(origin);
log(`header origin set to: ${origin}`);
}}
>
setOrigin
</Button>
</SettingsItem>
</View>
</ScrollView>
</View>
</View>
)}