import { RichTextProcessor } from "../richtextprocessor"; import appMessagesManager from './appMessagesManager'; import appPeersManager from './appPeersManager'; import apiManager from "../mtproto/mtprotoworker"; import apiUpdatesManager from "./apiUpdatesManager"; import { $rootScope } from "../utils"; import { logger, LogLevels } from "../logger"; import appUsersManager, { User } from "./appUsersManager"; export type PollAnswer = { _: 'pollAnswer', text: string, option: Uint8Array }; export type PollAnswerVoters = { _: 'pollAnswerVoters', flags: number, option: Uint8Array, voters: number, pFlags: Partial<{ chosen: true, correct: true }> }; export type PollResult = { _: 'pollAnswerVoters', flags: number, option: Uint8Array, voters: number, pFlags?: Partial<{chosen: true, correct: true}> }; export type PollResults = { _: 'pollResults', flags: number, results?: Array, total_voters?: number, recent_voters?: number[], solution?: string, solution_entities?: any[], pFlags: Partial<{ min: true }>, }; export type Poll = { _: 'poll', flags: number, question: string, id: string, answers: Array, close_period?: number, close_date?: number pFlags?: Partial<{ closed: true, public_voters: true, multiple_choice: true, quiz: true }>, rQuestion?: string, rReply?: string, chosenIndexes?: number[] }; class AppPollsManager { public polls: {[id: string]: Poll} = {}; public results: {[id: string]: PollResults} = {}; private log = logger('POLLS', LogLevels.error); constructor() { $rootScope.$on('apiUpdate', (e: CustomEvent) => { let update = e.detail; this.handleUpdate(update); }); } public handleUpdate(update: any) { switch(update._) { case 'updateMessagePoll': { // when someone voted, we too this.log('updateMessagePoll:', update); let poll: Poll = /* this.polls[update.poll_id] || */update.poll; if(!poll) { break; } poll = this.savePoll(poll, update.results); $rootScope.$broadcast('poll_update', {poll, results: update.results}); break; } default: break; } } public savePoll(poll: Poll, results: PollResults) { const id = poll.id; if(this.polls[id]) { poll = Object.assign(this.polls[id], poll); this.saveResults(poll, results); return poll; } this.polls[id] = poll; poll.rQuestion = RichTextProcessor.wrapEmojiText(poll.question); poll.rReply = RichTextProcessor.wrapEmojiText('📊') + ' ' + (poll.rQuestion || 'poll'); poll.chosenIndexes = []; this.saveResults(poll, results); return poll; } public saveResults(poll: Poll, results: PollResults) { this.results[poll.id] = results; poll.chosenIndexes.length = 0; if(results?.results?.length) { results.results.forEach((answer, idx) => { if(answer.pFlags?.chosen) { poll.chosenIndexes.push(idx); } }); } } public getPoll(pollID: string): {poll: Poll, results: PollResults} { return { poll: this.polls[pollID], results: this.results[pollID] }; } public sendVote(mid: number, optionIDs: number[]) { const message = appMessagesManager.getMessage(mid); const poll: Poll = message.media.poll; const options: Uint8Array[] = optionIDs.map(index => { return poll.answers[index].option; }); const inputPeer = appPeersManager.getInputPeerByID(message.peerID); const messageID = message.id; return apiManager.invokeApi('messages.sendVote', { peer: inputPeer, msg_id: messageID, options }).then(updates => { this.log('sendVote updates:', updates); apiUpdatesManager.processUpdateMessage(updates); }); } public getResults(mid: number) { const message = appMessagesManager.getMessage(mid); const inputPeer = appPeersManager.getInputPeerByID(message.peerID); const messageID = message.id; return apiManager.invokeApi('messages.getPollResults', { peer: inputPeer, msg_id: messageID }).then(updates => { apiUpdatesManager.processUpdateMessage(updates); this.log('getResults updates:', updates); }); } public getVotes(mid: number, option?: Uint8Array, offset?: string, limit = 20) { const message = appMessagesManager.getMessage(mid); const inputPeer = appPeersManager.getInputPeerByID(message.peerID); const messageID = message.id; let flags = 0; if(option) { flags |= 1 << 0; } if(offset) { flags |= 1 << 1; } return apiManager.invokeApi('messages.getPollVotes', { flags, peer: inputPeer, id: messageID, option, offset, limit }).then((votesList: { _: 'messages.votesList', flags: number, count: number, next_offset: string, pFlags: {}, users: User[], votes: { _: 'messageUserVoteInputOption', date: number, user_id: number }[] }) => { this.log('getPollVotes messages:', votesList); appUsersManager.saveApiUsers(votesList.users); return votesList; }); } } const appPollsManager = new AppPollsManager(); // @ts-ignore if(process.env.NODE_ENV != 'production') { (window as any).appPollsManager = appPollsManager; } export default appPollsManager;