only show play/pause when there are animations

This commit is contained in:
Emi Matchu 2020-09-24 06:13:27 -07:00
parent 5027a62ec5
commit 53b4d34419
4 changed files with 45 additions and 7 deletions

View file

@ -29,7 +29,11 @@ import useOutfitAppearance from "../components/useOutfitAppearance";
* OutfitControls is the set of controls layered over the outfit preview, to * OutfitControls is the set of controls layered over the outfit preview, to
* control things like species/color and sharing links! * control things like species/color and sharing links!
*/ */
function OutfitControls({ outfitState, dispatchToOutfit }) { function OutfitControls({
outfitState,
dispatchToOutfit,
showAnimationControls,
}) {
const [focusIsLocked, setFocusIsLocked] = React.useState(false); const [focusIsLocked, setFocusIsLocked] = React.useState(false);
const onLockFocus = React.useCallback(() => setFocusIsLocked(true), [ const onLockFocus = React.useCallback(() => setFocusIsLocked(true), [
setFocusIsLocked, setFocusIsLocked,
@ -140,11 +144,13 @@ function OutfitControls({ outfitState, dispatchToOutfit }) {
d="inline-flex" // Not sure why <a> requires this to style right! ^^` d="inline-flex" // Not sure why <a> requires this to style right! ^^`
/> />
</Box> </Box>
{showAnimationControls && (
<Box gridArea="play-pause" display="flex" justifyContent="center"> <Box gridArea="play-pause" display="flex" justifyContent="center">
<DarkMode> <DarkMode>
<PlayPauseButton /> <PlayPauseButton />
</DarkMode> </DarkMode>
</Box> </Box>
)}
<Stack <Stack
gridArea="sharing" gridArea="sharing"
alignSelf="flex-end" alignSelf="flex-end"

View file

@ -29,6 +29,10 @@ function WardrobePage() {
const toast = useToast(); const toast = useToast();
const { loading, error, outfitState, dispatchToOutfit } = useOutfitState(); const { loading, error, outfitState, dispatchToOutfit } = useOutfitState();
// Whether the current outfit preview has animations. Determines whether we
// show the play/pause button.
const [hasAnimations, setHasAnimations] = React.useState(false);
usePageTitle(outfitState.name || "Untitled outfit"); usePageTitle(outfitState.name || "Untitled outfit");
// TODO: I haven't found a great place for this error UI yet, and this case // TODO: I haven't found a great place for this error UI yet, and this case
@ -64,12 +68,14 @@ function WardrobePage() {
appearanceId={outfitState.appearanceId} appearanceId={outfitState.appearanceId}
wornItemIds={outfitState.wornItemIds} wornItemIds={outfitState.wornItemIds}
engine="canvas" engine="canvas"
onChangeHasAnimations={setHasAnimations}
/> />
} }
controls={ controls={
<OutfitControls <OutfitControls
outfitState={outfitState} outfitState={outfitState}
dispatchToOutfit={dispatchToOutfit} dispatchToOutfit={dispatchToOutfit}
showAnimationControls={hasAnimations}
/> />
} }
itemsAndSearch={ itemsAndSearch={

View file

@ -8,7 +8,13 @@ const EaselContext = React.createContext({
removeResizeListener: () => {}, removeResizeListener: () => {},
}); });
function OutfitCanvas({ children, width, height, pauseMovieLayers }) { function OutfitCanvas({
children,
width,
height,
pauseMovieLayers = true,
onChangeHasAnimations = null,
}) {
const [stage, setStage] = React.useState(null); const [stage, setStage] = React.useState(null);
const resizeListenersRef = React.useRef([]); const resizeListenersRef = React.useRef([]);
const canvasRef = React.useRef(null); const canvasRef = React.useRef(null);
@ -43,6 +49,14 @@ function OutfitCanvas({ children, width, height, pauseMovieLayers }) {
if (afterFirstDraw) { if (afterFirstDraw) {
stage.on("drawend", afterFirstDraw, null, true); stage.on("drawend", afterFirstDraw, null, true);
} }
if (onChangeHasAnimations) {
const hasAnimations = stage.children.some((c) =>
createjsNodeHasAnimations(c)
);
onChangeHasAnimations(hasAnimations);
}
// NOTE: We don't bother firing an update, because we trust the ticker // NOTE: We don't bother firing an update, because we trust the ticker
// to do it on the next frame. // to do it on the next frame.
}, },
@ -52,6 +66,14 @@ function OutfitCanvas({ children, width, height, pauseMovieLayers }) {
const removeChild = React.useCallback( const removeChild = React.useCallback(
(child) => { (child) => {
stage.removeChild(child); stage.removeChild(child);
if (onChangeHasAnimations) {
const hasAnimations = stage.children.some((c) =>
createjsNodeHasAnimations(c)
);
onChangeHasAnimations(hasAnimations);
}
// NOTE: We don't bother firing an update, because we trust the ticker // NOTE: We don't bother firing an update, because we trust the ticker
// to do it on the next frame. (And, I don't understand why, but // to do it on the next frame. (And, I don't understand why, but
// updating here actually paused remaining movies! So, don't!) // updating here actually paused remaining movies! So, don't!)

View file

@ -39,6 +39,7 @@ function OutfitPreview({
loadingDelayMs, loadingDelayMs,
spinnerVariant, spinnerVariant,
engine = "images", engine = "images",
onChangeHasAnimations = null,
}) { }) {
const { loading, error, visibleLayers } = useOutfitAppearance({ const { loading, error, visibleLayers } = useOutfitAppearance({
speciesId, speciesId,
@ -72,6 +73,7 @@ function OutfitPreview({
loadingDelayMs={loadingDelayMs} loadingDelayMs={loadingDelayMs}
spinnerVariant={spinnerVariant} spinnerVariant={spinnerVariant}
engine={engine} engine={engine}
onChangeHasAnimations={onChangeHasAnimations}
doTransitions doTransitions
/> />
); );
@ -89,6 +91,7 @@ export function OutfitLayers({
spinnerVariant = "overlay", spinnerVariant = "overlay",
doTransitions = false, doTransitions = false,
engine = "images", engine = "images",
onChangeHasAnimations = null,
}) { }) {
const containerRef = React.useRef(null); const containerRef = React.useRef(null);
const [canvasSize, setCanvasSize] = React.useState(0); const [canvasSize, setCanvasSize] = React.useState(0);
@ -158,6 +161,7 @@ export function OutfitLayers({
width={canvasSize} width={canvasSize}
height={canvasSize} height={canvasSize}
pauseMovieLayers={isPaused} pauseMovieLayers={isPaused}
onChangeHasAnimations={onChangeHasAnimations}
> >
{visibleLayers.map((layer) => {visibleLayers.map((layer) =>
layer.canvasMovieLibraryUrl ? ( layer.canvasMovieLibraryUrl ? (