From eb2b0aeb125b1b348a7a26cd1313cf5b04c6c86e Mon Sep 17 00:00:00 2001 From: Eduard Kuzmenko Date: Sun, 8 Jan 2023 18:07:01 +0400 Subject: [PATCH] Fix topic notifications Fix add members layout Support urlAuthRequest --- src/components/chat/bubbles.ts | 108 +++++++++++++++++- src/components/confirmationPopup.ts | 14 ++- src/config/app.ts | 2 +- src/lang.ts | 2 + src/lib/appManagers/appDialogsManager.ts | 16 ++- src/lib/appManagers/appMessagesManager.ts | 29 ++++- .../appManagers/appNotificationsManager.ts | 14 ++- src/lib/appManagers/appPeersManager.ts | 6 +- src/scss/partials/_button.scss | 2 +- src/scss/partials/_chatlist.scss | 4 - src/scss/partials/_selector.scss | 2 +- 11 files changed, 180 insertions(+), 19 deletions(-) diff --git a/src/components/chat/bubbles.ts b/src/components/chat/bubbles.ts index 82e566e66..3ff729bf1 100644 --- a/src/components/chat/bubbles.ts +++ b/src/components/chat/bubbles.ts @@ -29,7 +29,7 @@ import LazyLoadQueue from '../lazyLoadQueue'; import ListenerSetter from '../../helpers/listenerSetter'; import PollElement from '../poll'; import AudioElement from '../audio'; -import {Chat as MTChat, ChatInvite, Document, Message, MessageEntity, MessageMedia, MessageReplyHeader, Photo, PhotoSize, ReactionCount, ReplyMarkup, SponsoredMessage, Update, User, WebPage} from '../../layer'; +import {Chat as MTChat, ChatInvite, Document, Message, MessageEntity, MessageMedia, MessageReplyHeader, Photo, PhotoSize, ReactionCount, ReplyMarkup, SponsoredMessage, Update, UrlAuthResult, User, WebPage} from '../../layer'; import {BOT_START_PARAM, NULL_PEER_ID, REPLIES_PEER_ID} from '../../lib/mtproto/mtproto_config'; import {FocusDirection, ScrollStartCallbackDimensions} from '../../helpers/fastSmoothScroll'; import useHeavyAnimationCheck, {getHeavyAnimationPromise, dispatchHeavyAnimationEvent, interruptHeavyAnimation} from '../../hooks/useHeavyAnimationCheck'; @@ -128,6 +128,10 @@ import wrapUrl from '../../lib/richTextProcessor/wrapUrl'; import getMessageThreadId from '../../lib/appManagers/utils/messages/getMessageThreadId'; import wrapTopicNameButton from '../wrappers/topicNameButton'; import wrapMediaSpoiler from '../wrappers/mediaSpoiler'; +import confirmationPopup from '../confirmationPopup'; +import wrapPeerTitle from '../wrappers/peerTitle'; +import {PopupPeerCheckboxOptions} from '../popups/peer'; +import toggleDisability from '../../helpers/dom/toggleDisability'; export const USER_REACTIONS_INLINE = false; const USE_MEDIA_TAILS = false; @@ -3970,6 +3974,105 @@ export default class ChatBubbles { break; } + case 'keyboardButtonUrlAuth': { + buttonEl = document.createElement('button'); + buttonEl.classList.add('is-url-auth'); + + const {peerId} = this; + const {mid} = message; + const {url, button_id} = button; + + const openWindow = (url: string) => { + window.open(url, '_blank'); + }; + + const onUrlAuthResultAccepted = (urlAuthResult: UrlAuthResult.urlAuthResultAccepted) => { + openWindow(urlAuthResult.url); + }; + + const onUrlAuthResult = async(urlAuthResult: UrlAuthResult): Promise => { + if(urlAuthResult._ === 'urlAuthResultRequest') { + const b = document.createElement('b'); + b.append(urlAuthResult.domain); + const peerTitle = await wrapPeerTitle({peerId: rootScope.myId}); + const botPeerTitle = await wrapPeerTitle({peerId: urlAuthResult.bot.id.toPeerId()}); + + const logInCheckbox: PopupPeerCheckboxOptions = { + text: 'OpenUrlOption1', + textArgs: [b.cloneNode(true), peerTitle], + checked: true + }; + + const allowMessagesCheckbox: PopupPeerCheckboxOptions = urlAuthResult.pFlags.request_write_access ? { + text: 'OpenUrlOption2', + textArgs: [botPeerTitle], + checked: true + } : undefined; + + const checkboxes: PopupPeerCheckboxOptions[] = [ + logInCheckbox, + allowMessagesCheckbox + ]; + + const confirmationPromise = confirmationPopup({ + titleLangKey: 'OpenUrlTitle', + button: { + langKey: 'Open' + }, + descriptionLangKey: 'OpenUrlAlert2', + descriptionLangArgs: [b], + checkboxes: checkboxes.filter(Boolean) + }); + + if(allowMessagesCheckbox) { + logInCheckbox.checkboxField.input.addEventListener('change', () => { + const disabled = !logInCheckbox.checkboxField.checked; + allowMessagesCheckbox.checkboxField.toggleDisability(disabled); + + if(disabled) { + allowMessagesCheckbox.checkboxField.checked = false; + } + }); + } + + const [logInChecked, allowMessagesChecked] = await confirmationPromise; + + if(!logInChecked) { + openWindow(url); + return; + } + + const result = await this.managers.appMessagesManager.acceptUrlAuth( + peerId, + mid, + url, + button_id, + allowMessagesChecked + ); + + return onUrlAuthResult(result); + } else if(urlAuthResult._ === 'urlAuthResultAccepted') { + onUrlAuthResultAccepted(urlAuthResult); + } else { + openWindow(url); + } + }; + + attachClickEvent(buttonEl, () => { + const toggle = toggleDisability([buttonEl], true); + this.managers.appMessagesManager.requestUrlAuth( + peerId, + mid, + url, + button_id + ).then((urlAuthResult) => { + toggle(); + onUrlAuthResult(urlAuthResult); + }); + }); + break; + } + default: { buttonEl = document.createElement('button'); break; @@ -4012,7 +4115,8 @@ export default class ChatBubbles { !target || target.classList.contains('is-link') || target.classList.contains('is-switch-inline') || - target.classList.contains('is-buy') + target.classList.contains('is-buy') || + target.classList.contains('is-url-auth') ) return; cancelEvent(e); diff --git a/src/components/confirmationPopup.ts b/src/components/confirmationPopup.ts index 811178094..f93314858 100644 --- a/src/components/confirmationPopup.ts +++ b/src/components/confirmationPopup.ts @@ -5,7 +5,7 @@ */ import {addCancelButton} from './popups'; -import PopupPeer, {PopupPeerOptions} from './popups/peer'; +import PopupPeer, {PopupPeerCheckboxOptions, PopupPeerOptions} from './popups/peer'; // type PopupConfirmationOptions = Pick; export type PopupConfirmationOptions = PopupPeerOptions & { @@ -13,11 +13,17 @@ export type PopupConfirmationOptions = PopupPeerOptions & { checkbox?: PopupPeerOptions['checkboxes'][0] }; -export default function confirmationPopup(options: PopupConfirmationOptions) { - return new Promise((resolve, reject) => { +export default function confirmationPopup( + options: T +): Promise : (T['checkbox'] extends PopupPeerCheckboxOptions ? boolean : void)> { + return new Promise((resolve, reject) => { const {button, checkbox} = options; button.callback = (set) => { - resolve(set ? !!set.size : undefined); + if(checkbox || !set) { + resolve(set ? !!set.size : undefined); + } else { + resolve(options.checkboxes.map((checkbox) => set.has(checkbox.text))); + } }; const buttons = addCancelButton(options.buttons || [button]); diff --git a/src/config/app.ts b/src/config/app.ts index 0df9a728d..cc88695f5 100644 --- a/src/config/app.ts +++ b/src/config/app.ts @@ -21,7 +21,7 @@ const App = { version: process.env.VERSION, versionFull: process.env.VERSION_FULL, build: +process.env.BUILD, - langPackVersion: '0.7.3', + langPackVersion: '0.7.5', langPack: 'webk', langPackCode: 'en', domains: MAIN_DOMAINS, diff --git a/src/lang.ts b/src/lang.ts index 3ed3cf347..fad668c99 100644 --- a/src/lang.ts +++ b/src/lang.ts @@ -853,6 +853,8 @@ const lang = { 'CreateGeneralTopicTitle': 'Choose topic name', 'EditTopicHide': 'Show in Topics', 'EditTopicHideInfo': 'If the \'General\' topic is hidden, group members can pull down in the topic list to view it.', + 'OpenUrlOption1': 'Log in to %1$s as **%2$s**', + 'OpenUrlOption2': 'Allow **%1$s** to send me messages', // * macos 'AccountSettings.Filters': 'Chat Folders', diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index c2c3464b2..81a31006c 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -1114,8 +1114,20 @@ class Some3 extends Some { appDialogsManager.setUnreadMessagesN({dialog, dialogElement: this.getDialogElement(this.getDialogKey(dialog))}); }); - this.listenerSetter.add(rootScope)('dialog_notify_settings', (dialog) => { - if(dialog._ !== 'forumTopic' || dialog.peerId !== this.peerId) { + this.listenerSetter.add(rootScope)('dialog_notify_settings', async(dialog) => { + if(dialog.peerId !== this.peerId) { + return; + } + + if(dialog._ === 'dialog') { + const all = this.sortedList.getAll(); + const entries = [...all.entries()]; + const promises = entries.map(([id]) => this.managers.dialogsStorage.getForumTopic(this.peerId, id)); + const topics = await Promise.all(promises); + entries.forEach(([id, element], idx) => { + appDialogsManager.setUnreadMessagesN({dialog: topics[idx], dialogElement: element.dialogElement}); // возможно это не нужно, но нужно менять is-muted + }); + return; } diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 9cd714233..f2adf849e 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -13,7 +13,7 @@ import LazyLoadQueueBase from '../../components/lazyLoadQueueBase'; import deferredPromise, {CancellablePromise} from '../../helpers/cancellablePromise'; import tsNow from '../../helpers/tsNow'; import {randomLong} from '../../helpers/random'; -import {Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason, MessagesGetDialogs, InputChannel, InputDialogPeer, ReactionCount, MessagePeerReaction, MessagesSearchCounter, Peer, MessageReactions, Document, InputFile, Reaction, ForumTopic as MTForumTopic, MessagesForumTopics, MessagesGetReplies, MessagesGetHistory, MessagesAffectedHistory} from '../../layer'; +import {Chat, ChatFull, Dialog as MTDialog, DialogPeer, DocumentAttribute, InputMedia, InputMessage, InputPeerNotifySettings, InputSingleMedia, Message, MessageAction, MessageEntity, MessageFwdHeader, MessageMedia, MessageReplies, MessageReplyHeader, MessagesDialogs, MessagesFilter, MessagesMessages, MethodDeclMap, NotifyPeer, PeerNotifySettings, PhotoSize, SendMessageAction, Update, Photo, Updates, ReplyMarkup, InputPeer, InputPhoto, InputDocument, InputGeoPoint, WebPage, GeoPoint, ReportReason, MessagesGetDialogs, InputChannel, InputDialogPeer, ReactionCount, MessagePeerReaction, MessagesSearchCounter, Peer, MessageReactions, Document, InputFile, Reaction, ForumTopic as MTForumTopic, MessagesForumTopics, MessagesGetReplies, MessagesGetHistory, MessagesAffectedHistory, UrlAuthResult} from '../../layer'; import {ArgumentTypes, InvokeApiOptions} from '../../types'; import {logger, LogTypes} from '../logger'; import type {ApiFileManager} from '../mtproto/apiFileManager'; @@ -6399,4 +6399,31 @@ export class AppMessagesManager extends AppManager { send_as: this.appPeersManager.getInputPeerById(sendAsPeerId) }); } + + public requestUrlAuth(peerId: PeerId, mid: number, url: string, buttonId: number) { + return this.apiManager.invokeApi('messages.requestUrlAuth', { + button_id: buttonId, + msg_id: getServerMessageId(mid), + peer: this.appPeersManager.getInputPeerById(peerId), + url + }).then((urlAuthResult) => { + if(urlAuthResult._ === 'urlAuthResultRequest') { + this.appUsersManager.saveApiUser(urlAuthResult.bot); + } + + return urlAuthResult; + }); + } + + public acceptUrlAuth(peerId: PeerId, mid: number, url: string, buttonId: number, writeAllowed?: boolean) { + return this.apiManager.invokeApi('messages.acceptUrlAuth', { + button_id: buttonId, + msg_id: getServerMessageId(mid), + peer: this.appPeersManager.getInputPeerById(peerId), + url, + write_allowed: writeAllowed + }).then((urlAuthResult) => { + return urlAuthResult as Exclude; + }); + } } diff --git a/src/lib/appManagers/appNotificationsManager.ts b/src/lib/appManagers/appNotificationsManager.ts index 65b42f4a4..4d445168f 100644 --- a/src/lib/appManagers/appNotificationsManager.ts +++ b/src/lib/appManagers/appNotificationsManager.ts @@ -300,10 +300,20 @@ export class AppNotificationsManager extends AppManager { return options; } - public isPeerLocalMuted(options: Parameters[0]) { + public isPeerLocalMuted(options: Parameters[0]): boolean { if(!(options = this.validatePeerSettings(options))) return false; + if(options.threadId) { + const notifySettings = this.getPeerLocalSettings({...options, respectType: false}); + if(notifySettings.silent !== undefined || notifySettings.mute_until !== undefined) { + return this.isMuted(notifySettings); + } else { + return this.isPeerLocalMuted({...options, threadId: undefined}); + } + } + const notifySettings = this.getPeerLocalSettings(options); - return this.isMuted(notifySettings); + const isMuted = this.isMuted(notifySettings); + return isMuted; } } diff --git a/src/lib/appManagers/appPeersManager.ts b/src/lib/appManagers/appPeersManager.ts index 743778b36..c8e398635 100644 --- a/src/lib/appManagers/appPeersManager.ts +++ b/src/lib/appManagers/appPeersManager.ts @@ -191,7 +191,11 @@ export class AppPeersManager extends AppManager { peerId: PeerId, ignorePeerId?: boolean, threadId?: number - }>({peerId, ignorePeerId, threadId}: T): T['ignorePeerId'] extends true ? Exclude : (T['threadId'] extends number ? InputNotifyPeer.inputNotifyForumTopic : InputNotifyPeer.inputNotifyPeer) { + }>({ + peerId, + ignorePeerId, + threadId + }: T): T['ignorePeerId'] extends true ? Exclude : (T['threadId'] extends number ? InputNotifyPeer.inputNotifyForumTopic : InputNotifyPeer.inputNotifyPeer) { if(ignorePeerId) { if(peerId.isUser()) { return {_: 'inputNotifyUsers'} as any; diff --git a/src/scss/partials/_button.scss b/src/scss/partials/_button.scss index 93be606b7..6583f66e1 100644 --- a/src/scss/partials/_button.scss +++ b/src/scss/partials/_button.scss @@ -335,7 +335,7 @@ $btn-menu-z-index: 4; font-size: .75rem; width: fit-content; min-width: calc(100% - .625rem); - max-width: fit-content; + max-width: 16.25rem; .btn-menu-item-text { white-space: pre-wrap; diff --git a/src/scss/partials/_chatlist.scss b/src/scss/partials/_chatlist.scss index 3c280f352..873011046 100644 --- a/src/scss/partials/_chatlist.scss +++ b/src/scss/partials/_chatlist.scss @@ -255,10 +255,6 @@ ul.chatlist { } } - &.menu-open { - --background: var(--light-secondary-text-color); - } - @include respond-to(not-handhelds) { &.active { --background: var(--primary-color) !important; diff --git a/src/scss/partials/_selector.scss b/src/scss/partials/_selector.scss index 4ea58257d..d3c01f2bf 100644 --- a/src/scss/partials/_selector.scss +++ b/src/scss/partials/_selector.scss @@ -190,7 +190,7 @@ left: 1.25rem !important; } - .chatlist-chat { + .chatlist-chat.row-with-padding { padding-left: #{4.5rem + $add} !important; // 4.5 + x }