Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix - Android 13 Upload images #1613

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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