Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/polls #78

Merged
merged 38 commits into from
May 31, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
268c0e7
wip: Initial support for polls
misupov May 6, 2020
a5e9b5d
wip: Polls
misupov May 6, 2020
d05a081
mtproto updated
misupov May 7, 2020
bed9ad2
mtproto updated
misupov May 7, 2020
0ca1390
Merge commit 'a572699d0801147895a965e0bbb341742129c3af' into feature/…
misupov May 7, 2020
245c885
Minor refactoring
misupov May 7, 2020
526ba91
Merge commit '58a5a5e65292da2b89ce5c2e1b4916fd74419877' into feature/…
misupov May 7, 2020
8c86b37
Votes in polls
misupov May 8, 2020
e9b1230
Quiz colors
misupov May 8, 2020
f60755d
minor fixes
misupov May 8, 2020
21a4b4e
Merge branch 'dev' into feature/polls
misupov May 8, 2020
ed5992d
Update mtproto
misupov May 8, 2020
063e317
Storybook for polls
misupov May 8, 2020
77d9c3f
Update message cache on poll updates
misupov May 10, 2020
2f94120
Merge commit '0db45c474c6a45bba236e877c591cb70d75560da' into feature/…
misupov May 10, 2020
f2f6b2b
Poll message cache refactored
misupov May 10, 2020
b763593
Merge commit 'c0e82b59c49931b21aed56b020f1cecd48cd7cd0' into feature/…
misupov May 10, 2020
c26858b
Display recent voters avatars
misupov May 10, 2020
2f384cf
fix
misupov May 10, 2020
7f0aef5
Added multi-choice support
misupov May 10, 2020
cbb5e15
Minor improvements
misupov May 10, 2020
73078ea
Minor fixes
misupov May 10, 2020
68b6d74
Files renamed
misupov May 11, 2020
abba977
Poll results popup
misupov May 11, 2020
80407aa
Merge commit 'b92c0329f620b2745759863558315e72e1817990' into feature/…
misupov May 11, 2020
e5d87c1
Merge commit '1dceff9c6a2b70907709ca04bd09c4e1d88c0aa8' into feature/…
misupov May 12, 2020
6f65014
wip
misupov May 15, 2020
55af643
wip
misupov May 16, 2020
0a7cece
wip
misupov May 23, 2020
1938db0
Merge commit '870c846b754d048031bced659091443fa864f25c' into feature/…
misupov May 23, 2020
b9b4aef
wip
misupov May 24, 2020
21fd544
Merge branch 'dev' into feature/polls
misupov May 25, 2020
2266d8e
Merge branch 'bugfix/proper-thumb-when-image-zooms-in' into feature/p…
misupov May 26, 2020
fe001d6
Merge branch 'dev' into feature/polls
misupov May 26, 2020
2e4536a
Merge branch 'dev' into feature/polls
misupov May 26, 2020
cd10c56
Review fixes
misupov May 30, 2020
904bd47
Review fixes
misupov May 30, 2020
297485a
Style fix
misupov May 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 83 additions & 0 deletions src/cache/fastStorages/indices/pollsIndex.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Message, PollResults, Update } from 'mtproto-js';
import Collection from '../collection';

const decoder = new TextDecoder();

