react-native#TVEventHandler JavaScript Examples
The following examples show how to use
react-native#TVEventHandler.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: VideoProgressBar.js From react-native-tv-demo with MIT License | 5 votes |
VideoProgressBar = (props) => {
const {duration, time, seek} = props;
const [percentage, setPercentage] = useState(0);
const durationRef = useRef(duration);
const timeRef = useRef(time);
const indicatorRef = useRef(null);
const indicatorHandle = useNodeHandle(indicatorRef);
useEffect(() => {
if (time >= 0 && duration > 0) {
setPercentage(Math.floor((time / duration) * 100));
}
durationRef.current = duration;
timeRef.current = time;
}, [duration, time]);
useEffect(() => {
// Listen to TV events
const tvEventHandler = new TVEventHandler();
tvEventHandler.enable(null, tvEventListener);
// Clean up
return () => {
// Remove TV event listener
if (tvEventHandler) {
tvEventHandler.disable();
}
};
}, []);
function tvEventListener(component, event) {
if (event.tag === findNodeID(indicatorRef.current)) {
if (event.eventKeyAction === 0) {
const currentTime = timeRef.current;
const currentDuration = durationRef.current;
if (event.eventType === 'left') {
// Rewind
if (currentTime > SEEK_STEP) {
if (seek) {
seek(currentTime - SEEK_STEP);
}
}
} else if (event.eventType === 'right') {
// Fast forward
if (currentTime < currentDuration - SEEK_STEP) {
if (seek) {
seek(currentTime + SEEK_STEP);
}
}
}
}
}
}
return (
<View style={[props.style, styles.progressBar]}>
<FocusableHighlight
ref={indicatorRef}
nextFocusLeft={indicatorHandle}
nextFocusRight={indicatorHandle}
nativeID={'progress_bar_indicator'}
style={[styles.progressBarIndicator, {left: percentage + '%'}]}
underlayColor={Style.buttonFocusedColor}
/>
<View style={styles.progressBarContainer}>
<View style={[styles.progressBarStatus, {width: percentage + '%'}]} />
</View>
</View>
);
}
Example #2
Source File: EventsDemo.js From react-native-tv-demo with MIT License | 4 votes |
EventsDemo = () => {
const [tvEventStack, setTvEventStack] = useState([]);
const [componentEventStack, setComponentEventStack] = useState([]);
useFocusEffect(
useCallback(() => {
// Listen to back button
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
backEventListener,
);
// Enabled TVEventHandler
const tvEventHandler = new TVEventHandler();
tvEventHandler.enable(null, tvEventListener);
// Clean up
return () => {
// Remove BackHandler
backHandler.remove();
// Disable TVEventHandler
tvEventHandler.disable();
};
}, []),
);
function backEventListener(event) {
// Just add some logs here as navigation will change screen
console.log('backEventListener received hardwareBackPress event');
console.log(JSON.stringify(event));
}
function tvEventListener(component, event) {
//console.log('tvEventListener:', event.eventType);
setTvEventStack((oldTvEventStack) =>
[...oldTvEventStack, JSON.stringify(event)].slice(EVENT_LINES * -1),
);
}
function componentEventListener(event) {
if (!event.eventType) {
return;
}
//console.log('componentEventListener:', event.eventType);
setComponentEventStack((oldComponentEventStack) =>
[...oldComponentEventStack, JSON.stringify(event)].slice(
EVENT_LINES * -1,
),
);
}
return (
<View style={Style.styles.right}>
<View style={Style.styles.header}>
<Text style={Style.styles.headerText}>{'Events Demo'}</Text>
</View>
<View style={Style.styles.content}>
<View style={styles.buttons}>
<FocusableHighlight
nativeID={'events_left_button'}
onPress={componentEventListener}
onFocus={componentEventListener}
onBlur={componentEventListener}
style={styles.button}
underlayColor={Style.buttonFocusedColor}>
<Text style={styles.buttonText}>{'Left Button'}</Text>
</FocusableHighlight>
<FocusableHighlight
nativeID={'events_middle_button'}
onPress={componentEventListener}
onFocus={componentEventListener}
onBlur={componentEventListener}
style={styles.button}
hasTVPreferredFocus={true}
underlayColor={Style.buttonFocusedColor}>
<Text style={styles.buttonText}>{'Middle Button'}</Text>
</FocusableHighlight>
<FocusableHighlight
nativeID={'events_right_button'}
onPress={componentEventListener}
onFocus={componentEventListener}
onBlur={componentEventListener}
style={styles.button}
underlayColor={Style.buttonFocusedColor}>
<Text style={styles.buttonText}>{'Right Button'}</Text>
</FocusableHighlight>
</View>
<Text style={[styles.eventHeader, styles.tvEventHeader]}>
TVEventHandler events
</Text>
<Text style={styles.eventType} numberOfLines={EventsDemo.EVENT_LINES}>
{tvEventStack.join('\n')}
</Text>
<Text style={styles.eventHeader}>TouchableHighlight events</Text>
<Text style={styles.eventType} numberOfLines={EventsDemo.EVENT_LINES}>
{componentEventStack.join('\n')}
</Text>
</View>
</View>
);
}
Example #3
Source File: VideoDemo.js From react-native-tv-demo with MIT License | 4 votes |
VideoDemo = () => {
let hideOverlayTimer = null;
const navigation = useNavigation();
// Init Refs
const playerRef = useRef(null);
const playPauseButtonRef = useRef(null);
// Context
const [appContext, setAppContext] = useContext(AppContext);
// State
const [source, setSource] = useState(sampleVideoSource);
const [videoEventStack, setVideoEventStack] = useState([]);
const [videoDuration, setVideoDuration] = useState(0);
const [videoTime, setVideoTime] = useState(0);
const [isReady, setIsReady] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isPlaying, setIsPlaying] = useState(false);
// State Refs
const [pausedRef, isPaused, setPaused] = useStateRef(true);
const [overlayRef, isOverlayVisible, setIsOverlayVisible] = useStateRef(true);
const [fullscreenRef, isFullscreen, setIsFullscreen] = useStateRef(false);
useFocusEffect(
useCallback(() => {
// Listen to back button
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
backHandlerListener,
);
// Listen to TV events
const tvEventHandler = new TVEventHandler();
tvEventHandler.enable(null, tvEventListener);
// Clean up
return () => {
// Pause playback
if (!isPaused()) {
setPaused(true);
}
// Clean timeout
if (hideOverlayTimer) {
clearTimeout(hideOverlayTimer);
}
// Remove backHandler
backHandler.remove();
// Remove TV event listener
if (tvEventHandler) {
tvEventHandler.disable();
}
};
}, []),
);
useFocusEffect(
useCallback(() => {
// Prevent react navigation to handle back button is player is fullscreen
return navigation.addListener('beforeRemove', (e) => {
if (isFullscreen()) {
e.preventDefault();
}
});
}, []),
);
useEffect(() => {
// Toggle menu
setAppContext({menuVisible: !isFullscreen()});
}, [fullscreenRef.current]);
function toggleFullscreen() {
pushVideoEventStack(isFullscreen() ? 'exitFullscreen' : 'enterFullscreen');
// Toggle fullscreen
setIsFullscreen(!isFullscreen());
}
function setOverlayVisible() {
console.log('setOverlayVisible', isOverlayVisible());
if (isOverlayVisible() === false) {
setIsOverlayVisible(true);
if (playPauseButtonRef) {
playPauseButtonRef.current.focus();
}
}
setOverlayHiddenAfterDelay();
}
function setOverlayHidden() {
if (isOverlayVisible() === true && !isPaused()) {
setIsOverlayVisible(false);
}
}
function setOverlayHiddenAfterDelay() {
console.log('setOverlayHiddenAfterDelay');
if (hideOverlayTimer) {
clearTimeout(hideOverlayTimer);
}
hideOverlayTimer = setTimeout(setOverlayHidden, 4000);
}
function backHandlerListener() {
console.log('backHandleListener => got back button event');
if (isFullscreen()) {
toggleFullscreen();
}
return true;
}
function tvEventListener(component, event) {
//console.log('VideoDemo.tvEventListener()', event);
if (event.eventKeyAction === 0) {
// Show overlay
setOverlayVisible();
// Toggle play / pause
if (event.eventType === 'playPause') {
setPaused(!isPaused());
}
}
}
// Video Events
function pushVideoEventStack(event, params) {
let eventStr = event + '(' + (params ? JSON.stringify(params) : '') + ')';
console.log('Video event: ' + eventStr);
const eventLines = isFullscreen() ? EVENT_LINES_FULLSCREEN : EVENT_LINES;
setVideoEventStack((oldVideoEventStack) =>
[...oldVideoEventStack, eventStr].slice(eventLines * -1),
);
}
function onReadyForDisplay() {
setIsReady(true);
pushVideoEventStack('onReadyForDisplay');
}
function onLoad(data) {
setIsLoading(false);
setVideoDuration(data.duration);
pushVideoEventStack('onLoad', data);
}
function onLoadStart(data) {
setIsLoading(true);
pushVideoEventStack('onLoadStart', data);
}
function onPlaybackRateChange(data) {
setIsPlaying(data.playbackRate > 0);
pushVideoEventStack('onPlaybackRateChange', data);
}
function onProgress(data) {
setVideoTime(data.currentTime);
pushVideoEventStack('onProgress', data);
}
function onEnd() {
setVideoTime(0);
setPaused(true);
setIsPlaying(false);
pushVideoEventStack('onEnd');
setOverlayVisible();
}
function onError(error) {
pushVideoEventStack('onError', error);
}
function formatTime(time) {
let seconds = parseInt(time, 10);
let hours = Math.floor(seconds / 3600);
let minutes = Math.floor((seconds - hours * 3600) / 60);
seconds = seconds - hours * 3600 - minutes * 60;
let timeFormat = '';
if (hours > 0) {
if (hours < 10) {
hours = '0' + hours;
}
timeFormat += hours + ':';
}
if (minutes < 10) {
minutes = '0' + minutes;
}
if (seconds < 10) {
seconds = '0' + seconds;
}
// Fix NaN
if (isNaN(minutes)) {
minutes = '-';
}
if (isNaN(seconds)) {
seconds = '-';
}
timeFormat += minutes + ':' + seconds;
return timeFormat;
}
return (
<View style={[Style.styles.right, isFullscreen() && styles.fullscreen]}>
{!isFullscreen() && (
<View style={Style.styles.header}>
<Text style={Style.styles.headerText}>{'Video Demo'}</Text>
</View>
)}
<View style={[Style.styles.content, isFullscreen() && styles.fullscreen]}>
<View
style={
isFullscreen()
? styles.videoContainerFullscreen
: styles.videoContainer
}>
<VideoContainer
ref={playerRef}
source={source}
paused={isPaused()}
onReadyForDisplay={onReadyForDisplay}
onLoadStart={onLoadStart}
onLoad={onLoad}
onPlaybackRateChange={onPlaybackRateChange}
onProgress={onProgress}
onEnd={onEnd}
onError={onError}
/>
<View
style={
isOverlayVisible()
? styles.videoOverlayVisible
: styles.videoOverlayHidden
}>
<View style={styles.videoOverlayBackground} />
<View style={styles.videoEvents}>
<Text style={styles.videoEventsText}>
{'Video Events:\n' + videoEventStack.join('\n')}
</Text>
</View>
<VideoProgressBar
duration={videoDuration}
time={videoTime}
style={styles.progressBar}
seek={(seconds) => {
playerRef.current.seek(seconds);
}}
/>
<View style={styles.videoControls}>
<FocusableHighlight
nativeID={'play_pause_button'}
ref={playPauseButtonRef}
onPress={(e) => {
if (e.eventKeyAction === 0 && e.eventType === 'select') {
setPaused(!isPaused());
}
}}
style={styles.videoControl}
hasTVPreferredFocus={true}
underlayColor={Style.buttonFocusedColor}>
<Text style={styles.videoControlText}>
{isPaused() ? 'Play' : 'Pause'}
</Text>
</FocusableHighlight>
<FocusableHighlight
nativeID={'fullscreen_button'}
onPress={(e) => {
if (e.eventKeyAction === 0 && e.eventType === 'select') {
toggleFullscreen();
}
}}
style={styles.videoControl}
underlayColor={Style.buttonFocusedColor}>
<Text style={styles.videoControlText}>
{isFullscreen() ? 'Exit Fullscreen' : 'Enter Fullscreen'}
</Text>
</FocusableHighlight>
<View style={styles.videoTime}>
<Text style={styles.videoTimeText}>
{formatTime(videoTime) + ' / ' + formatTime(videoDuration)}
</Text>
</View>
</View>
</View>
</View>
</View>
</View>
);
}