From bc06876b0248d6b1a7a5988cf40ed861c58ef35a Mon Sep 17 00:00:00 2001 From: deam Date: Mon, 22 Oct 2018 10:04:24 +0200 Subject: [PATCH] Fix #486: Video creation directly in DAC/Campaign/Milestone --- .eslintrc | 40 ++++-- package-lock.json | 105 ++++++++------ public/index.html | 80 ++++++----- src/components/QuillFormsy.jsx | 10 ++ src/components/VideoPopup.jsx | 247 +++++++++++++++++++++++++++++++++ 5 files changed, 395 insertions(+), 87 deletions(-) create mode 100644 src/components/VideoPopup.jsx diff --git a/.eslintrc b/.eslintrc index e8af7d480..8917a8248 100644 --- a/.eslintrc +++ b/.eslintrc @@ -8,30 +8,42 @@ "prettier/standard" ], "rules": { - "jsx-a11y/anchor-is-valid": [ "error", { - "components": [ "Link" ], - "specialLink": [ "to", "hrefLeft", "hrefRight" ], - "aspects": [ "noHref", "invalidHref", "preferButton" ] - }], - "no-param-reassign": [2, { - "props": false - }], + "jsx-a11y/anchor-is-valid": [ + "error", + { + "components": ["Link"], + "specialLink": ["to", "hrefLeft", "hrefRight"], + "aspects": ["noHref", "invalidHref", "preferButton"] + } + ], + "no-param-reassign": [ + 2, + { + "props": false + } + ], "no-underscore-dangle": 0, - "no-unused-vars": ["error", { + "no-unused-vars": [ + "error", + { "vars": "all", "args": "after-used", "ignoreRestSiblings": true, "argsIgnorePattern": "^_" } ], - "prettier/prettier": ["error", { - "singleQuote": true, - "trailingComma": "all" - }], + "prettier/prettier": [ + "error", + { + "singleQuote": true, + "trailingComma": "all" + } + ], "react-app/jsx-a11y/href-no-hash": "off", // This rule is dropped but create-react-app uses old rules "jsx-a11y/label-has-for": "off", // This rule will be dropped soon anyways "react/destructuring-assignment": "off", // Seems to be way too restrictive - "import/no-cycle": 1 // Should be addressed eventually but does not break + "import/no-cycle": 1, // Should be addressed eventually but does not break + "jsx-a11y/media-has-caption": "off" // Pretty hard to do for every video.. }, "env": { "jest": true, diff --git a/package-lock.json b/package-lock.json index 627e2430a..77e115569 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5784,10 +5784,17 @@ "resolved": "https://registry.npmjs.org/eth-sig-util/-/eth-sig-util-1.4.2.tgz", "integrity": "sha1-jZWCAsftuq6Dlwf7pvCf8ydgYhA=", "requires": { - "ethereumjs-abi": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", "ethereumjs-util": "^5.1.1" }, "dependencies": { + "ethereumjs-abi": { + "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", + "requires": { + "bn.js": "^4.10.0", + "ethereumjs-util": "^5.0.0" + } + }, "ethereumjs-util": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", @@ -5914,27 +5921,12 @@ "integrity": "sha512-XOnAR/3rntJgbCdGhqdaLIxDLWKLmsZOGhHdBKadEr6gEnJLH52k93Ou+TUdFaPN3hJc3isBZBal3U/XZ15abA==" }, "ethereumjs-abi": { - "version": "git+https://github.com/ethereumjs/ethereumjs-abi.git#00ba8463a7f7a67fcad737ff9c2ebd95643427f7", - "from": "git+https://github.com/ethereumjs/ethereumjs-abi.git", + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz", + "integrity": "sha1-WmN+8Wq0NHP6cqKa2QhxQFs/UkE=", "requires": { "bn.js": "^4.10.0", - "ethereumjs-util": "^5.0.0" - }, - "dependencies": { - "ethereumjs-util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz", - "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==", - "requires": { - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "ethjs-util": "^0.1.3", - "keccak": "^1.0.2", - "rlp": "^2.0.0", - "safe-buffer": "^5.1.1", - "secp256k1": "^3.0.1" - } - } + "ethereumjs-util": "^4.3.0" } }, "ethereumjs-account": { @@ -8275,11 +8267,16 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.6.tgz", "integrity": "sha1-PpcwauAk+yThCj11yIQwJWIhUSA=", "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", "xmlhttprequest": "*" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" + } } }, "web3-provider-engine": { @@ -8312,10 +8309,15 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.16.0.tgz", "integrity": "sha1-pFVBdc1GKUMDWx8dOUMvdBxrYBk=", "requires": { - "bignumber.js": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xmlhttprequest": "*" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9", + "from": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9" + } } } } @@ -13298,11 +13300,16 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.6.tgz", "integrity": "sha1-PpcwauAk+yThCj11yIQwJWIhUSA=", "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", "xmlhttprequest": "*" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" + } } }, "web3-provider-engine": { @@ -13335,10 +13342,15 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.16.0.tgz", "integrity": "sha1-pFVBdc1GKUMDWx8dOUMvdBxrYBk=", "requires": { - "bignumber.js": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xmlhttprequest": "*" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9", + "from": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9" + } } } } @@ -21679,10 +21691,15 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.16.0.tgz", "integrity": "sha1-pFVBdc1GKUMDWx8dOUMvdBxrYBk=", "requires": { - "bignumber.js": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xmlhttprequest": "*" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9", + "from": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9" + } } } } @@ -21722,11 +21739,16 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.20.6.tgz", "integrity": "sha1-PpcwauAk+yThCj11yIQwJWIhUSA=", "requires": { - "bignumber.js": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xhr2": "*", "xmlhttprequest": "*" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934", + "from": "git+https://github.com/frozeman/bignumber.js-nolookahead.git#57692b3ecfc98bbdd6b3a516cb2353652ea49934" + } } }, "web3-provider-engine": { @@ -21759,10 +21781,15 @@ "resolved": "https://registry.npmjs.org/web3/-/web3-0.16.0.tgz", "integrity": "sha1-pFVBdc1GKUMDWx8dOUMvdBxrYBk=", "requires": { - "bignumber.js": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9", "crypto-js": "^3.1.4", "utf8": "^2.1.1", "xmlhttprequest": "*" + }, + "dependencies": { + "bignumber.js": { + "version": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9", + "from": "git+https://github.com/debris/bignumber.js.git#c7a38de919ed75e6fb6ba38051986e294b328df9" + } } } } @@ -22849,6 +22876,14 @@ "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz", "integrity": "sha1-UzRK2xRhehP26N0s4okF0cC6MhU=" }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, "eth-lib": { "version": "0.1.27", "resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.27.tgz", @@ -23134,28 +23169,17 @@ "integrity": "sha512-Cx64NgDStynKaUGDIIOfaCd0fZusL8h5avKTkdTjUu2aHhFJhZoVBGVLhoDtUaqZGWIZGcBJOoVf2JkGUOjDRQ==", "requires": { "underscore": "1.8.3", - "web3-core-helpers": "1.0.0-beta.35", - "websocket": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2" + "web3-core-helpers": "1.0.0-beta.35" }, "dependencies": { "websocket": { "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", - "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", + "from": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", "requires": { "debug": "^2.2.0", "nan": "^2.3.3", "typedarray-to-buffer": "^3.1.2", "yaeti": "^0.0.6" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } } } } @@ -23189,6 +23213,7 @@ "version": "git://github.com/frozeman/WebSocket-Node.git#6c72925e3f8aaaea8dc8450f97627e85263999f2", "from": "git://github.com/frozeman/WebSocket-Node.git#browserifyCompatible", "requires": { + "debug": "^2.2.0", "nan": "^2.3.3", "typedarray-to-buffer": "^3.1.2", "yaeti": "^0.0.6" diff --git a/public/index.html b/public/index.html index 759dcaffa..ac94d5a3b 100644 --- a/public/index.html +++ b/public/index.html @@ -1,16 +1,17 @@ - - - - - - - - - - - - - - - - - - - - - - - - Giveth Dapp - - - -
- + + + + + + + + + + + + + + + + + + + + + Giveth Dapp + + + + +
+ - - + + + \ No newline at end of file diff --git a/src/components/QuillFormsy.jsx b/src/components/QuillFormsy.jsx index 26f7338f2..aefb9eb45 100644 --- a/src/components/QuillFormsy.jsx +++ b/src/components/QuillFormsy.jsx @@ -4,6 +4,8 @@ import { withFormsy } from 'formsy-react'; import ReactQuill from 'react-quill'; import { feathersRest } from '../lib/feathersClient'; +import VideoPopup from './VideoPopup'; + class QuillFormsy extends Component { constructor(props) { super(props); @@ -17,6 +19,14 @@ class QuillFormsy extends Component { componentDidMount() { const toolbar = this.reactQuillRef.getEditor().getModule('toolbar'); toolbar.addHandler('image', this.imageHandler); + toolbar.addHandler('video', () => { + const quill = this.reactQuillRef.getEditor(); + const index = quill.getLength() - 1; + VideoPopup(url => { + quill.insertEmbed(index, 'video', url); + React.swal.close(); + }); + }); if (this.props.templatesDropdown) { const placeholderPickerItems = Array.prototype.slice.call( document.querySelectorAll('.ql-template .ql-picker-item'), diff --git a/src/components/VideoPopup.jsx b/src/components/VideoPopup.jsx new file mode 100644 index 000000000..51d2e57bb --- /dev/null +++ b/src/components/VideoPopup.jsx @@ -0,0 +1,247 @@ +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import IPFSService from '../services/IPFSService'; +import config from '../configuration'; + +const Label = ({ children }) => ; + +Label.propTypes = { + children: PropTypes.node.isRequired, +}; + +class Content extends Component { + constructor(props) { + super(props); + this.state = { + type: null, + url: null, + file: null, + blob: null, + currentState: '', + stream: null, + recordVideo: null, + }; + + this.handleFile = this.handleFile.bind(this); + this.handleCamera = this.handleCamera.bind(this); + this.handleUpload = this.handleUpload.bind(this); + this.startRecording = this.startRecording.bind(this); + this.stopRecording = this.stopRecording.bind(this); + this.detectExtension = this.detectExtension.bind(this); + this.handleScreenSharing = this.handleScreenSharing.bind(this); + } + + handleFile(e) { + this.setState({ + file: URL.createObjectURL(e.target.files[0]), + blob: e.target.files[0], + }); + } + + handleCamera() { + const params = { audio: true, video: true }; + navigator.getUserMedia( + params, + () => { + navigator.mediaDevices.getUserMedia({ video: true, audio: true }).then(cameraStream => { + this.setState( + { + stream: new window.MultiStreamsMixer([cameraStream]), + }, + () => { + this.state.stream.frameInterval = 1; // eslint-disable-line react/no-direct-mutation-state + this.state.stream.startDrawingFrames(); + window.setSrcObject( + this.state.stream.getMixedStream(), + document.getElementById('video'), + ); + }, + ); + }); + }, + () => { + alert('No camera devices found'); + }, + ); + } + + handleUpload() { + this.setState( + { + currentState: 'uploading', + }, + () => { + IPFSService.upload(this.state.blob) + .then(hash => this.props.handleQuillInsert(config.ipfsGateway + hash.slice(6))) + .catch(err => console.log(err)); + }, + ); + } + + startRecording() { + const { stream } = this.state; + window.setSrcObject(stream.getMixedStream(), document.getElementById('video')); + this.setState( + { + recordVideo: window.RecordRTC(stream.getMixedStream(), { + type: 'video', + }), + currentState: 'recording', + }, + () => this.state.recordVideo.startRecording(), + ); + } + + stopRecording() { + const { recordVideo } = this.state; + recordVideo.stopRecording(() => { + this.setState({ + file: window.URL.createObjectURL(recordVideo.getBlob()), + blob: recordVideo.getBlob(), + currentState: '', + }); + window.RecordRTC.writeToDisk(); + }); + } + + detectExtension() { + const extensionid = 'ajhifddimkapgcifgcodmmfdlknahffk'; + const image = document.createElement('img'); + image.src = `chrome-extension://${extensionid}/icon.png`; + + image.onload = () => { + this.handleScreenSharing(); + }; + image.onerror = () => { + this.setState({ currentState: 'missing extension' }); + }; + } + + handleScreenSharing() { + this.setState({ type: 'screen' }); + window.getScreenId((err, sourceId, screenContraints) => { + if (err) { + console.log(err); + } + navigator.mediaDevices.getUserMedia({ video: false, audio: true }).then(audioStream => { + navigator.getUserMedia = navigator.mozGetUserMedia || navigator.webkitGetUserMedia; + navigator.mediaDevices.getUserMedia(screenContraints).then(screenStream => { + screenStream.fullcanvas = false; + screenStream.width = window.screen.width; // or 3840 + screenStream.height = window.screen.height; // or 2160 + this.setState( + { + stream: new window.MultiStreamsMixer([screenStream, audioStream]), + }, + () => { + this.state.stream.frameInterval = 1; // eslint-disable-line react/no-direct-mutation-state + this.state.stream.startDrawingFrames(); + window.setSrcObject( + this.state.stream.getMixedStream(), + document.getElementById('video'), + ); + }, + ); + }); + }); + }); + } + + render() { + const { handleQuillInsert } = this.props; + const { type, url, file, currentState } = this.state; + + return ( +
+ + + + + +
+ {type === 'link' && ( +
+ this.setState({ url: e.target.value })} + /> + +
+ )} + {type === 'file' && ( +
+ +
+ )} +
+ {currentState === 'missing extension' && ( +
+ You need to install this + + Chrome extension + {' '} + and reload +
+ )} + {(file || type === 'camera' || type === 'screen') && ( +
+
+ )} +
+ ); + } +} + +Content.propTypes = { + handleQuillInsert: PropTypes.func.isRequired, +}; + +export default handleQuillInsert => { + React.swal({ + title: 'Attach a video to milestone', + content: React.swal.msg(), + button: { + visible: false, + }, + }); +};