export default function pollsIndex(collection: Collection<Message, any, string>) {
const pollMessageIds = new Map<string, Set<string>>();
collection.changes.subscribe((collectionChanges) => {
collectionChanges.forEach(([action, item, key]) => {
if (item._ !== 'message' || item.media?._ !== 'messageMediaPoll') {
return;
}
switch (action) {
case 'add': {
let messageIds = pollMessageIds.get(item.media.poll.id);
if (!messageIds) {
pollMessageIds.set(item.media.poll.id, messageIds = new Set());
}
messageIds.add(key);
break;
}
case 'remove': {
const messageIds = pollMessageIds.get(item.media.poll.id);
if (messageIds) {
messageIds.delete(key);
if (messageIds.size === 0) {
pollMessageIds.delete(item.media.poll.id);
}
}
break;
}
default:
}
},
);
});

const applyMinPollResults = (prevPollResults: PollResults, newPollResults: PollResults) => {
if (!newPollResults.min) {
return newPollResults;
}
const pollResults: PollResults = { ...prevPollResults, ...newPollResults };
if (prevPollResults.results && newPollResults.results) {
const results = pollResults.results = newPollResults.results.map((r) => ({ ...r }));
const prevResultOptions = new Map(prevPollResults.results.map((r) => [decoder.decode(r.option), r]));
for (let index = 0; index < results.length; index++) {
const result = results[index];
const prevResults = prevResultOptions.get(decoder.decode(result.option));
if (prevResults) {
result.correct = prevResults.correct;
result.chosen = prevResults.chosen;
}
}
}
return pollResults;
};

return {
updatePoll(update: Update.updateMessagePoll) {
const messageIds = pollMessageIds.get(update.poll_id);
if (messageIds) {
messageIds.forEach((messageId) => {
const message = collection.get(messageId);
if (message?._ === 'message' && message.media?._ === 'messageMediaPoll') {
const updatedResults = applyMinPollResults(message.media.results, update.results);
const updatedMedia = {
...message.media,
results: updatedResults,
};
if (update.poll) {
updatedMedia.poll = update.poll;
}
const updatedMessage = {
...message,
media: updatedMedia,
};
collection.change(messageId, updatedMessage);
spalt08 marked this conversation as resolved.
Show resolved Hide resolved
}
});
}
},
};
}
2 changes: 2 additions & 0 deletions src/cache/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import Collection, { GetId, makeGetIdFromProp } from './fastStorages/collection'
import { orderBy } from './fastStorages/indices';
import messageHistory from './fastStorages/indices/messageHistory';
import sharedMediaIndex from './fastStorages/indices/sharedMediaIndex';
import pollsIndex from './fastStorages/indices/pollsIndex';

// todo: Save the main part of the cache to a persistent storage

Expand Down Expand Up @@ -53,6 +54,7 @@ export const messageCache = new Collection({
photoVideos: sharedMediaIndex,
documents: sharedMediaIndex,
links: sharedMediaIndex,
polls: pollsIndex,
},
});

Expand Down
51 changes: 50 additions & 1 deletion src/client/workers/mocks/call.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* eslint-disable no-param-reassign */
import { MethodDeclMap } from 'mtproto-js';
import { MethodDeclMap, PollResults, PollAnswerVoters, MessageEntity } from 'mtproto-js';
import { users } from './user';
import { chats } from './chat';
import { mockDialogForPeers } from './dialog';
Expand Down Expand Up @@ -66,6 +66,55 @@ export function callMock<T extends keyof MethodDeclMap>(method: T, params: Metho
});
break;

case 'messages.sendVote': {
const { options } = params as MethodDeclMap['messages.sendVote']['req'];
const selectedOption = new Uint8Array(options[0])[0];
const pollAnswerVoters1 = Math.round(Math.random() * 100);
const pollAnswerVoters2 = Math.round(Math.random() * 100);
const pollAnswerVoters3 = Math.round(Math.random() * 100);
const result = {
_: 'updates',
updates: [
{
_: 'updateMessagePoll',
poll_id: '1',
results: {
_: 'pollResults',
results: [
{
_: 'pollAnswerVoters',
chosen: selectedOption === 0,
correct: false,
option: new Int8Array([0]).buffer,
voters: pollAnswerVoters1,
},
{
_: 'pollAnswerVoters',
chosen: selectedOption === 1,
correct: true,
option: new Int8Array([1]).buffer,
voters: pollAnswerVoters2,
},
{
_: 'pollAnswerVoters',
chosen: selectedOption === 2,
correct: false,
option: new Int8Array([2]).buffer,
voters: pollAnswerVoters3,
},
] as PollAnswerVoters[],
total_voters: pollAnswerVoters1 + pollAnswerVoters2 + pollAnswerVoters3,
recent_voters: [],
solution: 'string',
solution_entities: [] as MessageEntity[],
} as PollResults,
},
],
};
timeout<T>(1000, cb, result);
break;
}

