227 lines
6.4 KiB
JavaScript
227 lines
6.4 KiB
JavaScript
|
|
import React, { Component } from 'react';
|
|
import PropTypes from 'prop-types';
|
|
import { ipcRenderer } from 'electron';
|
|
import clazz from 'classname';
|
|
|
|
import classes from './style.css';
|
|
import Emoji from './Emoji';
|
|
|
|
export default class MessageInput extends Component {
|
|
static propTypes = {
|
|
me: PropTypes.object,
|
|
sendMessage: PropTypes.func.isRequired,
|
|
showMessage: PropTypes.func.isRequired,
|
|
user: PropTypes.array.isRequired,
|
|
confirmSendImage: PropTypes.func.isRequired,
|
|
process: PropTypes.func.isRequired,
|
|
};
|
|
|
|
static defaultProps = {
|
|
me: {},
|
|
};
|
|
|
|
canisend() {
|
|
var user = this.props.user;
|
|
|
|
if (
|
|
true
|
|
&& user.length === 1
|
|
&& user.slice(-1).pop().UserName === this.props.me.UserName
|
|
) {
|
|
this.props.showMessage('不能向自己发送消息');
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
async handleEnter(e) {
|
|
var message = this.refs.input.value.trim();
|
|
var user = this.props.user;
|
|
var batch = user.length > 1;
|
|
|
|
if (
|
|
false
|
|
|| !this.canisend()
|
|
|| !message
|
|
|| e.charCode !== 13
|
|
) return;
|
|
|
|
// You can not send message to yourself
|
|
Promise.all(
|
|
user.filter(e => e.UserName !== this.props.me.UserName).map(
|
|
async e => {
|
|
let res = await this.props.sendMessage(
|
|
e,
|
|
{
|
|
content: message,
|
|
type: 1,
|
|
},
|
|
true
|
|
);
|
|
|
|
if (!res) {
|
|
await this.props.showMessage(batch ? `Sending message to ${e.NickName} has failed!` : '消息发送失败');
|
|
}
|
|
|
|
return true;
|
|
}
|
|
)
|
|
);
|
|
|
|
this.refs.input.value = '';
|
|
}
|
|
|
|
state = {
|
|
showEmoji: false
|
|
};
|
|
|
|
toggleEmoji(show = !this.state.showEmoji) {
|
|
this.setState({ showEmoji: show });
|
|
}
|
|
|
|
writeEmoji(emoji) {
|
|
var input = this.refs.input;
|
|
|
|
input.value += `[${emoji}]`;
|
|
input.focus();
|
|
}
|
|
|
|
async batchProcess(file) {
|
|
var message;
|
|
var batch = this.props.user.length > 1;
|
|
var receiver = this.props.user.filter(e => e.UserName !== this.props.me.UserName);
|
|
var showMessage = this.props.showMessage;
|
|
|
|
if (this.canisend() === false) {
|
|
return;
|
|
}
|
|
|
|
for (let user of receiver) {
|
|
if (message) {
|
|
await this.props.sendMessage(user, message, true)
|
|
.catch(ex => showMessage(`Sending message to ${user.NickName} has failed!`));
|
|
continue;
|
|
}
|
|
|
|
// Do not repeat upload file, forward the message to another user
|
|
message = await this.props.process(file, user);
|
|
|
|
if (message === false) {
|
|
if (batch) {
|
|
showMessage(`Send message to ${user.NickName} is failed!`);
|
|
continue;
|
|
}
|
|
// In batch mode just show the failed message
|
|
showMessage('发送图片失败');
|
|
}
|
|
}
|
|
}
|
|
|
|
async handlePaste(e) {
|
|
var args = ipcRenderer.sendSync('file-paste');
|
|
|
|
if (args.hasImage && this.canisend()) {
|
|
e.preventDefault();
|
|
|
|
if ((await this.props.confirmSendImage(args.filename)) === false) {
|
|
return;
|
|
}
|
|
|
|
let parts = [
|
|
new window.Blob([new window.Uint8Array(args.raw.data)], { type: 'image/png' })
|
|
];
|
|
let file = new window.File(parts, args.filename, {
|
|
lastModified: new Date(),
|
|
type: 'image/png'
|
|
});
|
|
|
|
this.batchProcess(file);
|
|
}
|
|
}
|
|
|
|
componentWillReceiveProps(nextProps) {
|
|
var input = this.refs.input;
|
|
|
|
// When user has changed clear the input
|
|
if (
|
|
true
|
|
&& input
|
|
&& input.value
|
|
&& this.props.user.map(e => e.UserName).join() !== nextProps.user.map(e => e.UserName).join()
|
|
) {
|
|
input.value = '';
|
|
}
|
|
}
|
|
|
|
render() {
|
|
var canisend = !!this.props.user.length;
|
|
|
|
return (
|
|
<div
|
|
className={
|
|
clazz(
|
|
classes.container,
|
|
this.props.className,
|
|
{
|
|
[classes.shouldSelectUser]: !canisend,
|
|
}
|
|
)
|
|
}
|
|
>
|
|
<div
|
|
className={classes.tips}
|
|
>
|
|
You should choose a contact first.
|
|
</div>
|
|
|
|
<input
|
|
id="messageInput"
|
|
ref="input"
|
|
type="text"
|
|
placeholder="在此输入内容..."
|
|
readOnly={!canisend}
|
|
onPaste={e => this.handlePaste(e)}
|
|
onKeyPress={e => this.handleEnter(e)}
|
|
/>
|
|
|
|
<div className={classes.action}>
|
|
<i
|
|
className="icon-ion-android-attach"
|
|
id="showUploader"
|
|
onClick={e => canisend && this.refs.uploader.click()}
|
|
/>
|
|
|
|
<i
|
|
className="icon-ion-ios-heart"
|
|
id="showEmoji"
|
|
onClick={e => canisend && this.toggleEmoji(true)}
|
|
style={{
|
|
color: 'red',
|
|
}}
|
|
/>
|
|
|
|
<input
|
|
onChange={e => {
|
|
this.batchProcess(e.target.files[0]);
|
|
e.target.value = '';
|
|
}}
|
|
ref="uploader"
|
|
style={{
|
|
display: 'none',
|
|
}}
|
|
type="file"
|
|
/>
|
|
|
|
<Emoji
|
|
close={e => setTimeout(() => this.toggleEmoji(false), 100)}
|
|
output={emoji => this.writeEmoji(emoji)}
|
|
show={this.state.showEmoji}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
}
|