add toast on isBlocked, isKicked, ... for sending of messages

pull/1381/head
Audric Ackermann 4 years ago
parent 866c28bc20
commit f3430bdcb5
No known key found for this signature in database
GPG Key ID: 999F434D76324AD4

@ -517,6 +517,7 @@
isOnline: this.isOnline(), isOnline: this.isOnline(),
hasNickname: !!this.getNickname(), hasNickname: !!this.getNickname(),
isKickedFromGroup: !!this.get('isKickedFromGroup'), isKickedFromGroup: !!this.get('isKickedFromGroup'),
leftGroup: !!this.get('left'),
selectedMessages: this.selectedMessages, selectedMessages: this.selectedMessages,

@ -660,8 +660,8 @@
contact.number && contact.number[0] && contact.number[0].value; contact.number && contact.number[0] && contact.number[0].value;
const onSendMessage = firstNumber const onSendMessage = firstNumber
? () => { ? () => {
this.trigger('open-conversation', firstNumber); this.trigger('open-conversation', firstNumber);
} }
: null; : null;
const onClick = async () => { const onClick = async () => {
// First let's be sure that the signal account check is complete. // First let's be sure that the signal account check is complete.
@ -692,8 +692,8 @@
!path && !objectUrl !path && !objectUrl
? null ? null
: Object.assign({}, attachment.thumbnail || {}, { : Object.assign({}, attachment.thumbnail || {}, {
objectUrl: path || objectUrl, objectUrl: path || objectUrl,
}); });
return Object.assign({}, attachment, { return Object.assign({}, attachment, {
isVoiceMessage: Signal.Types.Attachment.isVoiceMessage(attachment), isVoiceMessage: Signal.Types.Attachment.isVoiceMessage(attachment),
@ -746,13 +746,13 @@
const onClick = noClick const onClick = noClick
? null ? null
: event => { : event => {
event.stopPropagation(); event.stopPropagation();
this.trigger('scroll-to-message', { this.trigger('scroll-to-message', {
author, author,
id, id,
referencedMessageNotFound, referencedMessageNotFound,
}); });
}; };
const firstAttachment = quote.attachments && quote.attachments[0]; const firstAttachment = quote.attachments && quote.attachments[0];
@ -787,15 +787,15 @@
url: path ? getAbsoluteAttachmentPath(path) : null, url: path ? getAbsoluteAttachmentPath(path) : null,
screenshot: screenshot screenshot: screenshot
? { ? {
...screenshot, ...screenshot,
url: getAbsoluteAttachmentPath(screenshot.path), url: getAbsoluteAttachmentPath(screenshot.path),
} }
: null, : null,
thumbnail: thumbnail thumbnail: thumbnail
? { ? {
...thumbnail, ...thumbnail,
url: getAbsoluteAttachmentPath(thumbnail.path), url: getAbsoluteAttachmentPath(thumbnail.path),
} }
: null, : null,
}; };
}, },
@ -824,9 +824,9 @@
const phoneNumbers = this.isIncoming() const phoneNumbers = this.isIncoming()
? [this.get('source')] ? [this.get('source')]
: _.union( : _.union(
this.get('sent_to') || [], this.get('sent_to') || [],
this.get('recipients') || this.getConversation().getRecipients() this.get('recipients') || this.getConversation().getRecipients()
); );
// This will make the error message for outgoing key errors a bit nicer // This will make the error message for outgoing key errors a bit nicer
const allErrors = (this.get('errors') || []).map(error => { const allErrors = (this.get('errors') || []).map(error => {
@ -1052,7 +1052,6 @@
window.log.warn('retrySend: Nobody to send to!'); window.log.warn('retrySend: Nobody to send to!');
return this.commit(); return this.commit();
} }
const { body, attachments, preview, quote } = await this.uploadData(); const { body, attachments, preview, quote } = await this.uploadData();
@ -1276,8 +1275,8 @@
*/ */
const hasBodyOrAttachments = Boolean( const hasBodyOrAttachments = Boolean(
dataMessage && dataMessage &&
(dataMessage.body || (dataMessage.body ||
(dataMessage.attachments && dataMessage.attachments.length)) (dataMessage.attachments && dataMessage.attachments.length))
); );
const shouldNotifyPushServer = const shouldNotifyPushServer =
hasBodyOrAttachments && isSessionOrClosedMessage; hasBodyOrAttachments && isSessionOrClosedMessage;
@ -1448,7 +1447,6 @@
}); });
await this.commit(); await this.commit();
}, },
getServerId() { getServerId() {
return this.get('serverId'); return this.get('serverId');
@ -1463,7 +1461,6 @@
}); });
await this.commit(); await this.commit();
}, },
async setServerTimestamp(serverTimestamp) { async setServerTimestamp(serverTimestamp) {
if (_.isEqual(this.get('serverTimestamp'), serverTimestamp)) { if (_.isEqual(this.get('serverTimestamp'), serverTimestamp)) {
@ -1475,7 +1472,6 @@
}); });
await this.commit(); await this.commit();
}, },
async setIsPublic(isPublic) { async setIsPublic(isPublic) {
if (_.isEqual(this.get('isPublic'), isPublic)) { if (_.isEqual(this.get('isPublic'), isPublic)) {
@ -1487,7 +1483,6 @@
}); });
await this.commit(); await this.commit();
}, },
async sendSyncMessageOnly(dataMessage) { async sendSyncMessageOnly(dataMessage) {
@ -1499,7 +1494,6 @@
await this.commit(); await this.commit();
const data = const data =
dataMessage instanceof libsession.Messages.Outgoing.DataMessage dataMessage instanceof libsession.Messages.Outgoing.DataMessage
? dataMessage.dataProto() ? dataMessage.dataProto()
@ -1531,7 +1525,6 @@
this.set({ sentSync: true }); this.set({ sentSync: true });
await this.commit(); await this.commit();
}, },
someRecipientsFailed() { someRecipientsFailed() {
@ -1613,8 +1606,6 @@
forceSave, forceSave,
Message: Whisper.Message, Message: Whisper.Message,
}); });
console.warn('case commit')
this.trigger('change'); this.trigger('change');
return id; return id;
}, },

