From f2af93d361adc064526943caded7d7709683eb79 Mon Sep 17 00:00:00 2001 From: Ivan Velasquez Date: Tue, 26 May 2020 02:19:12 -0500 Subject: [PATCH] allow users to draw while they are recording --- src/applications/canvas/index.tsx | 88 +++++++++++++++++++++++++++++ src/applications/canvas/styles.scss | 39 +++++++++++++ src/applications/tools/index.tsx | 15 +++++ src/applications/tools/styles.scss | 18 ++++++ src/config/icons.ts | 4 +- src/electron.ts | 17 ++++++ src/index.tsx | 4 ++ src/windows/canvas.ts | 37 ++++++++++++ src/windows/tools.ts | 4 +- 9 files changed, 223 insertions(+), 3 deletions(-) create mode 100644 src/applications/canvas/index.tsx create mode 100644 src/applications/canvas/styles.scss create mode 100644 src/windows/canvas.ts diff --git a/src/applications/canvas/index.tsx b/src/applications/canvas/index.tsx new file mode 100644 index 0000000..e11c1d0 --- /dev/null +++ b/src/applications/canvas/index.tsx @@ -0,0 +1,88 @@ +import React, { useState, useEffect, useRef } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' +import { ipcRenderer, remote } from 'electron'; +import cx from 'classnames'; +import './styles.scss'; + +const PALETTE = [ + '#29292B', + '#FFFFFF', + '#516BF0', + '#17AEFF', + '#29E484', + '#FEC350', + '#FD5E5F' +] + +const Canvas : React.FC = () => { + const canvas = useRef(null) + const [color, setColor] = useState('#FD5E5F'); + + const closeCanvas = () => { + ipcRenderer.send('CLOSE_CANVAS'); + } + + useEffect(() => { + let painting = false; + const ctx : CanvasRenderingContext2D = canvas.current.getContext('2d'); + const { width, height } = remote.screen.getPrimaryDisplay().workAreaSize; + canvas.current.width = width + canvas.current.height = height; + + const startPainting = (e: MouseEvent) => { + painting = true; + draw(e); + }; + + const finishPainting = () => { + painting = false; + ctx.beginPath(); + }; + + const draw = (event : MouseEvent) => { + if(!painting) return; + + ctx.lineWidth = 10; + ctx.lineCap = 'round'; + ctx.strokeStyle = color; + ctx.lineTo(event.clientX, event.clientY); + ctx.stroke(); + } + + canvas.current.addEventListener('mousedown', startPainting); + canvas.current.addEventListener('mouseup', finishPainting); + canvas.current.addEventListener('mousemove', draw); + + return () => { + canvas.current.removeEventListener('mousedown', startPainting); + canvas.current.removeEventListener('mouseup', finishPainting); + canvas.current.removeEventListener('mousemove', draw); + } + }, [ + color, + canvas + ]); + + return ( +
+ +
+ + {PALETTE.map(palette => ( +
setColor(palette)} + className={cx('color', { selected: palette === color})} + style={{ backgroundColor: palette }} /> + ))} +
+ Done +
+
+
+ ); +} + +export default Canvas; diff --git a/src/applications/canvas/styles.scss b/src/applications/canvas/styles.scss new file mode 100644 index 0000000..bfc8137 --- /dev/null +++ b/src/applications/canvas/styles.scss @@ -0,0 +1,39 @@ +.canvas { + #canvas { + height: 100vh; + width: 100vw; + } + + .palette { + width: 80px; + height: 290px; + padding-top: 10px; + background-color: #29292B; + position: absolute; + left: 0; + top: calc(50vh - 290px); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + border-radius: 6px; + color: #FFF; + + svg { + font-size: 20px; + margin-bottom: 10px; + } + + .color { + width: 30px; + height: 30px; + border-radius: 50%; + border: 4px solid #FFF; + margin-bottom: 5px; + + &.selected { + border: 6px solid #FFF; + } + } + } +} diff --git a/src/applications/tools/index.tsx b/src/applications/tools/index.tsx index 7feb204..9110754 100644 --- a/src/applications/tools/index.tsx +++ b/src/applications/tools/index.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; import { ipcRenderer } from 'electron'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import cx from 'classnames'; import './styles.scss'; @@ -10,6 +11,12 @@ const Tools : React.FC = () => { ipcRenderer.send('STOP_RECORDING'); } + const openCanvas = () => { + if(recording) { + ipcRenderer.send('OPEN_CANVAS'); + } + }; + useEffect(() => { ipcRenderer.on('START_RECORDING', () => { setRecording(true); @@ -24,6 +31,7 @@ const Tools : React.FC = () => { ipcRenderer.removeAllListeners('STOP_RECORDING'); } }, []); + return (
@@ -32,6 +40,13 @@ const Tools : React.FC = () => { className={cx('stop-button is-danger', { recording })}>
+
+
+ +
+
); }; diff --git a/src/applications/tools/styles.scss b/src/applications/tools/styles.scss index 02ea19a..a0c89f6 100644 --- a/src/applications/tools/styles.scss +++ b/src/applications/tools/styles.scss @@ -6,6 +6,7 @@ width: 40px; height: 40px; background-color: #292A2C; + &:hover { cursor: pointer; } @@ -26,4 +27,21 @@ } } } + + .brush { + margin-top: 20px; + display: flex; + justify-content: center; + align-items: center; + width: 40px; + height: 40px; + background-color: #292A2C; + color: #7E7E80; + font-size: 22px; + + .recording { + color: #FFF; + } + } + } diff --git a/src/config/icons.ts b/src/config/icons.ts index 3ca1989..98026c4 100644 --- a/src/config/icons.ts +++ b/src/config/icons.ts @@ -4,7 +4,8 @@ import { faUserCircle, faMicrophone, faCamera, - faSpinner + faSpinner, + faPaintBrush } from '@fortawesome/free-solid-svg-icons'; library.add( @@ -13,4 +14,5 @@ library.add( faMicrophone, faCamera, faSpinner, + faPaintBrush ); diff --git a/src/electron.ts b/src/electron.ts index 53ab150..cd91a9f 100644 --- a/src/electron.ts +++ b/src/electron.ts @@ -11,6 +11,7 @@ import CameraWindow from '@app/windows/camera'; import PreviewWindow from '@app/windows/preview'; import ToolsWindow from '@app/windows/tools'; import QuickStartWindow from '@app/windows/quick_start'; +import CanvasWindow from '@app/windows/canvas'; autoUpdater.logger = log; @@ -20,6 +21,7 @@ let cameraWindow : CameraWindow; let previewWindow : PreviewWindow; let toolsWindow : ToolsWindow; let quickStart : QuickStartWindow; +let canvas : CanvasWindow; const lockSingleInstance = app.requestSingleInstanceLock(); autoUpdater.checkForUpdates().catch((err) => log.warn(err.message)); @@ -94,12 +96,24 @@ ipcMain.on('DISPLAY_PREVIEW', displayPreview); ipcMain.on('EXPORT', (_, data) => { convert(data, previewWindow); }); + ipcMain.on('FINISH_QUICK_START', () => { store.set('quick_start', true); app.relaunch(); app.exit(); }); +ipcMain.on('OPEN_CANVAS', () => { + toolsWindow.window.hide(); + canvas = new CanvasWindow(); + canvas.window.on('close', () => canvas = null); +}); + +ipcMain.on('CLOSE_CANVAS', () => { + toolsWindow.window.show(); + canvas.window.close(); +}); + function initApplicationBindings() { app.on('ready', createWindow); @@ -244,6 +258,9 @@ function stopRecording() { toolsWindow.window.webContents.send(STOP_RECORDING); toolsWindow.window.hide(); application.isRecording = false; + if(canvas) { + canvas.window.close(); + } } function errorRecording() { diff --git a/src/index.tsx b/src/index.tsx index 5f62f24..e924eb4 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -6,6 +6,7 @@ import Camera from '@app/applications/camera'; import Preview from '@app/applications/preview'; import Tools from '@app/applications/tools'; import QuickStart from '@app/applications/quick_start'; +import Canvas from '@app/applications/canvas'; import 'bulma/css/bulma.css' import '@app/assets/styles/main.scss'; import querystring from 'querystring'; @@ -26,6 +27,9 @@ switch(params.screen) { case 'quick_start': RootComponet = QuickStart; break; + case 'canvas': + RootComponet = Canvas; + break; default: RootComponet = Main; break; diff --git a/src/windows/canvas.ts b/src/windows/canvas.ts new file mode 100644 index 0000000..2bbe684 --- /dev/null +++ b/src/windows/canvas.ts @@ -0,0 +1,37 @@ +import path from 'path'; +import { BrowserWindow, screen } from 'electron'; + +class Canvas { + public window: BrowserWindow; + constructor() { + const { width, height } = screen.getPrimaryDisplay().workAreaSize; + this.window = new BrowserWindow({ + resizable: false, + skipTaskbar: true, + maximizable: false, + fullscreenable: false, + frame: false, + movable: false, + show: false, + enableLargerThanScreen: true, + width, + height, + transparent: true, + focusable: false, + webPreferences: { + nodeIntegration: true + } + }); + + this.window.loadURL(`file://${path.join(__dirname, 'index.html')}?screen=canvas`); + this.window.setVisibleOnAllWorkspaces(true); + this.window.setAlwaysOnTop(true, 'screen-saver'); + this.show(); + } + + show() { + this.window.show(); + } +} + +export default Canvas; diff --git a/src/windows/tools.ts b/src/windows/tools.ts index 94eb2d1..e07b218 100644 --- a/src/windows/tools.ts +++ b/src/windows/tools.ts @@ -12,8 +12,8 @@ class Tools { frame: false, movable: false, show: false, - width: 40, - height: 40, + width: 200, + height: 200, transparent: true, alwaysOnTop: true, focusable: false,