Browse Source

Report messages

master
Eduard Kuzmenko 3 years ago
parent
commit
0478be1603
  1. 10
      src/components/chat/contextMenu.ts
  2. 2
      src/components/inputField.ts
  3. 3
      src/components/popups/index.ts
  4. 26
      src/components/popups/peer.ts
  5. 54
      src/components/popups/reportMessages.ts
  6. 66
      src/components/popups/reportMessagesConfirm.ts
  7. 12
      src/lang.ts
  8. 13
      src/lib/appManagers/appMessagesManager.ts
  9. 15
      src/lib/appManagers/appStickersManager.ts
  10. 6
      src/scss/partials/popups/_instanceDeactivated.scss
  11. 6
      src/scss/partials/popups/_joinChatInvite.scss
  12. 28
      src/scss/partials/popups/_reportMessages.scss
  13. 1
      src/scss/style.scss

10
src/components/chat/contextMenu.ts

@ -26,6 +26,7 @@ import cancelSelection from "../../helpers/dom/cancelSelection"; @@ -26,6 +26,7 @@ import cancelSelection from "../../helpers/dom/cancelSelection";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import isSelectionEmpty from "../../helpers/dom/isSelectionEmpty";
import { Message } from "../../layer";
import PopupReportMessages from "../popups/reportMessages";
export default class ChatContextMenu {
private buttons: (ButtonMenuItemOptions & {verify: () => boolean, notDirect?: () => boolean, withSelection?: true})[];
@ -322,6 +323,15 @@ export default class ChatContextMenu { @@ -322,6 +323,15 @@ export default class ChatContextMenu {
!this.chat.selection.selectionForwardBtn.hasAttribute('disabled'),
notDirect: () => true,
withSelection: true
}, {
icon: 'flag',
text: 'ReportChat',
onClick: () => {
new PopupReportMessages(this.peerId, [this.mid]);
},
verify: () => !this.message.pFlags.out && !this.message.pFlags.is_outgoing && this.appPeersManager.isChannel(this.peerId),
notDirect: () => true,
withSelection: true
}, {
icon: 'select',
text: 'Message.Context.Select',

2
src/components/inputField.ts

@ -95,7 +95,7 @@ class InputField { @@ -95,7 +95,7 @@ class InputField {
this.container.classList.add('input-field');
if(options.maxLength) {
options.showLengthOn = Math.round(options.maxLength / 3);
options.showLengthOn = Math.min(40, Math.round(options.maxLength / 3));
}
const {placeholder, maxLength, showLengthOn, name, plainText} = options;

3
src/components/popups/index.ts

@ -36,6 +36,7 @@ export default class PopupElement { @@ -36,6 +36,7 @@ export default class PopupElement {
protected btnClose: HTMLElement;
protected btnConfirm: HTMLElement;
protected body: HTMLElement;
protected buttons: HTMLElement;
protected onClose: () => void;
protected onCloseAfterTimeout: () => void;
@ -91,7 +92,7 @@ export default class PopupElement { @@ -91,7 +92,7 @@ export default class PopupElement {
}
if(buttons && buttons.length) {
const buttonsDiv = document.createElement('div');
const buttonsDiv = this.buttons = document.createElement('div');
buttonsDiv.classList.add('popup-buttons');
if(buttons.length === 2) {

26
src/components/popups/peer.ts

@ -18,15 +18,16 @@ export type PopupPeerOptions = PopupOptions & Partial<{ @@ -18,15 +18,16 @@ export type PopupPeerOptions = PopupOptions & Partial<{
title: string,
titleLangKey?: LangPackKey,
titleLangArgs?: any[],
noTitle?: boolean,
description: string,
descriptionLangKey?: LangPackKey,
descriptionLangArgs?: any[],
buttons: Array<Omit<PopupButton, 'callback'> & Partial<{callback: PopupPeerButtonCallback}>>,
buttons?: Array<Omit<PopupButton, 'callback'> & Partial<{callback: PopupPeerButtonCallback}>>,
checkboxes: Array<PopupPeerCheckboxOptions>
}>;
export default class PopupPeer extends PopupElement {
constructor(private className: string, options: PopupPeerOptions = {}) {
super('popup-peer' + (className ? ' ' + className : ''), addCancelButton(options.buttons), {overlayClosable: true, ...options});
super('popup-peer' + (className ? ' ' + className : ''), options.buttons && addCancelButton(options.buttons), {overlayClosable: true, ...options});
if(options.peerId) {
let avatarEl = new AvatarElement();
@ -36,16 +37,21 @@ export default class PopupPeer extends PopupElement { @@ -36,16 +37,21 @@ export default class PopupPeer extends PopupElement {
this.header.prepend(avatarEl);
}
if(options.titleLangKey || !options.title) this.title.append(i18n(options.titleLangKey || 'AppName', options.titleLangArgs));
else this.title.innerText = options.title || '';
let p = document.createElement('p');
p.classList.add('popup-description');
if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey, options.descriptionLangArgs));
else p.innerHTML = options.description;
if(!options.noTitle) {
if(options.titleLangKey || !options.title) this.title.append(i18n(options.titleLangKey || 'AppName', options.titleLangArgs));
else this.title.innerText = options.title || '';
}
const fragment = document.createDocumentFragment();
fragment.append(p);
if(options.descriptionLangKey || options.description) {
const p = document.createElement('p');
p.classList.add('popup-description');
if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey, options.descriptionLangArgs));
else if(options.description) p.innerHTML = options.description;
fragment.append(p);
}
if(options.checkboxes) {
this.container.classList.add('have-checkbox');

54
src/components/popups/reportMessages.ts

@ -0,0 +1,54 @@ @@ -0,0 +1,54 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import findUpClassName from "../../helpers/dom/findUpClassName";
import whichChild from "../../helpers/dom/whichChild";
import { ReportReason } from "../../layer";
import appStickersManager from "../../lib/appManagers/appStickersManager";
import { LangPackKey } from "../../lib/langPack";
import Button from "../button";
import PopupPeer from "./peer";
import PopupReportMessagesConfirm from "./reportMessagesConfirm";
export default class PopupReportMessages extends PopupPeer {
constructor(peerId: number, mids: number[], onConfirm?: () => void) {
super('popup-report-messages', {titleLangKey: 'ChatTitle.ReportMessages', buttons: [], body: true});
mids = mids.slice();
const buttons: [LangPackKey, ReportReason['_']][] = [
['ReportChatSpam', 'inputReportReasonSpam'],
['ReportChatViolence', 'inputReportReasonViolence'],
['ReportChatChild', 'inputReportReasonChildAbuse'],
['ReportChatPornography', 'inputReportReasonPornography'],
['ReportChatOther', 'inputReportReasonOther']
];
const className = 'btn-primary btn-transparent';
buttons.forEach(b => {
const button = Button(className, {/* icon: 'edit', */text: b[0]});
this.body.append(button);
});
const preloadStickerPromise = appStickersManager.preloadAnimatedEmojiSticker(PopupReportMessagesConfirm.STICKER_EMOJI);
this.body.addEventListener('click', (e) => {
const target = findUpClassName(e.target, 'btn-primary');
const reason = buttons[whichChild(target)][1];
preloadStickerPromise.then(() => {
this.hide();
new PopupReportMessagesConfirm(peerId, mids, reason, onConfirm);
});
});
this.body.style.margin = '0 -1rem';
this.buttons.style.marginTop = '.5rem';
this.show();
}
}

66
src/components/popups/reportMessagesConfirm.ts

@ -0,0 +1,66 @@ @@ -0,0 +1,66 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { ReportReason } from "../../layer";
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
import appStickersManager from "../../lib/appManagers/appStickersManager";
import InputField from "../inputField";
import { toastNew } from "../toast";
import { wrapSticker } from "../wrappers";
import PopupPeer from "./peer";
export default class PopupReportMessagesConfirm extends PopupPeer {
public static STICKER_EMOJI = '👮';
constructor(peerId: number, mids: number[], reason: ReportReason['_'], onConfirm?: () => void) {
super('popup-report-messages-confirm', {
noTitle: true,
descriptionLangKey: 'ReportInfo',
buttons: [{
langKey: 'ReportChat',
callback: () => {
if(!inputField.isValid()) {
return;
}
onConfirm && onConfirm();
appMessagesManager.reportMessages(peerId, mids, reason, inputField.value).then(bool => {
if(!bool) return;
toastNew({
langPackKey: 'ReportSentInfo'
});
});
}
}],
body: true
});
const div = document.createElement('div');
const doc = appStickersManager.getAnimatedEmojiSticker(PopupReportMessagesConfirm.STICKER_EMOJI);
const size = 100;
wrapSticker({
doc,
div,
emoji: PopupReportMessagesConfirm.STICKER_EMOJI,
width: size,
height: size,
loop: false,
play: true
}).finally(() => {
this.show();
});
this.header.append(div);
const inputField = new InputField({
label: 'ReportHint',
maxLength: 512,
placeholder: 'ReportChatDescription'
});
this.body.append(inputField.container);
}
}

12
src/lang.ts

@ -549,6 +549,17 @@ const lang = { @@ -549,6 +549,17 @@ const lang = {
"Create": "Create",
"ViewDiscussion": "View discussion",
"MessageScheduledUntilOnline": "Scheduled until online",
"ReportChat": "Report",
"ReportChatSpam": "Spam",
// "ReportChatFakeAccount": "Fake Account",
"ReportChatViolence": "Violence",
"ReportChatPornography": "Pornography",
"ReportChatChild": "Child Abuse",
"ReportChatOther": "Other",
"ReportChatDescription": "Description",
"ReportInfo": "Please enter any additional details relevant to your report.",
"ReportSentInfo": "Telegram moderators will review your report.\nThank you for your cooperation!",
"ReportHint": "Additional details...",
// * macos
"AccountSettings.Filters": "Chat Folders",
@ -609,6 +620,7 @@ const lang = { @@ -609,6 +620,7 @@ const lang = {
"one_value": "%d Comment",
"other_value": "%d Comments"
},
"ChatTitle.ReportMessages": "Report Messages",
"Chat.Send.WithoutSound": "Send Without Sound",
"Chat.Send.SetReminder": "Set a Reminder",
"Chat.Send.ScheduledMessage": "Schedule Message",

13
src/lib/appManagers/appMessagesManager.ts

@ -17,7 +17,7 @@ import { createPosterForVideo } from "../../helpers/files"; @@ -17,7 +17,7 @@ import { createPosterForVideo } from "../../helpers/files";
import { copy, getObjectKeysAndSort } from "../../helpers/object";
import { randomLong } from "../../helpers/random";
import { splitStringByLength, limitSymbols, escapeRegExp } from "../../helpers/string";
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 } 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 } from "../../layer";
import { InvokeApiOptions } from "../../types";
import I18n, { i18n, join, langPack, LangPackKey, _i18n } from "../langPack";
import { logger, LogTypes } from "../logger";
@ -2866,6 +2866,17 @@ export class AppMessagesManager { @@ -2866,6 +2866,17 @@ export class AppMessagesManager {
}
}
public reportMessages(peerId: number, mids: number[], reason: ReportReason['_'], message?: string) {
return apiManager.invokeApiSingle('messages.report', {
peer: appPeersManager.getInputPeerById(peerId),
id: mids.map(mid => appMessagesIdsManager.getServerMessageId(mid)),
reason: {
_: reason
},
message
});
}
public startBot(botId: number, chatId: number, startParam: string) {
const peerId = chatId ? -chatId : botId;
if(startParam) {

15
src/lib/appManagers/appStickersManager.ts

@ -32,7 +32,7 @@ export class AppStickersManager { @@ -32,7 +32,7 @@ export class AppStickersManager {
private getGreetingStickersPromise: Promise<void>;
constructor() {
this.getStickerSet({id: 'emoji'}, {saveById: true});
this.getAnimatedEmojiStickerSet();
rootScope.addMultipleEventsListeners({
updateNewStickerSet: (update) => {
@ -121,6 +121,10 @@ export class AppStickersManager { @@ -121,6 +121,10 @@ export class AppStickersManager {
});
}
public getAnimatedEmojiStickerSet() {
return this.getStickerSet({id: 'emoji'}, {saveById: true});
}
public async getRecentStickers(): Promise<Modify<MessagesRecentStickers.messagesRecentStickers, {
stickers: Document[]
}>> {
@ -139,6 +143,15 @@ export class AppStickersManager { @@ -139,6 +143,15 @@ export class AppStickersManager {
const pack = stickerSet.packs.find(p => p.emoticon === emoji);
return pack ? appDocsManager.getDoc(pack.documents[0]) : undefined;
}
public preloadAnimatedEmojiSticker(emoji: string) {
return this.getAnimatedEmojiStickerSet().then(() => {
const doc = this.getAnimatedEmojiSticker(emoji);
if(doc) {
return appDocsManager.downloadDoc(doc);
}
});
}
public saveStickerSet(res: Omit<MessagesStickerSet.messagesStickerSet, '_'>, id: string) {
//console.log('stickers save set', res);w

6
src/scss/partials/popups/_instanceDeactivated.scss

@ -1,3 +1,9 @@ @@ -1,3 +1,9 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
.popup-instance-deactivated {
background-color: rgba(0, 0, 0, .6);

6
src/scss/partials/popups/_joinChatInvite.scss

@ -1,3 +1,9 @@ @@ -1,3 +1,9 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
.popup-join-chat-invite {
user-select: none;

28
src/scss/partials/popups/_reportMessages.scss

@ -0,0 +1,28 @@ @@ -0,0 +1,28 @@
.popup-report-messages-confirm {
user-select: none;
.media-sticker-wrapper {
width: 100px;
height: 100px;
position: relative;
margin: 0 auto;
}
.popup-body {
margin: 1em -.5rem .375rem -.5rem;
overflow: unset;
}
.popup-description {
font-size: .875rem;
text-align: center;
}
.popup-buttons {
margin-top: .625rem;
}
.input-field {
width: 100%;
}
}

1
src/scss/style.scss

@ -276,6 +276,7 @@ html.night { @@ -276,6 +276,7 @@ html.night {
@import "partials/popups/forward";
@import "partials/popups/instanceDeactivated";
@import "partials/popups/joinChatInvite";
@import "partials/popups/reportMessages";
@import "partials/pages/pages";
@import "partials/pages/authCode";

Loading…
Cancel
Save