Browse Source

Prepare audio & gif tab & minor fixes

master
morethanwords 5 years ago
parent
commit
316693a88e
  1. 5
      src/components/appSearch.ts
  2. 94
      src/components/emoticonsDropdown.ts
  3. 2
      src/components/lazyLoadQueue.ts
  4. 3
      src/components/preloader.ts
  5. 131
      src/components/wrappers.ts
  6. 6
      src/lib/appManagers/appDialogsManager.ts
  7. 4
      src/lib/appManagers/appImManager.ts
  8. 8
      src/lib/appManagers/appMediaViewer.ts
  9. 35
      src/lib/appManagers/appSidebarRight.ts
  10. 0
      src/lib/ckin_js.js
  11. 6
      src/lib/config.js
  12. 375
      src/lib/mediaPlayer.ts
  13. 6
      src/lib/mtproto/networker.ts
  14. 27
      src/lib/tl_utils.ts
  15. 29
      src/scss/partials/_chat.scss
  16. 9
      src/scss/partials/_chatlist.scss
  17. 92
      src/scss/partials/_ckin.scss
  18. 25
      src/scss/partials/_emojiDropdown.scss
  19. 82
      src/scss/partials/_rightSIdebar.scss
  20. 8
      src/scss/partials/_sidebar.scss
  21. 7
      src/scss/style.scss

5
src/components/appSearch.ts

@ -175,9 +175,8 @@ export default class AppSearch {
} }
}); });
if(results.length) { if(results.length) group.setActive();
group.setActive(); else group.clear();
}
}; };
setResults(contacts.my_results, this.searchGroups.contacts, true); setResults(contacts.my_results, this.searchGroups.contacts, true);

94
src/components/emoticonsDropdown.ts

@ -3,7 +3,7 @@ import { AppMessagesManager } from "../lib/appManagers/appMessagesManager";
import { horizontalMenu } from "./misc"; import { horizontalMenu } from "./misc";
import lottieLoader from "../lib/lottieLoader"; import lottieLoader from "../lib/lottieLoader";
import Scrollable from "./scrollable"; import Scrollable from "./scrollable";
import { findUpTag, whichChild } from "../lib/utils"; import { findUpTag, whichChild, calcImageInBox } from "../lib/utils";
import { RichTextProcessor } from "../lib/richtextprocessor"; import { RichTextProcessor } from "../lib/richtextprocessor";
import appStickersManager, { MTStickerSet } from "../lib/appManagers/appStickersManager"; import appStickersManager, { MTStickerSet } from "../lib/appManagers/appStickersManager";
import apiManager from '../lib/mtproto/apiManager'; import apiManager from '../lib/mtproto/apiManager';
@ -11,6 +11,8 @@ import CryptoWorker from '../lib/crypto/cryptoworker';
import LazyLoadQueue from "./lazyLoadQueue"; import LazyLoadQueue from "./lazyLoadQueue";
import { MTDocument, wrapSticker } from "./wrappers"; import { MTDocument, wrapSticker } from "./wrappers";
import appWebpManager from "../lib/appManagers/appWebpManager"; import appWebpManager from "../lib/appManagers/appWebpManager";
import appDocsManager from "../lib/appManagers/appDocsManager";
import ProgressivePreloader from "./preloader";
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown'; export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
@ -29,10 +31,12 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
if(id == 1 && stickersInit) { if(id == 1 && stickersInit) {
stickersInit(); stickersInit();
} else if(id == 2 && gifsInit) {
gifsInit();
} }
}, () => { }, () => {
lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP); lottieLoader.checkAnimations(false, EMOTICONSSTICKERGROUP);
lazyLoadQueue.check(); // for stickers lazyLoadQueue.check(); // for stickers or gifs
}); });
(tabs.firstElementChild.children[0] as HTMLLIElement).click(); // set emoji tab (tabs.firstElementChild.children[0] as HTMLLIElement).click(); // set emoji tab
@ -395,6 +399,92 @@ const initEmoticonsDropdown = (pageEl: HTMLDivElement,
}); });
}; };
let gifsInit = () => {
let contentDiv = document.getElementById('content-gifs') as HTMLDivElement;
let masonry = contentDiv.firstElementChild as HTMLDivElement;
let scroll = new Scrollable(contentDiv, 'y', 500, 'GIFS', null);
scroll.container.addEventListener('scroll', (e) => {
lazyLoadQueue.check();
});
let width = 400;
let maxSingleWidth = width - 100;
let height = 100;
apiManager.invokeApi('messages.getSavedGifs', {hash: 0}).then((_res) => {
let res = _res as {
_: 'messages.savedGifs',
gifs: MTDocument[],
hash: number
};
console.log('getSavedGifs res:', res);
let line: MTDocument[] = [];
let wastedWidth = 0;
res.gifs.forEach((gif, idx) => {
res.gifs[idx] = appDocsManager.saveDoc(gif);
});
for(let i = 0, length = res.gifs.length; i < length;) {
let gif = res.gifs[i];
let gifWidth = gif.w;
let gifHeight = gif.h;
if(gifHeight < height) {
gifWidth = height / gifHeight * gifWidth;
gifHeight = height;
}
let willUseWidth = Math.min(maxSingleWidth, width - wastedWidth, gifWidth);
let {w, h} = calcImageInBox(gifWidth, gifHeight, willUseWidth, height);
/* wastedWidth += w;
if(wastedWidth == width || h < height) {
wastedWidth = 0;
console.log('completed line', i, line);
line = [];
continue;
}
line.push(gif); */
++i;
console.log('gif:', gif, w, h);
let div = document.createElement('div');
div.style.width = w + 'px';
//div.style.height = h + 'px';
div.dataset.documentID = gif.id;
masonry.append(div);
let preloader = new ProgressivePreloader(div);
lazyLoadQueue.push({
div,
load: () => {
let promise = appDocsManager.downloadDoc(gif);
preloader.attach(div, true, promise);
promise.then(blob => {
preloader.detach();
div.innerHTML = `<video autoplay="true" muted="true" loop="true" src="${gif.url}" type="video/mp4"></video>`;
});
return promise;
}
});
}
});
gifsInit = undefined;
};
return {dropdown, lazyLoadQueue}; return {dropdown, lazyLoadQueue};
}; };

2
src/components/lazyLoadQueue.ts

@ -2,7 +2,7 @@ import { isElementInViewport } from "../lib/utils";
type LazyLoadElement = { type LazyLoadElement = {
div: HTMLDivElement, div: HTMLDivElement,
load: () => Promise<void>, load: () => Promise<any>,
wasSeen?: boolean wasSeen?: boolean
}; };

3
src/components/preloader.ts

