Browse Source

Increment channel post views

Add missing comment translations
master
morethanwords 3 years ago
parent
commit
552611ce6c
  1. 75
      src/components/chat/bubbles.ts
  2. 2
      src/components/chat/messageRender.ts
  3. 12
      src/components/chat/replies.ts
  4. 7
      src/lang.ts
  5. 7
      src/layer.d.ts
  6. 42
      src/lib/appManagers/appMessagesManager.ts
  7. 1
      src/lib/langPack.ts
  8. 2
      src/lib/rootScope.ts
  9. 7
      src/scripts/in/schema_additional_params.json

75
src/components/chat/bubbles.ts

@ -71,6 +71,8 @@ import whichChild from "../../helpers/dom/whichChild";
import { cancelAnimationByKey } from "../../helpers/animation"; import { cancelAnimationByKey } from "../../helpers/animation";
import assumeType from "../../helpers/assumeType"; import assumeType from "../../helpers/assumeType";
import { EmoticonsDropdown } from "../emoticonsDropdown"; import { EmoticonsDropdown } from "../emoticonsDropdown";
import debounce from "../../helpers/schedulers/debounce";
import { formatNumber } from "../../helpers/number";
const USE_MEDIA_TAILS = false; const USE_MEDIA_TAILS = false;
const IGNORE_ACTIONS: Set<Message.messageService['action']['_']> = new Set([ const IGNORE_ACTIONS: Set<Message.messageService['action']['_']> = new Set([
@ -162,6 +164,10 @@ export default class ChatBubbles {
private resolveLadderAnimation: () => Promise<any>; private resolveLadderAnimation: () => Promise<any>;
private emptyPlaceholderMid: number; private emptyPlaceholderMid: number;
private viewsObserver: IntersectionObserver;
private viewsMids: Set<number> = new Set();
private sendViewCountersDebounced: () => Promise<void>;
constructor(private chat: Chat, constructor(private chat: Chat,
private appMessagesManager: AppMessagesManager, private appMessagesManager: AppMessagesManager,
private appStickersManager: AppStickersManager, 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) => { this.unreadedObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => { entries.forEach(entry => {
if(entry.isIntersecting) { 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) { if('ResizeObserver' in window) {
let wasHeight = this.scrollable.container.offsetHeight; let wasHeight = this.scrollable.container.offsetHeight;
let resizing = false; let resizing = false;
@ -1291,6 +1335,10 @@ export default class ChatBubbles {
this.unreadedObserver.unobserve(bubble); this.unreadedObserver.unobserve(bubble);
this.unreaded.delete(bubble); this.unreaded.delete(bubble);
} }
if(this.viewsObserver) {
this.viewsObserver.unobserve(bubble);
this.viewsMids.delete(mid);
}
//this.unreaded.findAndSplice(mid => mid === id); //this.unreaded.findAndSplice(mid => mid === id);
bubble.remove(); bubble.remove();
//bubble.remove(); //bubble.remove();
@ -1515,10 +1563,12 @@ export default class ChatBubbles {
this.lazyLoadQueue.clear(); this.lazyLoadQueue.clear();
this.unreadedObserver && this.unreadedObserver.disconnect(); this.unreadedObserver && this.unreadedObserver.disconnect();
this.viewsObserver && this.viewsObserver.disconnect();
this.stickyIntersector && this.stickyIntersector.disconnect(); this.stickyIntersector && this.stickyIntersector.disconnect();
delete this.lazyLoadQueue; delete this.lazyLoadQueue;
this.unreadedObserver && delete this.unreadedObserver; this.unreadedObserver && delete this.unreadedObserver;
this.viewsObserver && delete this.viewsObserver;
this.stickyIntersector && delete this.stickyIntersector; this.stickyIntersector && delete this.stickyIntersector;
} }
@ -1569,6 +1619,11 @@ export default class ChatBubbles {
this.unreadedSeen.clear(); this.unreadedSeen.clear();
this.readPromise = undefined; this.readPromise = undefined;
} }
if(this.viewsObserver) {
this.viewsObserver.disconnect();
this.viewsMids.clear();
}
this.loadedTopTimes = this.loadedBottomTimes = 0; 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() { public getMiddleware() {
@ -2227,6 +2286,10 @@ export default class ChatBubbles {
bubbleContainer.prepend(messageDiv); bubbleContainer.prepend(messageDiv);
//bubble.prepend(timeSpan, messageDiv); // that's bad //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) { 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; const rows = (message.reply_markup as ReplyMarkup.replyKeyboardMarkup).rows;
@ -2421,9 +2484,9 @@ export default class ChatBubbles {
case 'messageMediaWebPage': { case 'messageMediaWebPage': {
processingWebPage = true; processingWebPage = true;
let webpage: WebPage.webPage | WebPage.webPageEmpty = messageMedia.webpage; let webpage: WebPage = messageMedia.webpage;
////////this.log('messageMediaWebPage', webpage); ////////this.log('messageMediaWebPage', webpage);
if(webpage._ === 'webPageEmpty') { if(webpage._ !== 'webPage') {
break; break;
} }
@ -2445,10 +2508,8 @@ export default class ChatBubbles {
previewResizer.append(preview); previewResizer.append(preview);
} }
let doc: any = null; const doc = webpage.document as MyDocument;
if(webpage.document) { if(doc) {
doc = webpage.document;
if(doc.type === 'gif' || doc.type === 'video') { if(doc.type === 'gif' || doc.type === 'video') {
//if(doc.size <= 20e6) { //if(doc.size <= 20e6) {
bubble.classList.add('video'); bubble.classList.add('video');

2
src/components/chat/messageRender.ts

@ -27,7 +27,7 @@ export namespace MessageRender {
const postAuthor = message.post_author || message.fwd_from?.post_author; const postAuthor = message.post_author || message.fwd_from?.post_author;
bubble.classList.add('channel-post'); 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') { if(!message.fwd_from?.saved_from_msg_id && chat.type !== 'pinned') {
const forward = document.createElement('div'); const forward = document.createElement('div');

12
src/components/chat/replies.ts

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

7
src/lang.ts

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

7
src/layer.d.ts vendored

@ -996,7 +996,7 @@ export namespace MessageMedia {
/** /**
* @link https://core.telegram.org/type/MessageAction * @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 namespace MessageAction {
export type messageActionEmpty = { export type messageActionEmpty = {
@ -1156,6 +1156,10 @@ export namespace MessageAction {
schedule_date: number schedule_date: number
}; };
export type messageActionDiscussionStarted = {
_: 'messageActionDiscussionStarted'
};
export type messageActionChatLeave = { export type messageActionChatLeave = {
_: 'messageActionChatLeave', _: 'messageActionChatLeave',
user_id?: number user_id?: number
@ -9822,6 +9826,7 @@ export interface ConstructorDeclMap {
'messageEntityHighlight': MessageEntity.messageEntityHighlight, 'messageEntityHighlight': MessageEntity.messageEntityHighlight,
'messageEntityLinebreak': MessageEntity.messageEntityLinebreak, 'messageEntityLinebreak': MessageEntity.messageEntityLinebreak,
'messageEntityCaret': MessageEntity.messageEntityCaret, 'messageEntityCaret': MessageEntity.messageEntityCaret,
'messageActionDiscussionStarted': MessageAction.messageActionDiscussionStarted,
'messageActionChatLeave': MessageAction.messageActionChatLeave, 'messageActionChatLeave': MessageAction.messageActionChatLeave,
'messageActionChannelDeletePhoto': MessageAction.messageActionChannelDeletePhoto, 'messageActionChannelDeletePhoto': MessageAction.messageActionChannelDeletePhoto,
'messageActionChannelEditTitle': MessageAction.messageActionChannelEditTitle, 'messageActionChannelEditTitle': MessageAction.messageActionChannelEditTitle,

42
src/lib/appManagers/appMessagesManager.ts

@ -120,9 +120,6 @@ type PendingAfterMsg = Partial<InvokeApiOptions & {
}>; }>;
export class AppMessagesManager { export class AppMessagesManager {
private static MESSAGE_ID_INCREMENT = 0x10000;
private static MESSAGE_ID_OFFSET = 0xFFFFFFFF;
private messagesStorageByPeerId: {[peerId: string]: MessagesStorage}; private messagesStorageByPeerId: {[peerId: string]: MessagesStorage};
public groupedMessagesStorage: {[groupId: string]: MessagesStorage}; // will be used for albums public groupedMessagesStorage: {[groupId: string]: MessagesStorage}; // will be used for albums
private scheduledMessagesStorage: {[peerId: string]: MessagesStorage}; private scheduledMessagesStorage: {[peerId: string]: MessagesStorage};
@ -3463,8 +3460,7 @@ export class AppMessagesManager {
from_id: {_: 'peerUser', user_id: 0}/* message.from_id */, from_id: {_: 'peerUser', user_id: 0}/* message.from_id */,
peer_id: message.peer_id, peer_id: message.peer_id,
action: { action: {
_: 'messageActionCustomAction', _: 'messageActionDiscussionStarted'
message: 'Discussion started'
}, },
reply_to: this.generateReplyHeader(message.id) reply_to: this.generateReplyHeader(message.id)
}; };
@ -4280,12 +4276,12 @@ export class AppMessagesManager {
private onUpdateChannelMessageViews = (update: Update.updateChannelMessageViews) => { private onUpdateChannelMessageViews = (update: Update.updateChannelMessageViews) => {
const views = update.views; const views = update.views;
//const mid = update.id; const peerId = -update.channel_id;
const mid = appMessagesIdsManager.generateMessageId(update.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) { if(!message.deleted && message.views && message.views < 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<{ private notifyAboutMessage(message: MyMessage, options: Partial<{
fwdCount: number, fwdCount: number,
peerTypeNotifySettings: PeerNotifySettings peerTypeNotifySettings: PeerNotifySettings

1
src/lib/langPack.ts

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

2
src/lib/rootScope.ts

@ -57,7 +57,7 @@ export type BroadcastEvents = {
//'history_request': void, //'history_request': void,
'message_edit': {storage: MessagesStorage, peerId: number, mid: number}, '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}, 'message_sent': {storage: MessagesStorage, tempId: number, tempMessage: any, mid: number},
'messages_pending': void, 'messages_pending': void,
'messages_read': void, 'messages_read': void,

7
src/scripts/in/schema_additional_params.json

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

Loading…
Cancel
Save