case 'messages.search': {
const { peer, filter, limit, offset_id } = params as MethodDeclMap['messages.search']['req'];
const { count, messages } = mockHistorySearch(limit, offset_id, filter, peer);
Expand Down
2 changes: 2 additions & 0 deletions src/client/workers/mocks/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export function mockMessage({
grouped_id = '',
restriction_reason = [],
date = 0,
media = undefined,
}: Partial<Message.message> & { from_id: number, to_id: Peer }): Message.message {
return {
_: 'message',
Expand All @@ -61,5 +62,6 @@ export function mockMessage({
post_author,
grouped_id,
restriction_reason,
media,
};
}
31 changes: 30 additions & 1 deletion src/client/workers/mocks/storybook.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BehaviorSubject } from 'rxjs';
import type { Photo } from 'mtproto-js';
import { Photo } from 'mtproto-js';
import { task } from 'client/context';
import { getPhotoLocation } from 'helpers/photo';
import { locationToURL } from 'helpers/files';
Expand Down Expand Up @@ -51,3 +51,32 @@ export const MessageRegular = mockMessage({
from_id: users[1].id,
to_id: { _: 'peerUser', user_id: me.id },
});

export const MessagePoll = mockMessage({
from_id: users[1].id,
to_id: { _: 'peerUser', user_id: me.id },
media: {
_: 'messageMediaPoll',
poll: {
_: 'poll' as const,
id: '1',
question: 'Question',
answers: [
{
_: 'pollAnswer',
text: 'Option 1',
option: new ArrayBuffer(1),
},
{
_: 'pollAnswer',
text: 'Option 2',
option: new ArrayBuffer(1),
},
],

},
results: {
_: 'pollResults',
},
},
});
14 changes: 7 additions & 7 deletions src/components/media/document/file.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Document, Message } from 'mtproto-js';
import { cached as getCached, file } from 'client/media';
import { materialSpinner } from 'components/icons';
import { datetime } from 'components/ui';
import { listen, mount, unmountChildren } from 'core/dom';
import { div, text } from 'core/html';
import { getAttributeFilename, getReadableSize, getDocumentLocation } from 'helpers/files';
import { getAttributeFilename, getDocumentLocation, getReadableSize } from 'helpers/files';
import { downloadByUrl } from 'helpers/other';
import { datetime } from 'components/ui';
import { listen, mount, unmountChildren, unmount } from 'core/dom';
import { materialSpinner, down } from 'components/icons';
import { download, cached as getCached, file } from 'client/media';
import { Document, Message } from 'mtproto-js';
import photoRenderer from '../photo/photo';
import './file.scss';

Expand Down Expand Up @@ -64,7 +64,7 @@ export default function documentFile(document: Document.document, message?: Mess
sizeEl.textContent = '0%';

downloadByUrl(filename, file(getDocumentLocation(document, ''), { dc_id: document.dc_id, size: document.size, mime_type: document.mime_type }));

// download(
// getDocumentLocation(document, ''),
// { dc_id: document.dc_id, size: document.size, mime_type: document.mime_type },
Expand Down
78 changes: 78 additions & 0 deletions src/components/media/poll/poll.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
.poll {
user-select: none;
font-size: 1rem;

&__body {
padding: 7PX 10PX 0 10PX;
}

&__footer {
display: grid;

>* {
grid-row: 1;
grid-column: 1;
}
}

&__message-info {
justify-self: end;
align-self: end;
margin: 0 10PX 1PX 0 !important;
}

&__question {
font-weight: 500;
}

&__info {
display: flex;
align-items: center;
}

&__type {
color: var(--accent-color-inactive);
font-size: 0.9rem;
}

&__recent-voters {
padding-left: 8px;
display: flex;
flex-direction: row-reverse;
}

& &__avatar-wrapper {
position: relative;
width: 13px;
height: 18px;

.avatar {
position: absolute;
width: 18px;
height: 18px;
min-width: 18px;
min-height: 18px;
border: 1px solid var(--bubble-background);
--initials-font-size: 0.6rem;
}
}

&__voters {
color: var(--accent-color-inactive);
font-size: 0.9rem;
padding: 10px 0 4px 10px;
}

&__vote-button {
margin: 8PX 0;
text-align: center;
color: var(--accent-color);
transition: color 0.3s;
cursor: pointer;
}

&__vote-button.-inactive {
color: var(--accent-color-inactive);
cursor: default;
}
}
Loading