@ -94,7 +94,10 @@ export default class ProgressivePreloader {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
if(!this.detached) return; if(!this.detached) return;
this.detached = true; this.detached = true;
if(this.preloader.parentElement) {
this.preloader.parentElement.removeChild(this.preloader); this.preloader.parentElement.removeChild(this.preloader);
}
}); });
} }
} }

131
src/components/wrappers.ts

@ -8,7 +8,7 @@ import ProgressivePreloader from './preloader';
import LazyLoadQueue from './lazyLoadQueue'; import LazyLoadQueue from './lazyLoadQueue';
import apiFileManager from '../lib/mtproto/apiFileManager'; import apiFileManager from '../lib/mtproto/apiFileManager';
import appWebpManager from '../lib/appManagers/appWebpManager'; import appWebpManager from '../lib/appManagers/appWebpManager';
import {wrapPlayer} from '../lib/ckin'; import VideoPlayer, { MediaProgressLine } from '../lib/mediaPlayer';
import { RichTextProcessor } from '../lib/richtextprocessor'; import { RichTextProcessor } from '../lib/richtextprocessor';
import { CancellablePromise } from '../lib/polyfill'; import { CancellablePromise } from '../lib/polyfill';
import { renderImageFromUrl } from './misc'; import { renderImageFromUrl } from './misc';
@ -138,11 +138,7 @@ export function wrapVideo({doc, container, message, justLoader, preloader, round
if(!justLoader || round) { if(!justLoader || round) {
video.dataset.ckin = round ? 'circle' : 'default'; video.dataset.ckin = round ? 'circle' : 'default';
video.dataset.overlay = '1'; video.dataset.overlay = '1';
let wrapper = wrapPlayer(video); let player = new VideoPlayer(video, !round);
if(!round) {
(wrapper.querySelector('.toggle') as HTMLButtonElement).click();
}
} else if(doc.type == 'gif') { } else if(doc.type == 'gif') {
video.autoplay = true; video.autoplay = true;
video.loop = true; video.loop = true;
@ -176,7 +172,9 @@ export function wrapVideo({doc, container, message, justLoader, preloader, round
export function wrapDocument(doc: MTDocument, withTime = false, uploading = false): HTMLDivElement { export function wrapDocument(doc: MTDocument, withTime = false, uploading = false): HTMLDivElement {
if(doc.type == 'voice') { if(doc.type == 'voice') {
return wrapAudio(doc, withTime); return wrapVoiceMessage(doc, withTime);
} else if(doc.type == 'audio') {
return wrapAudio(doc);
} }
let docDiv = document.createElement('div'); let docDiv = document.createElement('div');
@ -250,15 +248,124 @@ export function wrapDocument(doc: MTDocument, withTime = false, uploading = fals
return docDiv; return docDiv;
} }
let lastAudioToggle: HTMLDivElement = null;
export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement { export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
let div = document.createElement('div'); let div = document.createElement('div');
div.classList.add('audio'); div.classList.add('audio');
console.log('wrapAudio doc:', doc);
/* let durationStr = String(doc.duration | 0).toHHMMSS(true);
let title = doc.audioTitle || doc.file_name;
let subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : ''; */
let durationStr = '3:24';
let title = 'Million Telegrams';
let subtitle = 'Best Artist';
div.innerHTML = `
<div class="audio-title">${title}</div>
<div class="audio-subtitle">${subtitle}</div>
<div class="audio-toggle audio-ico tgico-largeplay"></div>
<div class="audio-download"><div class="tgico-download"></div></div>
<div class="audio-time">${durationStr}</div>
`;
//////console.log('wrapping audio', doc, doc.attributes[0].waveform);
let timeDiv = div.lastElementChild as HTMLDivElement;
let downloadDiv = div.querySelector('.audio-download') as HTMLDivElement;
let preloader: ProgressivePreloader;
let promise: CancellablePromise<Blob>;
let progress: MediaProgressLine;
let onClick = () => {
if(!promise) {
if(downloadDiv.classList.contains('downloading')) {
return; // means not ready yet
}
if(!preloader) {
preloader = new ProgressivePreloader(null, true);
}
let promise = appDocsManager.downloadDoc(doc.id);
preloader.attach(downloadDiv, true, promise);
promise.then(blob => {
downloadDiv.classList.remove('downloading');
downloadDiv.remove();
let audio = document.createElement('audio');
let source = document.createElement('source');
source.src = URL.createObjectURL(blob);
source.type = doc.mime_type;
audio.volume = 1;
progress = new MediaProgressLine(audio);
div.removeEventListener('click', onClick);
let toggle = div.querySelector('.audio-toggle') as HTMLDivElement;
let subtitle = div.querySelector('.audio-subtitle') as HTMLDivElement;
toggle.addEventListener('click', () => {
subtitle.innerHTML = '';
subtitle.append(progress.container);
if(audio.paused) {
if(lastAudioToggle && lastAudioToggle.classList.contains('tgico-largepause')) {
lastAudioToggle.click();
}
audio.currentTime = 0;
audio.play();
lastAudioToggle = toggle;
toggle.classList.remove('tgico-largeplay');
toggle.classList.add('tgico-largepause');
} else {
audio.pause();
toggle.classList.add('tgico-largeplay');
toggle.classList.remove('tgico-largepause');
}
});
audio.addEventListener('ended', () => {
toggle.classList.add('tgico-largeplay');
toggle.classList.remove('tgico-largepause');
timeDiv.innerText = String(audio.currentTime | 0).toHHMMSS(true);
});
audio.style.display = 'none';
audio.append(source);
div.append(audio);
});
downloadDiv.classList.add('downloading');
} else {
downloadDiv.classList.remove('downloading');
promise = null;
}
};
div.addEventListener('click', onClick);
div.click();
return div;
}
let lastAudioToggle: HTMLDivElement = null;
export function wrapVoiceMessage(doc: MTDocument, withTime = false): HTMLDivElement {
let div = document.createElement('div');
div.classList.add('audio', 'is-voice');
let duration = doc.duration; let duration = doc.duration;
// @ts-ignore
let durationStr = String(duration | 0).toHHMMSS(true); let durationStr = String(duration | 0).toHHMMSS(true);
div.innerHTML = ` div.innerHTML = `
@ -360,7 +467,6 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
return; return;
} }
// @ts-ignore
timeDiv.innerText = String(audio.currentTime | 0).toHHMMSS(true); timeDiv.innerText = String(audio.currentTime | 0).toHHMMSS(true);
lastIndex = Math.round(audio.currentTime / audio.duration * 47); lastIndex = Math.round(audio.currentTime / audio.duration * 47);
@ -387,7 +493,6 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
clearInterval(interval); clearInterval(interval);
(Array.from(svg.children) as HTMLElement[]).forEach(node => node.classList.remove('active')); (Array.from(svg.children) as HTMLElement[]).forEach(node => node.classList.remove('active'));
// @ts-ignore
timeDiv.innerText = String(audio.currentTime | 0).toHHMMSS(true); timeDiv.innerText = String(audio.currentTime | 0).toHHMMSS(true);
}); });
@ -430,8 +535,8 @@ export function wrapAudio(doc: MTDocument, withTime = false): HTMLDivElement {
audio.currentTime = scrubTime; audio.currentTime = scrubTime;
} }
audio.append(source);
audio.style.display = 'none'; audio.style.display = 'none';
audio.append(source);
div.append(audio); div.append(audio);
}); });

