add warning when peer's messaging is disabled

This commit is contained in:
or-else
2019-03-02 15:52:58 +03:00
parent a9ba11a0ff
commit 29425b48fc
14 changed files with 170 additions and 59 deletions
+27 -5
View File
@@ -519,6 +519,11 @@ table.permission-editor td.checkbox {
cursor: pointer; cursor: pointer;
} }
.clean-clickable {
cursor: pointer;
}
/* END of top-level layout */ /* END of top-level layout */
/* Sidepanel styles */ /* Sidepanel styles */
@@ -1072,18 +1077,35 @@ i.search {
#write-only-note { #write-only-note {
position: absolute; position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: white; background-color: white;
color: #666; color: #666;
height: auto; height: auto;
width: auto; width: auto;
line-height: 2rem; line-height: 2rem;
text-align: center; text-align: center;
top: 50%; padding: 0.75rem 1.25rem 0.75rem 1.25rem;
left: 50%; border-radius: 0.5rem;
transform: translate(-50%, -50%); box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.12);
padding: 0.25rem 1.5rem;
box-shadow: 0.1rem 0.1rem 0.1rem rgba(0,0,0,0.2);
} }
#peer-messaging-disabled-note {
position: absolute;
left: 50%;
bottom: 4.3rem;
transform: translate(-50%);
background-color: white;
color: #666;
width: fit-content;
line-height: 2rem;
text-align: center;
padding: 0.75rem 1.25rem 0.75rem 1.25rem;
border-radius: 0.5rem;
box-shadow: 0 1px 0.5px rgba(0, 0, 0, 0.12);
}
/* Footer-panel with the input for the new message */ /* Footer-panel with the input for the new message */
#send-message-panel { #send-message-panel {
display: flex; display: flex;
+1 -1
View File
File diff suppressed because one or more lines are too long
+3
View File
@@ -25,6 +25,9 @@ export const MIN_TAG_LENGTH = 4;
// Access mode for subscriptions initiated by the current user. // Access mode for subscriptions initiated by the current user.
export const DEFAULT_ACCESS_MODE = 'JRWPS'; export const DEFAULT_ACCESS_MODE = 'JRWPS';
// Access mode for no access.
export const NO_ACCESS_MODE = 'N';
// Mediaquery breakpoint between desktop and mobile, in px. Should match the value // Mediaquery breakpoint between desktop and mobile, in px. Should match the value
// in @media (max-size: 640px) in base.css // in @media (max-size: 640px) in base.css
export const MEDIA_BREAKPOINT = 640; export const MEDIA_BREAKPOINT = 640;
+2
View File
@@ -45,6 +45,8 @@
"title_not_found": "Not found", "title_not_found": "Not found",
"unnamed_topic": "Unnamed", "unnamed_topic": "Unnamed",
"messages_not_readable": "no access to messages", "messages_not_readable": "no access to messages",
"peers_messaging_disabled": "Peer's messaging is disabled.",
"enable_peers_messaging": "Enable",
"tabtitle_find_user": "find", "tabtitle_find_user": "find",
"tabtitle_new_group": "new group", "tabtitle_new_group": "new group",
"tabtitle_group_by_id": "by id", "tabtitle_group_by_id": "by id",
+3 -1
View File
@@ -129,5 +129,7 @@
"chat_invitation": "Вас пригласили начать новый чат. Как вы хотите поступить?", "chat_invitation": "Вас пригласили начать новый чат. Как вы хотите поступить?",
"chat_invitation_accept": "Принять", "chat_invitation_accept": "Принять",
"chat_invitation_ignore": "Игнорировать", "chat_invitation_ignore": "Игнорировать",
"chat_invitation_block": "Заблокировать" "chat_invitation_block": "Заблокировать",
"peers_messaging_disabled": "Чат заблокирован у корреспондента.",
"enable_peers_messaging": "Разблокировать."
} }
+5 -1
View File
@@ -46,6 +46,8 @@
"title_not_found": "Not found", "title_not_found": "Not found",
"unnamed_topic": "Unnamed", "unnamed_topic": "Unnamed",
"messages_not_readable": "no access to messages", "messages_not_readable": "no access to messages",
"peers_messaging_disabled": "Peer's messaging is disabled.",
"enable_peers_messaging": "Enable",
"tabtitle_find_user": "find", "tabtitle_find_user": "find",
"tabtitle_new_group": "new group", "tabtitle_new_group": "new group",
"tabtitle_group_by_id": "by id", "tabtitle_group_by_id": "by id",
@@ -263,6 +265,8 @@
"chat_invitation": "Вас пригласили начать новый чат. Как вы хотите поступить?", "chat_invitation": "Вас пригласили начать новый чат. Как вы хотите поступить?",
"chat_invitation_accept": "Принять", "chat_invitation_accept": "Принять",
"chat_invitation_ignore": "Игнорировать", "chat_invitation_ignore": "Игнорировать",
"chat_invitation_block": "Заблокировать" "chat_invitation_block": "Заблокировать",
"peers_messaging_disabled": "Чат заблокирован у корреспондента.",
"enable_peers_messaging": "Разблокировать."
} }
} }
+7 -2
View File
@@ -15,6 +15,8 @@ import MoreButton from '../widgets/more-button.jsx';
import PermissionsEditor from '../widgets/permissions-editor.jsx'; import PermissionsEditor from '../widgets/permissions-editor.jsx';
import TagManager from '../widgets/tag-manager.jsx'; import TagManager from '../widgets/tag-manager.jsx';
import { NO_ACCESS_MODE } from '../config.js';
import { makeImageUrl } from '../lib/blob-helpers.js'; import { makeImageUrl } from '../lib/blob-helpers.js';
import { vcard } from '../lib/utils.js'; import { vcard } from '../lib/utils.js';
@@ -145,6 +147,9 @@ class InfoView extends React.Component {
if (user2) { if (user2) {
newState.modeGiven2 = user2.acs.getGiven(); newState.modeGiven2 = user2.acs.getGiven();
newState.modeWant2 = user2.acs.getWant(); newState.modeWant2 = user2.acs.getWant();
} else {
newState.modeGiven2 = NO_ACCESS_MODE;
newState.modeWant2 = NO_ACCESS_MODE;
} }
} else { } else {
topic.subscribers((sub) => { topic.subscribers((sub) => {
@@ -196,7 +201,7 @@ class InfoView extends React.Component {
} }
} }
onSubsUpdated() { onSubsUpdated(subs) {
const topic = this.props.tinode.getTopic(this.props.topic); const topic = this.props.tinode.getTopic(this.props.topic);
if (!topic) { if (!topic) {
return; return;
@@ -204,7 +209,7 @@ class InfoView extends React.Component {
this.resetSubs(topic, this.props); this.resetSubs(topic, this.props);
if (this.previousSubsUpdated && this.previousSubsUpdated != this.onSubsUpdated) { if (this.previousSubsUpdated && this.previousSubsUpdated != this.onSubsUpdated) {
this.previousSubsUpdated(); this.previousSubsUpdated(subs);
} }
} }
+49 -21
View File
@@ -14,7 +14,7 @@ import LoadSpinner from '../widgets/load-spinner.jsx';
import LogoView from './logo-view.jsx'; import LogoView from './logo-view.jsx';
import SendMessage from '../widgets/send-message.jsx'; import SendMessage from '../widgets/send-message.jsx';
import { KEYPRESS_DELAY, MESSAGES_PAGE } from '../config.js'; import { DEFAULT_ACCESS_MODE, KEYPRESS_DELAY, MESSAGES_PAGE } from '../config.js';
import { makeImageUrl } from '../lib/blob-helpers.js'; import { makeImageUrl } from '../lib/blob-helpers.js';
import { shortDateFormat } from '../lib/strformat.js'; import { shortDateFormat } from '../lib/strformat.js';
@@ -67,6 +67,7 @@ class MessagesView extends React.Component {
this.handleShowContextMenuMessage = this.handleShowContextMenuMessage.bind(this); this.handleShowContextMenuMessage = this.handleShowContextMenuMessage.bind(this);
this.handleBackNavigation = this.handleBackNavigation.bind(this); this.handleBackNavigation = this.handleBackNavigation.bind(this);
this.handleNewChatAcceptance = this.handleNewChatAcceptance.bind(this); this.handleNewChatAcceptance = this.handleNewChatAcceptance.bind(this);
this.handleEnablePeer = this.handleEnablePeer.bind(this);
} }
componentDidMount() { componentDidMount() {
@@ -138,7 +139,7 @@ class MessagesView extends React.Component {
}); });
}) })
.catch((err) => { .catch((err) => {
console.log('Failed subscription to', this.state.topic); console.log("Failed subscription to", this.state.topic);
this.props.onError(err.message, 'err'); this.props.onError(err.message, 'err');
const blankState = MessagesView.getDerivedStateFromProps({}, {}); const blankState = MessagesView.getDerivedStateFromProps({}, {});
blankState.title = this.props.intl.formatMessage(messages.not_found); blankState.title = this.props.intl.formatMessage(messages.not_found);
@@ -160,7 +161,8 @@ class MessagesView extends React.Component {
imagePreview: null, imagePreview: null,
typingIndicator: false, typingIndicator: false,
scrollPosition: 0, scrollPosition: 0,
fetchingMessages: false fetchingMessages: false,
peerMessagingDisabled: false
}; };
} else if (nextProps.topic != prevState.topic) { } else if (nextProps.topic != prevState.topic) {
const topic = nextProps.tinode.getTopic(nextProps.topic); const topic = nextProps.tinode.getTopic(nextProps.topic);
@@ -191,29 +193,37 @@ class MessagesView extends React.Component {
} }
}); });
nextState = Object.assign(nextState, { Object.assign(nextState, {
messages: msgs, messages: msgs,
onlineSubs: subs onlineSubs: subs
}); });
if (topic.public) { if (topic.public) {
nextState = Object.assign(nextState, { Object.assign(nextState, {
title: topic.public.fn, title: topic.public.fn,
avatar: makeImageUrl(topic.public.photo) avatar: makeImageUrl(topic.public.photo)
}); });
} else { } else {
nextState = Object.assign(nextState, { Object.assign(nextState, {
title: '', title: '',
avatar: null avatar: null
}); });
} }
const peer = topic.p2pPeerDesc();
if (peer && peer.acs) {
Object.assign(nextState, {
peerMessagingDisabled: !(peer.acs.isReader() && peer.acs.isWriter())
});
}
} else { } else {
// Invalid topic. // Invalid topic.
nextState = Object.assign(nextState, { Object.assign(nextState, {
messages: [], messages: [],
onlineSubs: [], onlineSubs: [],
title: '', title: '',
avatar: null avatar: null,
peerMessagingDisabled: false
}); });
} }
} }
@@ -286,9 +296,9 @@ class MessagesView extends React.Component {
this.setState({scrollPosition: event.target.scrollHeight - event.target.scrollTop}); this.setState({scrollPosition: event.target.scrollHeight - event.target.scrollTop});
if (event.target.scrollTop <= 0) { if (event.target.scrollTop <= 0) {
this.setState((prevState, props) => { this.setState((prevState, props) => {
let newState = {}; const newState = {};
if (!prevState.fetchingMessages) { if (!prevState.fetchingMessages) {
let topic = this.props.tinode.getTopic(this.state.topic); const topic = this.props.tinode.getTopic(this.state.topic);
if (topic && topic.isSubscribed() && topic.msgHasMoreMessages()) { if (topic && topic.isSubscribed() && topic.msgHasMoreMessages()) {
newState.fetchingMessages = true; newState.fetchingMessages = true;
topic.getMessagesPage(MESSAGES_PAGE).catch((err) => { topic.getMessagesPage(MESSAGES_PAGE).catch((err) => {
@@ -327,21 +337,28 @@ class MessagesView extends React.Component {
handleSubsUpdated() { handleSubsUpdated() {
if (this.state.topic) { if (this.state.topic) {
var subs = []; const subs = [];
var topic = this.props.tinode.getTopic(this.state.topic); const topic = this.props.tinode.getTopic(this.state.topic);
topic.subscribers((sub) => { topic.subscribers((sub) => {
if (sub.online && sub.user != this.props.myUserId) { if (sub.online && sub.user != this.props.myUserId) {
subs.push(sub); subs.push(sub);
} }
}); });
this.setState({onlineSubs: subs}); const newState = {onlineSubs: subs};
const peer = topic.p2pPeerDesc();
if (peer && peer.acs) {
Object.assign(newState, {
peerMessagingDisabled: !(peer.acs.isReader() && peer.acs.isWriter())
});
}
this.setState(newState);
} }
} }
handleNewMessage(msg) { handleNewMessage(msg) {
// Regenerate messages list // Regenerate messages list
var topic = this.props.tinode.getTopic(this.state.topic); const topic = this.props.tinode.getTopic(this.state.topic);
var newState = {messages: []}; const newState = {messages: []};
topic.messages(function(m) { topic.messages(function(m) {
if (!m.deleted) { if (!m.deleted) {
newState.messages = newState.messages.concat(m); newState.messages = newState.messages.concat(m);
@@ -410,7 +427,7 @@ class MessagesView extends React.Component {
this.props.sendMessage(Drafty.attachJSON(Drafty.parse(text), data)); this.props.sendMessage(Drafty.attachJSON(Drafty.parse(text), data));
} else if (action == 'url') { } else if (action == 'url') {
const url = new URL(data.ref); const url = new URL(data.ref);
let params = url.searchParams; const params = url.searchParams;
for (let key in data.resp) { for (let key in data.resp) {
if (data.resp.hasOwnProperty(key)) { if (data.resp.hasOwnProperty(key)) {
params.set(key, data.resp[key]); params.set(key, data.resp[key]);
@@ -456,6 +473,10 @@ class MessagesView extends React.Component {
this.props.onNewChat(this.state.topic, action); this.props.onNewChat(this.state.topic, action);
} }
handleEnablePeer() {
this.props.onChangePermissions(this.state.topic, DEFAULT_ACCESS_MODE, this.state.topic);
}
render() { render() {
const {formatMessage} = this.props.intl; const {formatMessage} = this.props.intl;
@@ -520,7 +541,7 @@ class MessagesView extends React.Component {
} }
let lastSeen = null; let lastSeen = null;
let cont = this.props.tinode.getMeTopic().getContact(this.state.topic); const cont = this.props.tinode.getMeTopic().getContact(this.state.topic);
if (cont && Tinode.topicType(cont.topic) == 'p2p') { if (cont && Tinode.topicType(cont.topic) == 'p2p') {
if (cont.online) { if (cont.online) {
lastSeen = formatMessage(messages.online_now); lastSeen = formatMessage(messages.online_now);
@@ -530,8 +551,8 @@ class MessagesView extends React.Component {
// TODO: also handle user agent in c.seen.ua // TODO: also handle user agent in c.seen.ua
} }
} }
let avatar = this.state.avatar || true; const avatar = this.state.avatar || true;
let online = this.props.online ? 'online' + (this.state.typingIndicator ? ' typing' : '') : 'offline'; const online = this.props.online ? 'online' + (this.state.typingIndicator ? ' typing' : '') : 'offline';
component = ( component = (
<div id="topic-view" className={this.props.hideSelf ? 'nodisplay' : null}> <div id="topic-view" className={this.props.hideSelf ? 'nodisplay' : null}>
@@ -592,6 +613,14 @@ class MessagesView extends React.Component {
</div> </div>
: null } : null }
</div> </div>
{this.state.peerMessagingDisabled && !this.state.unconfirmed ?
<div id="peer-messaging-disabled-note">
<i className="material-icons secondary">block</i> <FormattedMessage
id="peers_messaging_disabled" defaultMessage="Peer's messaging is disabled."
description="Shown when the p2p peer's messaging is disabled" /> <a href="javascript:;"
onClick={this.handleEnablePeer}><FormattedMessage id="enable_peers_messaging"
defaultMessage="Enable" description="Call to action to enable peer's messaging" /></a>.
</div> : null}
{this.state.unconfirmed ? {this.state.unconfirmed ?
<Invitation onAction={this.handleNewChatAcceptance} /> <Invitation onAction={this.handleNewChatAcceptance} />
: :
@@ -600,8 +629,7 @@ class MessagesView extends React.Component {
topic={this.props.topic} topic={this.props.topic}
disabled={!this.state.isWriter} disabled={!this.state.isWriter}
sendMessage={this.props.sendMessage} sendMessage={this.props.sendMessage}
onError={this.props.onError} /> onError={this.props.onError} />}
}
{this.state.imagePreview ? {this.state.imagePreview ?
<ImagePreview content={this.state.imagePreview} <ImagePreview content={this.state.imagePreview}
onClose={this.handleCloseImagePreview} /> : null} onClose={this.handleCloseImagePreview} /> : null}
+1 -1
View File
@@ -764,7 +764,6 @@ class TinodeWeb extends React.Component {
response = topic.delTopic(); response = topic.delTopic();
break; break;
case 'block': case 'block':
console.log("Blocking...");
// Ban the topic making futher invites impossible. // Ban the topic making futher invites impossible.
// Just self-ban. // Just self-ban.
const am = topic.getAccessMode().updateWant('-JP').getWant(); const am = topic.getAccessMode().updateWant('-JP').getWant();
@@ -1299,6 +1298,7 @@ class TinodeWeb extends React.Component {
onNewTopicCreated={this.handleNewTopicCreated} onNewTopicCreated={this.handleNewTopicCreated}
readTimerHandler={this.handleReadTimer} readTimerHandler={this.handleReadTimer}
showContextMenu={this.handleShowContextMenu} showContextMenu={this.handleShowContextMenu}
onChangePermissions={this.handleChangePermissions}
onNewChat={this.handleNewChatInvitation} onNewChat={this.handleNewChatInvitation}
sendMessage={this.handleSendMessage} /> sendMessage={this.handleSendMessage} />
+2 -2
View File
@@ -13,7 +13,7 @@ export default class MoreButton extends React.PureComponent {
} }
handleToggle() { handleToggle() {
let open = !this.state.open; const open = !this.state.open;
this.setState({open: open}); this.setState({open: open});
if (this.props.onToggle) { if (this.props.onToggle) {
this.props.onToggle(open); this.props.onToggle(open);
@@ -21,7 +21,7 @@ export default class MoreButton extends React.PureComponent {
} }
render() { render() {
return (<label className="small" onClick={this.handleToggle}>{this.props.title}... return (<label className="small clean-clickable" onClick={this.handleToggle}>{this.props.title}...
{this.state.open ? <i className="material-icons">expand_more</i> : {this.state.open ? <i className="material-icons">expand_more</i> :
<i className="material-icons">chevron_right</i>} <i className="material-icons">chevron_right</i>}
</label>); </label>);
+67 -22
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long