Skip to content

Commit

Permalink
Merge pull request #1613 from RodriSanchez1/fix/androidUploadImages
Browse files Browse the repository at this point in the history
Fix - Android 13 Upload images
  • Loading branch information
martinbedouret authored Nov 17, 2023
2 parents 83406db + 87995ca commit d9809b0
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 116 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
15 changes: 8 additions & 7 deletions src/components/Board/TileEditor/TileEditor.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -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();
}
}

Expand Down
131 changes: 92 additions & 39 deletions src/components/UI/InputImage/InputImage.component.js
Original file line number Diff line number Diff line change
@@ -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: false,
mimeType: 'image/png'
};
const configHQ = {
quality: 1,
maxWidth: 800,
maxHeight: 800,
autoRotate: true,
debug: false,
mimeType: 'image/png'
};
class InputImage extends Component {
static propTypes = {
/**
Expand All @@ -19,54 +36,90 @@ 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 () => {
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);
}
} catch (err) {
console.error(err);
}
};

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;
if (isCordova()) {
requestCvaPermissions();
}
return (
<div className="InputImage">
<PhotoCameraIcon />
<label className="InputImage__label">
{intl.formatMessage(messages.uploadImage)}
<input
className="InputImage__input"
type="file"
accept="image/*"
onChange={this.handleChange}
/>
</label>
<div>
{isAndroid() ? (
<div className="InputImage__buttonContainer">
<Button
variant="outlined"
onClick={this.onClick}
startIcon={<PhotoCameraIcon />}
className="InputImage__button"
>
{intl.formatMessage(messages.uploadImage)}
</Button>
</div>
) : (
<div className="InputImage">
<PhotoCameraIcon />
<label className="InputImage__label">
{intl.formatMessage(messages.uploadImage)}
<input
className="InputImage__input"
type="file"
accept="image/*"
onChange={this.handleChange}
/>
</label>
</div>
)}
</div>
);
}
Expand Down
7 changes: 7 additions & 0 deletions src/components/UI/InputImage/InputImage.css
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,10 @@
text-overflow: ellipsis;
white-space: nowrap;
}

.InputImage__button {
width: 100%;
}
.InputImage__buttonContainer {
margin-top: 6px;
}
1 change: 0 additions & 1 deletion src/components/UI/InputImage/InputImage.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
6 changes: 0 additions & 6 deletions src/components/VoiceRecorder/VoiceRecorder.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -32,11 +31,6 @@ class VoiceRecorder extends Component {
isRecording: false,
isPlaying: false
};
componentDidMount() {
if (isCordova()) {
requestCvaPermissions();
}
}

startRecording = () => {
navigator.mediaDevices
Expand Down
95 changes: 37 additions & 58 deletions src/cordova-util.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,72 +275,51 @@ 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',
READ_MEDIA_IMAGES: 'READ_MEDIA_IMAGES',
READ_MEDIA_AUDIO: 'READ_MEDIA_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);
// }
// );
}
}
};
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down

0 comments on commit d9809b0

Please sign in to comment.