112 lines
3.3 KiB
TypeScript
112 lines
3.3 KiB
TypeScript
import React, { createContext, useCallback, useContext, useEffect, useReducer } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
|
|
const DEFAULT_STATE = {
|
|
isCineEnabled: false,
|
|
cines: {
|
|
/*
|
|
* 1: { isPlaying: false, frameRate: 24 };
|
|
*/
|
|
},
|
|
};
|
|
|
|
const DEFAULT_CINE = { isPlaying: false, frameRate: 24 };
|
|
|
|
export const CineContext = createContext(DEFAULT_STATE);
|
|
|
|
export default function CineProvider({ children, service }) {
|
|
const reducer = (state, action) => {
|
|
switch (action.type) {
|
|
case 'SET_CINE': {
|
|
const { id, frameRate, isPlaying = undefined } = action.payload;
|
|
const cines = state.cines;
|
|
|
|
const syncedCineIds = service.getSyncedViewports(id).map(({ viewportId }) => viewportId);
|
|
const cineIdsToUpdate = [id, ...syncedCineIds].filter(curId => {
|
|
const currentCine = cines[curId] ?? {};
|
|
const shouldUpdateFrameRate =
|
|
currentCine.frameRate !== (frameRate ?? currentCine.frameRate);
|
|
const shouldUpdateIsPlaying =
|
|
currentCine.isPlaying !== (isPlaying ?? currentCine.isPlaying);
|
|
|
|
return shouldUpdateFrameRate || shouldUpdateIsPlaying;
|
|
});
|
|
|
|
cineIdsToUpdate.forEach(currId => {
|
|
let cine = cines[currId];
|
|
|
|
if (!cine) {
|
|
cine = { id, ...DEFAULT_CINE };
|
|
cines[currId] = cine;
|
|
}
|
|
|
|
cine.frameRate = frameRate ?? cine.frameRate;
|
|
cine.isPlaying = isPlaying ?? cine.isPlaying;
|
|
});
|
|
|
|
return { ...state, ...cines };
|
|
}
|
|
case 'SET_IS_CINE_ENABLED': {
|
|
return { ...state, ...{ isCineEnabled: action.payload } };
|
|
}
|
|
default:
|
|
return action.payload;
|
|
}
|
|
};
|
|
|
|
const [state, dispatch] = useReducer(reducer, DEFAULT_STATE);
|
|
|
|
const getState = useCallback(() => state, [state]);
|
|
|
|
const setIsCineEnabled = useCallback(
|
|
isCineEnabled => dispatch({ type: 'SET_IS_CINE_ENABLED', payload: isCineEnabled }),
|
|
[dispatch]
|
|
);
|
|
|
|
const setCine = useCallback(
|
|
({ id, frameRate, isPlaying }) =>
|
|
dispatch({
|
|
type: 'SET_CINE',
|
|
payload: {
|
|
id,
|
|
frameRate,
|
|
isPlaying,
|
|
},
|
|
}),
|
|
[dispatch]
|
|
);
|
|
|
|
/**
|
|
* Sets the implementation of a modal service that can be used by extensions.
|
|
*
|
|
* @returns void
|
|
*/
|
|
useEffect(() => {
|
|
if (service) {
|
|
service.setServiceImplementation({ getState, setIsCineEnabled, setCine });
|
|
}
|
|
}, [getState, service, setCine, setIsCineEnabled]);
|
|
|
|
const api = {
|
|
getState,
|
|
setCine,
|
|
setIsCineEnabled: isCineEnabled => service.setIsCineEnabled(isCineEnabled),
|
|
playClip: (element, playClipOptions) => service.playClip(element, playClipOptions),
|
|
stopClip: (element, stopClipOptions) => service.stopClip(element, stopClipOptions),
|
|
setViewportCineClosed: viewportId => service.setViewportCineClosed(viewportId),
|
|
clearViewportCineClosed: viewportId => service.clearViewportCineClosed(viewportId),
|
|
isViewportCineClosed: viewportId => service.isViewportCineClosed(viewportId),
|
|
};
|
|
|
|
return <CineContext.Provider value={[state, api]}>{children}</CineContext.Provider>;
|
|
}
|
|
|
|
CineProvider.propTypes = {
|
|
children: PropTypes.any,
|
|
service: PropTypes.shape({
|
|
setServiceImplementation: PropTypes.func,
|
|
}).isRequired,
|
|
};
|
|
|
|
export const useCine = () => useContext(CineContext);
|