split out a few modules, handle esc key
This commit is contained in:
+1
-1
@@ -1225,7 +1225,7 @@
|
||||
"label_description": {
|
||||
"translation": "الوصف",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1225,7 +1225,7 @@
|
||||
"label_description": {
|
||||
"translation": "Beschreibung",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1225,7 +1225,7 @@
|
||||
"label_description": {
|
||||
"translation": "Description",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1218,7 +1218,7 @@
|
||||
"label_description": {
|
||||
"translation": "Descripción",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
@@ -452,7 +452,7 @@
|
||||
},
|
||||
"label_description": {
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description"
|
||||
"description": "Label for description of user or topic"
|
||||
},
|
||||
"label_file_name": {
|
||||
"defaultMessage": "File name:",
|
||||
|
||||
+1
-1
@@ -1225,7 +1225,7 @@
|
||||
"label_description": {
|
||||
"translation": "Description",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1218,7 +1218,7 @@
|
||||
"label_description": {
|
||||
"translation": "Descrizione",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1218,7 +1218,7 @@
|
||||
"label_description": {
|
||||
"translation": "설명",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1218,7 +1218,7 @@
|
||||
"label_description": {
|
||||
"translation": "Descriere",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1218,7 +1218,7 @@
|
||||
"label_description": {
|
||||
"translation": "Описание",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1225,7 +1225,7 @@
|
||||
"label_description": {
|
||||
"translation": "คำอธิบาย",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1218,7 +1218,7 @@
|
||||
"label_description": {
|
||||
"translation": "Опис",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1218,7 +1218,7 @@
|
||||
"label_description": {
|
||||
"translation": "說明",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
+1
-1
@@ -1218,7 +1218,7 @@
|
||||
"label_description": {
|
||||
"translation": "说明",
|
||||
"defaultMessage": "Description",
|
||||
"description": "Label for editing topic description",
|
||||
"description": "Label for description of user or topic",
|
||||
"missing": false,
|
||||
"obsolete": false
|
||||
},
|
||||
|
||||
@@ -138,7 +138,7 @@ export default class AccountSettingsView extends React.Component {
|
||||
<div className="group">
|
||||
<label className="small">
|
||||
<FormattedMessage id="label_description" defaultMessage="Description"
|
||||
description="Label for editing topic description" />
|
||||
description="Label for description of user or topic" />
|
||||
</label>
|
||||
<div className="quoted">{this.state.description}</div>
|
||||
</div> : null}
|
||||
|
||||
+13
-4
@@ -2,7 +2,7 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage, FormattedNumber, defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import { AccessMode, Tinode } from 'tinode-sdk';
|
||||
import { AccessMode, Tinode, TheCard } from 'tinode-sdk';
|
||||
|
||||
import AvatarUpload from '../widgets/avatar-upload.jsx';
|
||||
import BadgeList from '../widgets/badge-list.jsx';
|
||||
@@ -20,7 +20,6 @@ import { MAX_TITLE_LENGTH, MAX_TOPIC_DESCRIPTION_LENGTH,
|
||||
NO_ACCESS_MODE, TOAST_DURATION } from '../config.js';
|
||||
|
||||
import { makeImageUrl } from '../lib/blob-helpers.js';
|
||||
import { theCard } from '../lib/utils.js';
|
||||
import { truncateString } from '../lib/strformat.js';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -147,6 +146,7 @@ class InfoView extends React.Component {
|
||||
this.handleLaunchPermissionsEditor = this.handleLaunchPermissionsEditor.bind(this);
|
||||
this.handleShowQRCode = this.handleShowQRCode.bind(this);
|
||||
this.handleCopyToClipboard = this.handleCopyToClipboard.bind(this);
|
||||
this.handleShare = this.handleShare.bind(this);
|
||||
this.handleShowAddMembers = this.handleShowAddMembers.bind(this);
|
||||
this.handleMemberUpdateRequest = this.handleMemberUpdateRequest.bind(this);
|
||||
this.handleMemberSelected = this.handleMemberSelected.bind(this);
|
||||
@@ -299,7 +299,7 @@ class InfoView extends React.Component {
|
||||
|
||||
handleImageChanged(mime, img) {
|
||||
this.setState({avatar: img});
|
||||
this.props.onTopicDescUpdate(this.props.topic, theCard(null, img || Tinode.DEL_CHAR), null);
|
||||
this.props.onTopicDescUpdate(this.props.topic, new TheCard(null, img || Tinode.DEL_CHAR), null);
|
||||
}
|
||||
|
||||
handleMuted(ignored, checked) {
|
||||
@@ -421,7 +421,13 @@ class InfoView extends React.Component {
|
||||
this.setState({toast: this.props.intl.formatMessage(messages.text_copied)});
|
||||
setTimeout(_ => { this.setState({toast: ''}); }, TOAST_DURATION);
|
||||
});
|
||||
}
|
||||
|
||||
handleShare(e) {
|
||||
e.preventDefault();
|
||||
const card = new TheCard(this.state.fullName, this.state.avatar, null, this.state.description);
|
||||
TheCard.setTinodeID(card, Tinode.URI_TOPIC_ID_PREFIX + this.props.topic);
|
||||
this.props.onShareTheCard(card);
|
||||
}
|
||||
|
||||
handleShowAddMembers(e) {
|
||||
@@ -629,6 +635,9 @@ class InfoView extends React.Component {
|
||||
<a href="#" onClick={this.handleShowQRCode}>
|
||||
<i className="material-icons">qr_code</i>
|
||||
</a>
|
||||
<a href="#" onClick={this.handleShare}>
|
||||
<i className="material-icons">share</i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{alias ?
|
||||
@@ -673,7 +682,7 @@ class InfoView extends React.Component {
|
||||
<div className="group">
|
||||
<label className="small">
|
||||
<FormattedMessage id="label_description" defaultMessage="Description"
|
||||
description="Label for editing topic description" />
|
||||
description="Label for description of user or topic" />
|
||||
</label>
|
||||
<div>{this.state.description}</div>
|
||||
</div> : null}
|
||||
|
||||
+102
-66
@@ -1,17 +1,17 @@
|
||||
// Panel with a chat.
|
||||
|
||||
import React from 'react';
|
||||
import React, { Suspense } from 'react';
|
||||
import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import { Drafty, Tinode, TheCard } from 'tinode-sdk';
|
||||
|
||||
import CallPanel from '../widgets/call-panel.jsx';
|
||||
const CallPanel = React.lazy(_ => import('../widgets/call-panel.jsx'));
|
||||
import ChatMessage from '../widgets/chat-message.jsx';
|
||||
import ContactBadges from '../widgets/contact-badges.jsx';
|
||||
import DocPreview from '../widgets/doc-preview.jsx';
|
||||
const DocPreview = React.lazy(_ => import('../widgets/doc-preview.jsx'));
|
||||
import ErrorPanel from '../widgets/error-panel.jsx';
|
||||
import GroupSubs from '../widgets/group-subs.jsx';
|
||||
import ImagePreview from '../widgets/image-preview.jsx';
|
||||
const ImagePreview = React.lazy(_ => import('../widgets/image-preview.jsx'));
|
||||
import Invitation from '../widgets/invitation.jsx';
|
||||
import LetterTile from '../widgets/letter-tile.jsx';
|
||||
import LoadSpinner from '../widgets/load-spinner.jsx';
|
||||
@@ -19,8 +19,8 @@ import LogoView from './logo-view.jsx';
|
||||
import MetaMessage from '../widgets/meta-message.jsx';
|
||||
import PinnedMessages from '../widgets/pinned-messages.jsx';
|
||||
import SendMessage from '../widgets/send-message.jsx';
|
||||
import TheCardPreview from '../widgets/the-card-preview.jsx';
|
||||
import VideoPreview from '../widgets/video-preview.jsx';
|
||||
const TheCardPreview = React.lazy(_ => import('../widgets/the-card-preview.jsx'));
|
||||
const VideoPreview = React.lazy(_ => import('../widgets/video-preview.jsx'));
|
||||
|
||||
import { DEFAULT_P2P_ACCESS_MODE, EDIT_PREVIEW_LENGTH, IMAGE_PREVIEW_DIM, IMMEDIATE_P2P_SUBSCRIPTION,
|
||||
DRAFTY_FR_MIME_TYPE_LEGACY, KEYPRESS_DELAY, MESSAGES_PAGE, MAX_EXTERN_ATTACHMENT_SIZE, MAX_IMAGE_DIM,
|
||||
@@ -390,11 +390,18 @@ class MessagesView extends React.Component {
|
||||
};
|
||||
|
||||
if (nextProps.forwardMessage) {
|
||||
// We are forwarding a message. Show preview.
|
||||
nextState.reply = {
|
||||
content: nextProps.forwardMessage.preview,
|
||||
seq: null
|
||||
};
|
||||
if (nextProps.forwardMessage.content) {
|
||||
nextState.docPreview = {
|
||||
object: nextProps.forwardMessage.content,
|
||||
type: nextProps.forwardMessage.type
|
||||
};
|
||||
} else {
|
||||
// We are forwarding a message. Show preview.
|
||||
nextState.reply = {
|
||||
content: nextProps.forwardMessage.preview,
|
||||
seq: null
|
||||
};
|
||||
}
|
||||
} else {
|
||||
nextState.reply = null;
|
||||
}
|
||||
@@ -908,7 +915,14 @@ class MessagesView extends React.Component {
|
||||
if (this.state.videoPreview && this.state.videoPreview.url) {
|
||||
URL.revokeObjectURL(this.state.videoPreview.url);
|
||||
}
|
||||
this.setState({ imagePostview: null, imagePreview: null, docPreview: null, videoPreview: null, videoPostview: null});
|
||||
this.setState({
|
||||
imagePostview: null,
|
||||
imagePreview: null,
|
||||
docPreview: null,
|
||||
videoPreview: null,
|
||||
videoPostview: null,
|
||||
});
|
||||
this.props.onCancelForwardMessage();
|
||||
}
|
||||
|
||||
handleFormResponse(action, text, data) {
|
||||
@@ -1522,22 +1536,25 @@ class MessagesView extends React.Component {
|
||||
// P2P call is an overlay, not a separate component because it cannot be
|
||||
// re-mounted between full screen/minimized.
|
||||
const overlay = this.state.rtcPanel &&
|
||||
<CallPanel
|
||||
topic={this.state.topic}
|
||||
seq={this.props.callSeq}
|
||||
callState={this.props.callState}
|
||||
callAudioOnly={this.props.callAudioOnly}
|
||||
tinode={this.props.tinode}
|
||||
title={this.state.title}
|
||||
avatar={this.state.avatar || true}
|
||||
minimized={this.state.minimizedCallPanel}
|
||||
onError={this.props.onError}
|
||||
onHangup={this.handleCallHangup}
|
||||
onToggleMinimize={this.handleCallPanelToggle}
|
||||
onInvite={this.props.onCallInvite}
|
||||
onSendOffer={this.props.onCallSendOffer}
|
||||
onIceCandidate={this.props.onCallIceCandidate}
|
||||
onSendAnswer={this.props.onCallSendAnswer} />;
|
||||
<Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<CallPanel
|
||||
topic={this.state.topic}
|
||||
seq={this.props.callSeq}
|
||||
callState={this.props.callState}
|
||||
callAudioOnly={this.props.callAudioOnly}
|
||||
tinode={this.props.tinode}
|
||||
title={this.state.title}
|
||||
avatar={this.state.avatar || true}
|
||||
minimized={this.state.minimizedCallPanel}
|
||||
onError={this.props.onError}
|
||||
onHangup={this.handleCallHangup}
|
||||
onToggleMinimize={this.handleCallPanelToggle}
|
||||
onInvite={this.props.onCallInvite}
|
||||
onSendOffer={this.props.onCallSendOffer}
|
||||
onIceCandidate={this.props.onCallIceCandidate}
|
||||
onSendAnswer={this.props.onCallSendAnswer} />
|
||||
</Suspense>;
|
||||
|
||||
let component;
|
||||
if (!this.state.topic) {
|
||||
@@ -1550,57 +1567,76 @@ class MessagesView extends React.Component {
|
||||
if (this.state.imagePreview) {
|
||||
// Preview image before sending.
|
||||
component2 = (
|
||||
<ImagePreview
|
||||
content={this.state.imagePreview}
|
||||
tinode={this.props.tinode}
|
||||
reply={this.state.reply}
|
||||
onCancelReply={this.handleCancelReply}
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendImageAttachment} />
|
||||
<Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<ImagePreview
|
||||
content={this.state.imagePreview}
|
||||
tinode={this.props.tinode}
|
||||
reply={this.state.reply}
|
||||
onCancelReply={this.handleCancelReply}
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendImageAttachment} />
|
||||
</Suspense>
|
||||
);
|
||||
} else if (this.state.videoPreview) {
|
||||
// Preview video.
|
||||
component2 = <VideoPreview
|
||||
content={this.state.videoPreview}
|
||||
tinode={this.props.tinode}
|
||||
reply={this.state.reply}
|
||||
onError={this.props.onError}
|
||||
onCancelReply={this.handleCancelReply}
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendVideoAttachment} />;
|
||||
component2 = <Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<VideoPreview
|
||||
content={this.state.videoPreview}
|
||||
tinode={this.props.tinode}
|
||||
reply={this.state.reply}
|
||||
onError={this.props.onError}
|
||||
onCancelReply={this.handleCancelReply}
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendVideoAttachment} />
|
||||
</Suspense>;
|
||||
|
||||
} else if (this.state.imagePostview) {
|
||||
// Expand received image.
|
||||
component2 = <ImagePreview
|
||||
content={this.state.imagePostview}
|
||||
onClose={this.handleClosePreview} />;
|
||||
component2 = <Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<ImagePreview
|
||||
content={this.state.imagePostview}
|
||||
onClose={this.handleClosePreview} />
|
||||
</Suspense>;
|
||||
|
||||
} else if (this.state.videoPostview) {
|
||||
// Play received video.
|
||||
component2 = <VideoPreview
|
||||
content={this.state.videoPostview}
|
||||
tinode={this.props.tinode}
|
||||
onError={this.props.onError}
|
||||
onClose={this.handleClosePreview} />;
|
||||
component2 = <Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<VideoPreview
|
||||
content={this.state.videoPostview}
|
||||
tinode={this.props.tinode}
|
||||
onError={this.props.onError}
|
||||
onClose={this.handleClosePreview} />
|
||||
</Suspense>;
|
||||
|
||||
} else if (this.state.docPreview) {
|
||||
// Preview attachment before sending.
|
||||
if (TheCard.isFileSupported(this.state.docPreview.type, this.state.docPreview.name)) {
|
||||
component2 = <TheCardPreview
|
||||
content={this.state.docPreview}
|
||||
tinode={this.props.tinode}
|
||||
reply={this.state.reply}
|
||||
onCancelReply={this.handleCancelReply}
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendFileAttachment} />;
|
||||
if (TheCard.isFileSupported(this.state.docPreview.type, this.state.docPreview.name) ||
|
||||
this.state.docPreview.type == TheCard.contentType) {
|
||||
component2 = <Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<TheCardPreview
|
||||
content={this.state.docPreview}
|
||||
tinode={this.props.tinode}
|
||||
reply={this.state.reply}
|
||||
onCancelReply={this.handleCancelReply}
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendFileAttachment} />
|
||||
</Suspense>;
|
||||
} else {
|
||||
component2 = <DocPreview
|
||||
content={this.state.docPreview}
|
||||
tinode={this.props.tinode}
|
||||
reply={this.state.reply}
|
||||
onCancelReply={this.handleCancelReply}
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendFileAttachment} />;
|
||||
component2 = <Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<DocPreview
|
||||
content={this.state.docPreview}
|
||||
tinode={this.props.tinode}
|
||||
reply={this.state.reply}
|
||||
onCancelReply={this.handleCancelReply}
|
||||
onClose={this.handleClosePreview}
|
||||
onSendMessage={this.sendFileAttachment} />
|
||||
</Suspense>;
|
||||
}
|
||||
} else {
|
||||
const topic = this.props.tinode.getTopic(this.state.topic);
|
||||
|
||||
+87
-47
@@ -15,7 +15,7 @@ import CallIncoming from '../widgets/call-incoming.jsx';
|
||||
const PhoneCountrySelector = React.lazy(_ => import('../widgets/phone-country-selector.jsx'));
|
||||
|
||||
const InfoView = React.lazy(_ => import('./info-view.jsx'));
|
||||
import MessagesView from './messages-view.jsx';
|
||||
const MessagesView = React.lazy(_ => import('./messages-view.jsx'));
|
||||
import SidepanelView from './sidepanel-view.jsx';
|
||||
|
||||
import { API_KEY, APP_NAME, DEFAULT_COLOR_SCHEME, DEFAULT_P2P_ACCESS_MODE, DEFAULT_TEXT_SIZE, FORWARDED_PREVIEW_LENGTH,
|
||||
@@ -108,6 +108,7 @@ class TinodeWeb extends React.Component {
|
||||
this.handleResize = this.handleResize.bind(this);
|
||||
this.handleHashRoute = this.handleHashRoute.bind(this);
|
||||
this.handleOnline = this.handleOnline.bind(this);
|
||||
this.handleEscapeKey = this.handleEscapeKey.bind(this);
|
||||
this.handleColorSchemeChange = this.handleColorSchemeChange.bind(this);
|
||||
this.checkForAppUpdate = this.checkForAppUpdate.bind(this);
|
||||
this.handleVisibilityEvent = this.handleVisibilityEvent.bind(this);
|
||||
@@ -165,6 +166,7 @@ class TinodeWeb extends React.Component {
|
||||
this.handleLeaveUnsubRequest = this.handleLeaveUnsubRequest.bind(this);
|
||||
this.handleBlockTopicRequest = this.handleBlockTopicRequest.bind(this);
|
||||
this.handleReportTopic = this.handleReportTopic.bind(this);
|
||||
this.handleShareTheCard = this.handleShareTheCard.bind(this);
|
||||
this.handleShowContextMenu = this.handleShowContextMenu.bind(this);
|
||||
this.defaultTopicContextMenu = this.defaultTopicContextMenu.bind(this);
|
||||
this.handleHideContextMenu = this.handleHideContextMenu.bind(this);
|
||||
@@ -318,6 +320,9 @@ class TinodeWeb extends React.Component {
|
||||
|
||||
// Window/tab visible or invisible for pausing timers.
|
||||
document.addEventListener('visibilitychange', this.handleVisibilityEvent);
|
||||
|
||||
// Listen for Escape key to clear selections.
|
||||
document.addEventListener('keydown', this.handleEscapeKey);
|
||||
|
||||
document.documentElement.style.colorScheme = this.state.colorSchema == 'auto' ? 'light dark' : this.state.colorSchema;
|
||||
document.documentElement.style.setProperty('--message-text-size', `${this.state.textSize}pt`);
|
||||
@@ -407,6 +412,7 @@ class TinodeWeb extends React.Component {
|
||||
window.removeEventListener('offline', this.handleOnlineOff);
|
||||
window.matchMedia('(prefers-color-scheme: dark)').removeEventListener('change', this.handleColorSchemeChange);
|
||||
document.removeEventListener('visibilitychange', this.handleVisibilityEvent);
|
||||
document.removeEventListener('keydown', this.handleEscapeKey);
|
||||
|
||||
clearInterval(this.wakeUpTicker);
|
||||
}
|
||||
@@ -516,6 +522,27 @@ class TinodeWeb extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleEscapeKey(e) {
|
||||
if (e.key === 'Escape' || e.keyCode === 27) {
|
||||
// Clear selections and navigate to base state
|
||||
this.setState({
|
||||
topicSelected: null,
|
||||
errorText: '',
|
||||
errorLevel: null,
|
||||
mobilePanel: 'sidepanel',
|
||||
topicSelectedOnline: false,
|
||||
topicSelectedAcs: null,
|
||||
infoPanel: undefined,
|
||||
forwardMessage: null,
|
||||
contextMenuVisible: false,
|
||||
forwardDialogVisible: false,
|
||||
alertVisible: false
|
||||
});
|
||||
// Navigate to contacts or login view
|
||||
HashNavigation.navigateTo(HashNavigation.setUrlTopic('', null));
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a newer version of TinodeWeb app is available at the server.
|
||||
checkForAppUpdate(reg) {
|
||||
reg.onupdatefound = _ => {
|
||||
@@ -1703,7 +1730,7 @@ class TinodeWeb extends React.Component {
|
||||
// If the Find panel is active, close it.
|
||||
this.handleSidepanelCancel();
|
||||
}
|
||||
const header = '➦ ' + params.userName;
|
||||
const header = params.userName ? '➦ ' + params.userName : '';
|
||||
const content = typeof params.content == 'string' ? Drafty.init(params.content) : Drafty.forwardedContent(params.content);
|
||||
const preview = Drafty.preview(content, FORWARDED_PREVIEW_LENGTH, true);
|
||||
const msg = Drafty.append(Drafty.appendLineBreak(Drafty.mention(header, params.userFrom)), content);
|
||||
@@ -1718,6 +1745,16 @@ class TinodeWeb extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
handleShareTheCard(card) {
|
||||
this.setState({
|
||||
forwardDialogVisible: true,
|
||||
forwardMessage: {
|
||||
content: card,
|
||||
type: card.contentType,
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
defaultTopicContextMenu(topicName) {
|
||||
const topic = this.tinode.getTopic(topicName);
|
||||
|
||||
@@ -2228,56 +2265,59 @@ class TinodeWeb extends React.Component {
|
||||
: null}
|
||||
|
||||
{!this.state.displayMobile || (this.state.mobilePanel == 'topic-view' && !this.state.infoPanel) ?
|
||||
<MessagesView
|
||||
tinode={this.tinode}
|
||||
connected={this.state.connected}
|
||||
ready={this.state.ready}
|
||||
online={this.state.topicSelectedOnline}
|
||||
acs={this.state.topicSelectedAcs}
|
||||
displayMobile={this.state.displayMobile}
|
||||
viewportWidth={this.state.viewportWidth}
|
||||
viewportHeight={this.state.viewportHeight}
|
||||
topic={this.state.topicSelected}
|
||||
myUserId={this.state.myUserId}
|
||||
// User public.fn.
|
||||
myUserName={this.state.sidePanelTitle}
|
||||
serverVersion={this.state.serverVersion}
|
||||
serverAddress={this.state.serverAddress}
|
||||
applicationVisible={this.state.applicationVisible}
|
||||
colorSchema={colorSchema}
|
||||
sendOnEnter={this.state.sendOnEnter}
|
||||
wallpaper={this.state.wallpaper}
|
||||
<Suspense fallback={<div><FormattedMessage id="loading_note" defaultMessage="Loading..."
|
||||
description="Message shown when component is loading"/></div>}>
|
||||
<MessagesView
|
||||
tinode={this.tinode}
|
||||
connected={this.state.connected}
|
||||
ready={this.state.ready}
|
||||
online={this.state.topicSelectedOnline}
|
||||
acs={this.state.topicSelectedAcs}
|
||||
displayMobile={this.state.displayMobile}
|
||||
viewportWidth={this.state.viewportWidth}
|
||||
viewportHeight={this.state.viewportHeight}
|
||||
topic={this.state.topicSelected}
|
||||
myUserId={this.state.myUserId}
|
||||
// User public.fn.
|
||||
myUserName={this.state.sidePanelTitle}
|
||||
serverVersion={this.state.serverVersion}
|
||||
serverAddress={this.state.serverAddress}
|
||||
applicationVisible={this.state.applicationVisible}
|
||||
colorSchema={colorSchema}
|
||||
sendOnEnter={this.state.sendOnEnter}
|
||||
wallpaper={this.state.wallpaper}
|
||||
|
||||
forwardMessage={this.state.forwardMessage}
|
||||
onCancelForwardMessage={this.handleHideForwardDialog}
|
||||
forwardMessage={this.state.forwardMessage}
|
||||
onCancelForwardMessage={this.handleHideForwardDialog}
|
||||
|
||||
callTopic={this.state.callTopic}
|
||||
callSeq={this.state.callSeq}
|
||||
callState={this.state.callState}
|
||||
callAudioOnly={this.state.callAudioOnly}
|
||||
onCallHangup={this.handleCallHangup}
|
||||
onAcceptCall={this.handleCallAccept}
|
||||
callTopic={this.state.callTopic}
|
||||
callSeq={this.state.callSeq}
|
||||
callState={this.state.callState}
|
||||
callAudioOnly={this.state.callAudioOnly}
|
||||
onCallHangup={this.handleCallHangup}
|
||||
onAcceptCall={this.handleCallAccept}
|
||||
|
||||
onCallInvite={this.handleCallInvite}
|
||||
onCallSendOffer={this.handleCallSendOffer}
|
||||
onCallIceCandidate={this.handleCallIceCandidate}
|
||||
onCallSendAnswer={this.handleCallSendAnswer}
|
||||
onCallInvite={this.handleCallInvite}
|
||||
onCallSendOffer={this.handleCallSendOffer}
|
||||
onCallIceCandidate={this.handleCallIceCandidate}
|
||||
onCallSendAnswer={this.handleCallSendAnswer}
|
||||
|
||||
errorText={this.state.errorText}
|
||||
errorLevel={this.state.errorLevel}
|
||||
errorAction={this.state.errorAction}
|
||||
errorActionText={this.state.errorActionText}
|
||||
errorText={this.state.errorText}
|
||||
errorLevel={this.state.errorLevel}
|
||||
errorAction={this.state.errorAction}
|
||||
errorActionText={this.state.errorActionText}
|
||||
|
||||
newTopicParams={this.state.newTopicParams}
|
||||
newTopicParams={this.state.newTopicParams}
|
||||
|
||||
onHideMessagesView={this.handleHideMessagesView}
|
||||
onError={this.handleError}
|
||||
onNewTopicCreated={this.handleNewTopicCreated}
|
||||
showContextMenu={this.handleShowContextMenu}
|
||||
onChangePermissions={this.handleChangePermissions}
|
||||
onNewChat={this.handleNewChatInvitation}
|
||||
sendMessage={this.handleSendMessage}
|
||||
onVideoCallClosed={this.handleCallClose} />
|
||||
onHideMessagesView={this.handleHideMessagesView}
|
||||
onError={this.handleError}
|
||||
onNewTopicCreated={this.handleNewTopicCreated}
|
||||
showContextMenu={this.handleShowContextMenu}
|
||||
onChangePermissions={this.handleChangePermissions}
|
||||
onNewChat={this.handleNewChatInvitation}
|
||||
sendMessage={this.handleSendMessage}
|
||||
onVideoCallClosed={this.handleCallClose} />
|
||||
</Suspense>
|
||||
: null}
|
||||
|
||||
{this.state.infoPanel ?
|
||||
@@ -2307,7 +2347,7 @@ class TinodeWeb extends React.Component {
|
||||
onLeaveTopic={this.handleLeaveUnsubRequest}
|
||||
onBlockTopic={this.handleBlockTopicRequest}
|
||||
onReportTopic={this.handleReportTopic}
|
||||
onAddMember={this.handleManageGroupMembers}
|
||||
onShareTheCard={this.handleShareTheCard}
|
||||
onTopicTagsUpdateRequest={this.handleTagsUpdateRequest}
|
||||
onTopicUnArchive={this.handleUnarchive}
|
||||
onInitFind={this.tnInitFind}
|
||||
|
||||
@@ -46,7 +46,7 @@ export default class DocPreview extends React.PureComponent {
|
||||
}
|
||||
return (
|
||||
<div id="image-preview">
|
||||
<div id="image-preview-caption-panel">
|
||||
<div id="preview-caption-panel">
|
||||
<span>{this.props.content.name}</span>
|
||||
<a href="#" onClick={(e) => {e.preventDefault(); this.props.onClose();}}><i className="material-icons gray">close</i></a>
|
||||
</div>
|
||||
|
||||
@@ -77,7 +77,7 @@ export default class ImagePreview extends React.PureComponent {
|
||||
|
||||
return (
|
||||
<div id="image-preview">
|
||||
<div id="image-preview-caption-panel">
|
||||
<div id="preview-caption-panel">
|
||||
{this.props.onSendMessage ?
|
||||
<span>{fname}</span>
|
||||
:
|
||||
|
||||
@@ -161,7 +161,7 @@ export default class NewTopicGroup extends React.PureComponent {
|
||||
<div className="group">
|
||||
<label className="small" htmlFor="new-topic-desc">
|
||||
<FormattedMessage id="label_description" defaultMessage="Description"
|
||||
description="Label for editing topic description" />
|
||||
description="Label for description of user or topic" />
|
||||
</label>
|
||||
<FormattedMessage id="description_editing_placeholder" defaultMessage="Description (optional)"
|
||||
description="Placeholder for editing topic description">{
|
||||
|
||||
@@ -23,6 +23,7 @@ export default class ShowQRCode extends React.PureComponent {
|
||||
<div className="panel-form-column">
|
||||
<br />
|
||||
<div className="qr-code" ref={this.qrCodeRef} />
|
||||
<div><tt>{this.props.uri}</tt></div>
|
||||
<div className="dialog-buttons">
|
||||
<button className="outline" onClick={this.props.onCancel}>
|
||||
<FormattedMessage id="button_ok" defaultMessage="OK" description="Button [OK]" />
|
||||
|
||||
@@ -21,13 +21,15 @@ export default class TheCardPreview extends React.PureComponent {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
content: null
|
||||
content: props.content.object
|
||||
};
|
||||
|
||||
importVCard(props.content.file)
|
||||
.then(card => {
|
||||
this.setState({ content: card });
|
||||
});
|
||||
if (!props.content.object) {
|
||||
importVCard(props.content.file)
|
||||
.then(card => {
|
||||
this.setState({ content: card });
|
||||
});
|
||||
}
|
||||
|
||||
this.handleSendCard = this.handleSendCard.bind(this);
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
@@ -122,7 +124,7 @@ export default class TheCardPreview extends React.PureComponent {
|
||||
|
||||
return (
|
||||
<div id="image-preview">
|
||||
<div id="image-preview-caption-panel">
|
||||
<div id="preview-caption-panel">
|
||||
<span><FormattedMessage id="label_contact_card" defaultMessage="Contact Card"
|
||||
description="Label for contact card preview" /></span>
|
||||
<a href="#" onClick={(e) => {e.preventDefault(); this.props.onClose();}}>
|
||||
@@ -153,7 +155,7 @@ export default class TheCardPreview extends React.PureComponent {
|
||||
<div className="group">
|
||||
<label className="small">
|
||||
<FormattedMessage id="label_description" defaultMessage="Description"
|
||||
description="Label for description" />
|
||||
description="Label for description of user or topic" />
|
||||
</label>
|
||||
<div className="quoted">{note}</div>
|
||||
</div>
|
||||
|
||||
@@ -363,7 +363,7 @@ class TopicDescEdit extends React.Component {
|
||||
<div className="group">
|
||||
<div><label className="small">
|
||||
<FormattedMessage id="label_description" defaultMessage="Description"
|
||||
description="Label for editing topic description" />
|
||||
description="Label for description of user or topic" />
|
||||
</label></div>
|
||||
<div>
|
||||
<FormattedMessage id="description_editing_placeholder"
|
||||
|
||||
@@ -81,7 +81,7 @@ class VideoPreview extends React.PureComponent {
|
||||
|
||||
return (
|
||||
<div id="image-preview">
|
||||
<div id="image-preview-caption-panel">
|
||||
<div id="preview-caption-panel">
|
||||
<span>{this.props.content.filename}</span>
|
||||
<a href="#" onClick={e => {e.preventDefault(); this.props.onClose();}}><i className="material-icons gray">close</i></a>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user