Fix topic notifications

Fix add members layout
Support urlAuthRequest
This commit is contained in:
Eduard Kuzmenko 2023-01-08 18:07:01 +04:00
parent 2c96273e59
commit eb2b0aeb12
11 changed files with 180 additions and 19 deletions

View File

@ -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<void> => {
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);

View File

@ -5,7 +5,7 @@
*/
import {addCancelButton} from './popups';
import PopupPeer, {PopupPeerOptions} from './popups/peer';
import PopupPeer, {PopupPeerCheckboxOptions, PopupPeerOptions} from './popups/peer';
// type PopupConfirmationOptions = Pick<PopupPeerOptions, 'titleLangKey'>;
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<boolean | void>((resolve, reject) => {
export default function confirmationPopup<T extends PopupConfirmationOptions>(
options: T
): Promise<T['checkboxes'] extends PopupPeerCheckboxOptions[] ? Array<boolean> : (T['checkbox'] extends PopupPeerCheckboxOptions ? boolean : void)> {
return new Promise<any>((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]);

View File

@ -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,

View File

@ -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',

View File

@ -1114,8 +1114,20 @@ class Some3 extends Some<ForumTopic> {
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;
}

View File

@ -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<UrlAuthResult, UrlAuthResult.urlAuthResultRequest>;
});
}
}

View File

@ -300,10 +300,20 @@ export class AppNotificationsManager extends AppManager {
return options;
}
public isPeerLocalMuted(options: Parameters<AppNotificationsManager['getPeerLocalSettings']>[0]) {
public isPeerLocalMuted(options: Parameters<AppNotificationsManager['getPeerLocalSettings']>[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;
}
}

View File

@ -191,7 +191,11 @@ export class AppPeersManager extends AppManager {
peerId: PeerId,
ignorePeerId?: boolean,
threadId?: number
}>({peerId, ignorePeerId, threadId}: T): T['ignorePeerId'] extends true ? Exclude<InputNotifyPeer, InputNotifyPeer.inputNotifyPeer | InputNotifyPeer.inputNotifyForumTopic> : (T['threadId'] extends number ? InputNotifyPeer.inputNotifyForumTopic : InputNotifyPeer.inputNotifyPeer) {
}>({
peerId,
ignorePeerId,
threadId
}: T): T['ignorePeerId'] extends true ? Exclude<InputNotifyPeer, InputNotifyPeer.inputNotifyPeer | InputNotifyPeer.inputNotifyForumTopic> : (T['threadId'] extends number ? InputNotifyPeer.inputNotifyForumTopic : InputNotifyPeer.inputNotifyPeer) {
if(ignorePeerId) {
if(peerId.isUser()) {
return {_: 'inputNotifyUsers'} as any;

View File

@ -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;

View File

@ -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;

View File

@ -190,7 +190,7 @@
left: 1.25rem !important;
}
.chatlist-chat {
.chatlist-chat.row-with-padding {
padding-left: #{4.5rem + $add} !important; // 4.5 + x
}