Browse Source

Support phone number links

Layer 139
Fix displaying message text as italic after search
Added new report reasons
master
Eduard Kuzmenko 3 years ago
parent
commit
15b7d1afc9
  1. 4
      src/components/popups/reportMessages.ts
  2. 2
      src/lang.ts
  3. 80
      src/layer.d.ts
  4. 28
      src/lib/appManagers/appImManager.ts
  5. 1
      src/lib/appManagers/appMessagesManager.ts
  6. 18
      src/lib/appManagers/appUsersManager.ts
  7. 13
      src/lib/appManagers/internalLink.ts
  8. 2
      src/lib/mtproto/schema.ts
  9. 5
      src/lib/richtextprocessor.ts
  10. 4
      src/scripts/in/schema.json
  11. 2
      src/scripts/out/schema.json

4
src/components/popups/reportMessages.ts

@ -25,7 +25,9 @@ export default class PopupReportMessages extends PopupPeer {
['ReportChatViolence', 'inputReportReasonViolence'], ['ReportChatViolence', 'inputReportReasonViolence'],
['ReportChatChild', 'inputReportReasonChildAbuse'], ['ReportChatChild', 'inputReportReasonChildAbuse'],
['ReportChatPornography', 'inputReportReasonPornography'], ['ReportChatPornography', 'inputReportReasonPornography'],
['ReportChatOther', 'inputReportReasonOther'] ['ReportChatOther', 'inputReportReasonOther'],
['ReportChatPersonalDetails', 'inputReportReasonPersonalDetails'],
['ReportChatIllegalDrugs', 'inputReportReasonIllegalDrugs']
]; ];
const className = 'btn-primary btn-transparent'; const className = 'btn-primary btn-transparent';

2
src/lang.ts

