Voice messages privacy
This commit is contained in:
parent
31ac41c354
commit
34572dbf3a
@ -565,6 +565,19 @@ export default class ChatBubbles {
|
||||
this.safeRenderMessage(message, true, bubble);
|
||||
});
|
||||
|
||||
this.listenerSetter.add(rootScope)('message_error', async({storageKey, tempId}) => {
|
||||
if(storageKey !== this.chat.messagesStorageKey) return;
|
||||
|
||||
const bubble = this.bubbles[tempId];
|
||||
if(!bubble) return;
|
||||
|
||||
await getHeavyAnimationPromise();
|
||||
if(this.bubbles[tempId] !== bubble) return;
|
||||
|
||||
bubble.classList.remove('is-outgoing');
|
||||
bubble.classList.add('is-error');
|
||||
});
|
||||
|
||||
this.listenerSetter.add(rootScope)('album_edit', ({peerId, messages, deletedMids}) => {
|
||||
if(peerId !== this.peerId) return;
|
||||
|
||||
@ -2094,7 +2107,7 @@ export default class ChatBubbles {
|
||||
if(bubble) {
|
||||
this.unreadOut.delete(msgId);
|
||||
|
||||
if(bubble.classList.contains('is-outgoing')) {
|
||||
if(bubble.classList.contains('is-outgoing') || bubble.classList.contains('is-error')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -3764,12 +3777,13 @@ export default class ChatBubbles {
|
||||
if(our) {
|
||||
if(message.pFlags.unread || isOutgoing) this.unreadOut.add(message.mid);
|
||||
let status = '';
|
||||
if(isOutgoing) status = 'is-sending';
|
||||
if(message.error) status = 'is-error';
|
||||
else if(isOutgoing) status = 'is-sending';
|
||||
else status = message.pFlags.unread || (message as Message.message).pFlags.is_scheduled ? 'is-sent' : 'is-read';
|
||||
bubble.classList.add(status);
|
||||
}
|
||||
|
||||
if(isOutgoing) {
|
||||
if(isOutgoing && !message.error) {
|
||||
bubble.classList.add('is-outgoing');
|
||||
}
|
||||
|
||||
|
@ -17,10 +17,9 @@ import emoticonsDropdown from '../emoticonsDropdown';
|
||||
import PopupCreatePoll from '../popups/createPoll';
|
||||
import PopupForward from '../popups/forward';
|
||||
import PopupNewMedia from '../popups/newMedia';
|
||||
import {toast} from '../toast';
|
||||
import {toast, toastNew} from '../toast';
|
||||
import {wrapReply} from '../wrappers';
|
||||
import InputField from '../inputField';
|
||||
import {MessageEntity, DraftMessage, WebPage, Message, ChatFull, UserFull} from '../../layer';
|
||||
import {MessageEntity, DraftMessage, WebPage, Message, UserFull} from '../../layer';
|
||||
import StickersHelper from './stickersHelper';
|
||||
import ButtonIcon from '../buttonIcon';
|
||||
import ButtonMenuToggle from '../buttonMenuToggle';
|
||||
@ -96,6 +95,7 @@ import filterAsync from '../../helpers/array/filterAsync';
|
||||
import InputFieldAnimated from '../inputFieldAnimated';
|
||||
import getStickerEffectThumb from '../../lib/appManagers/utils/stickers/getStickerEffectThumb';
|
||||
import PopupStickers from '../popups/stickers';
|
||||
import wrapPeerTitle from '../wrappers/peerTitle';
|
||||
|
||||
const RECORD_MIN_TIME = 500;
|
||||
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
|
||||
@ -2086,7 +2086,8 @@ export default class ChatInput {
|
||||
this.sendMessage();
|
||||
}
|
||||
} else {
|
||||
if(this.chat.peerId.isAnyChat() && !(await this.chat.canSend('send_media'))) {
|
||||
const isAnyChat = this.chat.peerId.isAnyChat();
|
||||
if(isAnyChat && !(await this.chat.canSend('send_media'))) {
|
||||
toast(POSTING_MEDIA_NOT_ALLOWED);
|
||||
return;
|
||||
}
|
||||
@ -2094,6 +2095,23 @@ export default class ChatInput {
|
||||
this.chatInput.classList.add('is-locked');
|
||||
blurActiveElement();
|
||||
|
||||
let restricted = false;
|
||||
if(!isAnyChat) {
|
||||
const userFull = await this.managers.appProfileManager.getProfile(this.chat.peerId.toUserId());
|
||||
if(userFull?.pFlags.voice_messages_forbidden) {
|
||||
toastNew({
|
||||
langPackKey: 'Chat.SendVoice.PrivacyError',
|
||||
langPackArguments: [await wrapPeerTitle({peerId: this.chat.peerId})]
|
||||
});
|
||||
restricted = true;
|
||||
}
|
||||
}
|
||||
|
||||
if(restricted) {
|
||||
this.chatInput.classList.remove('is-locked');
|
||||
return;
|
||||
}
|
||||
|
||||
this.recorder.start().then(() => {
|
||||
this.releaseMediaPlayback = appMediaPlaybackController.setSingleMedia();
|
||||
this.recordCanceled = false;
|
||||
@ -2427,6 +2445,13 @@ export default class ChatInput {
|
||||
...sendingParams,
|
||||
dropAuthor: this.forwardElements && this.forwardElements.hideSender.checkboxField.checked,
|
||||
dropCaptions: this.isDroppingCaptions()
|
||||
}).catch(async(err: ApiError) => {
|
||||
if(err.type === 'VOICE_MESSAGES_FORBIDDEN') {
|
||||
toastNew({
|
||||
langPackKey: 'Chat.SendVoice.PrivacyError',
|
||||
langPackArguments: [await wrapPeerTitle({peerId})]
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -853,6 +853,7 @@ export default class ChatSelection extends AppSelection {
|
||||
public canSelectBubble(bubble: HTMLElement) {
|
||||
return !bubble.classList.contains('service') &&
|
||||
!bubble.classList.contains('is-outgoing') &&
|
||||
!bubble.classList.contains('is-error') &&
|
||||
!bubble.classList.contains('bubble-first') &&
|
||||
!bubble.classList.contains('avoid-selection');
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ export default class PrivacySection {
|
||||
]>);
|
||||
for(const [k, chatKey, usersKey] of a) {
|
||||
if(this.exceptions.get(k).row.container.classList.contains('hide')) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
|
||||
const _peerIds = this.peerIds[k];
|
||||
|
@ -30,9 +30,11 @@ export function setSendingStatus(
|
||||
message?: Message.message | Message.messageService,
|
||||
disableAnimationIfRippleFound?: boolean
|
||||
) {
|
||||
let className: 'check' | 'checks' | 'sending';
|
||||
let className: 'check' | 'checks' | 'sending' | 'sendingerror';
|
||||
if(message?.pFlags.out) {
|
||||
if(message.pFlags.is_outgoing) {
|
||||
if(message.error) {
|
||||
className = 'sendingerror';
|
||||
} else if(message.pFlags.is_outgoing) {
|
||||
className = 'sending';
|
||||
} else if(message.pFlags.unread) {
|
||||
className = 'check';
|
||||
|
28
src/components/sidebarLeft/tabs/privacy/voices.ts
Normal file
28
src/components/sidebarLeft/tabs/privacy/voices.ts
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* https://github.com/morethanwords/tweb
|
||||
* Copyright (C) 2019-2021 Eduard Kuzmenko
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import {SliderSuperTabEventable} from '../../../sliderTab';
|
||||
import PrivacySection from '../../../privacySection';
|
||||
import {LangPackKey} from '../../../../lib/langPack';
|
||||
|
||||
export default class AppPrivacyVoicesTab extends SliderSuperTabEventable {
|
||||
protected init() {
|
||||
this.header.classList.add('with-border');
|
||||
this.container.classList.add('privacy-tab', 'privacy-voices');
|
||||
this.setTitle('PrivacyVoiceMessages');
|
||||
|
||||
const caption: LangPackKey = 'PrivacyVoiceMessagesInfo';
|
||||
new PrivacySection({
|
||||
tab: this,
|
||||
title: 'PrivacyVoiceMessagesTitle',
|
||||
inputKey: 'inputPrivacyKeyVoiceMessages',
|
||||
captions: [caption, caption, caption],
|
||||
exceptionTexts: ['PrivacySettingsController.NeverAllow', 'PrivacySettingsController.AlwaysAllow'],
|
||||
appendTo: this.scrollable,
|
||||
managers: this.managers
|
||||
});
|
||||
}
|
||||
}
|
@ -32,6 +32,7 @@ import PrivacyType from '../../../lib/appManagers/utils/privacy/privacyType';
|
||||
import confirmationPopup, {PopupConfirmationOptions} from '../../confirmationPopup';
|
||||
import noop from '../../../helpers/noop';
|
||||
import {toastNew} from '../../toast';
|
||||
import AppPrivacyVoicesTab from './privacy/voices';
|
||||
|
||||
export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
private activeSessionsRow: Row;
|
||||
@ -209,6 +210,19 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const voicesRow = rowsByKeys['inputPrivacyKeyVoiceMessages'] = new Row({
|
||||
titleLangKey: 'PrivacyVoiceMessagesTitle',
|
||||
subtitleLangKey: SUBTITLE,
|
||||
clickable: () => {
|
||||
if(!rootScope.premium) {
|
||||
toastNew({langPackKey: 'PrivacyVoiceMessagesPremiumOnly'});
|
||||
} else {
|
||||
this.slider.createTab(AppPrivacyVoicesTab).open();
|
||||
}
|
||||
},
|
||||
listenerSetter: this.listenerSetter
|
||||
});
|
||||
|
||||
const updatePrivacyRow = (key: InputPrivacyKey['_']) => {
|
||||
const row = rowsByKeys[key];
|
||||
if(!row) {
|
||||
@ -236,7 +250,8 @@ export default class AppPrivacyAndSecurityTab extends SliderSuperTabEventable {
|
||||
photoVisibilityRow.container,
|
||||
callRow.container,
|
||||
linkAccountRow.container,
|
||||
groupChatsAddRow.container
|
||||
groupChatsAddRow.container,
|
||||
voicesRow.container
|
||||
);
|
||||
this.scrollable.append(section.container);
|
||||
|
||||
|
@ -19,7 +19,7 @@ const App = {
|
||||
version: process.env.VERSION,
|
||||
versionFull: process.env.VERSION_FULL,
|
||||
build: +process.env.BUILD,
|
||||
langPackVersion: '0.4.5',
|
||||
langPackVersion: '0.4.6',
|
||||
langPack: 'macos',
|
||||
langPackCode: 'en',
|
||||
domains: [MAIN_DOMAIN] as string[],
|
||||
|
3
src/global.d.ts
vendored
3
src/global.d.ts
vendored
@ -42,7 +42,8 @@ declare global {
|
||||
|
||||
type ServerErrorType = 'FILE_REFERENCE_EXPIRED' | 'SESSION_REVOKED' | 'AUTH_KEY_DUPLICATED' |
|
||||
'SESSION_PASSWORD_NEEDED' | 'CONNECTION_NOT_INITED' | 'ERROR_EMPTY' | 'MTPROTO_CLUSTER_INVALID' |
|
||||
'BOT_PRECHECKOUT_TIMEOUT' | 'TMP_PASSWORD_INVALID' | 'PASSWORD_HASH_INVALID' | 'CHANNEL_PRIVATE';
|
||||
'BOT_PRECHECKOUT_TIMEOUT' | 'TMP_PASSWORD_INVALID' | 'PASSWORD_HASH_INVALID' | 'CHANNEL_PRIVATE' |
|
||||
'VOICE_MESSAGES_FORBIDDEN' | 'PHOTO_INVALID_DIMENSIONS' | 'PHOTO_SAVE_FILE_INVALID';
|
||||
|
||||
type ErrorType = LocalErrorType | ServerErrorType;
|
||||
|
||||
|
@ -6,13 +6,19 @@
|
||||
|
||||
import type {MyDocument} from '../lib/appManagers/appDocsManager';
|
||||
import type {MyPhoto} from '../lib/appManagers/appPhotosManager';
|
||||
import {THUMB_TYPE_FULL} from '../lib/mtproto/mtproto_config';
|
||||
import type {ThumbCache} from '../lib/storages/thumbs';
|
||||
import getImageFromStrippedThumb from './getImageFromStrippedThumb';
|
||||
|
||||
export default function getStrippedThumbIfNeeded(photo: MyPhoto | MyDocument, cacheContext: ThumbCache, useBlur: boolean, ignoreCache = false) {
|
||||
const isVideo = (['video', 'gif'] as MyDocument['type'][]).includes((photo as MyDocument).type);
|
||||
if(!cacheContext.downloaded || isVideo || ignoreCache) {
|
||||
if(photo._ === 'document' && cacheContext.downloaded && !ignoreCache && !isVideo) {
|
||||
if(
|
||||
photo._ === 'document' &&
|
||||
cacheContext.downloaded &&
|
||||
!ignoreCache &&
|
||||
(!isVideo || cacheContext.type !== THUMB_TYPE_FULL)
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,11 @@ export default function copy<T>(obj: T): T {
|
||||
return clonedArr;
|
||||
}
|
||||
|
||||
if(ArrayBuffer.isView(obj)) {
|
||||
// @ts-ignore
|
||||
return obj.slice();
|
||||
}
|
||||
|
||||
// lastly, handle objects
|
||||
// @ts-ignore
|
||||
const clonedObj = new obj.constructor();
|
||||
|
@ -759,6 +759,10 @@ const lang = {
|
||||
'NewChatsFromNonContacts': 'New chats from unknown users',
|
||||
'ArchiveAndMute': 'Archive and Mute',
|
||||
'ArchiveAndMuteInfo': 'Automatically archive and mute new chats, groups and channels from non-contacts.',
|
||||
'PrivacyVoiceMessages': 'Voice Messages',
|
||||
'PrivacyVoiceMessagesTitle': 'Who can send me voice or video messages?',
|
||||
'PrivacyVoiceMessagesInfo': 'You can restrict who can send you voice or video messages with granular precision.',
|
||||
'PrivacyVoiceMessagesPremiumOnly': 'Only subscribers of *Telegram Premium* can restrict receiving voice messages.',
|
||||
|
||||
// * macos
|
||||
'AccountSettings.Filters': 'Chat Folders',
|
||||
@ -835,6 +839,7 @@ const lang = {
|
||||
'Chat.DropQuickDesc': 'in a quick way',
|
||||
'Chat.DropAsFilesDesc': 'without compression',
|
||||
'Chat.Edit.Cancel.Text': 'Are you sure you want to discard all changes?',
|
||||
'Chat.SendVoice.PrivacyError': '%@ doesn\'t accept voice and video messages',
|
||||
'Chat.Service.Call.Cancelled': 'Cancelled',
|
||||
'Chat.Service.Call.Missed': 'Missed',
|
||||
'Chat.Service.PeerJoinedTelegram': '%@ joined Telegram',
|
||||
|
10
src/layer.d.ts
vendored
10
src/layer.d.ts
vendored
@ -881,14 +881,15 @@ export namespace Message {
|
||||
viaBotId?: PeerId,
|
||||
clear_history?: boolean,
|
||||
pending?: boolean,
|
||||
error?: any,
|
||||
error?: ApiError,
|
||||
send?: () => Promise<any>,
|
||||
totalEntities?: MessageEntity[],
|
||||
reply_to_mid?: number,
|
||||
savedFrom?: string,
|
||||
sponsoredMessage?: SponsoredMessage.sponsoredMessage,
|
||||
promise?: CancellablePromise<void>,
|
||||
uploadingFileName?: string
|
||||
uploadingFileName?: string,
|
||||
storageKey?: MessagesStorageKey
|
||||
};
|
||||
|
||||
export type messageService = {
|
||||
@ -920,11 +921,12 @@ export namespace Message {
|
||||
rReply?: string,
|
||||
viaBotId?: PeerId,
|
||||
pending?: boolean,
|
||||
error?: any,
|
||||
error?: ApiError,
|
||||
send?: () => Promise<any>,
|
||||
random_id?: string,
|
||||
reply_to_mid?: number,
|
||||
clear_history?: boolean
|
||||
clear_history?: boolean,
|
||||
storageKey?: MessagesStorageKey
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -530,17 +530,13 @@ export class AppMessagesManager extends AppManager {
|
||||
};
|
||||
}
|
||||
|
||||
const toggleError = (on: boolean) => {
|
||||
if(on) {
|
||||
message.error = true;
|
||||
} else {
|
||||
delete message.error;
|
||||
}
|
||||
const toggleError = (error?: ApiError) => {
|
||||
this.onMessagesSendError([message], error);
|
||||
this.rootScope.dispatchEvent('messages_pending');
|
||||
};
|
||||
|
||||
message.send = () => {
|
||||
toggleError(false);
|
||||
toggleError();
|
||||
const sentRequestOptions: PendingAfterMsg = {};
|
||||
if(this.pendingAfterMsgs[peerId]) {
|
||||
sentRequestOptions.afterMessageId = this.pendingAfterMsgs[peerId].messageId;
|
||||
@ -637,9 +633,10 @@ export class AppMessagesManager extends AppManager {
|
||||
// ApiUpdatesManager.processUpdateMessage(upd)
|
||||
// }, 5000)
|
||||
message.promise.resolve();
|
||||
}, (error: any) => {
|
||||
toggleError(true);
|
||||
}, (error: ApiError) => {
|
||||
toggleError(error);
|
||||
message.promise.reject(error);
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {
|
||||
delete this.pendingAfterMsgs[peerId];
|
||||
@ -916,13 +913,8 @@ export class AppMessagesManager extends AppManager {
|
||||
this.uploadFilePromises[uploadingFileName] = sentDeferred;
|
||||
}
|
||||
|
||||
const toggleError = (on: boolean) => {
|
||||
if(on) {
|
||||
message.error = true;
|
||||
} else {
|
||||
delete message.error;
|
||||
}
|
||||
|
||||
const toggleError = (error?: ApiError) => {
|
||||
this.onMessagesSendError([message], error);
|
||||
this.rootScope.dispatchEvent('messages_pending');
|
||||
};
|
||||
|
||||
@ -1012,8 +1004,9 @@ export class AppMessagesManager extends AppManager {
|
||||
}
|
||||
|
||||
sentDeferred.resolve(inputMedia);
|
||||
}, (/* error */) => {
|
||||
toggleError(true);
|
||||
}, (error: ApiError) => {
|
||||
toggleError(error);
|
||||
throw error;
|
||||
});
|
||||
|
||||
return sentDeferred;
|
||||
@ -1057,7 +1050,7 @@ export class AppMessagesManager extends AppManager {
|
||||
send_as: options.sendAsPeerId ? this.appPeersManager.getInputPeerById(options.sendAsPeerId) : undefined
|
||||
}).then((updates) => {
|
||||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||||
}, (error) => {
|
||||
}, (error: ApiError) => {
|
||||
if(attachType === 'photo' &&
|
||||
error.code === 400 &&
|
||||
(error.type === 'PHOTO_INVALID_DIMENSIONS' ||
|
||||
@ -1068,7 +1061,7 @@ export class AppMessagesManager extends AppManager {
|
||||
return;
|
||||
}
|
||||
|
||||
toggleError(true);
|
||||
toggleError(error);
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
@ -1173,13 +1166,8 @@ export class AppMessagesManager extends AppManager {
|
||||
// * test pending
|
||||
// return;
|
||||
|
||||
const toggleError = (message: any, on: boolean) => {
|
||||
if(on) {
|
||||
message.error = true;
|
||||
} else {
|
||||
delete message.error;
|
||||
}
|
||||
|
||||
const toggleError = (message: Message.message, error?: ApiError) => {
|
||||
this.onMessagesSendError([message], error);
|
||||
this.rootScope.dispatchEvent('messages_pending');
|
||||
};
|
||||
|
||||
@ -1201,8 +1189,8 @@ export class AppMessagesManager extends AppManager {
|
||||
}).then((updates) => {
|
||||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||||
deferred.resolve();
|
||||
}, (error) => {
|
||||
messages.forEach((message) => toggleError(message, true));
|
||||
}, (error: ApiError) => {
|
||||
messages.forEach((message) => toggleError(message, error));
|
||||
deferred.reject(error);
|
||||
});
|
||||
}
|
||||
@ -1243,13 +1231,9 @@ export class AppMessagesManager extends AppManager {
|
||||
}
|
||||
|
||||
return inputSingleMedia;
|
||||
}).catch((err: any) => {
|
||||
if(err.name === 'AbortError') {
|
||||
return null;
|
||||
}
|
||||
|
||||
}).catch((err: ApiError) => {
|
||||
this.log.error('sendAlbum upload item error:', err, message);
|
||||
toggleError(message, true);
|
||||
toggleError(message, err);
|
||||
throw err;
|
||||
});
|
||||
});
|
||||
@ -1366,19 +1350,8 @@ export class AppMessagesManager extends AppManager {
|
||||
|
||||
message.media = media;
|
||||
|
||||
const toggleError = (on: boolean) => {
|
||||
/* const historyMessage = this.messagesForHistory[messageId];
|
||||
if (on) {
|
||||
message.error = true
|
||||
if (historyMessage) {
|
||||
historyMessage.error = true
|
||||
}
|
||||
} else {
|
||||
delete message.error
|
||||
if (historyMessage) {
|
||||
delete historyMessage.error
|
||||
}
|
||||
} */
|
||||
const toggleError = (error?: ApiError) => {
|
||||
this.onMessagesSendError([message], error);
|
||||
this.rootScope.dispatchEvent('messages_pending');
|
||||
};
|
||||
|
||||
@ -1428,8 +1401,9 @@ export class AppMessagesManager extends AppManager {
|
||||
}
|
||||
|
||||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||||
}, (error) => {
|
||||
toggleError(true);
|
||||
}, (error: ApiError) => {
|
||||
toggleError(error);
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {
|
||||
delete this.pendingAfterMsgs[peerId];
|
||||
@ -1469,6 +1443,7 @@ export class AppMessagesManager extends AppManager {
|
||||
const messageId = message.id;
|
||||
const peerId = this.getMessagePeer(message);
|
||||
const storage = options.isScheduled ? this.getScheduledMessagesStorage(peerId) : this.getHistoryMessagesStorage(peerId);
|
||||
message.storageKey = storage.key;
|
||||
const callbacks: Array<() => void> = [];
|
||||
if(options.isScheduled) {
|
||||
// if(!options.isGroupedItem) {
|
||||
@ -2146,6 +2121,9 @@ export class AppMessagesManager extends AppManager {
|
||||
}, sentRequestOptions).then((updates) => {
|
||||
this.log('forwardMessages updates:', updates);
|
||||
this.apiUpdatesManager.processUpdateMessage(updates);
|
||||
}, (error: ApiError) => {
|
||||
this.onMessagesSendError(newMessages, error);
|
||||
throw error;
|
||||
}).finally(() => {
|
||||
if(this.pendingAfterMsgs[peerId] === sentRequestOptions) {
|
||||
delete this.pendingAfterMsgs[peerId];
|
||||
@ -2173,6 +2151,26 @@ export class AppMessagesManager extends AppManager {
|
||||
// };
|
||||
}
|
||||
|
||||
private onMessagesSendError(messages: Message.message[], error?: ApiError) {
|
||||
messages.forEach((message) => {
|
||||
if(message.error === error) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(error) {
|
||||
message.error = error;
|
||||
this.rootScope.dispatchEvent('message_error', {storageKey: message.storageKey, tempId: message.mid, error});
|
||||
|
||||
const dialog = this.getDialogOnly(message.peerId);
|
||||
if(dialog) {
|
||||
this.rootScope.dispatchEvent('dialog_unread', {peerId: message.peerId, dialog});
|
||||
}
|
||||
} else {
|
||||
delete message.error;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public getMessagesStorageByKey(key: MessagesStorageKey) {
|
||||
const s = key.split('_');
|
||||
const peerId: PeerId = +s[0];
|
||||
@ -3208,7 +3206,7 @@ export class AppMessagesManager extends AppManager {
|
||||
message.pFlags.out ||
|
||||
this.appChatsManager.getChat(message.peerId.toChatId())._ === 'chat' ||
|
||||
this.appChatsManager.hasRights(message.peerId.toChatId(), 'delete_messages')
|
||||
) && !message.pFlags.is_outgoing;
|
||||
) && (!message.pFlags.is_outgoing || !!message.error);
|
||||
}
|
||||
|
||||
public getReplyKeyboard(peerId: PeerId) {
|
||||
|
@ -1892,7 +1892,12 @@ export default class MTPNetworker {
|
||||
} */
|
||||
const pingId = message.ping_id;
|
||||
if(this.lastPingDelayDisconnectId === pingId) {
|
||||
this.pingDelayDisconnectDeferred.resolve('pong');
|
||||
const deferred = this.pingDelayDisconnectDeferred;
|
||||
if(deferred) {
|
||||
deferred.resolve('pong');
|
||||
} else {
|
||||
this.log('ping deferred deleted', pingId);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -71,6 +71,7 @@ export type BroadcastEvents = {
|
||||
|
||||
'message_edit': {storageKey: MessagesStorageKey, peerId: PeerId, mid: number, message: MyMessage},
|
||||
'message_sent': {storageKey: MessagesStorageKey, tempId: number, tempMessage: any, mid: number, message: MyMessage},
|
||||
'message_error': {storageKey: MessagesStorageKey, tempId: number, error: ApiError},
|
||||
'messages_views': {peerId: PeerId, mid: number, views: number}[],
|
||||
'messages_reactions': {message: Message.message, changedResults: ReactionCount[]}[],
|
||||
'messages_pending': void,
|
||||
|
@ -90,7 +90,7 @@
|
||||
{"name": "viaBotId", "type": "PeerId"},
|
||||
{"name": "clear_history", "type": "boolean"},
|
||||
{"name": "pending", "type": "boolean"},
|
||||
{"name": "error", "type": "any"},
|
||||
{"name": "error", "type": "ApiError"},
|
||||
{"name": "send", "type": "() => Promise<any>"},
|
||||
{"name": "totalEntities", "type": "MessageEntity[]"},
|
||||
{"name": "reply_to_mid", "type": "number"},
|
||||
@ -99,7 +99,8 @@
|
||||
{"name": "local", "type": "true"},
|
||||
{"name": "sponsoredMessage", "type": "SponsoredMessage.sponsoredMessage"},
|
||||
{"name": "promise", "type": "CancellablePromise<void>"},
|
||||
{"name": "uploadingFileName", "type": "string"}
|
||||
{"name": "uploadingFileName", "type": "string"},
|
||||
{"name": "storageKey", "type": "MessagesStorageKey"}
|
||||
]
|
||||
}, {
|
||||
"predicate": "messageService",
|
||||
@ -114,12 +115,13 @@
|
||||
{"name": "viaBotId", "type": "PeerId"},
|
||||
{"name": "is_single", "type": "true"},
|
||||
{"name": "pending", "type": "boolean"},
|
||||
{"name": "error", "type": "any"},
|
||||
{"name": "error", "type": "ApiError"},
|
||||
{"name": "send", "type": "() => Promise<any>"},
|
||||
{"name": "random_id", "type": "string"},
|
||||
{"name": "reply_to_mid", "type": "number"},
|
||||
{"name": "clear_history", "type": "boolean"},
|
||||
{"name": "local", "type": "true"}
|
||||
{"name": "local", "type": "true"},
|
||||
{"name": "storageKey", "type": "MessagesStorageKey"}
|
||||
]
|
||||
}, {
|
||||
"predicate": "messageEmpty",
|
||||
|
@ -2566,6 +2566,14 @@ $bubble-beside-button-width: 38px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-error {
|
||||
.time:after,
|
||||
.time .inner:after {
|
||||
content: $tgico-sendingerror;
|
||||
color: var(--message-error-color);
|
||||
}
|
||||
}
|
||||
|
||||
/* &.is-reply .name {
|
||||
display: none;
|
||||
} */
|
||||
|
@ -268,7 +268,8 @@ ul.chatlist {
|
||||
.message-status,
|
||||
.text-highlight,
|
||||
.premium-icon,
|
||||
.verified-icon {
|
||||
.verified-icon,
|
||||
.sending-status-icon {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
|
@ -228,6 +228,7 @@ $chat-input-inner-padding-handhelds: .25rem;
|
||||
--message-primary-color: var(--primary-color);
|
||||
--light-filled-message-primary-color: var(--light-filled-primary-color);
|
||||
--message-secondary-color: var(--secondary-color);
|
||||
--message-error-color: var(--danger-color);
|
||||
|
||||
$message-out-background-color: #eeffde;
|
||||
@include splitColor(message-out-background-color, $message-out-background-color, true, true);
|
||||
@ -300,6 +301,7 @@ $chat-input-inner-padding-handhelds: .25rem;
|
||||
--message-checkbox-color: var(--primary-color);
|
||||
--message-checkbox-border-color: #fff;
|
||||
--message-secondary-color: var(--secondary-color);
|
||||
--message-error-color: #fff;
|
||||
|
||||
$message-out-background-color: #8774E1;
|
||||
//@include splitColor(message-out-background-color, #ae582d, true, true);
|
||||
@ -1637,6 +1639,10 @@ hr {
|
||||
}
|
||||
} */
|
||||
|
||||
.tgico-sendingerror {
|
||||
color: var(--danger-color);
|
||||
}
|
||||
|
||||
&-icon {
|
||||
position: absolute;
|
||||
line-height: 1 !important;
|
||||
|
Loading…
x
Reference in New Issue
Block a user