wip: out of band avatars
This commit is contained in:
+6
-3
@@ -45,9 +45,12 @@ export const MEDIA_BREAKPOINT = 640;
|
||||
// Size of css 'rem' unit in pixels. Default 1rem = 10pt = 13px.
|
||||
export const REM_SIZE = 13;
|
||||
|
||||
// Size of the avatar image: When an avatar image is uploaded, it's resized to
|
||||
// a square of this size.
|
||||
export const AVATAR_SIZE = 128;
|
||||
// Size of the avatar image: when an image is uploaded, it's resized to
|
||||
// a square of this size or less.
|
||||
export const AVATAR_SIZE = 384;
|
||||
|
||||
// Maximum size of an avatar in bytes for sending in-band. Bigger avatars will be sent out of band (as uploads).
|
||||
export const MAX_AVATAR_BYTES = 8192;
|
||||
|
||||
// Size of the broken_image shown in MessagesView
|
||||
export const BROKEN_IMAGE_SIZE = 32;
|
||||
|
||||
@@ -146,6 +146,7 @@ export default class AccGeneralView extends React.Component {
|
||||
}</FormattedMessage></div>
|
||||
</div>
|
||||
<AvatarUpload
|
||||
tinode={this.props.tinode}
|
||||
avatar={this.state.avatar}
|
||||
uid={this.props.myUserId}
|
||||
title={this.state.fullName}
|
||||
|
||||
@@ -92,6 +92,7 @@ export default class CreateAccountView extends React.PureComponent {
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
<AvatarUpload
|
||||
tinode={this.props.tinode}
|
||||
onImageChanged={this.handleImageChanged}
|
||||
onError={this.props.onError} />
|
||||
</div>
|
||||
|
||||
@@ -36,6 +36,7 @@ export default class EditAccountView extends React.Component {
|
||||
<BadgeList trustedBadges={this.props.trustedBadges} />
|
||||
</div>
|
||||
<AvatarUpload
|
||||
tinode={this.props.tinode}
|
||||
avatar={this.state.avatar}
|
||||
readOnly={!this.state.owner}
|
||||
uid={this.props.myUserId}
|
||||
|
||||
@@ -600,6 +600,7 @@ class InfoView extends React.Component {
|
||||
<BadgeList trustedBadges={this.state.trustedBadges} />
|
||||
</div>
|
||||
<AvatarUpload
|
||||
tinode={this.props.tinode}
|
||||
avatar={this.state.avatar}
|
||||
readOnly={!this.state.owner}
|
||||
uid={this.props.topic}
|
||||
|
||||
@@ -150,6 +150,7 @@ class SidepanelView extends React.Component {
|
||||
|
||||
view === 'register' ?
|
||||
<CreateAccountView
|
||||
tinode={this.props.tinode}
|
||||
onCreateAccount={this.props.onCreateAccount}
|
||||
onCancel={this.props.onCancel}
|
||||
onError={this.props.onError} /> :
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import React from 'react';
|
||||
|
||||
import LetterTile from './letter-tile.jsx';
|
||||
import LoadSpinner from './load-spinner.jsx';
|
||||
|
||||
import { AVATAR_SIZE, MAX_EXTERN_ATTACHMENT_SIZE } from '../config.js';
|
||||
import { AVATAR_SIZE, IMAGE_PREVIEW_DIM, MAX_AVATAR_BYTES, MAX_EXTERN_ATTACHMENT_SIZE,
|
||||
MAX_INBAND_ATTACHMENT_SIZE } from '../config.js';
|
||||
import { imageScaled, blobToBase64, makeImageDataUrl } from '../lib/blob-helpers.js';
|
||||
|
||||
export default class AvatarUpload extends React.Component {
|
||||
@@ -10,7 +12,8 @@ export default class AvatarUpload extends React.Component {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
dataUrl: props.avatar
|
||||
dataUrl: props.avatar,
|
||||
uploading: false
|
||||
};
|
||||
|
||||
this.handleFileUpload = this.handleFileUpload.bind(this);
|
||||
@@ -18,25 +21,44 @@ export default class AvatarUpload extends React.Component {
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.props.avatar != prevProps.avatar) {
|
||||
this.setState({dataUrl: this.props.avatar})
|
||||
this.setState({dataUrl: this.props.avatar});
|
||||
}
|
||||
}
|
||||
|
||||
handleFileUpload(e) {
|
||||
imageScaled(e.target.files[0], AVATAR_SIZE, AVATAR_SIZE, MAX_EXTERN_ATTACHMENT_SIZE, true,
|
||||
// Image successfully scaled and converted.
|
||||
(mime, blob) => {
|
||||
// Convert blob to base64-encoded bits.
|
||||
blobToBase64(blob, (unused, base64bits) => {
|
||||
const du = makeImageDataUrl({data: base64bits, type: mime});
|
||||
this.setState({dataUrl: du});
|
||||
this.props.onImageChanged(du);
|
||||
const image = e.target.files[0];
|
||||
if (image.size > MAX_AVATAR_BYTES) {
|
||||
// Too large to send inband - uploading out of band and sending as a link.
|
||||
const uploader = this.props.tinode.getLargeFileHelper();
|
||||
if (!uploader) {
|
||||
this.props.onError(this.props.intl.formatMessage(messages.cannot_initiate_upload));
|
||||
return;
|
||||
}
|
||||
|
||||
uploader.upload(image)
|
||||
.then(() => {})
|
||||
.catch((err) => {
|
||||
this.props.onError(err, 'err');
|
||||
})
|
||||
.finally(() => {
|
||||
this.setState({uploading: false});
|
||||
});
|
||||
},
|
||||
// Failure
|
||||
(err) => {
|
||||
this.props.onError(err, 'err');
|
||||
});
|
||||
} else {
|
||||
imageScaled(image, AVATAR_SIZE, AVATAR_SIZE, MAX_EXTERN_ATTACHMENT_SIZE, true,
|
||||
// Image successfully scaled and converted.
|
||||
(mime, blob) => {
|
||||
// Convert blob to base64-encoded bits.
|
||||
blobToBase64(blob, (unused, base64bits) => {
|
||||
const du = makeImageDataUrl({data: base64bits, type: mime});
|
||||
this.setState({dataUrl: du});
|
||||
this.props.onImageChanged(du);
|
||||
});
|
||||
},
|
||||
// Failure
|
||||
(err) => {
|
||||
this.props.onError(err, 'err');
|
||||
});
|
||||
}
|
||||
// Clear the value so the same file can be uploaded again.
|
||||
e.target.value = '';
|
||||
}
|
||||
@@ -71,6 +93,7 @@ export default class AvatarUpload extends React.Component {
|
||||
<label htmlFor={randId} className="round">
|
||||
<i className="material-icons">file_upload</i>
|
||||
</label>}
|
||||
<LoadSpinner show={this.state.uploading} large={true} clear={true} centered={true} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,7 +2,9 @@ import React from 'react';
|
||||
|
||||
export default class LoadSpinner extends React.PureComponent {
|
||||
render() {
|
||||
const className = 'load-spinner-box' + (this.props.large ? ' large' : '')
|
||||
+ (this.props.clear ? ' clear' : '') + (this.props.centered ? ' centered' : '');
|
||||
return (this.props.show ?
|
||||
<div className="load-spinner-box"><div className="loader-spinner"></div></div> : null);
|
||||
<div className={className}><div className="loader-spinner"></div></div> : null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ export default class NewTopicGroup extends React.PureComponent {
|
||||
}</FormattedMessage>
|
||||
</div>
|
||||
<AvatarUpload
|
||||
tinode={this.props.tinode}
|
||||
onError={this.props.onError}
|
||||
onImageChanged={this.handleImageChanged} />
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user