@ -686,6 +686,8 @@ const lang = {
"VoipUserMicrophoneIsOff": "%s\'s microphone is off", "VoipUserMicrophoneIsOff": "%s\'s microphone is off",
"VoipUserCameraIsOff": "%s\'s camera is off", "VoipUserCameraIsOff": "%s\'s camera is off",
"PrivacyPhoneInfo4": "This public link opens a chat with you:", "PrivacyPhoneInfo4": "This public link opens a chat with you:",
"ReportChatIllegalDrugs": "Illegal Drugs",
"ReportChatPersonalDetails": "Personal Details",
// * macos // * macos
"AccountSettings.Filters": "Chat Folders", "AccountSettings.Filters": "Chat Folders",

80
src/layer.d.ts vendored

@ -1591,7 +1591,7 @@ export namespace WallPaper {
/** /**
* @link https://core.telegram.org/type/ReportReason * @link https://core.telegram.org/type/ReportReason
*/ */
export type ReportReason = ReportReason.inputReportReasonSpam | ReportReason.inputReportReasonViolence | ReportReason.inputReportReasonPornography | ReportReason.inputReportReasonChildAbuse | ReportReason.inputReportReasonOther | ReportReason.inputReportReasonCopyright | ReportReason.inputReportReasonGeoIrrelevant | ReportReason.inputReportReasonFake; export type ReportReason = ReportReason.inputReportReasonSpam | ReportReason.inputReportReasonViolence | ReportReason.inputReportReasonPornography | ReportReason.inputReportReasonChildAbuse | ReportReason.inputReportReasonOther | ReportReason.inputReportReasonCopyright | ReportReason.inputReportReasonGeoIrrelevant | ReportReason.inputReportReasonFake | ReportReason.inputReportReasonIllegalDrugs | ReportReason.inputReportReasonPersonalDetails;
export namespace ReportReason { export namespace ReportReason {
export type inputReportReasonSpam = { export type inputReportReasonSpam = {
@ -1625,6 +1625,14 @@ export namespace ReportReason {
export type inputReportReasonFake = { export type inputReportReasonFake = {
_: 'inputReportReasonFake' _: 'inputReportReasonFake'
}; };
export type inputReportReasonIllegalDrugs = {
_: 'inputReportReasonIllegalDrugs'
};
export type inputReportReasonPersonalDetails = {
_: 'inputReportReasonPersonalDetails'
};
} }
/** /**
@ -8728,6 +8736,8 @@ export namespace GroupCall {
schedule_start_subscribed?: true, schedule_start_subscribed?: true,
can_start_video?: true, can_start_video?: true,
record_video_active?: true, record_video_active?: true,
rtmp_stream?: true,
listeners_hidden?: true,
}>, }>,
id: string | number, id: string | number,
access_hash: string | number, access_hash: string | number,
@ -9408,6 +9418,45 @@ export namespace MessagePeerReaction {
}; };
} }
/**
* @link https://core.telegram.org/type/GroupCallStreamChannel
*/
export type GroupCallStreamChannel = GroupCallStreamChannel.groupCallStreamChannel;
export namespace GroupCallStreamChannel {
export type groupCallStreamChannel = {
_: 'groupCallStreamChannel',
channel: number,
scale: number,
last_timestamp_ms: string | number
};
}
/**
* @link https://core.telegram.org/type/phone.GroupCallStreamChannels
*/
export type PhoneGroupCallStreamChannels = PhoneGroupCallStreamChannels.phoneGroupCallStreamChannels;
export namespace PhoneGroupCallStreamChannels {
export type phoneGroupCallStreamChannels = {
_: 'phone.groupCallStreamChannels',
channels: Array<GroupCallStreamChannel>
};
}
/**
* @link https://core.telegram.org/type/phone.GroupCallStreamRtmpUrl
*/
export type PhoneGroupCallStreamRtmpUrl = PhoneGroupCallStreamRtmpUrl.phoneGroupCallStreamRtmpUrl;
export namespace PhoneGroupCallStreamRtmpUrl {
export type phoneGroupCallStreamRtmpUrl = {
_: 'phone.groupCallStreamRtmpUrl',
url: string,
key: string
};
}
export interface ConstructorDeclMap { export interface ConstructorDeclMap {
'error': Error.error, 'error': Error.error,
'inputPeerEmpty': InputPeer.inputPeerEmpty, 'inputPeerEmpty': InputPeer.inputPeerEmpty,
@ -10358,6 +10407,11 @@ export interface ConstructorDeclMap {
'messages.translateNoResult': MessagesTranslatedText.messagesTranslateNoResult, 'messages.translateNoResult': MessagesTranslatedText.messagesTranslateNoResult,
'messages.translateResultText': MessagesTranslatedText.messagesTranslateResultText, 'messages.translateResultText': MessagesTranslatedText.messagesTranslateResultText,
'messagePeerReaction': MessagePeerReaction.messagePeerReaction, 'messagePeerReaction': MessagePeerReaction.messagePeerReaction,
'groupCallStreamChannel': GroupCallStreamChannel.groupCallStreamChannel,
'phone.groupCallStreamChannels': PhoneGroupCallStreamChannels.phoneGroupCallStreamChannels,
'inputReportReasonIllegalDrugs': ReportReason.inputReportReasonIllegalDrugs,
'inputReportReasonPersonalDetails': ReportReason.inputReportReasonPersonalDetails,
'phone.groupCallStreamRtmpUrl': PhoneGroupCallStreamRtmpUrl.phoneGroupCallStreamRtmpUrl,
'messageEntityEmoji': MessageEntity.messageEntityEmoji, 'messageEntityEmoji': MessageEntity.messageEntityEmoji,
'messageEntityHighlight': MessageEntity.messageEntityHighlight, 'messageEntityHighlight': MessageEntity.messageEntityHighlight,
'messageEntityLinebreak': MessageEntity.messageEntityLinebreak, 'messageEntityLinebreak': MessageEntity.messageEntityLinebreak,
@ -12378,6 +12432,7 @@ export type MessagesUnpinAllMessages = {
export type PhoneCreateGroupCall = { export type PhoneCreateGroupCall = {
flags?: number, flags?: number,
rtmp_stream?: boolean,
peer: InputPeer, peer: InputPeer,
random_id: number, random_id: number,
title?: string, title?: string,
@ -12762,6 +12817,25 @@ export type MessagesReadReactions = {
peer: InputPeer peer: InputPeer
}; };
export type ContactsResolvePhone = {
phone: string
};
export type PhoneGetGroupCallStreamChannels = {
call: InputGroupCall
};
export type PhoneGetGroupCallStreamRtmpUrl = {
peer: InputPeer,
revoke: boolean
};
export type MessagesSearchSentMedia = {
q: string,
filter: MessagesFilter,
limit: number
};
export interface MethodDeclMap { export interface MethodDeclMap {
'invokeAfterMsg': {req: InvokeAfterMsg, res: any}, 'invokeAfterMsg': {req: InvokeAfterMsg, res: any},
'invokeAfterMsgs': {req: InvokeAfterMsgs, res: any}, 'invokeAfterMsgs': {req: InvokeAfterMsgs, res: any},
@ -13178,5 +13252,9 @@ export interface MethodDeclMap {
'messages.translateText': {req: MessagesTranslateText, res: MessagesTranslatedText}, 'messages.translateText': {req: MessagesTranslateText, res: MessagesTranslatedText},
'messages.getUnreadReactions': {req: MessagesGetUnreadReactions, res: MessagesMessages}, 'messages.getUnreadReactions': {req: MessagesGetUnreadReactions, res: MessagesMessages},
'messages.readReactions': {req: MessagesReadReactions, res: MessagesAffectedHistory}, 'messages.readReactions': {req: MessagesReadReactions, res: MessagesAffectedHistory},
'contacts.resolvePhone': {req: ContactsResolvePhone, res: ContactsResolvedPeer},
'phone.getGroupCallStreamChannels': {req: PhoneGetGroupCallStreamChannels, res: PhoneGroupCallStreamChannels},
'phone.getGroupCallStreamRtmpUrl': {req: PhoneGetGroupCallStreamRtmpUrl, res: PhoneGroupCallStreamRtmpUrl},
'messages.searchSentMedia': {req: MessagesSearchSentMedia, res: MessagesMessages},
} }

28
src/lib/appManagers/appImManager.ts

@ -492,7 +492,12 @@ export class AppImManager {
name: 'im', name: 'im',
callback: async({pathnameParams, uriParams}) => { callback: async({pathnameParams, uriParams}) => {
let link: InternalLink; let link: InternalLink;
if(pathnameParams[0] === 'c') { if(RichTextProcessor.PHONE_NUMBER_REG_EXP.test(pathnameParams[0])) {
link = {
_: INTERNAL_LINK_TYPE.USER_PHONE_NUMBER,
phone: pathnameParams[0].slice(1)
};
} else if(pathnameParams[0] === 'c') {
link = { link = {
_: INTERNAL_LINK_TYPE.PRIVATE_POST, _: INTERNAL_LINK_TYPE.PRIVATE_POST,
channel: pathnameParams[1], channel: pathnameParams[1],
@ -533,14 +538,17 @@ export class AppImManager {
voicechat?: string, voicechat?: string,
post?: string, post?: string,
thread?: string, thread?: string,
comment?: string comment?: string,
phone?: string
} }
}>({ }>({
name: 'resolve', name: 'resolve',
protocol: 'tg', protocol: 'tg',
callback: ({uriParams}) => { callback: ({uriParams}) => {
let link: InternalLink; let link: InternalLink;
if(uriParams.domain === 'telegrampassport') { if(uriParams.phone) {
link = this.makeLink(INTERNAL_LINK_TYPE.USER_PHONE_NUMBER, uriParams as Required<typeof uriParams>);
} else if(uriParams.domain === 'telegrampassport') {
} else { } else {
link = this.makeLink(INTERNAL_LINK_TYPE.MESSAGE, uriParams); link = this.makeLink(INTERNAL_LINK_TYPE.MESSAGE, uriParams);
@ -790,6 +798,20 @@ export class AppImManager {
break; break;
} }
case INTERNAL_LINK_TYPE.USER_PHONE_NUMBER: {
appUsersManager.resolvePhone(link.phone).then(user => {
this.setInnerPeer({
peerId: user.id.toPeerId(false)
});
}).catch(err => {
if(err.type === 'PHONE_NOT_OCCUPIED') {
toastNew({langPackKey: 'Alert.UserDoesntExists'});
}
});
break;
}
default: { default: {
this.log.warn('Not supported internal link:', link); this.log.warn('Not supported internal link:', link);
break; break;

1
src/lib/appManagers/appMessagesManager.ts

@ -3018,6 +3018,7 @@ export class AppMessagesManager {
let found = false; let found = false;
let match: any; let match: any;
let regExp = new RegExp(escapeRegExp(highlightWord), 'gi'); let regExp = new RegExp(escapeRegExp(highlightWord), 'gi');
entities = entities.slice(); // fix leaving highlight entity
while((match = regExp.exec(text)) !== null) { while((match = regExp.exec(text)) !== null) {
entities.push({_: 'messageEntityHighlight', length: highlightWord.length, offset: match.index}); entities.push({_: 'messageEntityHighlight', length: highlightWord.length, offset: match.index});
found = true; found = true;

18
src/lib/appManagers/appUsersManager.ts

@ -20,7 +20,7 @@ import { formatPhoneNumber } from "../../helpers/formatPhoneNumber";
import isObject from "../../helpers/object/isObject"; import isObject from "../../helpers/object/isObject";
import safeReplaceObject from "../../helpers/object/safeReplaceObject"; import safeReplaceObject from "../../helpers/object/safeReplaceObject";
import { isRestricted } from "../../helpers/restrictions"; import { isRestricted } from "../../helpers/restrictions";
import { Chat, InputContact, InputGeoPoint, InputMedia, InputPeer, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer"; import { Chat, ContactsResolvedPeer, InputContact, InputGeoPoint, InputMedia, InputPeer, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer";
import I18n, { i18n, LangPackKey } from "../langPack"; import I18n, { i18n, LangPackKey } from "../langPack";
//import apiManager from '../mtproto/apiManager'; //import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
@ -260,10 +260,20 @@ export class AppUsersManager {
} }
return apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => { return apiManager.invokeApi('contacts.resolveUsername', {username}).then(resolvedPeer => {
this.saveApiUsers(resolvedPeer.users); return this.processResolvedPeer(resolvedPeer);
appChatsManager.saveApiChats(resolvedPeer.chats); });
}
private processResolvedPeer(resolvedPeer: ContactsResolvedPeer.contactsResolvedPeer) {
this.saveApiUsers(resolvedPeer.users);
appChatsManager.saveApiChats(resolvedPeer.chats);
return appPeersManager.getPeer(appPeersManager.getPeerId(resolvedPeer.peer)) as Chat | User;
}
return appPeersManager.getPeer(appPeersManager.getPeerId(resolvedPeer.peer)); public resolvePhone(phone: string) {
return apiManager.invokeApi('contacts.resolvePhone', {phone}).then(resolvedPeer => {
return this.processResolvedPeer(resolvedPeer) as User;
}); });
} }

13
src/lib/appManagers/internalLink.ts

@ -9,10 +9,11 @@ export enum INTERNAL_LINK_TYPE {
PRIVATE_POST, PRIVATE_POST,
STICKER_SET, STICKER_SET,
JOIN_CHAT, JOIN_CHAT,
VOICE_CHAT VOICE_CHAT,
USER_PHONE_NUMBER
}; };
export type InternalLink = InternalLink.InternalLinkMessage | InternalLink.InternalLinkPrivatePost | InternalLink.InternalLinkStickerSet | InternalLink.InternalLinkJoinChat | InternalLink.InternalLinkVoiceChat; export type InternalLink = InternalLink.InternalLinkMessage | InternalLink.InternalLinkPrivatePost | InternalLink.InternalLinkStickerSet | InternalLink.InternalLinkJoinChat | InternalLink.InternalLinkVoiceChat | InternalLink.InternalLinkUserPhoneNumber;
export namespace InternalLink { export namespace InternalLink {
export interface InternalLinkMessage { export interface InternalLinkMessage {
@ -50,6 +51,11 @@ export namespace InternalLink {
access_hash: string, access_hash: string,
chat_id: string chat_id: string
} }
export interface InternalLinkUserPhoneNumber {
_: INTERNAL_LINK_TYPE.USER_PHONE_NUMBER,
phone: string
}
} }
export type InternalLinkTypeMap = { export type InternalLinkTypeMap = {
@ -57,5 +63,6 @@ export type InternalLinkTypeMap = {
[INTERNAL_LINK_TYPE.PRIVATE_POST]: InternalLink.InternalLinkPrivatePost, [INTERNAL_LINK_TYPE.PRIVATE_POST]: InternalLink.InternalLinkPrivatePost,
[INTERNAL_LINK_TYPE.STICKER_SET]: InternalLink.InternalLinkStickerSet, [INTERNAL_LINK_TYPE.STICKER_SET]: InternalLink.InternalLinkStickerSet,
[INTERNAL_LINK_TYPE.JOIN_CHAT]: InternalLink.InternalLinkJoinChat, [INTERNAL_LINK_TYPE.JOIN_CHAT]: InternalLink.InternalLinkJoinChat,
[INTERNAL_LINK_TYPE.VOICE_CHAT]: InternalLink.InternalLinkVoiceChat [INTERNAL_LINK_TYPE.VOICE_CHAT]: InternalLink.InternalLinkVoiceChat,
[INTERNAL_LINK_TYPE.USER_PHONE_NUMBER]: InternalLink.InternalLinkUserPhoneNumber
}; };

2
src/lib/mtproto/schema.ts

File diff suppressed because one or more lines are too long

5
src/lib/richtextprocessor.ts

@ -117,6 +117,8 @@ for(let i in markdownEntities) {
} }
namespace RichTextProcessor { namespace RichTextProcessor {
export const PHONE_NUMBER_REG_EXP = /^\+\d+$/;
export function getEmojiSpritesheetCoords(emojiCode: string) { export function getEmojiSpritesheetCoords(emojiCode: string) {
let unified = encodeEmoji(emojiCode).replace(/-?fe0f/g, ''); let unified = encodeEmoji(emojiCode).replace(/-?fe0f/g, '');
@ -950,7 +952,8 @@ namespace RichTextProcessor {
} else */if((tgMeMatch = url.match(/^(?:https?:\/\/)?t(?:elegram)?\.me\/(.+)/))) { } else */if((tgMeMatch = url.match(/^(?:https?:\/\/)?t(?:elegram)?\.me\/(.+)/))) {
const fullPath = tgMeMatch[1]; const fullPath = tgMeMatch[1];
if(/^\W/.test(fullPath)) { // second regexp is for phone numbers (t.me/+38050...)
if(/^\W/.test(fullPath) && !PHONE_NUMBER_REG_EXP.test(fullPath)) {
onclick = 'joinchat'; onclick = 'joinchat';
return {url, onclick}; return {url, onclick};
} }

4
src/scripts/in/schema.json

File diff suppressed because one or more lines are too long

2
src/scripts/out/schema.json

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save