Browse Source

webp detect & new message paddings & forward forwarded & down button & avatar click

master
Eduard Kuzmenko 5 years ago
parent
commit
9f695bc863
  1. 2
      src/components/lazyLoadQueue.ts
  2. 6
      src/components/pageIm.ts
  3. 11
      src/components/wrappers.ts
  4. 4
      src/lib/appManagers/appDialogsManager.ts
  5. 87
      src/lib/appManagers/appImManager.ts
  6. 4
      src/lib/appManagers/appMediaViewer.ts
  7. 3
      src/lib/appManagers/appMessagesManager.ts
  8. 49
      src/lib/appManagers/appWebpManager.ts
  9. 2
      src/lib/ckin.js
  10. 95
      src/scss/partials/_chat.scss
  11. 11
      src/scss/partials/_ckin.scss

2
src/components/lazyLoadQueue.ts

@ -106,7 +106,7 @@ export default class LazyLoadQueue { @@ -106,7 +106,7 @@ export default class LazyLoadQueue {
let {div} = this.lazyLoadMedia[i];
if(isElementInViewport(div)) {
console.log('will load div:', div);
//console.log('will load div:', div);
this.lazyLoadMedia[i].wasSeen = true;
this.processQueue(i);
//this.lazyLoadMedia.splice(i, 1);

6
src/components/pageIm.ts

@ -70,18 +70,20 @@ export default () => import('../lib/services').then(services => { @@ -70,18 +70,20 @@ export default () => import('../lib/services').then(services => {
console.log('updating dialog:', dialog);
++performed;
if(!(dialog.peerID in appDialogsManager.doms)) {
appDialogsManager.addDialog(dialog);
continue;
}
appDialogsManager.setLastMessage(dialog);
++performed;
}
if(performed) {
console.log('will sortDom');
appDialogsManager.sortDom();
appDialogsManager.sortDom(true);
}
});

11
src/components/wrappers.ts

@ -108,10 +108,17 @@ export function wrapVideo(this: any, doc: MTDocument, container: HTMLDivElement, @@ -108,10 +108,17 @@ export function wrapVideo(this: any, doc: MTDocument, container: HTMLDivElement,
container.append(video);
if(!justLoader) {
if(!justLoader || round) {
video.dataset.ckin = round ? 'circle' : 'default';
video.dataset.overlay = '1';
wrapPlayer(video);
let wrapper = wrapPlayer(video);
if(!round) {
(wrapper.querySelector('.toggle') as HTMLButtonElement).click();
}
} else if(doc.type == 'gif') {
video.autoplay = true;
video.loop = true;
}
//container.style.width = '';

4
src/lib/appManagers/appDialogsManager.ts

@ -61,9 +61,9 @@ export class AppDialogsManager { @@ -61,9 +61,9 @@ export class AppDialogsManager {
return;
}
if(this.lastActiveListElement) {
/* if(this.lastActiveListElement) {
this.lastActiveListElement.classList.remove('active');
}
} */
if(elem) {
/* if(chatClosedDiv) {

87
src/lib/appManagers/appImManager.ts

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
import apiManager from '../mtproto/apiManager';
import { $rootScope, isElementInViewport, numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, calcImageInBox } from "../utils";
import { $rootScope, isElementInViewport, numberWithCommas, findUpClassName, formatNumber, placeCaretAtEnd, calcImageInBox, findUpTag } from "../utils";
import appUsersManager from "./appUsersManager";
import appMessagesManager from "./appMessagesManager";
import appPeersManager from "./appPeersManager";
@ -435,6 +435,7 @@ export class AppImManager { @@ -435,6 +435,7 @@ export class AppImManager {
public subtitleEl = document.getElementById('im-subtitle') as HTMLDivElement;
public chatInner = document.getElementById('bubbles-inner') as HTMLDivElement;
public searchBtn = this.pageEl.querySelector('.chat-search-button') as HTMLButtonElement;
public goDownBtn = this.pageEl.querySelector('#bubbles-go-down') as HTMLButtonElement;
public firstContainerDiv: HTMLDivElement;
public lastContainerDiv: HTMLDivElement;
private getHistoryPromise: Promise<boolean>;
@ -664,6 +665,8 @@ export class AppImManager { @@ -664,6 +665,8 @@ export class AppImManager {
if(!bubble) return;
if(['IMG', 'VIDEO', 'SVG', 'DIV'].indexOf(target.tagName) === -1) target = findUpTag(target, 'DIV');
/* if(target.tagName == 'VIDEO' && bubble.classList.contains('round')) {
let video = target as HTMLVideoElement;
video.currentTime = 0;
@ -678,6 +681,24 @@ export class AppImManager { @@ -678,6 +681,24 @@ export class AppImManager {
} */
if(target.tagName == 'DIV') {
if(target.classList.contains('forward')) {
let savedFrom = bubble.dataset.savedFrom;
let splitted = savedFrom.split('_');
let peerID = +splitted[0];
let msgID = +splitted[1];
this.log('savedFrom', peerID, msgID);
this.setPeer(peerID, msgID, true);
return;
} else if(target.classList.contains('user-avatar') || target.classList.contains('name')) {
let peerID = +target.dataset.peerID;
if(!isNaN(peerID)) {
this.setPeer(peerID);
}
return;
}
let isReplyClick = false;
try {
@ -690,6 +711,12 @@ export class AppImManager { @@ -690,6 +711,12 @@ export class AppImManager {
}
} else if(bubble.classList.contains('round')) {
} else if(target.tagName == 'IMG' && target.parentElement.classList.contains('user-avatar')) {
let peerID = +target.parentElement.dataset.peerID;
if(!isNaN(peerID)) {
this.setPeer(peerID);
}
} else if((target.tagName == 'IMG' && !target.classList.contains('emoji')) || target.tagName == 'VIDEO') {
let messageID = +target.getAttribute('message-id');
let message = appMessagesManager.getMessage(messageID);
@ -889,6 +916,14 @@ export class AppImManager { @@ -889,6 +916,14 @@ export class AppImManager {
this.popupDeleteMessage.cancelBtn.click();
});
this.goDownBtn.addEventListener('click', () => {
if(this.lastDialog) {
this.setPeer(this.peerID, this.lastDialog.top_message);
} else {
this.scroll.scrollTop = this.scroll.scrollHeight;
}
});
this.updateStatusInterval = window.setInterval(() => this.updateStatus(), 50e3);
this.updateStatus();
setInterval(() => this.setPeerStatus(), 60e3);
@ -1056,7 +1091,8 @@ export class AppImManager { @@ -1056,7 +1091,8 @@ export class AppImManager {
let willLoad = false;
if(!this.scrolledAll) {
for(let i = 0; i < 10; ++i) {
let length = history.length < 10 ? history.length : 10;
for(let i = 0; i < length; ++i) {
let msgID = history[i];
let bubble = this.bubbles[msgID];
@ -1117,6 +1153,7 @@ export class AppImManager { @@ -1117,6 +1153,7 @@ export class AppImManager {
this.scroll = scroll;
this.scrollPosition = new ScrollPosition(this.chatInner);
this.scroll.addEventListener('scroll', this.onScroll.bind(this));
this.scroll.parentElement.classList.add('scrolled-down');
}
public setPeerStatus() {
@ -1242,10 +1279,10 @@ export class AppImManager { @@ -1242,10 +1279,10 @@ export class AppImManager {
//appSidebarRight.minMediaID = {};
}
public setPeer(peerID: number, lastMsgID = 0) {
public setPeer(peerID: number, lastMsgID = 0, forwarding = false) {
if(peerID == 0) {
appSidebarRight.toggleSidebar(false);
this.topbar.style.display = this.chatInput.style.display = 'none';
this.topbar.style.display = this.chatInput.style.display = this.goDownBtn.style.display = 'none';
this.cleanup();
return Promise.resolve(false);
}
@ -1285,9 +1322,12 @@ export class AppImManager { @@ -1285,9 +1322,12 @@ export class AppImManager {
this.preloader.attach(this.chatInner);
let dialog = this.lastDialog = appMessagesManager.getDialogByPeerID(this.peerID)[0] || null;
this.log('setPeer peerID:', this.peerID, dialog);
this.log('setPeer peerID:', this.peerID, dialog, lastMsgID);
appDialogsManager.loadDialogPhoto(this.avatarEl, this.peerID);
appDialogsManager.loadDialogPhoto(appSidebarRight.profileElements.avatar, this.peerID);
if(appDialogsManager.lastActiveListElement) {
appDialogsManager.lastActiveListElement.classList.remove('active');
}
this.firstTopMsgID = dialog ? dialog.top_message : 0;
@ -1305,7 +1345,7 @@ export class AppImManager { @@ -1305,7 +1345,7 @@ export class AppImManager {
//this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = dom.titleSpan.innerHTML;
this.titleEl.innerHTML = appSidebarRight.profileElements.name.innerHTML = appPeersManager.getPeerTitle(this.peerID);
this.topbar.style.display = '';
this.topbar.style.display = this.goDownBtn.style.display = '';
appSidebarRight.toggleSidebar(true);
this.chatInput.style.display = appPeersManager.isChannel(peerID) && !appPeersManager.isMegagroup(peerID) ? 'none' : '';
@ -1317,14 +1357,21 @@ export class AppImManager { @@ -1317,14 +1357,21 @@ export class AppImManager {
}
return Promise.all([
this.getHistory(lastMsgID).then(() => {
this.getHistory(forwarding ? lastMsgID + 1 : lastMsgID).then(() => {
this.log('setPeer removing preloader');
if(lastMsgID) {
this.renderMessage(appMessagesManager.getMessage(lastMsgID));
if(!forwarding) {
let message = appMessagesManager.getMessage(lastMsgID);
this.log('setPeer render last message:', message, lastMsgID);
this.renderMessage(message);
}
if(!dialog || lastMsgID != dialog.top_message) {
this.bubbles[lastMsgID].scrollIntoView();
let bubble = this.bubbles[lastMsgID];
if(bubble) this.bubbles[lastMsgID].scrollIntoView();
else this.log.warn('no bubble by lastMsgID:', lastMsgID);
} else {
this.scroll.scrollTop = this.scroll.scrollHeight;
}
@ -1418,6 +1465,8 @@ export class AppImManager { @@ -1418,6 +1465,8 @@ export class AppImManager {
}
public renderMessage(message: any, reverse = false, multipleRender?: boolean, bubble: HTMLDivElement = null) {
if(message.deleted) return;
let peerID = this.peerID;
let our = message.fromID == this.myID;
@ -1694,7 +1743,7 @@ export class AppImManager { @@ -1694,7 +1743,7 @@ export class AppImManager {
}
bubble.classList.add('video');
wrapVideo.call(this, doc, attachmentDiv, message, doc.type != 'round', null, false, doc.type == 'round');
wrapVideo.call(this, doc, attachmentDiv, message, true, null, false, doc.type == 'round');
break;
} else {
@ -1736,10 +1785,25 @@ export class AppImManager { @@ -1736,10 +1785,25 @@ export class AppImManager {
if(message.fwdFromID || message.fwd_from) {
bubble.classList.add('forwarded');
if(message.savedFrom) {
let fwd = document.createElement('div');
fwd.classList.add('forward'/* , 'tgico-forward' */);
fwd.innerHTML = `
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" preserveAspectRatio="xMidYMid meet" viewBox="0 0 24 24">
<defs>
<path d="M13.55 3.24L13.64 3.25L13.73 3.27L13.81 3.29L13.9 3.32L13.98 3.35L14.06 3.39L14.14 3.43L14.22 3.48L14.29 3.53L14.36 3.59L14.43 3.64L22.23 10.85L22.36 10.99L22.48 11.15L22.57 11.31L22.64 11.48L22.69 11.66L22.72 11.85L22.73 12.04L22.71 12.22L22.67 12.41L22.61 12.59L22.53 12.76L22.42 12.93L22.29 13.09L22.23 13.15L14.43 20.36L14.28 20.48L14.12 20.58L13.95 20.66L13.77 20.72L13.58 20.76L13.4 20.77L13.22 20.76L13.03 20.73L12.85 20.68L12.68 20.61L12.52 20.52L12.36 20.4L12.22 20.27L12.16 20.2L12.1 20.13L12.05 20.05L12.01 19.98L11.96 19.9L11.93 19.82L11.89 19.73L11.87 19.65L11.84 19.56L11.83 19.47L11.81 19.39L11.81 19.3L11.8 19.2L11.8 16.42L11 16.49L10.23 16.58L9.51 16.71L8.82 16.88L8.18 17.09L7.57 17.33L7.01 17.6L6.48 17.91L5.99 18.26L5.55 18.64L5.14 19.05L4.77 19.51L4.43 19.99L4.29 20.23L4.21 20.35L4.11 20.47L4 20.57L3.88 20.65L3.75 20.72L3.62 20.78L3.48 20.82L3.33 20.84L3.19 20.84L3.04 20.83L2.9 20.79L2.75 20.74L2.62 20.68L2.53 20.62L2.45 20.56L2.38 20.5L2.31 20.43L2.25 20.36L2.2 20.28L2.15 20.19L2.11 20.11L2.07 20.02L2.04 19.92L2.02 19.83L2.01 19.73L2 19.63L2.04 17.99L2.19 16.46L2.46 15.05L2.85 13.75L3.35 12.58L3.97 11.53L4.7 10.6L5.55 9.8L6.51 9.12L7.59 8.56L8.77 8.13L10.07 7.83L11.48 7.65L11.8 7.63L11.8 4.8L11.91 4.56L12.02 4.35L12.14 4.16L12.25 3.98L12.37 3.82L12.48 3.68L12.61 3.56L12.73 3.46L12.85 3.38L12.98 3.31L13.11 3.27L13.24 3.24L13.37 3.23L13.46 3.23L13.55 3.24Z" id="b13RmHDQtl"></path>
</defs>
<use xlink:href="#b13RmHDQtl" opacity="1" fill="#fff" fill-opacity="1"></use>
</svg>`;
bubble.append(fwd);
bubble.dataset.savedFrom = message.savedFrom;
}
if(!bubble.classList.contains('sticker')) {
let nameDiv = document.createElement('div');
nameDiv.classList.add('name');
nameDiv.innerHTML = 'Forwarded from ' + title;
nameDiv.dataset.peerID = message.fwdFromID;
//nameDiv.style.color = appPeersManager.getPeerColorByID(message.fromID, false);
bubble.append(nameDiv);
}
@ -1812,6 +1876,7 @@ export class AppImManager { @@ -1812,6 +1876,7 @@ export class AppImManager {
nameDiv.classList.add('name');
nameDiv.innerHTML = title;
nameDiv.style.color = appPeersManager.getPeerColorByID(message.fromID, false);
nameDiv.dataset.peerID = message.fromID;
bubble.append(nameDiv);
} else if(!message.reply_to_mid) {
bubble.classList.add('hide-name');
@ -1839,6 +1904,8 @@ export class AppImManager { @@ -1839,6 +1904,8 @@ export class AppImManager {
appDialogsManager.loadDialogPhoto(avatarDiv, title);
}
avatarDiv.dataset.peerID = message.fromID;
bubble.append(avatarDiv);
}
}

4
src/lib/appManagers/appMediaViewer.ts

@ -225,7 +225,9 @@ export class AppMediaViewer { @@ -225,7 +225,9 @@ export class AppMediaViewer {
let index = history.findIndex(m => m == message.mid);
let comparer = (mid: number) => {
let _message = appMessagesManager.getMessage(mid);
if(_message.media && _message.media.photo) return true;
let media = _message.media;
if(media && (media.photo || (media.document && ['video', 'gif'].indexOf(media.document.type) !== -1))) return true;
return false;
};

3
src/lib/appManagers/appMessagesManager.ts

@ -1034,10 +1034,11 @@ export class AppMessagesManager { @@ -1034,10 +1034,11 @@ export class AppMessagesManager {
apiMessage.fromID = fwdHeader.channel_id ? -fwdHeader.channel_id : fwdHeader.from_id;
} else {
apiMessage.fwdFromID = fwdHeader.channel_id ? -fwdHeader.channel_id : fwdHeader.from_id;
apiMessage.fwdPostID = fwdHeader.channel_post;
}
apiMessage.fwdFromID = fwdHeader.channel_id ? -fwdHeader.channel_id : fwdHeader.from_id;
fwdHeader.date -= serverTimeManager.serverTimeOffset;
}

49
src/lib/appManagers/appWebpManager.ts

@ -7,6 +7,7 @@ class AppWebpManager { @@ -7,6 +7,7 @@ class AppWebpManager {
public busyPromise: Promise<string>;
public queue: {bytes: Uint8Array, img: HTMLImageElement}[] = [];
//public worker: any;
public webpSupport: Promise<boolean> = null;
constructor() {
//let canvas = document.createElement('canvas');
@ -16,21 +17,25 @@ class AppWebpManager { @@ -16,21 +17,25 @@ class AppWebpManager {
console.log('got message from worker:', e, canvas.toDataURL());
}); */
this.loaded = new Promise((resolve, reject) => {
(window as any).webpLoaded = () => {
console.log('webpHero loaded');
this.webpMachine = new (window as any).WebpMachine();
resolve();
};
let sc = document.createElement('script');
sc.src = 'webp.bundle.js';
sc.async = true;
sc.onload = (window as any).webpLoaded;
document.body.appendChild(sc);
resolve();
this.webpSupported().then(res => {
this.loaded = new Promise((resolve, reject) => {
if(!res) {
(window as any).webpLoaded = () => {
console.log('webpHero loaded');
this.webpMachine = new (window as any).WebpMachine();
resolve();
};
let sc = document.createElement('script');
sc.src = 'webp.bundle.js';
sc.async = true;
sc.onload = (window as any).webpLoaded;
document.body.appendChild(sc);
} else {
resolve();
}
});
});
}
@ -56,11 +61,23 @@ class AppWebpManager { @@ -56,11 +61,23 @@ class AppWebpManager {
}
}
webpSupported() {
return this.webpSupport = new Promise((resolve, reject) => {
var webP = new Image();
webP.src = 'data:image/webp;base64,UklGRi4AAABXRUJQVlA4TCEAAAAvAUAAEB8wAiMw' +
'AgSSNtse/cXjxyCCmrYNWPwmHRH9jwMA';
webP.onload = webP.onerror = () => {
resolve(webP.height === 2);
};
});
}
async polyfillImage(img: HTMLImageElement, blob: Blob) {
/* console.log('polyfillImage', this);
return this.webpMachine.polyfillImage(image); */
if(await this.webpMachine.webpSupport) {
//if(await this.webpMachine.webpSupport) {
if(await this.webpSupport) {
img.src = URL.createObjectURL(blob);
return;
}

2
src/lib/ckin.js

@ -173,6 +173,8 @@ export function wrapPlayer(video) { @@ -173,6 +173,8 @@ export function wrapPlayer(video) {
wrapper.appendChild(video);
stylePlayer(wrapper, video);
return wrapper;
}
function buildControls(skin) {

95
src/scss/partials/_chat.scss

@ -111,9 +111,17 @@ @@ -111,9 +111,17 @@
overflow: hidden;
position: relative;
> .scrollable {
position: unset;
}
&:not(.scrolled-down) {
-webkit-mask-image: -webkit-linear-gradient(bottom, transparent, #000 20px);
mask-image: linear-gradient(0deg, transparent 0, #000 20px);
#bubbles-go-down {
opacity: 1;
}
}
.preloader {
@ -145,6 +153,30 @@ @@ -145,6 +153,30 @@
}
}
#bubbles-go-down {
position: absolute;
//opacity: 0;
background-color: #fff;
border-radius: 50%;
width: 3.25rem;
height: 3.25rem;
color: $placeholder-color;
font-size: 30px;
display: flex;
align-items: center;
justify-content: center;
right: 17.5px;
bottom: 17.5px;
cursor: pointer;
opacity: 0;
transition: .2s opacity;
user-select: none;
&:before {
margin-left: .75px;
}
}
.service {
justify-content: center;
align-self: center;
@ -173,6 +205,37 @@ @@ -173,6 +205,37 @@
width: max-content;
height: fit-content;
&.forwarded {
.forward {
opacity: 0;
position: absolute;
right: -46px;
bottom: 0;
width: 38px;
height: 38px;
font-size: 1.5rem;
align-items: center;
display: flex;
justify-content: center;
color: #fff;
border-radius: 50%;
background: rgba(0, 0, 0, 0.16);
cursor: pointer;
transition: .2s opacity;
svg {
width: 20px;
height: 20px;
}
}
}
&:hover {
.forward {
opacity: 1;
}
}
&.photo, &.video {
width: min-content;
@ -426,12 +489,14 @@ @@ -426,12 +489,14 @@
}
.message {
font-size: 1rem;
padding: 0 .6rem .2675rem .6rem;
font-size: 16px;
//padding: 0 .6rem .2675rem .6rem;
padding: 0 .6rem 6px .6rem;
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
color: #000;
line-height: 21px;
* {
overflow: hidden;
@ -439,7 +504,8 @@ @@ -439,7 +504,8 @@
}
&:last-child {
padding-top: .2675rem;
//padding-top: .2675rem;
padding-top: 6px;
}
&.message-empty {
@ -498,14 +564,14 @@ @@ -498,14 +564,14 @@
width: calc(5rem + 42px);
}
&.is-edited .time {
width: 90px;
}
&.channel-post .time {
width: 5rem;
}
&.is-edited .time {
width: 90px;
}
.user-avatar {
position: absolute;
left: -3rem;
@ -514,6 +580,7 @@ @@ -514,6 +580,7 @@
line-height: 40px;
bottom: 0;
font-size: 1rem;
cursor: pointer;
}
&:not(.forwarded).hide-name, &.emoji-big {
@ -543,17 +610,20 @@ @@ -543,17 +610,20 @@
&:not(.webpage) {
&.photo, &.video {
.name {
padding-bottom: .2675rem;
//padding-bottom: .2675rem;
padding-bottom: 6px;
}
.message:not(.message-empty) {
padding-top: .2675rem;
//padding-top: .2675rem;
padding-top: 6px;
}
}
}
&.hide-name .message:not(.message-empty) {
padding-top: .2675rem;
//padding-top: .2675rem;
padding-top: 6px;
}
&:not(.sticker):not(.emoji-big):not(.round):last-child:after {
@ -622,6 +692,7 @@ @@ -622,6 +692,7 @@
&:last-child {
border-radius: 6px 12px 12px 0px;
//border-radius: 12px 12px 12px 0px;
&:after {
left: -8.4px;
@ -708,6 +779,10 @@ @@ -708,6 +779,10 @@
display: none;
}
.bubble.is-edited .time {
width: 85px;
}
.bubble {
background-color: #eeffde;
border-radius: 12px 6px 6px 12px;

11
src/scss/partials/_ckin.scss

@ -42,6 +42,11 @@ @@ -42,6 +42,11 @@
border-radius: 0 !important;
display: -ms-flexbox;
display: flex;
video {
max-height: none;
max-width: none;
}
}
.default {
@ -290,7 +295,7 @@ video::-webkit-media-controls-enclosure { @@ -290,7 +295,7 @@ video::-webkit-media-controls-enclosure {
}
.bottom-controls {
padding: 3px 4px 5px 4px;
padding: 3px 4px 0px 4px;
//padding: 5px 4px 5px 4px;
display: flex;
justify-content: space-between;
@ -308,8 +313,8 @@ video::-webkit-media-controls-enclosure { @@ -308,8 +313,8 @@ video::-webkit-media-controls-enclosure {
color: #fff;
font-size: 13px;
float: left;
margin-top: 1px;
}
//margin-top: 1px;
}
.circle .circle-time-left {
position: absolute;
top: 3px;

Loading…
Cancel
Save