6
src/lib/appManagers/appDialogsManager.ts

@ -482,7 +482,7 @@ export class AppDialogsManager {
lastMessageText = '<i>GIF' + (lastMessage.message ? ', ' : '') + '</i>'; lastMessageText = '<i>GIF' + (lastMessage.message ? ', ' : '') + '</i>';
found = true; found = true;
} else if(document.type == 'round') { } else if(document.type == 'round') {
lastMessageText = '<i>Videomessage' + (lastMessage.message ? ', ' : '') + '</i>'; lastMessageText = '<i>Video message' + (lastMessage.message ? ', ' : '') + '</i>';
found = true; found = true;
} }
@ -524,7 +524,7 @@ export class AppDialogsManager {
let messageText = lastMessage.message; let messageText = lastMessage.message;
let messageWrapped = ''; let messageWrapped = '';
if(messageText) { if(messageText) {
let entities = RichTextProcessor.parseEntities(messageText, {noLinebreakers: true}); let entities = RichTextProcessor.parseEntities(messageText.replace(/\n/g, ' '), {noLinebreakers: true});
if(highlightWord) { if(highlightWord) {
let regExp = new RegExp(escapeRegExp(highlightWord), 'gi'); let regExp = new RegExp(escapeRegExp(highlightWord), 'gi');
let match: any; let match: any;
@ -541,7 +541,7 @@ export class AppDialogsManager {
} }
} }
messageWrapped = RichTextProcessor.wrapRichText(messageText.replace(/\n/g, ' '), { messageWrapped = RichTextProcessor.wrapRichText(messageText, {
noLinebreakers: true, noLinebreakers: true,
entities: entities, entities: entities,
noTextFormat: true noTextFormat: true

4
src/lib/appManagers/appImManager.ts

@ -355,7 +355,7 @@ export class AppImManager {
let targets = ids.map(id => ({ let targets = ids.map(id => ({
//element: (this.bubbles[id].querySelector('img, video') || this.bubbles[id].querySelector('image')) as HTMLElement, //element: (this.bubbles[id].querySelector('img, video') || this.bubbles[id].querySelector('image')) as HTMLElement,
element: this.bubbles[id].querySelector('img, video, .bubble__media-container') as HTMLElement, element: this.bubbles[id].querySelector('.attachment img, .preview img, video, .bubble__media-container') as HTMLElement,
mid: id mid: id
})); }));
@ -1490,7 +1490,7 @@ export class AppImManager {
}, this.lazyLoadQueue, 'chat', false, !!message.pending || !multipleRender); }, this.lazyLoadQueue, 'chat', false, !!message.pending || !multipleRender);
break; break;
} else if((doc.type == 'video' || doc.type == 'gif') && doc.size <= 20e6) { } else if((doc.type == 'video' || doc.type == 'gif' || doc.type == 'round') && doc.size <= 20e6) {
this.log('never get free 2', doc); this.log('never get free 2', doc);
if(doc.type == 'round') { if(doc.type == 'round') {

8
src/lib/appManagers/appMediaViewer.ts

@ -7,7 +7,7 @@ import { logger } from "../polyfill";
import ProgressivePreloader from "../../components/preloader"; import ProgressivePreloader from "../../components/preloader";
import { findUpClassName, $rootScope, generatePathData } from "../utils"; import { findUpClassName, $rootScope, generatePathData } from "../utils";
import appDocsManager from "./appDocsManager"; import appDocsManager from "./appDocsManager";
import { wrapPlayer } from "../ckin"; import VideoPlayer from "../mediaPlayer";
import { renderImageFromUrl } from "../../components/misc"; import { renderImageFromUrl } from "../../components/misc";
import appProfileManager from "./appProfileManager"; import appProfileManager from "./appProfileManager";
@ -664,12 +664,10 @@ export class AppMediaViewer {
video.append(source); video.append(source);
} }
let wrapper = wrapPlayer(video); let player = new VideoPlayer(video, true);
(wrapper.querySelector('.toggle') as HTMLButtonElement).click();
}); });
} else { } else {
let wrapper = wrapPlayer(video); let player = new VideoPlayer(video, true);
(wrapper.querySelector('.toggle') as HTMLButtonElement).click();
} }

35
src/lib/appManagers/appSidebarRight.ts

