diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index ec96f5b08..db050e766 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -656,8 +656,11 @@ "notStarted": { "message": "Not Started" }, + "noWebcamFoundTitle": { + "message": "Webcam not found" + }, "noWebcamFound": { - "message": "We couldn't find any webcam available on your computer. Make sure the device is connected and configured correctly." + "message": "Your computer's webcam was not found. Please try again." }, "oldUI": { "message": "Old UI" @@ -1101,8 +1104,11 @@ "unknownQrCode": { "message": "Error: We couldn't identify that QR code" }, + "unknownCameraErrorTitle": { + "message": "Ooops! Something went wrong...." + }, "unknownCameraError": { - "message": "Ooops! Something went wrong while trying to access you camera. Please try again..." + "message": "There was an error while trying to access you camera. Please try again..." }, "unlock": { "message": "Unlock" diff --git a/app/images/webcam.svg b/app/images/webcam.svg new file mode 100644 index 000000000..4b9b58148 --- /dev/null +++ b/app/images/webcam.svg @@ -0,0 +1,18 @@ + + + + webcam + Created with Sketch. + + + + + + + + + + + + + \ No newline at end of file diff --git a/ui/app/components/modals/qr-scanner/index.scss b/ui/app/components/modals/qr-scanner/index.scss index df65cfbbb..6fa81d51f 100644 --- a/ui/app/components/modals/qr-scanner/index.scss +++ b/ui/app/components/modals/qr-scanner/index.scss @@ -39,9 +39,45 @@ padding: 15px; } - &__status.error { - padding: 60px 45px 80px; + &__image { + font-size: 1.5rem; + font-weight: 500; + padding: 16px 0 0; + text-align: center; + } + + &__error { + text-align: center; font-size: 16px; + padding: 15px; + } + + &__footer { + padding: 20px; + flex-direction: row; + display: flex; + + button { + margin-right: 15px; + } + + button:last-of-type { + margin-right: 0; + background-color: #009eec; + border: none; + color: #fff; + } + } + + &__close::after { + content: '\00D7'; + font-size: 35px; + color: #9b9b9b; + position: absolute; + top: 4px; + right: 20px; + cursor: pointer; + font-weight: 300; } } diff --git a/ui/app/components/modals/qr-scanner/qr-scanner.component.js b/ui/app/components/modals/qr-scanner/qr-scanner.component.js index e6ba146d6..5ca19ccd8 100644 --- a/ui/app/components/modals/qr-scanner/qr-scanner.component.js +++ b/ui/app/components/modals/qr-scanner/qr-scanner.component.js @@ -9,6 +9,7 @@ export default class QrScanner extends Component { static propTypes = { hideModal: PropTypes.func.isRequired, qrCodeDetected: PropTypes.func, + scanQrCode: PropTypes.func, error: PropTypes.bool, errorType: PropTypes.string, } @@ -20,18 +21,9 @@ export default class QrScanner extends Component { constructor (props, context) { super(props) - let initialMsg = context.t('accessingYourCamera') - if (props.error) { - if (props.errorType === 'NO_WEBCAM_FOUND') { - initialMsg = context.t('noWebcamFound') - } else { - initialMsg = context.t('unknownCameraError') - } - } - this.state = { ready: false, - msg: initialMsg, + msg: context.t('accessingYourCamera'), } this.codeReader = null this.permissionChecker = null @@ -118,11 +110,22 @@ export default class QrScanner extends Component { stopAndClose = () => { - this.codeReader.reset() + if (this.codeReader) { + this.codeReader.reset() + } this.setState({ ready: false }) this.props.hideModal() } + tryAgain = () => { + // close the modal + this.stopAndClose() + // wait for the animation and try again + setTimeout(_ => { + this.props.scanQrCode() + }, 1000) + } + renderVideo () { return (
@@ -137,18 +140,61 @@ export default class QrScanner extends Component { ) } + renderErrorModal () { + let title, msg + + if (this.props.error) { + if (this.props.errorType === 'NO_WEBCAM_FOUND') { + title = this.context.t('noWebcamFoundTitle') + msg = this.context.t('noWebcamFound') + } else { + title = this.context.t('unknownCameraErrorTitle') + msg = this.context.t('unknownCameraError') + } + } + + return ( +
+
+ +
+ +
+
+ { title } +
+
+ {msg} +
+
+ + +
+
+ ) + } + render () { const { t } = this.context + if (this.props.error) { + return this.renderErrorModal() + } + return (
+
{ `${t('scanQrCode')}` }
- { !this.props.error ? this.renderVideo() : null} + { this.renderVideo() }
-
+
{this.state.msg}
diff --git a/ui/app/components/modals/qr-scanner/qr-scanner.container.js b/ui/app/components/modals/qr-scanner/qr-scanner.container.js index d50abe0ae..d0a35e03b 100644 --- a/ui/app/components/modals/qr-scanner/qr-scanner.container.js +++ b/ui/app/components/modals/qr-scanner/qr-scanner.container.js @@ -1,7 +1,10 @@ import { connect } from 'react-redux' import QrScanner from './qr-scanner.component' -const { hideModal, qrCodeDetected } = require('../../../actions') +const { hideModal, qrCodeDetected, showQrScanner } = require('../../../actions') +import { + SEND_ROUTE, +} from '../../../routes' const mapStateToProps = state => { return { @@ -14,6 +17,7 @@ const mapDispatchToProps = dispatch => { return { hideModal: () => dispatch(hideModal()), qrCodeDetected: (data) => dispatch(qrCodeDetected(data)), + scanQrCode: () => dispatch(showQrScanner(SEND_ROUTE)), } } diff --git a/ui/app/components/send/to-autocomplete/to-autocomplete.js b/ui/app/components/send/to-autocomplete/to-autocomplete.js index 14e30e84c..49ebf49d9 100644 --- a/ui/app/components/send/to-autocomplete/to-autocomplete.js +++ b/ui/app/components/send/to-autocomplete/to-autocomplete.js @@ -4,6 +4,7 @@ const h = require('react-hyperscript') const inherits = require('util').inherits const AccountListItem = require('../account-list-item/account-list-item.component').default const connect = require('react-redux').connect +const Tooltip = require('../../tooltip') ToAutoComplete.contextTypes = { t: PropTypes.func, @@ -109,10 +110,13 @@ ToAutoComplete.prototype.render = function () { borderColor: inError ? 'red' : null, }, }), - qrScanner && h(`i.fa.fa-qrcode.fa-lg.send-v2__to-autocomplete__qr-code`, { + qrScanner && h(Tooltip, { + title: this.context.t('scanQrCode'), + position: 'bottom', + }, h(`i.fa.fa-qrcode.fa-lg.send-v2__to-autocomplete__qr-code`, { style: { color: '#33333' }, onClick: () => this.props.scanQrCode(), - }), + })), !to && h(`i.fa.fa-caret-down.fa-lg.send-v2__to-autocomplete__down-caret`, { style: { color: '#dedede' }, onClick: () => this.handleInputEvent(), diff --git a/ui/app/css/itcss/components/send.scss b/ui/app/css/itcss/components/send.scss index ad6199f02..806ac8536 100644 --- a/ui/app/css/itcss/components/send.scss +++ b/ui/app/css/itcss/components/send.scss @@ -629,13 +629,19 @@ &__qr-code { position: absolute; - top: 21px; - left: 13px; + top: 13px; + right: 33px; cursor: pointer; + padding: 8px 5px 5px; + border-radius: 4px; + } + + &__qr-code:hover { + background: #f1f1f1; } &__input.with-qr { - padding-left: 40px; + padding-right: 65px; } } diff --git a/ui/lib/webcam-utils.js b/ui/lib/webcam-utils.js index 9b507cd99..b1609ff4a 100644 --- a/ui/lib/webcam-utils.js +++ b/ui/lib/webcam-utils.js @@ -8,28 +8,29 @@ class WebcamUtils { static checkStatus () { return new Promise((resolve, reject) => { - const isPopup = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP - const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1 - const isBrave = !!window.chrome.ipcRenderer - const isFirefoxOrBrave = isFirefox || isBrave - try { - DetectRTC.load(_ => { - if (DetectRTC.hasWebcam) { - let environmentReady = true - if ((isFirefoxOrBrave && isPopup) || (isPopup && !DetectRTC.isWebsiteHasWebcamPermissions)) { - environmentReady = false - } - resolve({ - permissions: DetectRTC.isWebsiteHasWebcamPermissions, - environmentReady, - }) - } else { - reject({type: 'NO_WEBCAM_FOUND'}) - } - }) - } catch (e) { - reject({type: 'UNKNOWN_ERROR'}) - } + reject({type: 'UNKNOWN_ERROR'}) + // const isPopup = getEnvironmentType(window.location.href) === ENVIRONMENT_TYPE_POPUP + // const isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1 + // const isBrave = !!window.chrome.ipcRenderer + // const isFirefoxOrBrave = isFirefox || isBrave + // try { + // DetectRTC.load(_ => { + // if (DetectRTC.hasWebcam) { + // let environmentReady = true + // if ((isFirefoxOrBrave && isPopup) || (isPopup && !DetectRTC.isWebsiteHasWebcamPermissions)) { + // environmentReady = false + // } + // resolve({ + // permissions: DetectRTC.isWebsiteHasWebcamPermissions, + // environmentReady, + // }) + // } else { + // reject({type: 'NO_WEBCAM_FOUND'}) + // } + // }) + // } catch (e) { + // reject({type: 'UNKNOWN_ERROR'}) + // } }) } }