From 631860bc9c5c569e7e73b059d7602b69ce4df304 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 13 Nov 2023 15:05:45 -0300 Subject: [PATCH 01/10] Refactor requestCvaPermissions --- src/cordova-util.js | 93 +++++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 58 deletions(-) diff --git a/src/cordova-util.js b/src/cordova-util.js index 7ce5965bb..07683893e 100644 --- a/src/cordova-util.js +++ b/src/cordova-util.js @@ -275,72 +275,49 @@ export const requestCvaWritePermissions = () => { } }; -export const requestCvaPermissions = () => { - if (isCordova()) { +export const requestCvaPermissions = async () => { + if (isAndroid()) { var permissions = window.cordova.plugins.permissions; - permissions.checkPermission( - permissions.READ_EXTERNAL_STORAGE, - function(status) { - console.log('Has READ_EXTERNAL_STORAGE:', status.hasPermission); - if (!status.hasPermission) { - permissions.requestPermission( - permissions.READ_EXTERNAL_STORAGE, - function(status) { - console.log( - 'success requesting READ_EXTERNAL_STORAGE permission' - ); - }, - function(err) { - console.warn('No permissions granted for READ_EXTERNAL_STORAGE'); - } - ); - } - }, - function(err) { - console.log(err); - } - ); + const androidPermissions = { + READ_EXTERNAL_STORAGE: 'READ_EXTERNAL_STORAGE', + RECORD_AUDIO: 'RECORD_AUDIO' + }; - permissions.checkPermission( - permissions.RECORD_AUDIO, - function(status) { - console.log('Has RECORD_AUDIO:', status.hasPermission); - if (!status.hasPermission) { - permissions.requestPermission( - permissions.RECORD_AUDIO, + for (let permission in androidPermissions) { + try { + const { hasPermission } = await new Promise((resolve, reject) => { + permissions.checkPermission( + permissions[permission], function(status) { - console.log('success requesting RECORD_AUDIO permission'); + console.log(`Has ${permission}:`, status.hasPermission); + resolve(status); }, function(err) { - console.warn('No permissions granted for RECORD_AUDIO'); + console.log(err); + resolve({ hasPermission: false }); } ); + }); + if (!hasPermission) { + await new Promise((resolve, reject) => { + permissions.requestPermission( + permissions[permission], + function(status) { + console.log(`Success requesting ${permission} permission`); + if (!status.hasPermission) + console.log(`No permissions granted for ${permission}`); + resolve(status); + }, + function(err) { + console.log(`No permissions granted for ${permission}`); + reject(err); + } + ); + }); } - }, - function(err) { - console.log(err); + } catch (err) { + console.error(err); } - ); - - // permissions.checkPermission( - // permissions.CAMERA, - // function(status) { - // console.log('Has CAMERA:', status.hasPermission); - // if (!status.hasPermission) { - // permissions.requestPermission( - // permissions.CAMERA, - // function(status) { - // console.log('success requesting CAMERA permission'); - // }, - // function(err) { - // console.warn('No permissions granted for CAMERA'); - // } - // ); - // } - // }, - // function(err) { - // console.log(err); - // } - // ); + } } }; From 1e58e042b3b5289efd85efb1e6da5d386c265def Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 13 Nov 2023 15:06:36 -0300 Subject: [PATCH 02/10] Add READ_MEDIA_IMAGES and AUDIO permissions --- src/cordova-util.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cordova-util.js b/src/cordova-util.js index 07683893e..b4b872742 100644 --- a/src/cordova-util.js +++ b/src/cordova-util.js @@ -280,7 +280,9 @@ export const requestCvaPermissions = async () => { var permissions = window.cordova.plugins.permissions; const androidPermissions = { READ_EXTERNAL_STORAGE: 'READ_EXTERNAL_STORAGE', - RECORD_AUDIO: 'RECORD_AUDIO' + RECORD_AUDIO: 'RECORD_AUDIO', + READ_MEDIA_IMAGES: 'READ_MEDIA_IMAGES', + READ_MEDIA_AUDIO: 'READ_MEDIA_AUDIO' }; for (let permission in androidPermissions) { From b80da7eca80c6d9a02718e17eaee7636f57de4b1 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 13 Nov 2023 15:08:06 -0300 Subject: [PATCH 03/10] Realocate requestCvaPermissions() --- .../Board/TileEditor/TileEditor.component.js | 15 ++++++++------- .../UI/InputImage/InputImage.component.js | 3 --- .../VoiceRecorder/VoiceRecorder.component.js | 5 ----- 3 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/components/Board/TileEditor/TileEditor.component.js b/src/components/Board/TileEditor/TileEditor.component.js index 03bf5de47..1678af743 100644 --- a/src/components/Board/TileEditor/TileEditor.component.js +++ b/src/components/Board/TileEditor/TileEditor.component.js @@ -34,7 +34,11 @@ import EditIcon from '@material-ui/icons/Edit'; import ImageEditor from '../ImageEditor'; import API from '../../../api'; -import { isAndroid, writeCvaFile } from '../../../cordova-util'; +import { + isAndroid, + requestCvaPermissions, + writeCvaFile +} from '../../../cordova-util'; import { convertImageUrlToCatchable } from '../../../helpers'; import PremiumFeature from '../../PremiumFeature'; @@ -119,12 +123,9 @@ export class TileEditor extends Component { this.setState({ editingTiles: props.editingTiles }); } componentDidUpdate(prevProps) { - if ( - this.props.open !== prevProps.open && - this.props.open && - this.editingTile() - ) { - this.setLinkedBoard(); + if (this.props.open !== prevProps.open && this.props.open) { + if (this.editingTile()) this.setLinkedBoard(); + if (isAndroid()) requestCvaPermissions(); } } diff --git a/src/components/UI/InputImage/InputImage.component.js b/src/components/UI/InputImage/InputImage.component.js index 97d421216..01096d4e2 100644 --- a/src/components/UI/InputImage/InputImage.component.js +++ b/src/components/UI/InputImage/InputImage.component.js @@ -52,9 +52,6 @@ class InputImage extends Component { }; render() { const { intl } = this.props; - if (isCordova()) { - requestCvaPermissions(); - } return (
diff --git a/src/components/VoiceRecorder/VoiceRecorder.component.js b/src/components/VoiceRecorder/VoiceRecorder.component.js index bbbeb4569..83b9e1572 100644 --- a/src/components/VoiceRecorder/VoiceRecorder.component.js +++ b/src/components/VoiceRecorder/VoiceRecorder.component.js @@ -32,11 +32,6 @@ class VoiceRecorder extends Component { isRecording: false, isPlaying: false }; - componentDidMount() { - if (isCordova()) { - requestCvaPermissions(); - } - } startRecording = () => { navigator.mediaDevices From 09f2e569ba687e70a20b914695291bc59347c0af Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 13 Nov 2023 15:09:28 -0300 Subject: [PATCH 04/10] Acces to device files via SAF on Android --- .../UI/InputImage/InputImage.component.js | 124 +++++++++++++----- src/components/UI/InputImage/InputImage.css | 7 + 2 files changed, 95 insertions(+), 36 deletions(-) diff --git a/src/components/UI/InputImage/InputImage.component.js b/src/components/UI/InputImage/InputImage.component.js index 01096d4e2..2c482a8b4 100644 --- a/src/components/UI/InputImage/InputImage.component.js +++ b/src/components/UI/InputImage/InputImage.component.js @@ -1,12 +1,29 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { injectIntl, intlShape } from 'react-intl'; -import { requestCvaPermissions, isCordova } from '../../../cordova-util'; +import { isAndroid } from '../../../cordova-util'; import PhotoCameraIcon from '@material-ui/icons/PhotoCamera'; -import readAndCompressImage from 'browser-image-resizer'; +import { readAndCompressImage } from 'browser-image-resizer'; import messages from './InputImage.messages'; import './InputImage.css'; +import Button from '@material-ui/core/Button'; +const configLQ = { + quality: 7, + maxWidth: 200, + maxHeight: 200, + autoRotate: true, + debug: true, + mimeType: 'image/png' +}; +const configHQ = { + quality: 1, + maxWidth: 800, + maxHeight: 800, + autoRotate: true, + debug: true, + mimeType: 'image/png' +}; class InputImage extends Component { static propTypes = { /** @@ -19,51 +36,86 @@ class InputImage extends Component { onChange: PropTypes.func.isRequired }; - async resizeImage(file, config) { - const resizedBlob = await readAndCompressImage(file, config); - return resizedBlob; + async resizeImage(file, imageName = null) { + //if you cancel the image uploaded, the event is dispached and the file is null + try { + const { onChange } = this.props; + const resizedBlob = await readAndCompressImage(file, configLQ); + const blobHQ = await readAndCompressImage(file, configHQ); + const fileName = imageName || file.name; + onChange(resizedBlob, fileName, blobHQ); + } catch (err) { + console.error(err); + } } + onClick = async () => { + const imageURL = await window.cordova.plugins.safMediastore.selectFile(); + const imageName = await window.cordova.plugins.safMediastore.getFileName( + imageURL + ); + const file = await new Promise((resolve, reject) => { + window.resolveLocalFileSystemURL( + imageURL, + fileEntry => { + fileEntry.file( + file => { + resolve(file); + }, + err => { + console.error(err); + resolve(null); + } + ); + }, + err => { + console.error(err); + resolve(null); + } + ); + }); + + if (file) { + await this.resizeImage(file, imageName); + } + }; + handleChange = async event => { const file = event.target.files[0]; - const configLQ = { - quality: 7, - maxWidth: 200, - maxHeight: 200, - autoRotate: true, - debug: false, - mimeType: 'image/png' - }; - const configHQ = { - quality: 1, - maxWidth: 800, - maxHeight: 800, - autoRotate: true, - debug: false, - mimeType: 'image/png' - }; if (file) { //if you cancel the image uploaded, the event is dispached and the file is null - const { onChange } = this.props; - const resizedBlob = await this.resizeImage(file, configLQ); - const blobHQ = await this.resizeImage(file, configHQ); - onChange(resizedBlob, file.name, blobHQ); + await this.resizeImage(file); } }; render() { const { intl } = this.props; return ( -
- - +
+ {isAndroid() ? ( +
+ +
+ ) : ( +
+ + +
+ )}
); } diff --git a/src/components/UI/InputImage/InputImage.css b/src/components/UI/InputImage/InputImage.css index 1eda393b9..56e4b408f 100644 --- a/src/components/UI/InputImage/InputImage.css +++ b/src/components/UI/InputImage/InputImage.css @@ -27,3 +27,10 @@ text-overflow: ellipsis; white-space: nowrap; } + +.InputImage__button { + width: 100%; +} +.InputImage__buttonContainer { + margin-top: 6px; +} From 51abfca616f14d7ea219fcd3cf65e3b98726ffc4 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 13 Nov 2023 15:10:08 -0300 Subject: [PATCH 05/10] Bump browser-image-resizer package to v2.4.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0568658e9..863f046cb 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@redux-beacon/logger": "^1.0.0", "@redux-beacon/offline-web": "^1.0.0", "axios": "^0.26.1", - "browser-image-resizer": "^1.2.0", + "browser-image-resizer": "^2.4.1", "dom-to-image": "^2.6.0", "dotenv": "^16.1.4", "echarts": "5.4.3", From 1f6ee2aee6b80640cd8f0f2a15b1ef38b5fcfc0f Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 13 Nov 2023 15:10:49 -0300 Subject: [PATCH 06/10] Update lock file --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 74da2beff..2f27cf243 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3974,10 +3974,10 @@ brotli@^1.2.0: dependencies: base64-js "^1.1.2" -browser-image-resizer@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browser-image-resizer/-/browser-image-resizer-1.2.0.tgz#7cbe7e3aa4c01f83f5441585208d90df40fa1696" - integrity sha512-xMiB6BnRsD6RWmkD6Av90qXY7uaAOXJPaS5D8cSazyao/bx6ENCm67XGl6BIhn1ETjK52yEs8A/atmMPp74M4A== +browser-image-resizer@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/browser-image-resizer/-/browser-image-resizer-2.4.1.tgz#b3332bbd6745efb72c9c63b4578b2a29f199ace3" + integrity sha512-gqrmr7+NTI9FgZVVyw/GIqwJE3MhNWaBn1R5ptu75r+/M5ncyntSMQYuYhOPonm44qQNnkGN9cnghlpd9h1Hug== browser-process-hrtime@^1.0.0: version "1.0.0" From 9d54811b012677acce7c64d17a06a90f4935fd46 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Mon, 13 Nov 2023 17:55:48 -0300 Subject: [PATCH 07/10] Fix test --- src/components/UI/InputImage/InputImage.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/UI/InputImage/InputImage.test.js b/src/components/UI/InputImage/InputImage.test.js index 659b6d89a..5720749cb 100644 --- a/src/components/UI/InputImage/InputImage.test.js +++ b/src/components/UI/InputImage/InputImage.test.js @@ -3,7 +3,6 @@ import { shallowMatchSnapshot } from '../../../common/test_utils'; import { mount, shallow } from 'enzyme'; import InputImage from './InputImage.component'; -jest.mock('browser-image-resizer'); jest.mock('../../../api/api'); jest.mock('./InputImage.messages', () => { From dd08f3943e760d3146b200d145282d5baf05d80f Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Tue, 14 Nov 2023 18:16:27 -0300 Subject: [PATCH 08/10] Remove unnecessary imports --- src/components/VoiceRecorder/VoiceRecorder.component.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/VoiceRecorder/VoiceRecorder.component.js b/src/components/VoiceRecorder/VoiceRecorder.component.js index 83b9e1572..598a626a2 100644 --- a/src/components/VoiceRecorder/VoiceRecorder.component.js +++ b/src/components/VoiceRecorder/VoiceRecorder.component.js @@ -7,7 +7,6 @@ import ClearIcon from '@material-ui/icons/Clear'; import LinearProgress from '@material-ui/core/LinearProgress'; import IconButton from '../UI/IconButton'; -import { isCordova, requestCvaPermissions } from '../../cordova-util'; import messages from './VoiceRecorder.messages'; import './VoiceRecorder.css'; let mediaStream = undefined; From 6e52bb8924d975a44fd8bed190f3243be0b3628d Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Tue, 14 Nov 2023 18:44:41 -0300 Subject: [PATCH 09/10] Remove debug prop con resize image config --- src/components/UI/InputImage/InputImage.component.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/UI/InputImage/InputImage.component.js b/src/components/UI/InputImage/InputImage.component.js index 2c482a8b4..e29f0dc99 100644 --- a/src/components/UI/InputImage/InputImage.component.js +++ b/src/components/UI/InputImage/InputImage.component.js @@ -13,7 +13,7 @@ const configLQ = { maxWidth: 200, maxHeight: 200, autoRotate: true, - debug: true, + debug: false, mimeType: 'image/png' }; const configHQ = { @@ -21,7 +21,7 @@ const configHQ = { maxWidth: 800, maxHeight: 800, autoRotate: true, - debug: true, + debug: false, mimeType: 'image/png' }; class InputImage extends Component { From 87995ca842fd7a959230e3f2a48c1137afaa56d0 Mon Sep 17 00:00:00 2001 From: Rodri Sanchez Date: Tue, 14 Nov 2023 18:52:17 -0300 Subject: [PATCH 10/10] Catch error onClick --- .../UI/InputImage/InputImage.component.js | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/src/components/UI/InputImage/InputImage.component.js b/src/components/UI/InputImage/InputImage.component.js index e29f0dc99..ea8149cbc 100644 --- a/src/components/UI/InputImage/InputImage.component.js +++ b/src/components/UI/InputImage/InputImage.component.js @@ -50,33 +50,37 @@ class InputImage extends Component { } onClick = async () => { - const imageURL = await window.cordova.plugins.safMediastore.selectFile(); - const imageName = await window.cordova.plugins.safMediastore.getFileName( - imageURL - ); - const file = await new Promise((resolve, reject) => { - window.resolveLocalFileSystemURL( - imageURL, - fileEntry => { - fileEntry.file( - file => { - resolve(file); - }, - err => { - console.error(err); - resolve(null); - } - ); - }, - err => { - console.error(err); - resolve(null); - } + try { + const imageURL = await window.cordova.plugins.safMediastore.selectFile(); + const imageName = await window.cordova.plugins.safMediastore.getFileName( + imageURL ); - }); + const file = await new Promise((resolve, reject) => { + window.resolveLocalFileSystemURL( + imageURL, + fileEntry => { + fileEntry.file( + file => { + resolve(file); + }, + err => { + console.error(err); + resolve(null); + } + ); + }, + err => { + console.error(err); + resolve(null); + } + ); + }); - if (file) { - await this.resizeImage(file, imageName); + if (file) { + await this.resizeImage(file, imageName); + } + } catch (err) { + console.error(err); } };