From 2c8f11750a1f5a93c0da5e2d60b5fb1d97a4538e Mon Sep 17 00:00:00 2001 From: btzr-io Date: Wed, 1 Aug 2018 18:53:38 -0600 Subject: [PATCH] improve and optimize renderFile method (fileSource) --- src/renderer/component/fileRender/view.jsx | 19 +++++---- .../component/fileViewer/internal/player.jsx | 42 +++++++++---------- .../component/viewers/documentViewer.jsx | 25 +++++------ src/renderer/component/viewers/docxViewer.jsx | 18 ++++---- src/renderer/component/viewers/pdfViewer.jsx | 20 ++------- .../component/viewers/threeViewer/index.jsx | 2 +- .../viewers/threeViewer/internal/loader.js | 4 +- 7 files changed, 60 insertions(+), 70 deletions(-) diff --git a/src/renderer/component/fileRender/view.jsx b/src/renderer/component/fileRender/view.jsx index d2d91f6c1..34194b213 100644 --- a/src/renderer/component/fileRender/view.jsx +++ b/src/renderer/component/fileRender/view.jsx @@ -9,33 +9,36 @@ import DocxViewer from 'component/viewers/docxViewer'; type Props = { mediaType: string, source: { - filePath: string, + fileName: string, fileType: string, downloadPath: string, + stream: opts => void, + blob: callback => void, }, currentTheme: string, }; class FileRender extends React.PureComponent { renderViewer() { - const { source, mediaType, currentTheme: theme } = this.props; - const viewerProps = { source, theme }; + const { source, mediaType, currentTheme } = this.props; + + // Extract relevant data to render file + const { blob, stream, fileName, fileType, contentType, downloadPath } = source; // Supported mediaTypes const mediaTypes = { - '3D-file': , - document: , + '3D-file': , + document: , // Add routes to viewer... }; // Supported fileType const fileTypes = { - pdf: , - docx: , + pdf: , + docx: , // Add routes to viewer... }; - const { fileType } = source; const viewer = mediaType && source && (fileTypes[fileType] || mediaTypes[mediaType]); const unsupportedMessage = __("Sorry, looks like we can't preview this file."); const unsupported = ; diff --git a/src/renderer/component/fileViewer/internal/player.jsx b/src/renderer/component/fileViewer/internal/player.jsx index 6fdcfce8e..1482146bf 100644 --- a/src/renderer/component/fileViewer/internal/player.jsx +++ b/src/renderer/component/fileViewer/internal/player.jsx @@ -9,7 +9,7 @@ import FileRender from 'component/fileRender'; import Thumbnail from 'component/common/thumbnail'; import LoadingScreen from 'component/common/loading-screen'; -class VideoPlayer extends React.PureComponent { +class MediaPlayer extends React.PureComponent { static MP3_CONTENT_TYPES = ['audio/mpeg3', 'audio/mpeg']; static FILE_MEDIA_TYPES = ['e-book', 'comic-book', 'document', '3D-file']; @@ -54,7 +54,7 @@ class VideoPlayer extends React.PureComponent { }; // use renderAudio override for mp3 - if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) { + if (MediaPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) { this.renderAudio(container, null, false); } // Render custom viewer: FileRender @@ -105,7 +105,7 @@ class VideoPlayer extends React.PureComponent { if (this.playableType() && !startedPlaying && downloadCompleted) { const container = this.media.children[0]; - if (VideoPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) { + if (MediaPlayer.MP3_CONTENT_TYPES.indexOf(contentType) > -1) { this.renderAudio(this.media, true); } else { player.render(this.file(), container, { @@ -183,30 +183,30 @@ class VideoPlayer extends React.PureComponent { // This files are supported using a custom viewer const { mediaType } = this.props; - return VideoPlayer.FILE_MEDIA_TYPES.indexOf(mediaType) > -1; + return MediaPlayer.FILE_MEDIA_TYPES.indexOf(mediaType) > -1; } renderFile() { // This is what render-media does with unplayable files const { fileName, downloadPath, contentType, mediaType } = this.props; - toBlobURL(fs.createReadStream(downloadPath), contentType, (err, url) => { - if (err) { - this.setState({ unsupported: true }); - return false; - } + // File to render + const fileSource = { + fileName, + contentType, + downloadPath, + fileType: path.extname(fileName).substring(1), + }; - // File to render - const fileSource = { - fileName, - contentType, - downloadPath, - filePath: url, - fileType: path.extname(fileName).substring(1), - }; - // Update state - this.setState({ fileSource }); - }); + // Readable stream from file + fileSource.stream = opts => fs.createReadStream(downloadPath, opts); + + // Blob url from stream + fileSource.blob = callback => + toBlobURL(fs.createReadStream(downloadPath), contentType, callback); + + // Update state + this.setState({ fileSource }); } renderAudio(container, autoplay) { @@ -287,5 +287,5 @@ class VideoPlayer extends React.PureComponent { } } -export default VideoPlayer; +export default MediaPlayer; /* eslint-disable */ diff --git a/src/renderer/component/viewers/documentViewer.jsx b/src/renderer/component/viewers/documentViewer.jsx index efd4bac90..608d34873 100644 --- a/src/renderer/component/viewers/documentViewer.jsx +++ b/src/renderer/component/viewers/documentViewer.jsx @@ -1,7 +1,6 @@ // @flow import React from 'react'; -import fs from 'fs'; import LoadingScreen from 'component/common/loading-screen'; import CodeViewer from 'component/viewers/codeViewer'; import MarkdownPreview from 'component/common/markdown-preview'; @@ -9,9 +8,9 @@ import MarkdownPreview from 'component/common/markdown-preview'; type Props = { theme: string, source: { + stream: opts => void, fileType: string, - filePath: string, - downloadPath: string, + contentType: string, }, }; @@ -27,7 +26,7 @@ class DocumentViewer extends React.PureComponent { componentDidMount() { const { source } = this.props; - const stream = fs.createReadStream(source.downloadPath, 'utf8'); + const stream = source.stream('utf8'); let data = ''; @@ -40,23 +39,20 @@ class DocumentViewer extends React.PureComponent { }); stream.on('error', error => { - this.setState({ error }); + this.setState({ error: true, loading: false }); }); } - renderDocument() { + renderDocument(content = null) { let viewer = null; const { source, theme } = this.props; const { fileType, contentType } = source; - const { content, error } = this.state; - - const isReady = content && !error; const markdownType = ['md', 'markdown']; - if (isReady && markdownType.includes(fileType)) { + if (markdownType.includes(fileType)) { // Render markdown viewer = ; - } else if (isReady) { + } else { // Render plain text viewer = ; } @@ -65,15 +61,16 @@ class DocumentViewer extends React.PureComponent { } render() { - const { error, loading } = this.state; + const { error, loading, content } = this.state; + const isReady = content && !error; const loadingMessage = __('Rendering document.'); const errorMessage = __("Sorry, looks like we can't load the document."); return (
{loading && !error && } - {error && } - {this.renderDocument()} + {error && } + {isReady && this.renderDocument(content)}
); } diff --git a/src/renderer/component/viewers/docxViewer.jsx b/src/renderer/component/viewers/docxViewer.jsx index 040494200..9959678c5 100644 --- a/src/renderer/component/viewers/docxViewer.jsx +++ b/src/renderer/component/viewers/docxViewer.jsx @@ -7,11 +7,7 @@ import LoadingScreen from 'component/common/loading-screen'; import MarkdownPreview from 'component/common/markdown-preview'; type Props = { - source: { - fileType: string, - filePath: string, - downloadPath: string, - }, + source: string, }; class DocxViewer extends React.PureComponent { @@ -26,6 +22,7 @@ class DocxViewer extends React.PureComponent { componentDidMount() { const { source } = this.props; + // Overwrite element and styles const options = { styleMap: [ "p[style-name='Title'] => h1:fresh", @@ -38,15 +35,19 @@ class DocxViewer extends React.PureComponent { "p[style-name='Aside Text'] => div.aside > p:fresh", ], }; + + // Parse docx to html mammoth - .convertToHtml({ path: source.downloadPath }, options) + .convertToHtml({ path: source }, options) .then(result => { + // Remove images and tables const breakdance = new Breakdance({ omit: ['table', 'img'] }); + // Convert html to markdown const markdown = breakdance.render(result.value); this.setState({ content: markdown, loading: false }); }) .catch(error => { - this.setState({ error, loading: false }); + this.setState({ error: true, loading: false }); }) .done(); } @@ -54,11 +55,12 @@ class DocxViewer extends React.PureComponent { render() { const { content, error, loading } = this.state; const loadingMessage = __('Rendering document.'); + const errorMessage = __("Sorry, looks like we can't load the document."); return (
{loading && } - {error && } + {error && } {content && (
diff --git a/src/renderer/component/viewers/pdfViewer.jsx b/src/renderer/component/viewers/pdfViewer.jsx index 26a136e0b..ce0a2095a 100644 --- a/src/renderer/component/viewers/pdfViewer.jsx +++ b/src/renderer/component/viewers/pdfViewer.jsx @@ -1,12 +1,9 @@ // @flow import React from 'react'; +import { stopContextMenu } from 'util/contextMenu'; type Props = { - source: { - fileType: string, - filePath: string, - downloadPath: string, - }, + source: string, }; class PdfViewer extends React.PureComponent { @@ -15,20 +12,11 @@ class PdfViewer extends React.PureComponent { this.viewer = React.createRef(); } - // TODO: Enable context-menu - stopContextMenu = event => { - event.preventDefault(); - event.stopPropagation(); - }; - render() { const { source } = this.props; return ( -
- +
+
); } diff --git a/src/renderer/component/viewers/threeViewer/index.jsx b/src/renderer/component/viewers/threeViewer/index.jsx index 0ceea09d5..751c84dd2 100644 --- a/src/renderer/component/viewers/threeViewer/index.jsx +++ b/src/renderer/component/viewers/threeViewer/index.jsx @@ -14,7 +14,7 @@ type Props = { autoRotate: boolean, source: { fileType: string, - filePath: string, + downloadPath: string, }, }; diff --git a/src/renderer/component/viewers/threeViewer/internal/loader.js b/src/renderer/component/viewers/threeViewer/internal/loader.js index d69a93344..b2ca37f8d 100644 --- a/src/renderer/component/viewers/threeViewer/internal/loader.js +++ b/src/renderer/component/viewers/threeViewer/internal/loader.js @@ -17,13 +17,13 @@ const Loader = (fileType, manager) => { return fileTypes[fileType] ? fileTypes[fileType]() : null; }; -const ThreeLoader = ({ fileType, filePath }, renderModel, managerEvents) => { +const ThreeLoader = ({ fileType = null, downloadPath = null }, renderModel, managerEvents) => { if (fileType) { const manager = Manager(managerEvents); const loader = Loader(fileType, manager); if (loader) { - loader.load(filePath, data => { + loader.load(`file://${downloadPath}`, data => { renderModel(fileType, data); }); }