Gif panel for VideoViewer

This commit is contained in:
Pogodaanton 2020-06-24 17:33:48 +02:00
parent 793f051925
commit c0d9622bec
2 changed files with 67 additions and 5 deletions

View File

@ -8,5 +8,10 @@
"size": "Size",
"untitled": "-",
"download": "Download File",
"source": "View Original"
"source": "View Original",
"gif": {
"alt": "Animated GIF image of the video",
"load": "Loading GIF image...",
"loadError": "Sorry, we could not open this image!"
}
}

View File

@ -1,17 +1,20 @@
import React, { useContext, useRef, useLayoutEffect, useMemo } from "react";
import React, { useContext, useRef, useLayoutEffect, useMemo, useCallback } from "react";
import { VideoViewerProps, VideoViewerClassNameContract } from "./VideoViewer.props";
import { DesignSystem } from "@microsoft/fast-components-styles-msft";
import manageJss, { ComponentStyles } from "@microsoft/fast-jss-manager-react";
import { headerHeight } from "../../../_DesignSystem";
import { headerHeight, TabViewer, toast } from "../../../_DesignSystem";
import { ThumbnailContext, ssrContainer } from "../ThumbnailViewer/ThumbnailViewer";
import { SidebarData } from "../FVSidebar/FVSidebarContext";
import { useTranslation } from "react-i18next";
import { TabPanel } from "../../../_DesignSystem/Tabs/TabViewer/TabViewer.props";
import tabEventEmitter from "../../../_DesignSystem/Tabs/TabEvents";
const styles: ComponentStyles<VideoViewerClassNameContract, DesignSystem> = {
videoViewer: {
position: "absolute",
top: "64px",
transition: "width .15s",
"& video": {
"& video, & img": {
width: "100%",
height: "100%",
objectFit: "scale-down",
@ -42,6 +45,7 @@ const VideoViewer: React.ComponentType<VideoViewerProps> = ({
viewportWidth: originalViewportWidth,
viewportHeight,
} = useContext(ThumbnailContext);
const { t } = useTranslation("fileview");
// Sidebar data for viewport calculations
const { debouncedSidebarPos } = useContext(SidebarData);
@ -55,6 +59,11 @@ const VideoViewer: React.ComponentType<VideoViewerProps> = ({
*/
const videoRef = useRef<HTMLVideoElement>(null);
/**
* React.ref of the gif container
*/
const imgRef = useRef<HTMLImageElement>(null);
/**
* Listen to the finishing of the thumbnail animation.
* Load the high-res image afterwards and hide the thumbnail.
@ -89,6 +98,54 @@ const VideoViewer: React.ComponentType<VideoViewerProps> = ({
setThumbnailVisibility,
]);
const onGifAppear = useCallback(() => {
const imgEl = imgRef.current;
if (imgEl && !imgEl.src) {
let toastScheduler: number = null;
let toastId: React.ReactText = null;
const removeListeners = () => {
imgEl.onerror = () => {};
imgEl.onload = () => {};
};
const removeScheduledToast = () => {
clearTimeout(toastScheduler);
if (toastId) toast.dismiss(toastId);
return true;
};
imgEl.onerror = () => {
removeScheduledToast();
imgEl.style.display = "none";
toast.error(t("gif.loadError"), "", { autoClose: 10000 });
tabEventEmitter.emit("video-gif-update", "video");
removeListeners();
imgEl.src = "";
};
imgEl.onload = () => removeScheduledToast() && removeListeners();
toastScheduler = setTimeout(() => {
toastId = toast.info(t("gif.load"), "", { progress: 0 });
}, 500) as any;
imgEl.src = `${window.location.origin}/${id}.gif`;
}
}, [id, t]);
const tabContentItems: TabPanel[] = useMemo(
() => [
{ id: "video", children: <video muted autoPlay loop ref={videoRef} /> },
{
id: "gif",
children: <img alt={t("gif.alt")} ref={imgRef} />,
onLoad: onGifAppear,
},
],
[onGifAppear, t]
);
return (
<div
className={managedClasses.videoViewer}
@ -99,7 +156,7 @@ const VideoViewer: React.ComponentType<VideoViewerProps> = ({
height: viewportHeight,
}}
>
<video muted autoPlay loop ref={videoRef} />
<TabViewer id="video-gif" items={tabContentItems} />
</div>
);
};