Browse Source

Send stickers, gifs, polls, media, document rights

master
morethanwords 4 years ago
parent
commit
37a1eaa37d
  1. 97
      src/components/chat/input.ts
  2. 69
      src/components/emoticonsDropdown/index.ts
  3. 12
      src/components/emoticonsDropdown/tabs/emoji.ts
  4. 40
      src/components/emoticonsDropdown/tabs/stickers.ts
  5. 2
      src/components/horizontalMenu.ts
  6. 4
      src/components/popupCreatePoll.ts
  7. 52
      src/index.hbs
  8. 14
      src/lib/appManagers/appChatsManager.ts
  9. 4
      src/lib/rootScope.ts
  10. 2
      src/scss/partials/_chat.scss
  11. 28
      src/scss/partials/_emojiDropdown.scss
  12. 75
      src/scss/partials/_slider.scss
  13. 7
      src/scss/style.scss

97
src/components/chat/input.ts

@ -1,5 +1,6 @@
import Recorder from '../../../public/recorder.min'; import Recorder from '../../../public/recorder.min';
import { isTouchSupported } from "../../helpers/touchSupport"; import { isTouchSupported } from "../../helpers/touchSupport";
import appChatsManager from '../../lib/appManagers/appChatsManager';
import appDocsManager from "../../lib/appManagers/appDocsManager"; import appDocsManager from "../../lib/appManagers/appDocsManager";
import appImManager from "../../lib/appManagers/appImManager"; import appImManager from "../../lib/appManagers/appImManager";
import appMessagesManager from "../../lib/appManagers/appMessagesManager"; import appMessagesManager from "../../lib/appManagers/appMessagesManager";
@ -8,15 +9,19 @@ import apiManager from "../../lib/mtproto/mtprotoworker";
//import Recorder from '../opus-recorder/dist/recorder.min'; //import Recorder from '../opus-recorder/dist/recorder.min';
import opusDecodeController from "../../lib/opusDecodeController"; import opusDecodeController from "../../lib/opusDecodeController";
import { RichTextProcessor } from "../../lib/richtextprocessor"; import { RichTextProcessor } from "../../lib/richtextprocessor";
import $rootScope from '../../lib/rootScope';
import { calcImageInBox, cancelEvent, getRichValue } from "../../lib/utils"; import { calcImageInBox, cancelEvent, getRichValue } from "../../lib/utils";
import ButtonMenu, { ButtonMenuItemOptions } from '../buttonMenu';
import emoticonsDropdown from "../emoticonsDropdown"; import emoticonsDropdown from "../emoticonsDropdown";
import { Layouter, RectPart } from "../groupedLayout"; import { Layouter, RectPart } from "../groupedLayout";
import PopupCreatePoll from "../popupCreatePoll"; import PopupCreatePoll from "../popupCreatePoll";
import { ripple } from '../ripple';
import Scrollable from "../scrollable"; import Scrollable from "../scrollable";
import { toast } from "../toast"; import { toast } from "../toast";
import { wrapDocument, wrapReply } from "../wrappers"; import { wrapDocument, wrapReply } from "../wrappers";
const RECORD_MIN_TIME = 500; const RECORD_MIN_TIME = 500;
const POSTING_MEDIA_NOT_ALLOWED = 'Posting media content isn\'t allowed in this group.';
export class ChatInput { export class ChatInput {
public pageEl = document.getElementById('page-chats') as HTMLDivElement; public pageEl = document.getElementById('page-chats') as HTMLDivElement;
@ -32,12 +37,8 @@ export class ChatInput {
private inputContainer = this.btnSend.parentElement.parentElement as HTMLDivElement; private inputContainer = this.btnSend.parentElement.parentElement as HTMLDivElement;
private chatInput = this.inputContainer.parentElement as HTMLDivElement; private chatInput = this.inputContainer.parentElement as HTMLDivElement;
public attachMenu: { public attachMenu: HTMLButtonElement;
container?: HTMLButtonElement, private attachMenuButtons: (ButtonMenuItemOptions & {verify: (peerID: number) => boolean})[];
media?: HTMLDivElement,
document?: HTMLDivElement,
poll?: HTMLDivElement
} = {};
public attachMediaPopUp: { public attachMediaPopUp: {
container?: HTMLDivElement, container?: HTMLDivElement,
@ -71,10 +72,49 @@ export class ChatInput {
private scrollDiff = 0; private scrollDiff = 0;
constructor() { constructor() {
this.attachMenu.container = document.getElementById('attach-file') as HTMLButtonElement; this.attachMenu = document.getElementById('attach-file') as HTMLButtonElement;
this.attachMenu.media = this.attachMenu.container.querySelector('.menu-media') as HTMLDivElement;
this.attachMenu.document = this.attachMenu.container.querySelector('.menu-document') as HTMLDivElement; this.attachMenuButtons = [{
this.attachMenu.poll = this.attachMenu.container.querySelector('.menu-poll') as HTMLDivElement; icon: 'photo',
text: 'Photo or Video',
onClick: () => {
this.fileInput.setAttribute('accept', 'image/*, video/*');
willAttach.type = 'media';
this.fileInput.click();
},
verify: (peerID: number) => peerID > 0 || appChatsManager.hasRights(peerID, 'send', 'send_media')
}, {
icon: 'document',
text: 'Document',
onClick: () => {
this.fileInput.removeAttribute('accept');
willAttach.type = 'document';
this.fileInput.click();
},
verify: (peerID: number) => peerID > 0 || appChatsManager.hasRights(peerID, 'send', 'send_media')
}, {
icon: 'poll',
text: 'Poll',
onClick: () => {
new PopupCreatePoll().show();
},
verify: (peerID: number) => peerID < 0 && appChatsManager.hasRights(peerID, 'send', 'send_polls')
}];
/* this.attachMenu.addEventListener('mousedown', (e) => {
const hidden = this.attachMenu.querySelectorAll('.hide');
if(hidden.length == this.attachMenuButtons.length) {
toast(POSTING_MEDIA_NOT_ALLOWED);
cancelEvent(e);
return false;
}
}, {passive: false, capture: true}); */
const attachBtnMenu = ButtonMenu(this.attachMenuButtons);
attachBtnMenu.classList.add('top-left');
this.attachMenu.append(attachBtnMenu);
ripple(this.attachMenu);
this.attachMediaPopUp.container = this.pageEl.querySelector('.popup-send-photo') as HTMLDivElement; this.attachMediaPopUp.container = this.pageEl.querySelector('.popup-send-photo') as HTMLDivElement;
this.attachMediaPopUp.titleEl = this.attachMediaPopUp.container.querySelector('.popup-title') as HTMLDivElement; this.attachMediaPopUp.titleEl = this.attachMediaPopUp.container.querySelector('.popup-title') as HTMLDivElement;
@ -103,6 +143,19 @@ export class ChatInput {
this.updateSendBtn(); this.updateSendBtn();
$rootScope.$on('peer_changed', (e) => {
const peerID = e.detail;
const visible = this.attachMenuButtons.filter(button => {
const good = button.verify(peerID);
button.element.classList.toggle('hide', !good);
return good;
});
this.attachMenu.toggleAttribute('disabled', !visible.length);
this.updateSendBtn();
});
this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => { this.messageInput.addEventListener('keydown', (e: KeyboardEvent) => {
if(e.key == 'Enter' && !isTouchSupported) { if(e.key == 'Enter' && !isTouchSupported) {
/* if(e.ctrlKey || e.metaKey) { /* if(e.ctrlKey || e.metaKey) {
@ -429,24 +482,9 @@ export class ChatInput {
attachFiles(Array.from(files)); attachFiles(Array.from(files));
}, false); }, false);
this.attachMenu.media.addEventListener('click', () => {
this.fileInput.setAttribute('accept', 'image/*, video/*');
willAttach.type = 'media';
this.fileInput.click();
});
this.attachMenu.document.addEventListener('click', () => {
this.fileInput.removeAttribute('accept');
willAttach.type = 'document';
this.fileInput.click();
});
this.attachMenu.poll.addEventListener('click', () => {
new PopupCreatePoll().show();
});
document.addEventListener('paste', (event) => { document.addEventListener('paste', (event) => {
if(!appImManager.peerID || this.attachMediaPopUp.container.classList.contains('active')) { const peerID = $rootScope.selectedPeerID;
if(!peerID || this.attachMediaPopUp.container.classList.contains('active') || (peerID < 0 && !appChatsManager.hasRights(peerID, 'send', 'send_media'))) {
return; return;
} }
@ -529,6 +567,11 @@ export class ChatInput {
this.sendMessage(); this.sendMessage();
} }
} else { } else {
if($rootScope.selectedPeerID < 0 && !appChatsManager.hasRights($rootScope.selectedPeerID, 'send', 'send_media')) {
toast(POSTING_MEDIA_NOT_ALLOWED);
return;
}
this.chatInput.classList.add('is-locked'); this.chatInput.classList.add('is-locked');
this.recorder.start().then(() => { this.recorder.start().then(() => {
this.recordCanceled = false; this.recordCanceled = false;

69
src/components/emoticonsDropdown/index.ts

@ -1,16 +1,18 @@
import LazyLoadQueue, { LazyLoadQueueIntersector } from "../lazyLoadQueue"; import { isTouchSupported } from "../../helpers/touchSupport";
import GifsTab from "./tabs/gifs"; import appChatsManager from "../../lib/appManagers/appChatsManager";
import appImManager from "../../lib/appManagers/appImManager";
import { MOUNT_CLASS_TO } from "../../lib/mtproto/mtproto_config";
import $rootScope from "../../lib/rootScope";
import { findUpClassName, findUpTag, whichChild } from "../../lib/utils"; import { findUpClassName, findUpTag, whichChild } from "../../lib/utils";
import { horizontalMenu } from "../horizontalMenu";
import animationIntersector from "../animationIntersector"; import animationIntersector from "../animationIntersector";
import appSidebarRight from "../sidebarRight"; import { horizontalMenu } from "../horizontalMenu";
import appImManager from "../../lib/appManagers/appImManager"; import LazyLoadQueue, { LazyLoadQueueIntersector } from "../lazyLoadQueue";
import Scrollable, { ScrollableX } from "../scrollable"; import Scrollable, { ScrollableX } from "../scrollable";
import appSidebarRight from "../sidebarRight";
import StickyIntersector from "../stickyIntersector";
import EmojiTab from "./tabs/emoji"; import EmojiTab from "./tabs/emoji";
import GifsTab from "./tabs/gifs";
import StickersTab from "./tabs/stickers"; import StickersTab from "./tabs/stickers";
import StickyIntersector from "../stickyIntersector";
import { MOUNT_CLASS_TO } from "../../lib/mtproto/mtproto_config";
import { isTouchSupported } from "../../helpers/touchSupport";
export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown'; export const EMOTICONSSTICKERGROUP = 'emoticons-dropdown';
@ -53,6 +55,8 @@ export class EmoticonsDropdown {
onOpenAfter: [] onOpenAfter: []
}; };
private selectTab: ReturnType<typeof horizontalMenu>;
constructor() { constructor() {
this.element = document.getElementById('emoji-dropdown') as HTMLDivElement; this.element = document.getElementById('emoji-dropdown') as HTMLDivElement;
@ -113,13 +117,7 @@ export class EmoticonsDropdown {
this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement; this.container = this.element.querySelector('.emoji-container .tabs-container') as HTMLDivElement;
this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement; this.tabsEl = this.element.querySelector('.emoji-tabs') as HTMLUListElement;
horizontalMenu(this.tabsEl, this.container, (id) => { this.selectTab = horizontalMenu(this.tabsEl, this.container, this.onSelectTabClick, () => {
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
this.tabID = id;
this.searchButton.classList.toggle('hide', this.tabID == 0);
this.deleteBtn.classList.toggle('hide', this.tabID != 0);
}, () => {
const tab = this.tabs[this.tabID]; const tab = this.tabs[this.tabID];
if(tab.init) { if(tab.init) {
tab.init(); tab.init();
@ -156,10 +154,45 @@ export class EmoticonsDropdown {
//appSidebarRight.stickersTab.init(); //appSidebarRight.stickersTab.init();
}); });
(this.tabsEl.firstElementChild.children[1] as HTMLLIElement).click(); // set emoji tab (this.tabsEl.children[1] as HTMLLIElement).click(); // set emoji tab
this.tabs[0].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка this.tabs[0].init(); // onTransitionEnd не вызовется, т.к. это первая открытая вкладка
$rootScope.$on('peer_changed', this.checkRights);
this.checkRights();
} }
private onSelectTabClick = (id: number) => {
if(this.tabID == id) {
return;
}
animationIntersector.checkAnimations(true, EMOTICONSSTICKERGROUP);
this.tabID = id;
this.searchButton.classList.toggle('hide', this.tabID == 0);
this.deleteBtn.classList.toggle('hide', this.tabID != 0);
};
public checkRights = () => {
const peerID = $rootScope.selectedPeerID;
const children = this.tabsEl.children;
const tabsElements = Array.from(children) as HTMLElement[];
const canSendStickers = peerID > 0 || appChatsManager.hasRights(peerID, 'send', 'send_stickers');
tabsElements[2].toggleAttribute('disabled', !canSendStickers);
const canSendGifs = peerID > 0 || appChatsManager.hasRights(peerID, 'send', 'send_gifs');
tabsElements[3].toggleAttribute('disabled', !canSendGifs);
const active = this.tabsEl.querySelector('.active');
if(active && whichChild(active) != 1 && (!canSendStickers || !canSendGifs)) {
this.selectTab(0);
this.onSelectTabClick(0);
active.classList.remove('active');
children[1].classList.add('active');
}
};
public toggle = async(enable?: boolean) => { public toggle = async(enable?: boolean) => {
//if(!this.element) return; //if(!this.element) return;
const willBeActive = (!!this.element.style.display && enable === undefined) || enable; const willBeActive = (!!this.element.style.display && enable === undefined) || enable;
@ -241,7 +274,7 @@ export class EmoticonsDropdown {
//animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP); //animationIntersector.checkAnimations(false, EMOTICONSSTICKERGROUP);
}; };
public static menuOnClick = (menu: HTMLUListElement, scroll: Scrollable, menuScroll?: ScrollableX) => { public static menuOnClick = (menu: HTMLElement, scroll: Scrollable, menuScroll?: ScrollableX) => {
let prevId = 0; let prevId = 0;
let jumpedTo = -1; let jumpedTo = -1;
@ -284,7 +317,7 @@ export class EmoticonsDropdown {
menu.addEventListener('click', (e) => { menu.addEventListener('click', (e) => {
let target = e.target as HTMLElement; let target = e.target as HTMLElement;
target = findUpTag(target, 'LI'); target = findUpClassName(target, 'menu-horizontal-div-item');
if(!target) { if(!target) {
return; return;

12
src/components/emoticonsDropdown/tabs/emoji.ts

@ -1,10 +1,10 @@
import { EmoticonsTab, EmoticonsDropdown } from ".."; import { EmoticonsDropdown, EmoticonsTab } from "..";
import Scrollable from "../../scrollable"; import appImManager from "../../../lib/appManagers/appImManager";
import Config from "../../../lib/config";
import { putPreloader } from "../../misc";
import appStateManager from "../../../lib/appManagers/appStateManager"; import appStateManager from "../../../lib/appManagers/appStateManager";
import Config from "../../../lib/config";
import { RichTextProcessor } from "../../../lib/richtextprocessor"; import { RichTextProcessor } from "../../../lib/richtextprocessor";
import appImManager from "../../../lib/appManagers/appImManager"; import { putPreloader } from "../../misc";
import Scrollable from "../../scrollable";
import StickyIntersector from "../../stickyIntersector"; import StickyIntersector from "../../stickyIntersector";
export default class EmojiTab implements EmoticonsTab { export default class EmojiTab implements EmoticonsTab {
@ -80,7 +80,7 @@ export default class EmojiTab implements EmoticonsTab {
} }
//console.timeEnd('emojiParse'); //console.timeEnd('emojiParse');
const menu = this.content.previousElementSibling.firstElementChild as HTMLUListElement; const menu = this.content.previousElementSibling as HTMLElement;
const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI', null); const emojiScroll = this.scroll = new Scrollable(this.content, 'EMOJI', null);
//emojiScroll.setVirtualContainer(emojiScroll.container); //emojiScroll.setVirtualContainer(emojiScroll.container);

40
src/components/emoticonsDropdown/tabs/stickers.ts

@ -1,20 +1,20 @@
import emoticonsDropdown, { EmoticonsTab, EMOTICONSSTICKERGROUP, EmoticonsDropdown } from ".."; import emoticonsDropdown, { EmoticonsDropdown, EMOTICONSSTICKERGROUP, EmoticonsTab } from "..";
import { readBlobAsText } from "../../../helpers/blob";
import mediaSizes from "../../../helpers/mediaSizes";
import { StickerSet } from "../../../layer"; import { StickerSet } from "../../../layer";
import Scrollable, { ScrollableX } from "../../scrollable"; import appDocsManager, { MyDocument } from "../../../lib/appManagers/appDocsManager";
import { wrapSticker } from "../../wrappers";
import appStickersManager from "../../../lib/appManagers/appStickersManager";
import appDownloadManager from "../../../lib/appManagers/appDownloadManager"; import appDownloadManager from "../../../lib/appManagers/appDownloadManager";
import { readBlobAsText } from "../../../helpers/blob"; import appStickersManager from "../../../lib/appManagers/appStickersManager";
import lottieLoader from "../../../lib/lottieLoader"; import lottieLoader from "../../../lib/lottieLoader";
import { renderImageFromUrl, putPreloader } from "../../misc"; import apiManager from "../../../lib/mtproto/mtprotoworker";
import { RichTextProcessor } from "../../../lib/richtextprocessor"; import { RichTextProcessor } from "../../../lib/richtextprocessor";
import $rootScope from "../../../lib/rootScope"; import $rootScope from "../../../lib/rootScope";
import apiManager from "../../../lib/mtproto/mtprotoworker";
import StickyIntersector from "../../stickyIntersector";
import appDocsManager, {MyDocument} from "../../../lib/appManagers/appDocsManager";
import animationIntersector from "../../animationIntersector"; import animationIntersector from "../../animationIntersector";
import { LazyLoadQueueRepeat } from "../../lazyLoadQueue"; import { LazyLoadQueueRepeat } from "../../lazyLoadQueue";
import mediaSizes from "../../../helpers/mediaSizes"; import { putPreloader, renderImageFromUrl } from "../../misc";
import Scrollable, { ScrollableX } from "../../scrollable";
import StickyIntersector from "../../stickyIntersector";
import { wrapSticker } from "../../wrappers";
export default class StickersTab implements EmoticonsTab { export default class StickersTab implements EmoticonsTab {
public content: HTMLElement; public content: HTMLElement;
@ -29,7 +29,7 @@ export default class StickersTab implements EmoticonsTab {
private scroll: Scrollable; private scroll: Scrollable;
private menu: HTMLUListElement; private menu: HTMLElement;
private mounted = false; private mounted = false;
@ -110,18 +110,18 @@ export default class StickersTab implements EmoticonsTab {
const categoryDiv = document.createElement('div'); const categoryDiv = document.createElement('div');
categoryDiv.classList.add('sticker-category'); categoryDiv.classList.add('sticker-category');
const li = document.createElement('li'); const button = document.createElement('button');
li.classList.add('btn-icon'); button.classList.add('btn-icon', 'menu-horizontal-div-item');
this.stickerSets[set.id] = { this.stickerSets[set.id] = {
stickers: categoryDiv, stickers: categoryDiv,
tab: li tab: button
}; };
if(prepend) { if(prepend) {
this.menu.insertBefore(li, this.menu.firstElementChild.nextSibling); this.menu.insertBefore(button, this.menu.firstElementChild.nextSibling);
} else { } else {
this.menu.append(li); this.menu.append(button);
} }
//stickersScroll.append(categoryDiv); //stickersScroll.append(categoryDiv);
@ -142,7 +142,7 @@ export default class StickersTab implements EmoticonsTab {
//.then(JSON.parse) //.then(JSON.parse)
.then(json => { .then(json => {
lottieLoader.loadAnimationWorker({ lottieLoader.loadAnimationWorker({
container: li, container: button,
loop: true, loop: true,
autoplay: false, autoplay: false,
animationData: json, animationData: json,
@ -155,14 +155,14 @@ export default class StickersTab implements EmoticonsTab {
const image = new Image(); const image = new Image();
promise.then(blob => { promise.then(blob => {
renderImageFromUrl(image, URL.createObjectURL(blob), () => { renderImageFromUrl(image, URL.createObjectURL(blob), () => {
li.append(image); button.append(image);
}); });
}); });
} }
} else if(stickerSet.documents[0]._ != 'documentEmpty') { // as thumb will be used first sticker } else if(stickerSet.documents[0]._ != 'documentEmpty') { // as thumb will be used first sticker
wrapSticker({ wrapSticker({
doc: stickerSet.documents[0], doc: stickerSet.documents[0],
div: li as any, div: button as any,
group: EMOTICONSSTICKERGROUP group: EMOTICONSSTICKERGROUP
}); // kostil }); // kostil
} }
@ -230,7 +230,7 @@ export default class StickersTab implements EmoticonsTab {
this.recentDiv.classList.add('sticker-category'); this.recentDiv.classList.add('sticker-category');
let menuWrapper = this.content.previousElementSibling as HTMLDivElement; let menuWrapper = this.content.previousElementSibling as HTMLDivElement;
this.menu = menuWrapper.firstElementChild.firstElementChild as HTMLUListElement; this.menu = menuWrapper.firstElementChild as HTMLUListElement;
let menuScroll = new ScrollableX(menuWrapper); let menuScroll = new ScrollableX(menuWrapper);

2
src/components/horizontalMenu.ts

@ -116,7 +116,7 @@ export function horizontalMenu(tabs: HTMLElement, content: HTMLElement, onClick?
if(tabs) { if(tabs) {
const useStripe = !tabs.classList.contains('no-stripe'); const useStripe = !tabs.classList.contains('no-stripe');
const tagName = 'LI';//tabs.firstElementChild.tagName; const tagName = tabs.classList.contains('menu-horizontal-div') ? 'BUTTON' : 'LI';//tabs.firstElementChild.tagName;
tabs.addEventListener('click', function(e) { tabs.addEventListener('click', function(e) {
let target = e.target as HTMLElement; let target = e.target as HTMLElement;

4
src/components/popupCreatePoll.ts

@ -179,7 +179,9 @@ export default class PopupCreatePoll extends PopupElement {
}; };
//poll.id = randomIDS; //poll.id = randomIDS;
const inputMediaPoll = appPollsManager.getInputMediaPoll(poll, this.correctAnswers, this.quizSolutionInput ? this.quizSolutionInput.value : undefined); const inputMediaPoll = appPollsManager.getInputMediaPoll(poll, this.correctAnswers, this.quizSolutionInput.value || undefined);
//console.log('Will try to create poll:', inputMediaPoll);
appMessagesManager.sendOther($rootScope.selectedPeerID, inputMediaPoll); appMessagesManager.sendOther($rootScope.selectedPeerID, inputMediaPoll);
}; };

52
src/index.hbs

@ -513,13 +513,7 @@
<div class="input-message-container"> <div class="input-message-container">
<div id="input-message" contenteditable="true" data-placeholder="Message"></div> <div id="input-message" contenteditable="true" data-placeholder="Message"></div>
</div> </div>
<button class="btn-icon rp tgico-attach btn-menu-toggle" id="attach-file"> <button class="btn-icon tgico-attach btn-menu-toggle" id="attach-file"></button>
<div class="btn-menu top-left">
<div class="btn-menu-item menu-media tgico-photo rp">Photo or Video</div>
<div class="btn-menu-item menu-document tgico-document rp">Document</div>
<div class="btn-menu-item menu-poll tgico-poll rp">Poll</div>
</div>
</button>
<div class="record-time"></div> <div class="record-time"></div>
<input type="file" id="input-file" style="display: none;" multiple /> <input type="file" id="input-file" style="display: none;" multiple />
</div> </div>
@ -537,27 +531,23 @@
<div class="emoji-container"> <div class="emoji-container">
<div class="tabs-container"> <div class="tabs-container">
<div class="emoji-padding"> <div class="emoji-padding">
<nav class="menu-horizontal"> <nav class="menu-horizontal-div no-stripe">
<ul> <button class="menu-horizontal-div-item active btn-icon tgico-recent rp"></button>
<li class="active btn-icon tgico-recent rp"></li> <button class="menu-horizontal-div-item btn-icon tgico-smile rp"></button>
<li class="btn-icon tgico-smile rp"></li> <button class="menu-horizontal-div-item btn-icon tgico-animals rp"></button>
<li class="btn-icon tgico-animals rp"></li> <button class="menu-horizontal-div-item btn-icon tgico-eats rp"></button>
<li class="btn-icon tgico-eats rp"></li> <button class="menu-horizontal-div-item btn-icon tgico-car rp"></button>
<li class="btn-icon tgico-car rp"></li> <button class="menu-horizontal-div-item btn-icon tgico-sport rp"></button>
<li class="btn-icon tgico-sport rp"></li> <button class="menu-horizontal-div-item btn-icon tgico-lamp rp"></button>
<li class="btn-icon tgico-lamp rp"></li> <!-- <button class="menu-horizontal-div-item btn-icon tgico-info rp"></button> -->
<!-- <li class="btn-icon tgico-info rp"></li> --> <button class="menu-horizontal-div-item btn-icon tgico-flag rp"></button>
<li class="btn-icon tgico-flag rp"></li>
</ul>
</nav> </nav>
<div class="emoticons-content" id="content-emoji"></div> <div class="emoticons-content" id="content-emoji"></div>
</div> </div>
<div class="stickers-padding"> <div class="stickers-padding">
<div class="menu-wrapper"> <div class="menu-wrapper">
<nav class="menu-horizontal"> <nav class="menu-horizontal-div no-stripe justify-start">
<ul class="justify-start"> <button class="menu-horizontal-div-item btn-icon tgico-recent active"></button>
<li class="btn-icon tgico-recent active"></li>
</ul>
</nav> </nav>
</div> </div>
<div class="emoticons-content" id="content-stickers"></div> <div class="emoticons-content" id="content-stickers"></div>
@ -569,15 +559,13 @@
</div> </div>
</div> </div>
</div> </div>
<nav class="emoji-tabs menu-horizontal no-stripe"> <div class="emoji-tabs menu-horizontal-div no-stripe">
<ul> <button class="menu-horizontal-div-item emoji-tabs-search justify-self-start btn-icon tgico-search rp" data-tab="-1"></button>
<li class="emoji-tabs-search justify-self-start btn-icon tgico-search rp" data-tab="-1"></li> <button class="menu-horizontal-div-item emoji-tabs-emoji btn-icon tgico-smile rp" data-tab="0"></button>
<li class="emoji-tabs-emoji btn-icon tgico-smile rp" data-tab="0"></li> <button class="menu-horizontal-div-item emoji-tabs-stickers btn-icon tgico-stickers rp" data-tab="1"></button>
<li class="emoji-tabs-stickers btn-icon tgico-stickers rp" data-tab="1"></li> <button class="menu-horizontal-div-item emoji-tabs-gifs btn-icon tgico-gifs rp" data-tab="2"></button>
<li class="emoji-tabs-gifs btn-icon tgico-gifs rp" data-tab="2"></li> <button class="menu-horizontal-div-item emoji-tabs-delete justify-self-end btn-icon tgico-deleteleft rp" data-tab="-1"></button>
<li class="emoji-tabs-delete justify-self-end btn-icon tgico-deleteleft rp" data-tab="-1"></li> </div>
</ul>
</nav>
</div> </div>
</div> </div>
</div> </div>

14
src/lib/appManagers/appChatsManager.ts

@ -1,4 +1,4 @@
import { InputChannel, InputChatPhoto, InputPeer, Updates } from "../../layer"; import { ChatBannedRights, InputChannel, InputChatPhoto, InputPeer, Updates } from "../../layer";
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
import $rootScope from "../rootScope"; import $rootScope from "../rootScope";
@ -151,7 +151,7 @@ export class AppChatsManager {
return this.chats[id] || {_: 'chatEmpty', id: id, deleted: true, access_hash: this.channelAccess[id]}; return this.chats[id] || {_: 'chatEmpty', id: id, deleted: true, access_hash: this.channelAccess[id]};
} }
public hasRights(id: number, action: ChatRights) { public hasRights(id: number, action: ChatRights, flag?: keyof ChatBannedRights['pFlags']) {
const chat = this.getChat(id); const chat = this.getChat(id);
if(chat._ == 'chatEmpty') return false; if(chat._ == 'chatEmpty') return false;
@ -171,12 +171,16 @@ export class AppChatsManager {
switch(action) { switch(action) {
// good // good
case 'send': { case 'send': {
if(chat._ == 'channel' && if(flag && myFlags[flag]) {
!chat.pFlags.megagroup &&
!myFlags.post_messages) {
return false; return false;
} }
if(chat._ == 'channel') {
if((!chat.pFlags.megagroup && !myFlags.post_messages)) {
return false;
}
}
break; break;
} }

4
src/lib/rootScope.ts

@ -1,13 +1,14 @@
import type { StickerSet } from "../layer"; import type { StickerSet } from "../layer";
import type { MyDocument } from "./appManagers/appDocsManager"; import type { MyDocument } from "./appManagers/appDocsManager";
import type { Poll, PollResults } from "./appManagers/appPollsManager";
import type { AppMessagesManager, Dialog, MyDialogFilter } from "./appManagers/appMessagesManager"; import type { AppMessagesManager, Dialog, MyDialogFilter } from "./appManagers/appMessagesManager";
import type { Poll, PollResults } from "./appManagers/appPollsManager";
import { MOUNT_CLASS_TO } from "./mtproto/mtproto_config"; import { MOUNT_CLASS_TO } from "./mtproto/mtproto_config";
type BroadcastEvents = { type BroadcastEvents = {
'user_update': number, 'user_update': number,
'user_auth': {dcID?: number, id: number}, 'user_auth': {dcID?: number, id: number},
'peer_changed': number, 'peer_changed': number,
'peer_pinned_message': number,
'filter_delete': MyDialogFilter, 'filter_delete': MyDialogFilter,
'filter_update': MyDialogFilter, 'filter_update': MyDialogFilter,
@ -48,7 +49,6 @@ type BroadcastEvents = {
//'contacts_update': any, //'contacts_update': any,
'avatar_update': number, 'avatar_update': number,
'chat_full_update': number, 'chat_full_update': number,
'peer_pinned_message': number,
'poll_update': {poll: Poll, results: PollResults}, 'poll_update': {poll: Poll, results: PollResults},
'chat_update': number, 'chat_update': number,
'stateSynchronized': void, 'stateSynchronized': void,

2
src/scss/partials/_chat.scss

@ -342,7 +342,7 @@
} }
.btn-icon { .btn-icon {
transition: .2s color, background-color .2s; transition: .2s color, background-color .2s, .2s opacity;
} }
#btn-record-cancel, #btn-send { #btn-record-cancel, #btn-send {

28
src/scss/partials/_emojiDropdown.scss

@ -34,7 +34,7 @@
margin-left: -.5rem; margin-left: -.5rem;
} */ } */
> .menu-horizontal { > .menu-horizontal-div {
//font-weight: 500; //font-weight: 500;
margin-top: 2px; margin-top: 2px;
border: none; border: none;
@ -52,9 +52,7 @@
} }
.emoji-tabs { .emoji-tabs {
ul { justify-content: center;
justify-content: center;
}
&-search { &-search {
position: absolute; position: absolute;
@ -113,7 +111,7 @@
.emoji-padding.active { .emoji-padding.active {
@include respond-to(handhelds) { @include respond-to(handhelds) {
.menu-horizontal li { .menu-horizontal-div .menu-horizontal-div-item {
flex: unset; flex: unset;
padding: 0; padding: 0;
} }
@ -143,7 +141,7 @@
} }
.emoji-padding, .stickers-padding { .emoji-padding, .stickers-padding {
.menu-horizontal { .menu-horizontal-div {
height: 48px; height: 48px;
border-bottom: none; border-bottom: none;
padding: 2px; padding: 2px;
@ -151,7 +149,7 @@
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, 0.21); box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, 0.21);
z-index: 4; z-index: 4;
li { .menu-horizontal-div-item {
margin: 0; margin: 0;
} }
} }
@ -248,12 +246,6 @@
} }
} }
} }
.menu-horizontal {
li {
border-radius: 50%;
}
}
#content-stickers { #content-stickers {
.scrollable { .scrollable {
@ -261,12 +253,12 @@
} }
} }
.menu-horizontal { .menu-horizontal-div {
width: 100%; width: 100%;
height: 48px; height: 48px;
box-shadow: 0px -2px 5px -1px rgba(0, 0, 0, .21); box-shadow: 0px -2px 5px -1px rgba(0, 0, 0, .21);
li { .menu-horizontal-div-item {
font-size: 1.5rem; font-size: 1.5rem;
margin: 0 12px; margin: 0 12px;
width: 48px; width: 48px;
@ -285,10 +277,10 @@
box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .21); box-shadow: 0px 1px 5px -1px rgba(0, 0, 0, .21);
} }
.menu-horizontal { .menu-horizontal-div {
box-shadow: none; box-shadow: none;
& li { .menu-horizontal-div-item {
height: 48px; height: 48px;
width: 48px; width: 48px;
padding: 0; padding: 0;
@ -305,7 +297,7 @@
//border-top: 1px solid $lightgrey; //border-top: 1px solid $lightgrey;
} }
li { .menu-horizontal-div-item {
/* width: calc(100% / 7); */ /* width: calc(100% / 7); */
flex: 0 0 auto; flex: 0 0 auto;

75
src/scss/partials/_slider.scss

@ -1,5 +1,80 @@
$slider-time: .25s; $slider-time: .25s;
.menu-horizontal-div {
width: 100%;
display: flex;
justify-content: space-around;
align-items: center;
position: relative;
z-index: 2;
flex-direction: row;
color: $color-gray;
border-bottom: 1px solid $lightgrey;
position: relative;
&-item {
display: inline-block;
padding: .75rem 1rem;
cursor: pointer;
text-align: center;
flex: 1 1 auto;
//flex: 0 0 auto;
//overflow: hidden;
user-select: none;
// font-size: 1rem;
font-size: 14px;
font-weight: 500;
position: relative;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
html.no-touch & {
background-color: transparent;
transition: background-color .15s ease-in-out;
&:hover {
background-color: var(--color-gray-hover);
}
}
> span {
position: relative;
display: inline-flex;
align-items: center;
}
&.active {
color: $color-blue;
i {
opacity: 1;
}
}
}
i {
position: absolute;
bottom: calc(-.625rem - 2px);
left: 0;
opacity: 0;
background-color: $color-blue;
height: .1875rem;
width: 100%;
border-radius: .1875rem .1875rem 0 0;
pointer-events: none;
padding-right: .5rem;
margin-left: -.25rem;
box-sizing: content-box;
transform-origin: left;
z-index: 1;
&.animate {
transition: transform $slider-time;
}
}
}
.menu-horizontal { .menu-horizontal {
color: $color-gray; color: $color-gray;
border-bottom: 1px solid $lightgrey; border-bottom: 1px solid $lightgrey;

7
src/scss/style.scss

@ -302,7 +302,7 @@ input, textarea {
font-size: 1.5rem; font-size: 1.5rem;
line-height: 1.5rem; line-height: 1.5rem;
border-radius: 50%; border-radius: 50%;
transition: background-color .15s ease-in-out; transition: background-color .15s ease-in-out, opacity .15s ease-in-out;
color: $color-gray; color: $color-gray;
cursor: pointer; cursor: pointer;
background-color: transparent; background-color: transparent;
@ -323,6 +323,11 @@ input, textarea {
html.no-touch &:hover { html.no-touch &:hover {
background-color: var(--color-gray-hover); background-color: var(--color-gray-hover);
} }
&:disabled {
pointer-events: none !important;
opacity: .25;
}
} }
.btn-icon:disabled { .btn-icon:disabled {

Loading…
Cancel
Save