@ -1,5 +1,5 @@
/* eslint-env node */ /* eslint-env node */
/* global log, Signal, Whisper */ /* global log */
const fs = require('fs-extra'); const fs = require('fs-extra');
const path = require('path'); const path = require('path');

@ -8,7 +8,6 @@
textsecure, textsecure,
Whisper, Whisper,
ConversationController, ConversationController,
BlockedNumberController,
*/ */
// eslint-disable-next-line func-names // eslint-disable-next-line func-names
@ -1051,45 +1050,6 @@
toastOptions.title = i18n('expiredWarning'); toastOptions.title = i18n('expiredWarning');
toastOptions.id = 'expiredWarning'; toastOptions.id = 'expiredWarning';
} }
if (!window.clientClockSynced) {
let clockSynced = false;
if (window.setClockParams) {
// Check to see if user has updated their clock to current time
clockSynced = await window.setClockParams();
} else {
window.log.info('setClockParams not loaded yet');
}
if (clockSynced) {
toastOptions.title = i18n('clockOutOfSync');
toastOptions.id = 'clockOutOfSync';
}
}
if (
this.model.isPrivate() &&
BlockedNumberController.isBlocked(this.model.id)
) {
toastOptions.title = i18n('unblockToSend');
toastOptions.id = 'unblockToSend';
}
if (
!this.model.isPrivate() &&
BlockedNumberController.isGroupBlocked(this.model.id)
) {
toastOptions.title = i18n('unblockGroupToSend');
toastOptions.id = 'unblockGroupToSend';
}
if (!this.model.isPrivate() && this.model.get('left')) {
toastOptions.title = i18n('youLeftTheGroup');
toastOptions.id = 'youLeftTheGroup';
}
if (
message.length >
window.libsession.Constants.CONVERSATION.MAX_MESSAGE_BODY_LENGTH
) {
toastOptions.title = i18n('messageBodyTooLong');
toastOptions.id = 'messageBodyTooLong';
}
if (toastOptions.title) { if (toastOptions.title) {
window.pushToast(toastOptions); window.pushToast(toastOptions);
this.focusMessageFieldAndClearDisabled(); this.focusMessageFieldAndClearDisabled();

@ -59,6 +59,10 @@ interface Props {
onLoadVoiceNoteView: any; onLoadVoiceNoteView: any;
onExitVoiceNoteView: any; onExitVoiceNoteView: any;
isBlocked: boolean;
isPrivate: boolean;
isKickedFromGroup: boolean;
leftGroup: boolean;
quotedMessageProps?: ReplyingToMessageProps; quotedMessageProps?: ReplyingToMessageProps;
removeQuotedMessage: () => void; removeQuotedMessage: () => void;
@ -206,16 +210,35 @@ export class SessionCompositionBox extends React.Component<Props, State> {
} }
private renderCompositionView() { private renderCompositionView() {
const { placeholder } = this.props; const {
placeholder,
isBlocked,
isKickedFromGroup,
leftGroup,
isPrivate,
} = this.props;
const { showEmojiPanel, message } = this.state; const { showEmojiPanel, message } = this.state;
const typingEnabled = !(isBlocked || isKickedFromGroup || leftGroup);
const { i18n } = window;
const messageWithWarning = isKickedFromGroup
? i18n('youGotKickedFromGroup')
: leftGroup
? i18n('youLeftTheGroup')
: isBlocked && isPrivate
? i18n('unblockToSend')
: isBlocked && !isPrivate
? i18n('unblockGroupToSend')
: undefined;
return ( return (
<> <>
<SessionIconButton {typingEnabled && (
iconType={SessionIconType.CirclePlus} <SessionIconButton
iconSize={SessionIconSize.Large} iconType={SessionIconType.CirclePlus}
onClick={this.onChooseAttachment} iconSize={SessionIconSize.Large}
/> onClick={this.onChooseAttachment}
/>
)}
<input <input
className="hidden" className="hidden"
@ -226,11 +249,13 @@ export class SessionCompositionBox extends React.Component<Props, State> {
onChange={this.onChoseAttachment} onChange={this.onChoseAttachment}
/> />
<SessionIconButton {typingEnabled && (
iconType={SessionIconType.Microphone} <SessionIconButton
iconSize={SessionIconSize.Huge} iconType={SessionIconType.Microphone}
onClick={this.onLoadVoiceNoteView} iconSize={SessionIconSize.Huge}
/> onClick={this.onLoadVoiceNoteView}
/>
)}
<div <div
className="send-message-input" className="send-message-input"
@ -245,16 +270,19 @@ export class SessionCompositionBox extends React.Component<Props, State> {
placeholder={placeholder} placeholder={placeholder}
maxLength={Constants.CONVERSATION.MAX_MESSAGE_BODY_LENGTH} maxLength={Constants.CONVERSATION.MAX_MESSAGE_BODY_LENGTH}
onKeyDown={this.onKeyDown} onKeyDown={this.onKeyDown}
value={message} value={messageWithWarning || message}
onChange={this.onChange} onChange={this.onChange}
disabled={!typingEnabled}
/> />
</div> </div>
<SessionIconButton {typingEnabled && (
iconType={SessionIconType.Emoji} <SessionIconButton
iconSize={SessionIconSize.Large} iconType={SessionIconType.Emoji}
onClick={this.toggleEmojiPanel} iconSize={SessionIconSize.Large}
/> onClick={this.toggleEmojiPanel}
/>
)}
<div className="send-message-button"> <div className="send-message-button">
<SessionIconButton <SessionIconButton
iconType={SessionIconType.Send} iconType={SessionIconType.Send}
@ -264,18 +292,20 @@ export class SessionCompositionBox extends React.Component<Props, State> {
/> />
</div> </div>
<div {typingEnabled && (
ref={ref => (this.emojiPanel = ref)} <div
onKeyDown={this.onKeyDown} ref={ref => (this.emojiPanel = ref)}
role="button" onKeyDown={this.onKeyDown}
> role="button"
{showEmojiPanel && ( >
<SessionEmojiPanel {showEmojiPanel && (
onEmojiClicked={this.onEmojiClick} <SessionEmojiPanel
show={showEmojiPanel} onEmojiClicked={this.onEmojiClick}
/> show={showEmojiPanel}
)} />
</div> )}
</div>
)}
</> </>
); );
} }
@ -471,9 +501,19 @@ export class SessionCompositionBox extends React.Component<Props, State> {
}, ''); }, '');
} }
// tslint:disable-next-line: cyclomatic-complexity
private async onSendMessage() { private async onSendMessage() {
const messagePlaintext = this.parseEmojis(this.state.message); const messagePlaintext = this.parseEmojis(this.state.message);
const { isBlocked, isPrivate, leftGroup, isKickedFromGroup } = this.props;
if (isBlocked && isPrivate) {
ToastUtils.pushUnblockToSend();
return;
}
if (isBlocked && !isPrivate) {
ToastUtils.pushUnblockToSendGroup();
return;
}
// Verify message length // Verify message length
const msgLen = messagePlaintext?.length || 0; const msgLen = messagePlaintext?.length || 0;
if (msgLen > window.CONSTANTS.MAX_MESSAGE_BODY_LENGTH) { if (msgLen > window.CONSTANTS.MAX_MESSAGE_BODY_LENGTH) {
@ -484,6 +524,29 @@ export class SessionCompositionBox extends React.Component<Props, State> {
ToastUtils.pushMessageBodyMissing(); ToastUtils.pushMessageBodyMissing();
return; return;
} }
if (!window.clientClockSynced) {
let clockSynced = false;
if (window.setClockParams) {
// Check to see if user has updated their clock to current time
clockSynced = await window.setClockParams();
} else {
window.log.info('setClockParams not loaded yet');
}
if (clockSynced) {
ToastUtils.pushClockOutOfSync();
return;
}
}
if (!isPrivate && leftGroup) {
ToastUtils.pushYouLeftTheGroup();
return;
}
if (!isPrivate && isKickedFromGroup) {
ToastUtils.pushYouLeftTheGroup();
return;
}
const { quotedMessageProps } = this.props; const { quotedMessageProps } = this.props;
const { stagedLinkPreview } = this.state; const { stagedLinkPreview } = this.state;

@ -28,6 +28,8 @@ import * as MIME from '../../../types/MIME';
import { SessionFileDropzone } from './SessionFileDropzone'; import { SessionFileDropzone } from './SessionFileDropzone';
import { ConversationType } from '../../../state/ducks/conversations'; import { ConversationType } from '../../../state/ducks/conversations';
import { MessageView } from '../../MainViewController'; import { MessageView } from '../../MainViewController';
import { getMessageById } from '../../../../js/modules/data';
import { pushUnblockToSend } from '../../../session/utils/Toast';
interface State { interface State {
// Message sending progress // Message sending progress
@ -161,7 +163,6 @@ export class SessionConversation extends React.Component<Props, State> {
div?.removeEventListener('drop', this.handleDrop); div?.removeEventListener('drop', this.handleDrop);
} }
public componentDidMount() { public componentDidMount() {
// Pause thread to wait for rendering to complete // Pause thread to wait for rendering to complete
setTimeout(() => { setTimeout(() => {
@ -253,7 +254,12 @@ export class SessionConversation extends React.Component<Props, State> {
</div> </div>
{!isRss && ( {!isRss && (
// tslint:disable-next-line: use-simple-attributes
<SessionCompositionBox <SessionCompositionBox
isBlocked={conversation.isBlocked}
leftGroup={conversation.leftGroup}
isKickedFromGroup={conversation.isKickedFromGroup}
isPrivate={conversation.type === 'direct'}
sendMessage={sendMessageFn} sendMessage={sendMessageFn}
stagedAttachments={stagedAttachments} stagedAttachments={stagedAttachments}
onMessageSending={this.onMessageSending} onMessageSending={this.onMessageSending}
@ -689,6 +695,10 @@ export class SessionConversation extends React.Component<Props, State> {
// ~~~~~~~~~~~~~~ MESSAGE QUOTE ~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~ MESSAGE QUOTE ~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private async replyToMessage(quotedMessageTimestamp?: number) { private async replyToMessage(quotedMessageTimestamp?: number) {
if (this.props.conversation.isBlocked) {
pushUnblockToSend();
return;
}
if (!_.isEqual(this.state.quotedMessageTimestamp, quotedMessageTimestamp)) { if (!_.isEqual(this.state.quotedMessageTimestamp, quotedMessageTimestamp)) {
const { messages, conversationKey } = this.props; const { messages, conversationKey } = this.props;
const conversationModel = window.ConversationController.getOrThrow( const conversationModel = window.ConversationController.getOrThrow(
@ -697,7 +707,9 @@ export class SessionConversation extends React.Component<Props, State> {
let quotedMessageProps = null; let quotedMessageProps = null;
if (quotedMessageTimestamp) { if (quotedMessageTimestamp) {
const quotedMessage = messages.find(m => m.attributes.sent_at === quotedMessageTimestamp); const quotedMessage = messages.find(
m => m.attributes.sent_at === quotedMessageTimestamp
);
if (quotedMessage) { if (quotedMessage) {
const quotedMessageModel = await getMessageById(quotedMessage.id, { const quotedMessageModel = await getMessageById(quotedMessage.id, {

@ -144,6 +144,7 @@ export class SessionConversationMessagesList extends React.Component<
if (conversation.unreadCount === 0) { if (conversation.unreadCount === 0) {
findFirstUnreadIndex = -1; findFirstUnreadIndex = -1;
} }
const isConvoBlocked = conversation.isBlocked;
return ( return (
<> <>

@ -211,3 +211,19 @@ export function pushPairingRequestReceived(alreadyLinked: boolean) {
); );
} }
} }
export function pushUnblockToSend() {
pushToastInfo('unblockToSend', window.i18n('unblockToSend'));
}
export function pushUnblockToSendGroup() {
pushToastInfo('unblockGroupToSend', window.i18n('unblockGroupToSend'));
}
export function pushClockOutOfSync() {
pushToastError('clockOutOfSync', window.i18n('clockOutOfSync'));
}
export function pushYouLeftTheGroup() {
pushToastError('youLeftTheGroup', window.i18n('youLeftTheGroup'));
}

@ -56,6 +56,8 @@ export type ConversationType = {
isSecondary?: boolean; isSecondary?: boolean;
primaryDevice: string; primaryDevice: string;
isBlocked: boolean; isBlocked: boolean;
isKickedFromGroup: boolean;
leftGroup: boolean;
}; };
export type ConversationLookupType = { export type ConversationLookupType = {
[key: string]: ConversationType; [key: string]: ConversationType;

@ -8,7 +8,7 @@ export type MessagesStateType = Array<MessageType>;
export async function getMessages( export async function getMessages(
conversationKey: string, conversationKey: string,
numMessages: number numMessages: number
) : Promise<MessagesStateType> { ): Promise<MessagesStateType> {
const conversation = window.ConversationController.get(conversationKey); const conversation = window.ConversationController.get(conversationKey);
if (!conversation) { if (!conversation) {
// no valid conversation, early return // no valid conversation, early return
@ -88,12 +88,16 @@ const messageSlice = createSlice({
name: 'messages', name: 'messages',
initialState: [] as MessagesStateType, initialState: [] as MessagesStateType,
reducers: { reducers: {
messageChanged(state, action){ messageChanged(state, action) {
console.log('message changed ', state, action) // console.log('message changed ', action);
const messageInStoreIndex = state.findIndex(m => m.id === action.payload.id); const messageInStoreIndex = state.findIndex(
m => m.id === action.payload.id
);
if (messageInStoreIndex >= 0) { if (messageInStoreIndex >= 0) {
state[messageInStoreIndex] = _.omit(action.payload, toOmitFromMessageModel) state[messageInStoreIndex] = _.omit(
; action.payload,
toOmitFromMessageModel
);
} }
return state; return state;
}, },

@ -30,6 +30,8 @@ describe('state/selectors/conversations', () => {
isSelected: false, isSelected: false,
isTyping: false, isTyping: false,
isBlocked: false, isBlocked: false,
isKickedFromGroup: false,
leftGroup: false,
}, },
id2: { id2: {
id: 'id2', id: 'id2',
@ -49,6 +51,8 @@ describe('state/selectors/conversations', () => {
isSelected: false, isSelected: false,
isTyping: false, isTyping: false,
isBlocked: false, isBlocked: false,
isKickedFromGroup: false,
leftGroup: false,
}, },
id3: { id3: {
id: 'id3', id: 'id3',
@ -68,6 +72,8 @@ describe('state/selectors/conversations', () => {
isSelected: false, isSelected: false,
isTyping: false, isTyping: false,
isBlocked: false, isBlocked: false,
isKickedFromGroup: false,
leftGroup: false,
}, },
id4: { id4: {
id: 'id4', id: 'id4',
@ -78,7 +84,6 @@ describe('state/selectors/conversations', () => {
isArchived: false, isArchived: false,
isSecondary: false, isSecondary: false,
primaryDevice: 'id4', primaryDevice: 'id4',
type: 'direct', type: 'direct',
isMe: false, isMe: false,
lastUpdated: Date.now(), lastUpdated: Date.now(),
@ -87,6 +92,8 @@ describe('state/selectors/conversations', () => {
isSelected: false, isSelected: false,
isTyping: false, isTyping: false,
isBlocked: false, isBlocked: false,
isKickedFromGroup: false,
leftGroup: false,
}, },
id5: { id5: {
id: 'id5', id: 'id5',
@ -106,6 +113,8 @@ describe('state/selectors/conversations', () => {
isSelected: false, isSelected: false,
isTyping: false, isTyping: false,
isBlocked: false, isBlocked: false,
isKickedFromGroup: false,
leftGroup: false,
}, },
}; };
const comparator = _getConversationComparator(i18n, regionCode); const comparator = _getConversationComparator(i18n, regionCode);

2
ts/window.d.ts vendored

@ -109,5 +109,7 @@ declare global {
sessionGenerateKeyPair: ( sessionGenerateKeyPair: (
seed: ArrayBuffer seed: ArrayBuffer
) => Promise<{ pubKey: ArrayBufferLike; privKey: ArrayBufferLike }>; ) => Promise<{ pubKey: ArrayBufferLike; privKey: ArrayBufferLike }>;
setClockParams: any;
clientClockSynced: number | undefined;
} }
} }

Loading…
Cancel
Save