@ -11,7 +11,7 @@ import { logger } from "../polyfill";
import appImManager from "./appImManager"; import appImManager from "./appImManager";
import appMediaViewer from "./appMediaViewer"; import appMediaViewer from "./appMediaViewer";
import LazyLoadQueue from "../../components/lazyLoadQueue"; import LazyLoadQueue from "../../components/lazyLoadQueue";
import { wrapDocument, wrapAudio } from "../../components/wrappers"; import { wrapDocument } from "../../components/wrappers";
import AppSearch, { SearchGroup } from "../../components/appSearch"; import AppSearch, { SearchGroup } from "../../components/appSearch";
const testScroll = false; const testScroll = false;
@ -51,7 +51,7 @@ class AppSidebarRight {
'inputMessagesFilterPhotoVideo', 'inputMessagesFilterPhotoVideo',
'inputMessagesFilterDocument', 'inputMessagesFilterDocument',
'inputMessagesFilterUrl', 'inputMessagesFilterUrl',
'inputMessagesFilterVoice' 'inputMessagesFilterMusic'
]; ];
public sharedMediaType: string = ''; public sharedMediaType: string = '';
private sharedMediaSelected: HTMLDivElement = null; private sharedMediaSelected: HTMLDivElement = null;
@ -227,11 +227,7 @@ class AppSidebarRight {
let elemsToAppend: HTMLElement[] = []; let elemsToAppend: HTMLElement[] = [];
/*'inputMessagesFilterContacts', // https://core.telegram.org/type/MessagesFilter
'inputMessagesFilterPhotoVideo',
'inputMessagesFilterDocument',
'inputMessagesFilterUrl',
'inputMessagesFilterVoice'*/
switch(type) { switch(type) {
case 'inputMessagesFilterPhotoVideo': { case 'inputMessagesFilterPhotoVideo': {
sharedMediaDiv = this.sharedMedia.contentMedia; sharedMediaDiv = this.sharedMedia.contentMedia;
@ -316,7 +312,7 @@ class AppSidebarRight {
sharedMediaDiv = this.sharedMedia.contentDocuments; sharedMediaDiv = this.sharedMedia.contentDocuments;
for(let message of messages) { for(let message of messages) {
if(!message.media.document || message.media.document.type == 'voice') { if(!message.media.document || message.media.document.type == 'voice' || message.media.document.type == 'audio') {
continue; continue;
} }
@ -398,22 +394,19 @@ class AppSidebarRight {
break; break;
} }
/* case 'inputMessagesFilterVoice': { case 'inputMessagesFilterMusic': {
//this.log('wrapping audio', message.media); sharedMediaDiv = this.sharedMedia.contentAudio;
if(!message.media || !message.media.document || message.media.document.type != 'voice') {
break;
}
let doc = message.media.document;
this.log('wrapping audio', doc);
let audioDiv = wrapAudio(doc);
this.sharedMedia.contentAudio.append(audioDiv); for(let message of messages) {
if(!message.media.document || message.media.document.type != 'audio') {
continue;
}
let div = wrapDocument(message.media.document, true);
elemsToAppend.push(div);
}
break; break;
} */ }
default: default:
//console.warn('death is my friend', message); //console.warn('death is my friend', message);

0
src/lib/ckin.js → src/lib/ckin_js.js

6
src/lib/config.js

File diff suppressed because one or more lines are too long

375
src/lib/mediaPlayer.ts

@ -0,0 +1,375 @@
export class MediaProgressLine {
public container: HTMLDivElement;
private filled: HTMLDivElement;
private seek: HTMLInputElement;
private duration = 0;
constructor(private media: HTMLAudioElement | HTMLVideoElement) {
this.container = document.createElement('div');
this.container.classList.add('media-progress');
this.filled = document.createElement('div');
this.filled.classList.add('media-progress__filled');
let seek = this.seek = document.createElement('input');
seek.classList.add('media-progress__seek');
seek.value = '0';
seek.setAttribute('min', '0');
seek.setAttribute('max', '0');
seek.type = 'range';
seek.step = '0.1';
this.setSeekMax();
this.setListeners();
this.container.append(this.filled, seek);
}
private setSeekMax() {
let seek = this.seek;
this.duration = this.media.duration;
if(this.duration > 0) {
seek.setAttribute('max', '' + this.duration * 1000);
} else {
this.media.addEventListener('loadeddata', () => {
this.duration = this.media.duration;
seek.setAttribute('max', '' + this.duration * 1000);
});
}
}
private setProgress() {
let currentTime = this.media.currentTime;
let scaleX = (currentTime / this.duration);
this.filled.style.transform = 'scaleX(' + scaleX + ')';
this.seek.value = '' + currentTime * 1000;
}
private setListeners() {
let mousedown = false;
let stopAndScrubTimeout = 0;
this.media.addEventListener('ended', () => {
this.setProgress();
});
this.media.addEventListener('play', () => {
let r = () => {
this.setProgress();
!this.media.paused && window.requestAnimationFrame(r);
};
window.requestAnimationFrame(r);
});
this.container.addEventListener('mousemove', (e) => {
mousedown && this.scrub(e);
});
this.container.addEventListener('mousedown', (e) => {
this.scrub(e);
//Таймер для того, чтобы стопать видео, если зажал мышку и не отпустил клик
stopAndScrubTimeout = setTimeout(() => {
!this.media.paused && this.media.pause();
stopAndScrubTimeout = 0;
}, 150);
mousedown = true;
});
this.container.addEventListener('mouseup', () => {
if(stopAndScrubTimeout) {
clearTimeout(stopAndScrubTimeout);
}
this.media.paused && this.media.play();
mousedown = false;
});
}
private scrub(e: MouseEvent) {
let scrubTime = e.offsetX / this.container.offsetWidth * this.duration;
this.media.currentTime = scrubTime;
let scaleX = scrubTime / this.duration;
if(scaleX > 1) scaleX = 1;
if(scaleX < 0) scaleX = 0;
this.filled.style.transform = 'scaleX(' + scaleX + ')';
}
}
export default class VideoPlayer {
public wrapper: HTMLDivElement;
private skin: string;
private progress: MediaProgressLine;
constructor(public video: HTMLVideoElement, play = false) {
this.wrapper = document.createElement('div');
this.wrapper.classList.add('ckin__player');
video.parentNode.insertBefore(this.wrapper, video);
this.wrapper.appendChild(video);
this.skin = video.dataset.ckin ?? 'default';
this.stylePlayer();
if(this.skin == 'default') {
let controls = this.wrapper.querySelector('.default__controls.ckin__controls') as HTMLDivElement;
this.progress = new MediaProgressLine(video);
controls.prepend(this.progress.container);
}
if(play) {
(this.wrapper.querySelector('.toggle') as HTMLButtonElement).click();
}
}
private stylePlayer() {
let player = this.wrapper;
let video = this.video;
let skin = this.skin;
player.classList.add(skin);
let html = this.buildControls();
player.insertAdjacentHTML('beforeend', html);
let updateInterval = 0;
let elapsed = 0;
let prevTime = 0;
if(skin === 'default') {
var toggle = player.querySelectorAll('.toggle') as NodeListOf<HTMLElement>;
var fullScreenButton = player.querySelector('.fullscreen') as HTMLElement;
var timeElapsed = player.querySelector('#time-elapsed');
var timeDuration = player.querySelector('#time-duration') as HTMLElement;
timeDuration.innerHTML = String(video.duration | 0).toHHMMSS();
Array.from(toggle).forEach((button) => {
return button.addEventListener('click', () => {
this.togglePlay();
});
});
video.addEventListener('click', () => {
this.togglePlay();
});
video.addEventListener('play', () => {
this.updateButton(toggle);
});
video.addEventListener('pause', () => {
this.updateButton(toggle);
clearInterval(updateInterval);
});
video.addEventListener('dblclick', () => {
return this.toggleFullScreen(fullScreenButton);
})
fullScreenButton.addEventListener('click', (e) => {
return this.toggleFullScreen(fullScreenButton);
});
let b = () => this.onFullScreen();
'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange'.split(' ').forEach(eventName => {
player.addEventListener(eventName, b, false);
});
}
if(skin === 'circle') {
let wrapper = document.createElement('div');
wrapper.classList.add('circle-time-left');
video.parentNode.insertBefore(wrapper, video);
wrapper.innerHTML = '<div class="circle-time"></div><div class="iconVolume tgico-nosound"></div>';
var circle = player.querySelector('.progress-ring__circle') as SVGCircleElement;
var radius = circle.r.baseVal.value;
var circumference = 2 * Math.PI * radius;
var timeDuration = player.querySelector('.circle-time') as HTMLElement;
var iconVolume = player.querySelector('.iconVolume') as HTMLDivElement;
circle.style.strokeDasharray = circumference + ' ' + circumference;
circle.style.strokeDashoffset = '' + circumference;
circle.addEventListener('click', () => {
this.togglePlay();
});
video.addEventListener('play', () => {
iconVolume.style.display = 'none';
updateInterval = setInterval(() => {
//elapsed += 0.02; // Increase with timer interval
if(video.currentTime != prevTime) {
elapsed = video.currentTime; // Update if getCurrentTime was changed
prevTime = video.currentTime;
}
let offset = circumference - elapsed / video.duration * circumference;
circle.style.strokeDashoffset = '' + offset;
if(video.paused) clearInterval(updateInterval);
}, 20);
});
video.addEventListener('pause', () => {
iconVolume.style.display = '';
});
}
if(video.duration > 0) {
timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS();
} else {
video.addEventListener('loadeddata', () => {
timeDuration.innerHTML = String(Math.round(video.duration)).toHHMMSS();
});
}
video.addEventListener('timeupdate', () => {
if(skin == 'default') {
timeElapsed.innerHTML = String(video.currentTime | 0).toHHMMSS();
}
updateInterval = this.handleProgress(timeDuration, circumference, circle, updateInterval);
});
}
public togglePlay(stop?: boolean) {
if(stop) {
this.video.pause();
this.wrapper.classList.remove('is-playing');
return;
} else if(stop === false) {
this.video.play();
this.wrapper.classList.add('is-playing');
return;
}
this.video[this.video.paused ? 'play' : 'pause']();
this.video.paused ? this.wrapper.classList.remove('is-playing') : this.wrapper.classList.add('is-playing');
}
private handleProgress(timeDuration: HTMLElement, circumference: number, circle: SVGCircleElement, updateInterval: number) {
let video = this.video;
let skin = this.skin;
clearInterval(updateInterval);
let elapsed = 0;
let prevTime = 0;
if(skin === 'circle') {
updateInterval = setInterval(() => {
if(video.currentTime != prevTime) {
elapsed = video.currentTime; // Update if getCurrentTime was changed
prevTime = video.currentTime;
}
let offset = circumference - elapsed / video.duration * circumference;
circle.style.strokeDashoffset = '' + offset;
if(video.paused) clearInterval(updateInterval);
}, 20);
let timeLeft = String((video.duration - video.currentTime) | 0).toHHMMSS();
if(timeLeft != '0') timeDuration.innerHTML = timeLeft;
return updateInterval;
}
}
private buildControls() {
let skin = this.skin;
let html = [];
if(skin === 'default') {
html.push('<button class="' + skin + '__button--big toggle tgico-largeplay" title="Toggle Play"></button>');
html.push('<div class="' + skin + '__gradient-bottom ckin__controls"></div>');
html.push('<div class="' + skin + '__controls ckin__controls">');
html.push('<div class="bottom-controls">',
'<div class="left-controls"><button class="' + skin + '__button toggle tgico-play" title="Toggle Video"></button>',
'<div class="time">',
'<time id="time-elapsed">0:00</time>',
'<span> / </span>',
'<time id="time-duration">0:00</time>',
'</div>',
'</div>',
'<div class="right-controls"><button class="' + skin + '__button fullscreen tgico-fullscreen" title="Full Screen"></button></div></div>');
html.push('</div>');
} else if(skin === 'circle') {
html.push('<svg class="progress-ring" width="200px" height="200px">',
'<circle class="progress-ring__circle" stroke="white" stroke-opacity="0.3" stroke-width="3.5" cx="100" cy="100" r="93" fill="transparent" transform="rotate(-90, 100, 100)"/>',
'</svg>');
}
return html.join('');
}
public updateButton(toggle: NodeListOf<HTMLElement>) {
let icon = this.video.paused ? 'tgico-play' : 'tgico-pause';
Array.from(toggle).forEach((button) => {
button.classList.remove('tgico-play', 'tgico-pause');
button.classList.add(icon);
});
}
public toggleFullScreen(fullScreenButton: HTMLElement) {
// alternative standard method
let player = this.wrapper;
// @ts-ignore
if(!document.fullscreenElement && !document.mozFullScreenElement && !document.webkitFullscreenElement && !document.msFullscreenElement) {
player.classList.add('ckin__fullscreen');
if(player.requestFullscreen) {
player.requestFullscreen();
// @ts-ignore
} else if(player.mozRequestFullScreen) {
// @ts-ignore
player.mozRequestFullScreen(); // Firefox
// @ts-ignore
} else if(player.webkitRequestFullscreen) {
// @ts-ignore
player.webkitRequestFullscreen(); // Chrome and Safari
// @ts-ignore
} else if(player.msRequestFullscreen) {
// @ts-ignore
player.msRequestFullscreen();
}
fullScreenButton.classList.remove('tgico-fullscreen');
fullScreenButton.classList.add('tgico-smallscreen');
fullScreenButton.setAttribute('title', 'Exit Full Screen');
} else {
player.classList.remove('ckin__fullscreen');
// @ts-ignore
if(document.cancelFullScreen) {
// @ts-ignore
document.cancelFullScreen();
// @ts-ignore
} else if(document.mozCancelFullScreen) {
// @ts-ignore
document.mozCancelFullScreen();
// @ts-ignore
} else if(document.webkitCancelFullScreen) {
// @ts-ignore
document.webkitCancelFullScreen();
// @ts-ignore
} else if(document.msExitFullscreen) {
// @ts-ignore
document.msExitFullscreen();
}
fullScreenButton.classList.remove('tgico-smallscreen');
fullScreenButton.classList.add('tgico-fullscreen');
fullScreenButton.setAttribute('title', 'Full Screen');
}
}
public onFullScreen() {
// @ts-ignore
let isFullscreenNow = document.webkitFullscreenElement !== null;
if(!isFullscreenNow) {
this.wrapper.classList.remove('ckin__fullscreen');
} else {
}
}
}

6
src/lib/mtproto/networker.ts

@ -2,7 +2,6 @@ import {tsNow, isObject} from '../utils';
import {convertToUint8Array, import {convertToUint8Array,
bufferConcat, nextRandomInt, bytesToHex, longToBytes, bufferConcat, nextRandomInt, bytesToHex, longToBytes,
bytesCmp, uintToInt, bigStringInt} from '../bin_utils'; bytesCmp, uintToInt, bigStringInt} from '../bin_utils';
import {MTProto} from './mtproto';
import {TLDeserialization, TLSerialization} from '../tl_utils'; import {TLDeserialization, TLSerialization} from '../tl_utils';
import CryptoWorker from '../crypto/cryptoworker'; import CryptoWorker from '../crypto/cryptoworker';
import AppStorage from '../storage'; import AppStorage from '../storage';
@ -285,8 +284,11 @@ class MTPNetworker {
} }
if(options.afterMessageID) { if(options.afterMessageID) {
let invokeAfterMsg = Config.Schema.API.methods.find((m: any) => m.method == 'invokeAfterMsg');
if(!invokeAfterMsg) throw new Error('no invokeAfterMsg!');
this.log('Api call options.afterMessageID!'); this.log('Api call options.afterMessageID!');
serializer.storeInt(0xcb9f372d, 'invokeAfterMsg'); serializer.storeInt(+invokeAfterMsg.id >>> 0, 'invokeAfterMsg');
serializer.storeLong(options.afterMessageID, 'msg_id'); serializer.storeLong(options.afterMessageID, 'msg_id');
} }

27
src/lib/tl_utils.ts

@ -9,6 +9,13 @@ import {bigint, intToUint, bigStringInt, bytesToHex, gzipUncompress, uintToInt}
import {isObject} from './utils'; import {isObject} from './utils';
import * as Config from './config'; import * as Config from './config';
const boolFalse = +Config.Schema.API.constructors.find((c: any) => c.predicate == 'boolFalse').id >>> 0;
const boolTrue = +Config.Schema.API.constructors.find((c: any) => c.predicate == 'boolTrue').id >>> 0;
const vector = +Config.Schema.API.constructors.find((c: any) => c.predicate == 'vector').id >>> 0;
const gzipPacked = +Config.Schema.MTProto.constructors.find((c: any) => c.predicate == 'gzip_packed').id >>> 0;
//console.log('boolFalse', boolFalse == 0xbc799737);
class TLSerialization { class TLSerialization {
public maxLength = 2048; // 2Kb public maxLength = 2048; // 2Kb
public offset = 0; // in bytes public offset = 0; // in bytes
@ -92,9 +99,9 @@ class TLSerialization {
public storeBool(i: boolean, field?: string) { public storeBool(i: boolean, field?: string) {
if(i) { if(i) {
this.writeInt(0x997275b5, (field || '') + ':bool'); this.writeInt(boolTrue, (field || '') + ':bool');
} else { } else {
this.writeInt(0xbc799737, (field || '') + ':bool'); this.writeInt(boolFalse, (field || '') + ':bool');
} }
} }
@ -289,7 +296,7 @@ class TLSerialization {
if(Array.isArray(obj)) { if(Array.isArray(obj)) {
if(type.substr(0, 6) == 'Vector') { if(type.substr(0, 6) == 'Vector') {
this.writeInt(0x1cb5c415, field + '[id]'); this.writeInt(vector, field + '[id]');
} else if (type.substr(0, 6) != 'vector') { } else if (type.substr(0, 6) != 'vector') {
throw new Error('Invalid vector type ' + type); throw new Error('Invalid vector type ' + type);
} }
@ -378,7 +385,6 @@ class TLDeserialization {
constructor(buffer: ArrayBuffer | Uint8Array, options: any = {}) { constructor(buffer: ArrayBuffer | Uint8Array, options: any = {}) {
//buffer = addPadding(buffer, 4, true); // fix 21.01.2020 for wss //buffer = addPadding(buffer, 4, true); // fix 21.01.2020 for wss
//console.log("TCL: TLDeserialization -> constructor -> buffer", buffer, buffer instanceof ArrayBuffer);
if(buffer instanceof ArrayBuffer) { if(buffer instanceof ArrayBuffer) {
this.buffer = buffer; this.buffer = buffer;
this.byteView = new Uint8Array(this.buffer); this.byteView = new Uint8Array(this.buffer);
@ -387,6 +393,7 @@ class TLDeserialization {
this.byteView = buffer; this.byteView = buffer;
} }
//console.log("TCL: TLDeserialization -> constructor -> buffer", buffer, this.byteView, this.byteView.hex);
/* this.buffer = buffer; /* this.buffer = buffer;
//this.intView = new Uint32Array(this.buffer); //this.intView = new Uint32Array(this.buffer);
this.byteView = new Uint8Array(this.buffer); */ this.byteView = new Uint8Array(this.buffer); */
@ -444,9 +451,9 @@ class TLDeserialization {
public fetchBool(field?: string) { public fetchBool(field?: string) {
var i = this.readInt((field || '') + ':bool'); var i = this.readInt((field || '') + ':bool');
if(i == 0x997275b5) { if(i == boolTrue) {
return true; return true;
} else if(i == 0xbc799737) { } else if(i == boolFalse) {
return false; return false;
} }
@ -589,7 +596,7 @@ class TLDeserialization {
var constructor = this.readInt(field + '[id]'); var constructor = this.readInt(field + '[id]');
var constructorCmp = uintToInt(constructor); var constructorCmp = uintToInt(constructor);
if(constructorCmp == 0x3072cfa1) { // Gzip packed if(constructorCmp == gzipPacked) { // Gzip packed
var compressed = this.fetchBytes(field + '[packed_string]'); var compressed = this.fetchBytes(field + '[packed_string]');
var uncompressed = gzipUncompress(compressed); var uncompressed = gzipUncompress(compressed);
var newDeserializer = new TLDeserialization(uncompressed); var newDeserializer = new TLDeserialization(uncompressed);
@ -597,7 +604,7 @@ class TLDeserialization {
return newDeserializer.fetchObject(type, field); return newDeserializer.fetchObject(type, field);
} }
if(constructorCmp != 0x1cb5c415) { if(constructorCmp != vector) {
throw new Error('Invalid vector constructor ' + constructor); throw new Error('Invalid vector constructor ' + constructor);
} }
} }
@ -645,7 +652,7 @@ class TLDeserialization {
var constructor = this.readInt(field + '[id]'); var constructor = this.readInt(field + '[id]');
var constructorCmp = uintToInt(constructor); var constructorCmp = uintToInt(constructor);
if(constructorCmp == 0x3072cfa1) { // Gzip packed if(constructorCmp == gzipPacked) { // Gzip packed
var compressed = this.fetchBytes(field + '[packed_string]'); var compressed = this.fetchBytes(field + '[packed_string]');
var uncompressed = gzipUncompress(compressed); var uncompressed = gzipUncompress(compressed);
var newDeserializer = new TLDeserialization(uncompressed); var newDeserializer = new TLDeserialization(uncompressed);
@ -681,7 +688,7 @@ class TLDeserialization {
} }
if(!constructorData) { if(!constructorData) {
throw new Error('Constructor not found: ' + constructor + ' ' + this.fetchInt() + ' ' + this.fetchInt()); throw new Error('Constructor not found: ' + constructor + ' ' + this.fetchInt() + ' ' + this.fetchInt() + ' ' + field);
} }
} }

29
src/scss/partials/_chat.scss

@ -59,13 +59,18 @@ $chat-max-width: 696px;
display: flex; display: flex;
align-items: center; align-items: center;
box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07); box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.07);
padding: .5rem 17px; padding: .5rem 15px;
flex: 0 0 auto; /* Forces side columns to stay same width */ flex: 0 0 auto; /* Forces side columns to stay same width */
min-height: 60px; min-height: 61px;
max-height: 60px; max-height: 61px;
border-bottom: 1px solid #DADCE0;
& > * { /* & > * {
margin: 0 2px; margin: 0 2px;
} */
.chat-more-button {
margin-left: 8px;
} }
.chat-info { .chat-info {
@ -82,6 +87,7 @@ $chat-max-width: 696px;
display: flex; display: flex;
align-items: center; align-items: center;
cursor: pointer; cursor: pointer;
margin-left: 4px;
&:hover { &:hover {
background-color: transparent; background-color: transparent;
@ -168,7 +174,7 @@ $chat-max-width: 696px;
&.is-chat { &.is-chat {
.is-in .bubble__container { .is-in .bubble__container {
margin-left: 45px; margin-left: 3rem;
} }
} }
@ -207,10 +213,10 @@ $chat-max-width: 696px;
.service-msg { .service-msg {
color: #fff; color: #fff;
background-color: rgba(#000, 0.22); background-color: rgba(0, 0, 0, 0.24);
font-size: 14px;
padding: 0 8px; padding: 0 8px;
line-height: 24px; line-height: 24px;
font-size: 15px;
border-radius: 12px; border-radius: 12px;
user-select: none; user-select: none;
display: flex; display: flex;
@ -250,7 +256,8 @@ $chat-max-width: 696px;
} }
&__container { &__container {
min-width: 60px; //min-width: 60px;
min-width: 56px;
max-width: 85%; max-width: 85%;
border-radius: 12px; border-radius: 12px;
box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.15); box-shadow: 0 1px 2px 0 rgba(16, 35, 47, 0.15);
@ -685,10 +692,10 @@ $chat-max-width: 696px;
.message { .message {
position: absolute; position: absolute;
bottom: .1rem; bottom: .1rem;
right: .1rem; right: .2rem;
border-radius: 12px; border-radius: 12px;
background-color: rgba(0, 0, 0, .4); background-color: rgba(0, 0, 0, .4);
padding: 0 .3rem; padding: 0 .2rem;
z-index: 2; z-index: 2;
.time { .time {
@ -1064,7 +1071,7 @@ $chat-max-width: 696px;
} }
} }
&-time { &-time, &-subtitle {
color: #68AB5A; color: #68AB5A;
} }

9
src/scss/partials/_chatlist.scss

@ -120,7 +120,7 @@
/* font-size: .9rem; */ /* font-size: .9rem; */
//font-size: .8rem; //font-size: .8rem;
font-size: .75rem; font-size: .75rem;
padding: 2px 0px 0px 0px; padding: 1px 0px 0px 0px;
} }
.user-last-message + span:not(.tgico-pinnedchat) { .user-last-message + span:not(.tgico-pinnedchat) {
@ -153,7 +153,12 @@
color: $color-gray; color: $color-gray;
flex: 1 1 auto; flex: 1 1 auto;
padding-right: 3.5px; padding-right: 3.5px;
padding-left: 10px; padding-left: 9px;
padding-top: 1px;
p:last-child {
margin-top: -3px;
}
} }
.user-title { .user-title {

92
src/scss/partials/_ckin.scss

@ -175,23 +175,23 @@
transform: translateY(0); transform: translateY(0);
} }
.default .progress { .default {
position: relative; .media-progress {
margin: 0 16px; margin: 0 16px;
height: 5px; height: 5px;
transition: height 0.3s; transition: height 0.3s;
background: rgba(255, 255, 255, 0.38); background: rgba(255, 255, 255, 0.38);
cursor: pointer;
border-radius: 4px; border-radius: 4px;
overflow: visible; overflow: visible;
}
.default .progress__filled { &__filled {
background: #63a2e3; background: #63a2e3;
transform-origin: left; transform-origin: left;
border-radius: 4px; border-radius: 4px;
height: 5px; height: 5px;
transform: scaleX(0); transform: scaleX(0);
}
}
} }
@media (max-width: 480px) { @media (max-width: 480px) {
@ -204,7 +204,11 @@ video::-webkit-media-controls-enclosure {
display: none !important; display: none !important;
} }
.progress input { .media-progress {
position: relative;
cursor: pointer;
input[type=range] {
-webkit-appearance: none; -webkit-appearance: none;
-moz-appearance: none; -moz-appearance: none;
background: transparent; background: transparent;
@ -212,21 +216,28 @@ video::-webkit-media-controls-enclosure {
cursor: pointer; cursor: pointer;
padding: 0; padding: 0;
outline: none; outline: none;
}
.progress input[type=range]:focus { &:focus {
outline: none; outline: none;
}
.progress input[type=range]::-webkit-slider-runnable-track { &::-webkit-slider-runnable-track {
background: transparent;
}
&::-moz-range-track {
outline: none;
}
}
&::-webkit-slider-runnable-track {
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
border-radius: 1.3px; border-radius: 1.3px;
-webkit-appearance: none; -webkit-appearance: none;
transition: all 0.4s ease; transition: all 0.4s ease;
} }
.progress input[type=range]::-webkit-slider-thumb { &::-webkit-slider-thumb {
height: 15px; height: 15px;
width: 15px; width: 15px;
border-radius: 16px; border-radius: 16px;
@ -234,22 +245,18 @@ video::-webkit-media-controls-enclosure {
cursor: pointer; cursor: pointer;
-webkit-appearance: none; -webkit-appearance: none;
margin-left: -1px; margin-left: -1px;
} }
.progress input[type=range]:focus::-webkit-slider-runnable-track {
background: transparent;
}
.progress input[type=range]::-moz-range-track { &::-moz-range-track {
width: 100%; width: 100%;
height: 8.4px; height: 8.4px;
cursor: pointer; cursor: pointer;
border: 1px solid transparent; border: 1px solid transparent;
background: transparent; background: transparent;
border-radius: 1.3px; border-radius: 1.3px;
} }
.progress input[type=range]::-moz-range-thumb { &::-moz-range-thumb {
height: 14px; height: 14px;
width: 14px; width: 14px;
border-radius: 50px; border-radius: 50px;
@ -257,40 +264,36 @@ video::-webkit-media-controls-enclosure {
background: #63a2e3; background: #63a2e3;
cursor: pointer; cursor: pointer;
margin-top: 5px; margin-top: 5px;
} }
}
.progress input[type=range]:focus::-moz-range-track { &__seek {
outline: none; position: absolute;
top: 0;
width: 100%;
cursor: pointer;
margin: 0;
}
} }
input[type=range]::-ms-track { input[type=range] {
&::-ms-track {
visibility: hidden; visibility: hidden;
} }
input[type=range]::-ms-ticks { &::-ms-ticks {
background: none; background: none;
color: none; color: none;
border: none; border: none;
} }
input[type=range]::-ms-thumb { &::-ms-thumb {
visibility: hidden; visibility: hidden;
} }
input[type=range]::-ms-tooltip { &::-ms-tooltip {
visibility: hidden; visibility: hidden;
} }
.seek {
position: absolute;
top: 0;
width: 100%;
cursor: pointer;
margin: 0;
}
.seek:hover + .seek-tooltip {
display: block;
} }
.left-controls { .left-controls {
@ -342,9 +345,10 @@ video[data-ckin="circle"] {
top: 0; top: 0;
left: 0; left: 0;
cursor: pointer; cursor: pointer;
}
.progress-ring__circle { &__circle {
transition: stroke-dashoffset; transition: stroke-dashoffset;
}
} }
.ckin__player.circle { .ckin__player.circle {

25
src/scss/partials/_emojiDropdown.scss

@ -15,7 +15,7 @@
overflow: hidden; overflow: hidden;
transition: all 0.2s ease-out; transition: all 0.2s ease-out;
transform: scale(0); //transform: scale(0);
transform-origin: 0 100%; transform-origin: 0 100%;
&.active { &.active {
@ -232,4 +232,27 @@
} }
} }
} }
#content-gifs {
.gifs-masonry {
display: flex;
flex-wrap: wrap;
> div {
flex: 1 0 auto;
max-width: 100%;
height: 100px;
margin: 2.5px;
cursor: pointer;
background: #000;
position: relative;
video {
object-fit: cover;
width: 100%;
height: 100%;
}
}
}
}
} }

82
src/scss/partials/_rightSIdebar.scss

@ -28,6 +28,7 @@
.sidebar-header { .sidebar-header {
flex: 0 0 auto; flex: 0 0 auto;
padding: 10px 20px 11px 15px;
} }
#search-private-container { #search-private-container {
@ -38,17 +39,39 @@
} }
} }
.profile-content { .profile {
&-content {
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
.profile-name { [type="checkbox"] + span {
padding-left: 54px;
margin-left: -54px;
}
&-wrapper {
flex: 0 0 auto;
display: flex;
flex-direction: column;
}
.content-container {
width: 100%;
max-width: 100%;
//overflow: hidden;
flex: 1 1 auto;
position: relative;
//height: 1%; // fix safari
}
}
&-name {
text-align: center; text-align: center;
font-size: 23px; font-size: 24px;
line-height: 1.4;
font-weight: 500; font-weight: 500;
margin-bottom: 3px;
span.emoji { span.emoji {
vertical-align: inherit; vertical-align: inherit;
@ -56,26 +79,27 @@
} }
} }
.profile-subtitle { &-subtitle {
text-align: center; text-align: center;
color: $darkgrey; color: $darkgrey;
font-size: 14px; font-size: 14px;
margin-bottom: 2px;
&.online { &.online {
color: $darkblue; color: $darkblue;
} }
} }
.profile-row { &-row {
display: flex; display: flex;
width: 100%; width: 100%;
flex-direction: column; flex-direction: column;
padding-left: 80px; padding-left: 80px;
padding-top: 2px;
padding-right: 12px; padding-right: 12px;
font-size: 15px; font-size: 15px;
position: relative; position: relative;
margin-top: 1.75rem; margin-top: 31px;
line-height: 1.4;
&:before { &:before {
position: absolute; position: absolute;
@ -88,6 +112,7 @@
p { p {
color: #000; color: #000;
margin: 0; margin: 0;
font-size: 1rem;
} }
&-bio { &-bio {
@ -96,48 +121,28 @@
height: 24px; height: 24px;
} }
} }
}
p.profile-row-label { &-label {
color: $placeholder-color; color: $placeholder-color !important;
font-size: 14px; font-size: 14px !important;
margin-top: 1px; }
} }
.profile-avatar.user-avatar { &-avatar.user-avatar {
width: 120px; width: 120px;
height: 120px; height: 120px;
margin: 0 auto 20px; margin: 0 auto 21px;
font-size: 4rem; font-size: 4rem !important;
&.tgico-avatar_deletedaccount { &.tgico-avatar_deletedaccount {
font-size: 6rem; font-size: 6rem;
} }
} }
[type="checkbox"] + span { &-tabs {
padding-left: 54px; margin-top: 36px;
margin-left: -54px;
}
&-wrapper {
flex: 0 0 auto;
}
.content-container {
width: 100%;
max-width: 100%;
//overflow: hidden;
flex: 1 1 auto;
position: relative;
//height: 1%; // fix safari
}
.profile-tabs {
margin-top: 40px;
}
.profile-tabs-content { &-content {
min-height: 100%; min-height: 100%;
position: absolute; // FIX THE SAFARI! position: absolute; // FIX THE SAFARI!
/* width: 500%; /* width: 500%;
@ -304,4 +309,5 @@
} }
} }
} }
}
} }

8
src/scss/partials/_sidebar.scss

@ -19,9 +19,9 @@
&__title { &__title {
flex: 1; flex: 1;
padding-left: 2rem;
font-weight: 500; font-weight: 500;
font-size: 1.4rem; padding-left: 23px;
font-size: 20px;
} }
.btn-icon + .btn-icon { .btn-icon + .btn-icon {
@ -29,6 +29,10 @@
} }
} }
&-close-button {
padding-left: 10px;
}
&-content { &-content {
width: 100%; width: 100%;
max-height: 100%; max-height: 100%;

7
src/scss/style.scss

@ -485,7 +485,12 @@ input {
} }
} }
&-time { &-title {
font-size: 1rem;
color: #000;
}
&-time, &-subtitle {
font-size: 14px; font-size: 14px;
color: $color-gray; color: $color-gray;
margin-top: 3px; margin-top: 3px;

Loading…
Cancel
Save