Eduard Kuzmenko
5 years ago
41 changed files with 2531 additions and 2275 deletions
@ -0,0 +1,23 @@ |
|||||||
|
-----BEGIN CERTIFICATE----- |
||||||
|
MIIDwDCCAqigAwIBAgIJAOqEYb8IH1NQMA0GCSqGSIb3DQEBCwUAMHUxCzAJBgNV |
||||||
|
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX |
||||||
|
aWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCWxvY2FsaG9zdDEaMBgGCSqGSIb3DQEJ |
||||||
|
ARYLcXdlQGFzZC5jb20wHhcNMjAwNDEwMTc0OTU3WhcNMjAwNTEwMTc0OTU3WjB1 |
||||||
|
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 |
||||||
|
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxGjAYBgkq |
||||||
|
hkiG9w0BCQEWC3F3ZUBhc2QuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB |
||||||
|
CgKCAQEAxxzMhd/vxT84pEcRIIZwYKe6C00OaRZq8VErgNoOQVr8hejj7FueGjAu |
||||||
|
io841OcJjUHCgD7Bda/cu5FLs0ATxAkBow7K9+Qzx3Gnl87ZKkxlt4xFZ6mWvDiY |
||||||
|
hovliUL+I+ll29l2cF2PXhl8q/VEsOl0+M45d5rzT/qy3PD3H/5CwqCVnovCXe5H |
||||||
|
BEFCf82qYAEe+J/w5KjtiqgT4fx/n0XNXES0KO/ot2PWyjGnzs+V52yf2eChmfIr |
||||||
|
Ae7+ykRM60YwIR3HHvCiVO5XtEqB3x207ADwcQGpC0oOvuj8YB8Jj76QUfLm559/ |
||||||
|
pNjkZR07jMReX6Pzuuf7bEsQvfkMmwIDAQABo1MwUTAdBgNVHQ4EFgQUpn8Hwa3D |
||||||
|
qFgdzvB62FYygrvZSlcwHwYDVR0jBBgwFoAUpn8Hwa3DqFgdzvB62FYygrvZSlcw |
||||||
|
DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAQYb7MFbTQ7i6bwoc |
||||||
|
j6jQ67S3RkK1svqXVgoqjYHY69BEhO94vNQZeOgTJWRk1YjKfTwQAdLru8U2BjtA |
||||||
|
gh76OiMsTXhnhOv/TPGBRFUwPt2BSY5G/aa6ZJ0XB/exsOo0z/34k9IIGCO3g/g6 |
||||||
|
BpphITMjOJ8LbA8v0PBeHQD9d9u1ViuafgzvD6WwvmAkDKhGXDMyYDn5zjGo6L+w |
||||||
|
rjmGjOn4c0rJAxPGEMABaGusuxhRFrFLxolohru3jSvvjjZ/zbXo3V6bR+Ta2IIC |
||||||
|
cewd/gPI0odv1ObXNwdI/Dvu/1ymxcg8aVgjuMHtonkOAfxw9ghIuDfNtbV0Nb15 |
||||||
|
SEzY5w== |
||||||
|
-----END CERTIFICATE----- |
@ -0,0 +1,20 @@ |
|||||||
|
const compression = require('compression'); |
||||||
|
const express = require('express'); |
||||||
|
const https = require('https'); |
||||||
|
const fs = require('fs'); |
||||||
|
|
||||||
|
const app = express(); |
||||||
|
|
||||||
|
app.use(compression()); |
||||||
|
app.use(express.static('public')); |
||||||
|
|
||||||
|
app.get('/', (req, res) => { |
||||||
|
res.sendFile(__dirname + '/public/index.html'); |
||||||
|
}); |
||||||
|
|
||||||
|
https.createServer({ |
||||||
|
key: fs.readFileSync(__dirname + '/server.key'), |
||||||
|
cert: fs.readFileSync(__dirname + '/server.cert') |
||||||
|
}, app).listen(9001, () => { |
||||||
|
console.log('Listening...'); |
||||||
|
}); |
@ -0,0 +1,28 @@ |
|||||||
|
-----BEGIN PRIVATE KEY----- |
||||||
|
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHHMyF3+/FPzik |
||||||
|
RxEghnBgp7oLTQ5pFmrxUSuA2g5BWvyF6OPsW54aMC6KjzjU5wmNQcKAPsF1r9y7 |
||||||
|
kUuzQBPECQGjDsr35DPHcaeXztkqTGW3jEVnqZa8OJiGi+WJQv4j6WXb2XZwXY9e |
||||||
|
GXyr9USw6XT4zjl3mvNP+rLc8Pcf/kLCoJWei8Jd7kcEQUJ/zapgAR74n/DkqO2K |
||||||
|
qBPh/H+fRc1cRLQo7+i3Y9bKMafOz5XnbJ/Z4KGZ8isB7v7KREzrRjAhHcce8KJU |
||||||
|
7le0SoHfHbTsAPBxAakLSg6+6PxgHwmPvpBR8ubnn3+k2ORlHTuMxF5fo/O65/ts |
||||||
|
SxC9+QybAgMBAAECggEAdWzciU9p3k/MncVzqlTezYHdTHDjQMKBy1Ntbo4qvgxk |
||||||
|
xKx2Tpwxf4xOxlR01cpzbaUMigl4mmleqhekJ1Bw17ngB0PgG5Wvm73BctwAYtuv |
||||||
|
WTIWdG4lgVd3TFIQyoSB0LgC5Ec5fEcRGBO73MXG/vaPj3Q/m/P77n0RIw/RDkIg |
||||||
|
mZjPOAeVpaJxRInVgpEAfzPAB+yPyk1qxHzbBzQziyzZLxycF26vlHcGWbjWeOBA |
||||||
|
0CLVwAHeoctLpxPYSTlEc1PCZvn0Lm4kMFuuUnf03Tc/nlvGD0iQ2s6ThdUs2dNV |
||||||
|
uie5JzrgsZuRPQ2vxYGLAZZI4455HA+gENvQQd160QKBgQDsAwtAF1S4fAiuR9hY |
||||||
|
Nh5PEM3MRb9FMaRN5p4PdinnCmkymrUoW/LKotyU7ASwKnmALUzQ0eUoIjvRC85B |
||||||
|
rW5NpuK/GjURZYd6+AzrqoWcnuDe7ugj0G1U0yyBbtMbp+KELB30UMJexV7ovHPM |
||||||
|
rCi5mz1EUy0SUTj1CyWEazco5wKBgQDX+b3xu3gtOxbDi0hGJ1u/TAvJGndHXDBK |
||||||
|
yzaY0I8BIbPC6IWTiWkCImuogFoV7TruLpGJJa9QDzhBi2mkRGvS6XWDKEoRe/tb |
||||||
|
l8BhGFbNqdDyMb6tNh8k8cpYSDLlzMgK1/5S6gUsr5jWA0fFegXRcexYmj0r+ibN |
||||||
|
5AP1mZrELQKBgQCE5SXlnf2XsEgXEt+QtFCWxuiLWM7eQJi7QNvJ6winT2ZzF0hh |
||||||
|
BH2PeutodAojxJcMBPYXM8mssrIqAVLQCr9svEc7wp8VP61tIdXsseVwjsoi3jYb |
||||||
|
TJbzx8Fs1KHNFdjoAguP8hWw1cSemtc97cc01GRIX+mmQdQnr3IdwV2bCwKBgCiV |
||||||
|
cl7pRmThdJ6cHqGoJbJlvNU2VvGe3ig/1WuTzTt+NMRMY0VdDdFr3GUWcVcrc+Zr |
||||||
|
88ccwLu/kGeopdpLTSOd4QobWQe+D3afpnPYWf9diLjqJhVwVRvhH4/FSWMrPu/i |
||||||
|
tJSqCvzhpkuY5DS0gEFiMfJYUWRhJkeMMD5HdfClAoGBANTEaSrZhmw2HgdXD4iE |
||||||
|
sscOyh84+kJG77T+0B5jj+Oa5laulRwIjxZfndoSFlspQ+z1hDE9iqWGv+qd5u0u |
||||||
|
yWWf6LB88hBAcLTg82AUuPTQXsOtkzBeb1Ny+xoKCL73nGcHCydoih0AA8+4oQWT |
||||||
|
ecQb07xZUbaNB5HKRzcmalf6 |
||||||
|
-----END PRIVATE KEY----- |
@ -0,0 +1,162 @@ |
|||||||
|
import { generatePathData } from "../lib/utils"; |
||||||
|
|
||||||
|
export default class BubbleGroups { |
||||||
|
bubblesByGroups: Array<{timestamp: number, fromID: number, mid: number, group: HTMLDivElement[]}> = []; // map to group
|
||||||
|
groups: Array<HTMLDivElement[]> = []; |
||||||
|
//updateRAFs: Map<HTMLDivElement[], number> = new Map();
|
||||||
|
newGroupDiff = 120; |
||||||
|
|
||||||
|
removeBubble(bubble: HTMLDivElement, mid: number) { |
||||||
|
let details = this.bubblesByGroups.findAndSplice(g => g.mid == mid); |
||||||
|
if(details && details.group.length) { |
||||||
|
details.group.findAndSplice(d => d == bubble); |
||||||
|
if(!details.group.length) { |
||||||
|
this.groups.findAndSplice(g => g == details.group); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
addBubble(bubble: HTMLDivElement, message: any, reverse: boolean) { |
||||||
|
let timestamp = message.date; |
||||||
|
let fromID = message.fromID; |
||||||
|
let group: HTMLDivElement[]; |
||||||
|
|
||||||
|
// try to find added
|
||||||
|
//this.removeBubble(message.mid);
|
||||||
|
|
||||||
|
if(this.bubblesByGroups.length) { |
||||||
|
if(reverse) { |
||||||
|
let g = this.bubblesByGroups[0]; |
||||||
|
if(g.fromID == fromID && (g.timestamp - timestamp) < this.newGroupDiff) { |
||||||
|
group = g.group; |
||||||
|
group.unshift(bubble); |
||||||
|
} else { |
||||||
|
this.groups.unshift(group = [bubble]); |
||||||
|
} |
||||||
|
} else { |
||||||
|
let g = this.bubblesByGroups[this.bubblesByGroups.length - 1]; |
||||||
|
if(g.fromID == fromID && (timestamp - g.timestamp) < this.newGroupDiff) { |
||||||
|
group = g.group; |
||||||
|
group.push(bubble); |
||||||
|
} else { |
||||||
|
this.groups.push(group = [bubble]); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
this.groups.push(group = [bubble]); |
||||||
|
} |
||||||
|
|
||||||
|
//console.log('addBubble', bubble, message.mid, fromID, reverse, group);
|
||||||
|
|
||||||
|
this.bubblesByGroups[reverse ? 'unshift' : 'push']({timestamp, fromID, mid: message.mid, group}); |
||||||
|
this.updateGroup(group, reverse); |
||||||
|
} |
||||||
|
|
||||||
|
setClipIfNeeded(bubble: HTMLDivElement, remove = false) { |
||||||
|
//console.log('setClipIfNeeded', bubble, remove);
|
||||||
|
if(bubble.classList.contains('is-message-empty')/* && !bubble.classList.contains('is-reply') */ |
||||||
|
&& (bubble.classList.contains('photo') || bubble.classList.contains('video'))) { |
||||||
|
let container = bubble.querySelector('.bubble__media-container') as SVGSVGElement; |
||||||
|
//console.log('setClipIfNeeded', bubble, remove, container);
|
||||||
|
if(!container) return; |
||||||
|
|
||||||
|
Array.from(container.children).forEach(object => { |
||||||
|
if(object instanceof SVGDefsElement) return; |
||||||
|
|
||||||
|
if(remove) { |
||||||
|
object.removeAttributeNS(null, 'clip-path'); |
||||||
|
} else { |
||||||
|
let clipID = container.dataset.clipID; |
||||||
|
let path = container.firstElementChild.firstElementChild.lastElementChild as SVGPathElement; |
||||||
|
let width = +object.getAttributeNS(null, 'width'); |
||||||
|
let height = +object.getAttributeNS(null, 'height'); |
||||||
|
let isOut = bubble.classList.contains('is-out'); |
||||||
|
let isReply = bubble.classList.contains('is-reply'); |
||||||
|
let d = ''; |
||||||
|
|
||||||
|
//console.log('setClipIfNeeded', object, width, height, isOut);
|
||||||
|
|
||||||
|
let tr: number, tl: number; |
||||||
|
if(bubble.classList.contains('forwarded') || isReply) { |
||||||
|
tr = tl = 0; |
||||||
|
} else if(isOut) { |
||||||
|
tr = bubble.classList.contains('is-group-first') ? 12 : 6; |
||||||
|
tl = 12; |
||||||
|
} else { |
||||||
|
tr = 12; |
||||||
|
tl = bubble.classList.contains('is-group-first') ? 12 : 6; |
||||||
|
} |
||||||
|
|
||||||
|
if(isOut) { |
||||||
|
d = generatePathData(0, 0, width - 9, height, tl, tr, 0, 12); |
||||||
|
} else { |
||||||
|
d = generatePathData(9, 0, width - 9, height, tl, tr, 12, 0); |
||||||
|
} |
||||||
|
|
||||||
|
path.setAttributeNS(null, 'd', d); |
||||||
|
object.setAttributeNS(null, 'clip-path', 'url(#' + clipID + ')'); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
updateGroup(group: HTMLDivElement[], reverse = false) { |
||||||
|
/* if(this.updateRAFs.has(group)) { |
||||||
|
window.cancelAnimationFrame(this.updateRAFs.get(group)); |
||||||
|
this.updateRAFs.delete(group); |
||||||
|
} */ |
||||||
|
|
||||||
|
//this.updateRAFs.set(group, window.requestAnimationFrame(() => {
|
||||||
|
//this.updateRAFs.delete(group);
|
||||||
|
|
||||||
|
if(!group.length) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
let first = group[0]; |
||||||
|
|
||||||
|
//appImManager.scrollPosition.prepareFor(reverse ? 'up' : 'down');
|
||||||
|
|
||||||
|
//console.log('updateGroup', group, first);
|
||||||
|
|
||||||
|
if(group.length == 1) { |
||||||
|
first.classList.add('is-group-first', 'is-group-last'); |
||||||
|
this.setClipIfNeeded(first); |
||||||
|
return; |
||||||
|
} else { |
||||||
|
first.classList.remove('is-group-last'); |
||||||
|
first.classList.add('is-group-first'); |
||||||
|
this.setClipIfNeeded(first, true); |
||||||
|
} |
||||||
|
|
||||||
|
let length = group.length - 1; |
||||||
|
for(let i = 1; i < length; ++i) { |
||||||
|
let bubble = group[i]; |
||||||
|
bubble.classList.remove('is-group-last', 'is-group-first'); |
||||||
|
this.setClipIfNeeded(bubble, true); |
||||||
|
} |
||||||
|
|
||||||
|
let last = group[group.length - 1]; |
||||||
|
last.classList.remove('is-group-first'); |
||||||
|
last.classList.add('is-group-last'); |
||||||
|
this.setClipIfNeeded(last); |
||||||
|
|
||||||
|
//appImManager.scrollPosition.restore();
|
||||||
|
//}));
|
||||||
|
} |
||||||
|
|
||||||
|
updateGroupByMessageID(mid: number) { |
||||||
|
let details = this.bubblesByGroups.find(g => g.mid == mid); |
||||||
|
if(details) { |
||||||
|
this.updateGroup(details.group); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
cleanup() { |
||||||
|
this.bubblesByGroups = []; |
||||||
|
/* for(let value of this.updateRAFs.values()) { |
||||||
|
window.cancelAnimationFrame(value); |
||||||
|
} |
||||||
|
this.updateRAFs.clear(); */ |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,4 @@ |
|||||||
|
// @ts-ignore
|
||||||
|
import LottiePlayer from "lottie-web/build/player/lottie_canvas.min.js"; |
||||||
|
|
||||||
|
(window as any).lottie = LottiePlayer; |
Loading…
Reference in new issue