Increment channel post views

Add missing comment translations
This commit is contained in:
morethanwords 2021-08-10 19:52:12 +03:00
parent aff23a0d65
commit e06e987f92
9 changed files with 131 additions and 24 deletions

View File

@ -71,6 +71,8 @@ import whichChild from "../../helpers/dom/whichChild";
import { cancelAnimationByKey } from "../../helpers/animation";
import assumeType from "../../helpers/assumeType";
import { EmoticonsDropdown } from "../emoticonsDropdown";
import debounce from "../../helpers/schedulers/debounce";
import { formatNumber } from "../../helpers/number";
const USE_MEDIA_TAILS = false;
const IGNORE_ACTIONS: Set<Message.messageService['action']['_']> = new Set([
@ -162,6 +164,10 @@ export default class ChatBubbles {
private resolveLadderAnimation: () => Promise<any>;
private emptyPlaceholderMid: number;
private viewsObserver: IntersectionObserver;
private viewsMids: Set<number> = new Set();
private sendViewCountersDebounced: () => Promise<void>;
constructor(private chat: Chat,
private appMessagesManager: AppMessagesManager,
private appStickersManager: AppStickersManager,
@ -580,6 +586,27 @@ export default class ChatBubbles {
}
});
this.listenerSetter.add(rootScope)('message_views', (e) => {
if(this.peerId !== e.peerId) return;
fastRaf(() => {
const bubble = this.bubbles[e.mid];
if(!bubble) return;
const postViewsElements = Array.from(bubble.querySelectorAll('.post-views')) as HTMLElement[];
if(postViewsElements.length) {
const str = formatNumber(e.views, 1);
let different = false;
postViewsElements.forEach(postViews => {
if(different || postViews.innerHTML !== str) {
different = true;
postViews.innerHTML = str;
}
});
}
});
});
this.unreadedObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if(entry.isIntersecting) {
@ -590,6 +617,23 @@ export default class ChatBubbles {
});
});
this.viewsObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if(entry.isIntersecting) {
this.viewsMids.add(+(entry.target as HTMLElement).dataset.mid);
this.viewsObserver.unobserve(entry.target);
this.sendViewCountersDebounced();
}
});
});
this.sendViewCountersDebounced = debounce(() => {
const mids = [...this.viewsMids];
this.viewsMids.clear();
this.appMessagesManager.incrementMessageViews(this.peerId, mids);
}, 1000, false, true);
if('ResizeObserver' in window) {
let wasHeight = this.scrollable.container.offsetHeight;
let resizing = false;
@ -1291,6 +1335,10 @@ export default class ChatBubbles {
this.unreadedObserver.unobserve(bubble);
this.unreaded.delete(bubble);
}
if(this.viewsObserver) {
this.viewsObserver.unobserve(bubble);
this.viewsMids.delete(mid);
}
//this.unreaded.findAndSplice(mid => mid === id);
bubble.remove();
//bubble.remove();
@ -1515,10 +1563,12 @@ export default class ChatBubbles {
this.lazyLoadQueue.clear();
this.unreadedObserver && this.unreadedObserver.disconnect();
this.viewsObserver && this.viewsObserver.disconnect();
this.stickyIntersector && this.stickyIntersector.disconnect();
delete this.lazyLoadQueue;
this.unreadedObserver && delete this.unreadedObserver;
this.viewsObserver && delete this.viewsObserver;
this.stickyIntersector && delete this.stickyIntersector;
}
@ -1569,6 +1619,11 @@ export default class ChatBubbles {
this.unreadedSeen.clear();
this.readPromise = undefined;
}
if(this.viewsObserver) {
this.viewsObserver.disconnect();
this.viewsMids.clear();
}
this.loadedTopTimes = this.loadedBottomTimes = 0;
@ -2012,7 +2067,11 @@ export default class ChatBubbles {
}
}
this.bubbleGroups.addBubble(bubble, message, reverse);
if(message._ === 'message') {
this.bubbleGroups.addBubble(bubble, message, reverse);
} else {
bubble.classList.add('is-group-first', 'is-group-last');
}
}
public getMiddleware() {
@ -2227,6 +2286,10 @@ export default class ChatBubbles {
bubbleContainer.prepend(messageDiv);
//bubble.prepend(timeSpan, messageDiv); // that's bad
if(message.views && !message.pFlags.is_outgoing && this.viewsObserver) {
this.viewsObserver.observe(bubble);
}
if(message.reply_markup && message.reply_markup._ === 'replyInlineMarkup' && message.reply_markup.rows && message.reply_markup.rows.length) {
const rows = (message.reply_markup as ReplyMarkup.replyKeyboardMarkup).rows;
@ -2421,9 +2484,9 @@ export default class ChatBubbles {
case 'messageMediaWebPage': {
processingWebPage = true;
let webpage: WebPage.webPage | WebPage.webPageEmpty = messageMedia.webpage;
let webpage: WebPage = messageMedia.webpage;
////////this.log('messageMediaWebPage', webpage);
if(webpage._ === 'webPageEmpty') {
if(webpage._ !== 'webPage') {
break;
}
@ -2445,10 +2508,8 @@ export default class ChatBubbles {
previewResizer.append(preview);
}
let doc: any = null;
if(webpage.document) {
doc = webpage.document;
const doc = webpage.document as MyDocument;
if(doc) {
if(doc.type === 'gif' || doc.type === 'video') {
//if(doc.size <= 20e6) {
bubble.classList.add('video');

View File

@ -27,7 +27,7 @@ export namespace MessageRender {
const postAuthor = message.post_author || message.fwd_from?.post_author;
bubble.classList.add('channel-post');
time = formatNumber(message.views, 1) + ' <i class="tgico-channelviews time-icon"></i> ' + (postAuthor ? RichTextProcessor.wrapEmojiText(postAuthor) + ', ' : '') + time;
time = '<span class="post-views">' + formatNumber(message.views, 1) + '</span> <i class="tgico-channelviews time-icon"></i> ' + (postAuthor ? RichTextProcessor.wrapEmojiText(postAuthor) + ', ' : '') + time;
if(!message.fwd_from?.saved_from_msg_id && chat.type !== 'pinned') {
const forward = document.createElement('div');

View File

@ -12,6 +12,8 @@ import appPeersManager from "../../lib/appManagers/appPeersManager";
import rootScope from "../../lib/rootScope";
import { ripple } from "../ripple";
import AvatarElement from "../avatar";
import { i18n } from "../../lib/langPack";
import replaceContent from "../../helpers/dom/replaceContent";
const TAG_NAME = 'replies-element';
@ -103,15 +105,15 @@ export default class RepliesElement extends HTMLElement {
this.append(leftPart);
}
let text: string;
let text: HTMLElement;
if(replies) {
if(replies.replies) {
text = replies.replies + ' ' + (replies.replies > 1 ? 'Comments' : 'Comment');
text = i18n('Comments', [replies.replies]);
} else {
text = 'Leave a Comment';
text = i18n('LeaveAComment');
}
} else {
text = 'View in chat';
text = i18n('ViewInChat');
}
if(replies) {
@ -141,7 +143,7 @@ export default class RepliesElement extends HTMLElement {
this.append(textSpan, iconSpan, rippleContainer);
}
textSpan.innerHTML = text;
replaceContent(textSpan, text);
} else {
this.classList.add('bubble-beside-button');
this.innerHTML = `<span class="tgico-commentssticker"></span><span class="replies-beside-text">${replies?.replies ? formatNumber(replies.replies, 0) : ''}</span>`;

View File

@ -183,6 +183,7 @@ const lang = {
"ChannelMegaJoined": "You joined this group",
"Channel.DescriptionPlaceholder": "Description (optional)",
"DescriptionPlaceholder": "Description",
"DiscussionStarted": "Discussion started",
"Draft": "Draft",
"FilterAlwaysShow": "Include Chats",
"FilterNeverShow": "Exclude Chats",
@ -211,6 +212,10 @@ const lang = {
"one_value": "%1$d channel",
"other_value": "%1$d channels"
},
"Comments": {
"one_value": "%1$d Comment",
"other_value": "%1$d Comments"
},
"Groups": {
"one_value": "%1$d group",
"other_value": "%1$d groups"
@ -544,6 +549,8 @@ const lang = {
"Send": "Send",
"ChannelJoin": "JOIN",
"Yesterday": "yesterday",
"LeaveAComment": "Leave a comment",
"ViewInChat": "View in chat",
// * macos
"AccountSettings.Filters": "Chat Folders",

7
src/layer.d.ts vendored
View File

@ -996,7 +996,7 @@ export namespace MessageMedia {
/**
* @link https://core.telegram.org/type/MessageAction
*/
export type MessageAction = MessageAction.messageActionEmpty | MessageAction.messageActionChatCreate | MessageAction.messageActionChatEditTitle | MessageAction.messageActionChatEditPhoto | MessageAction.messageActionChatDeletePhoto | MessageAction.messageActionChatAddUser | MessageAction.messageActionChatDeleteUser | MessageAction.messageActionChatJoinedByLink | MessageAction.messageActionChannelCreate | MessageAction.messageActionChatMigrateTo | MessageAction.messageActionChannelMigrateFrom | MessageAction.messageActionPinMessage | MessageAction.messageActionHistoryClear | MessageAction.messageActionGameScore | MessageAction.messageActionPaymentSentMe | MessageAction.messageActionPaymentSent | MessageAction.messageActionPhoneCall | MessageAction.messageActionScreenshotTaken | MessageAction.messageActionCustomAction | MessageAction.messageActionBotAllowed | MessageAction.messageActionSecureValuesSentMe | MessageAction.messageActionSecureValuesSent | MessageAction.messageActionContactSignUp | MessageAction.messageActionGeoProximityReached | MessageAction.messageActionGroupCall | MessageAction.messageActionInviteToGroupCall | MessageAction.messageActionSetMessagesTTL | MessageAction.messageActionGroupCallScheduled | MessageAction.messageActionChatLeave | MessageAction.messageActionChannelDeletePhoto | MessageAction.messageActionChannelEditTitle | MessageAction.messageActionChannelEditPhoto | MessageAction.messageActionChannelEditVideo | MessageAction.messageActionChatEditVideo | MessageAction.messageActionChatAddUsers | MessageAction.messageActionChatJoined | MessageAction.messageActionChatReturn | MessageAction.messageActionChatJoinedYou | MessageAction.messageActionChatReturnYou;
export type MessageAction = MessageAction.messageActionEmpty | MessageAction.messageActionChatCreate | MessageAction.messageActionChatEditTitle | MessageAction.messageActionChatEditPhoto | MessageAction.messageActionChatDeletePhoto | MessageAction.messageActionChatAddUser | MessageAction.messageActionChatDeleteUser | MessageAction.messageActionChatJoinedByLink | MessageAction.messageActionChannelCreate | MessageAction.messageActionChatMigrateTo | MessageAction.messageActionChannelMigrateFrom | MessageAction.messageActionPinMessage | MessageAction.messageActionHistoryClear | MessageAction.messageActionGameScore | MessageAction.messageActionPaymentSentMe | MessageAction.messageActionPaymentSent | MessageAction.messageActionPhoneCall | MessageAction.messageActionScreenshotTaken | MessageAction.messageActionCustomAction | MessageAction.messageActionBotAllowed | MessageAction.messageActionSecureValuesSentMe | MessageAction.messageActionSecureValuesSent | MessageAction.messageActionContactSignUp | MessageAction.messageActionGeoProximityReached | MessageAction.messageActionGroupCall | MessageAction.messageActionInviteToGroupCall | MessageAction.messageActionSetMessagesTTL | MessageAction.messageActionGroupCallScheduled | MessageAction.messageActionDiscussionStarted | MessageAction.messageActionChatLeave | MessageAction.messageActionChannelDeletePhoto | MessageAction.messageActionChannelEditTitle | MessageAction.messageActionChannelEditPhoto | MessageAction.messageActionChannelEditVideo | MessageAction.messageActionChatEditVideo | MessageAction.messageActionChatAddUsers | MessageAction.messageActionChatJoined | MessageAction.messageActionChatReturn | MessageAction.messageActionChatJoinedYou | MessageAction.messageActionChatReturnYou;
export namespace MessageAction {
export type messageActionEmpty = {
@ -1156,6 +1156,10 @@ export namespace MessageAction {
schedule_date: number
};
export type messageActionDiscussionStarted = {
_: 'messageActionDiscussionStarted'
};
export type messageActionChatLeave = {
_: 'messageActionChatLeave',
user_id?: number
@ -9822,6 +9826,7 @@ export interface ConstructorDeclMap {
'messageEntityHighlight': MessageEntity.messageEntityHighlight,
'messageEntityLinebreak': MessageEntity.messageEntityLinebreak,
'messageEntityCaret': MessageEntity.messageEntityCaret,
'messageActionDiscussionStarted': MessageAction.messageActionDiscussionStarted,
'messageActionChatLeave': MessageAction.messageActionChatLeave,
'messageActionChannelDeletePhoto': MessageAction.messageActionChannelDeletePhoto,
'messageActionChannelEditTitle': MessageAction.messageActionChannelEditTitle,

View File

@ -120,9 +120,6 @@ type PendingAfterMsg = Partial<InvokeApiOptions & {
}>;
export class AppMessagesManager {
private static MESSAGE_ID_INCREMENT = 0x10000;
private static MESSAGE_ID_OFFSET = 0xFFFFFFFF;
private messagesStorageByPeerId: {[peerId: string]: MessagesStorage};
public groupedMessagesStorage: {[groupId: string]: MessagesStorage}; // will be used for albums
private scheduledMessagesStorage: {[peerId: string]: MessagesStorage};
@ -3463,8 +3460,7 @@ export class AppMessagesManager {
from_id: {_: 'peerUser', user_id: 0}/* message.from_id */,
peer_id: message.peer_id,
action: {
_: 'messageActionCustomAction',
message: 'Discussion started'
_: 'messageActionDiscussionStarted'
},
reply_to: this.generateReplyHeader(message.id)
};
@ -4280,12 +4276,12 @@ export class AppMessagesManager {
private onUpdateChannelMessageViews = (update: Update.updateChannelMessageViews) => {
const views = update.views;
//const mid = update.id;
const peerId = -update.channel_id;
const mid = appMessagesIdsManager.generateMessageId(update.id);
const message = this.getMessageByPeer(-update.channel_id, mid);
const message: Message.message = this.getMessageByPeer(peerId, mid);
if(!message.deleted && message.views && message.views < views) {
message.views = views;
rootScope.dispatchEvent('message_views', {mid, views});
rootScope.dispatchEvent('message_views', {peerId, mid, views});
}
};
@ -4627,6 +4623,36 @@ export class AppMessagesManager {
});
}
public incrementMessageViews(peerId: number, mids: number[]) {
if(!mids.length) {
return;
}
return apiManager.invokeApiSingle('messages.getMessagesViews', {
peer: appPeersManager.getInputPeerById(peerId),
id: mids.map(mid => appMessagesIdsManager.getServerMessageId(mid)),
increment: true
}).then(views => {
const updates: Update[] = new Array(mids.length);
const channelId = -peerId;
for(let i = 0, length = mids.length; i < length; ++i) {
updates[i] = {
_: 'updateChannelMessageViews',
channel_id: channelId,
id: mids[i],
views: views.views[i].views
};
}
apiUpdatesManager.processUpdateMessage({
_: 'updates',
updates,
chats: views.chats,
users: views.users
});
});
}
private notifyAboutMessage(message: MyMessage, options: Partial<{
fwdCount: number,
peerTypeNotifySettings: PeerNotifySettings

View File

@ -41,6 +41,7 @@ export const langPack: {[actionType: string]: LangPackKey} = {
"messageActionChannelEditVideo": "Chat.Service.Channel.UpdatedVideo",
"messageActionChannelDeletePhoto": "Chat.Service.Channel.RemovedPhoto",
"messageActionHistoryClear": "HistoryCleared",
"messageActionDiscussionStarted": "DiscussionStarted",
"messageActionChannelMigrateFrom": "ActionMigrateFromGroup",

View File

@ -57,7 +57,7 @@ export type BroadcastEvents = {
//'history_request': void,
'message_edit': {storage: MessagesStorage, peerId: number, mid: number},
'message_views': {mid: number, views: number},
'message_views': {peerId: number, mid: number, views: number},
'message_sent': {storage: MessagesStorage, tempId: number, tempMessage: any, mid: number},
'messages_pending': void,
'messages_read': void,

View File

@ -56,7 +56,8 @@
{"name": "clear_history", "type": "boolean"},
{"name": "pending", "type": "boolean"},
{"name": "error", "type": "any"},
{"name": "send", "type": "() => Promise<any>"}
{"name": "send", "type": "() => Promise<any>"},
{"name": "totalEntities", "type": "MessageEntity[]"}
]
}, {
"predicate": "messageService",
@ -152,6 +153,10 @@
"params": [
{"name": "initials", "type": "string"}
]
}, {
"predicate": "messageActionDiscussionStarted",
"params": [],
"type": "MessageAction"
}, {
"predicate": "messageActionChatLeave",
"params": [