More and more translations

This commit is contained in:
Eduard Kuzmenko 2021-03-28 22:37:11 +04:00
parent a43a0357bc
commit a90aae065e
38 changed files with 685 additions and 365 deletions

View File

@ -31,6 +31,7 @@ import DEBUG from "../config/debug";
import appNavigationController from "./appNavigationController"; import appNavigationController from "./appNavigationController";
import { Message } from "../layer"; import { Message } from "../layer";
import { forEachReverse } from "../helpers/array"; import { forEachReverse } from "../helpers/array";
import AppSharedMediaTab from "./sidebarRight/tabs/sharedMedia";
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию // TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода) // TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
@ -1257,7 +1258,10 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
//.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve()) //.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())
.then(() => { .then(() => {
if(mediaSizes.isMobile) { if(mediaSizes.isMobile) {
appSidebarRight.closeTab(AppSidebarRight.SLIDERITEMSIDS.sharedMedia); const tab = appSidebarRight.getTab(AppSharedMediaTab);
if(tab) {
tab.close();
}
} }
const message = appMessagesManager.getMessageByPeer(peerId, mid); const message = appMessagesManager.getMessageByPeer(peerId, mid);

View File

@ -29,6 +29,7 @@ import { months, ONE_DAY } from "../helpers/date";
import { SearchSuperContext } from "./appSearchSuper."; import { SearchSuperContext } from "./appSearchSuper.";
import { Message, PhotoSize } from "../layer"; import { Message, PhotoSize } from "../layer";
import { forEachReverse } from "../helpers/array"; import { forEachReverse } from "../helpers/array";
import AppSharedMediaTab from "./sidebarRight/tabs/sharedMedia";
// TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию // TODO: масштабирование картинок (не SVG) при ресайзе, и правильный возврат на исходную позицию
// TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода) // TODO: картинки "обрезаются" если возвращаются или появляются с места, где есть их перекрытие (топбар, поле ввода)
@ -1159,7 +1160,10 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
//.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve()) //.then(() => mediaSizes.isMobile ? appSidebarRight.sharedMediaTab.closeBtn.click() : Promise.resolve())
.then(() => { .then(() => {
if(mediaSizes.isMobile) { if(mediaSizes.isMobile) {
appSidebarRight.closeTab(AppSidebarRight.SLIDERITEMSIDS.sharedMedia); const tab = appSidebarRight.getTab(AppSharedMediaTab);
if(tab) {
tab.close();
}
} }
const message = appMessagesManager.getMessageByPeer(peerId, mid); const message = appMessagesManager.getMessageByPeer(peerId, mid);

View File

@ -676,9 +676,9 @@ export default class AppSearchSuper {
if(showMembersCount && (peer.participants_count || peer.participants)) { if(showMembersCount && (peer.participants_count || peer.participants)) {
const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(searchIndexManager.cleanSearchText(query))})`, 'gi'); const regExp = new RegExp(`(${escapeRegExp(query)}|${escapeRegExp(searchIndexManager.cleanSearchText(query))})`, 'gi');
dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>'); dom.titleSpan.innerHTML = dom.titleSpan.innerHTML.replace(regExp, '<i>$1</i>');
dom.lastMessageSpan.innerText = appChatsManager.getChatMembersString(-peerId); dom.lastMessageSpan.append(appChatsManager.getChatMembersString(-peerId));
} else if(peerId === rootScope.myId) { } else if(peerId === rootScope.myId) {
dom.lastMessageSpan.innerHTML = 'chat with yourself'; dom.lastMessageSpan.append(i18n('Presence.YourChat'));
} else { } else {
let username = appPeersManager.getPeerUsername(peerId); let username = appPeersManager.getPeerUsername(peerId);
if(!username) { if(!username) {
@ -769,7 +769,7 @@ export default class AppSearchSuper {
autonomous: true autonomous: true
}); });
dom.lastMessageSpan.innerText = peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appChatsManager.getChatMembersString(peerId); dom.lastMessageSpan.append(peerId > 0 ? appUsersManager.getUserStatusString(peerId) : appChatsManager.getChatMembersString(peerId));
}); });
if(!state.recentSearch.length) { if(!state.recentSearch.length) {

View File

@ -11,7 +11,7 @@ import { FocusDirection } from "../helpers/fastSmoothScroll";
import CheckboxField from "./checkboxField"; import CheckboxField from "./checkboxField";
import appProfileManager from "../lib/appManagers/appProfileManager"; import appProfileManager from "../lib/appManagers/appProfileManager";
import { safeAssign } from "../helpers/object"; import { safeAssign } from "../helpers/object";
import { LangPackKey, _i18n } from "../lib/langPack"; import { i18n, LangPackKey, _i18n } from "../lib/langPack";
type PeerType = 'contacts' | 'dialogs' | 'channelParticipants'; type PeerType = 'contacts' | 'dialogs' | 'channelParticipants';
@ -434,19 +434,16 @@ export default class AppSelectPeers {
dom.containerEl.prepend(checkboxField.label); dom.containerEl.prepend(checkboxField.label);
} }
let subtitle = ''; let subtitleEl: HTMLElement;
if(peerId < 0) { if(peerId < 0) {
subtitle = appChatsManager.getChatMembersString(-peerId); subtitleEl = appChatsManager.getChatMembersString(-peerId);
} else if(peerId === rootScope.myId) { } else if(peerId === rootScope.myId) {
subtitle = 'chat with yourself'; subtitleEl = i18n('Presence.YourChat');
} else { } else {
subtitle = appUsersManager.getUserStatusString(peerId); subtitleEl = appUsersManager.getUserStatusString(peerId);
if(subtitle === 'online') {
subtitle = `<i>${subtitle}</i>`;
}
} }
dom.lastMessageSpan.innerHTML = subtitle; dom.lastMessageSpan.append(subtitleEl);
}); });
} }

View File

@ -555,7 +555,8 @@ export default class ChatTopbar {
return; return;
} }
this.subtitle.innerHTML = subtitle; this.subtitle.textContent = '';
this.subtitle.append(subtitle);
}); });
}; };
} }

View File

@ -5,10 +5,11 @@ import appPollsManager, { Poll, PollResults } from "../lib/appManagers/appPollsM
import serverTimeManager from "../lib/mtproto/serverTimeManager"; import serverTimeManager from "../lib/mtproto/serverTimeManager";
import { RichTextProcessor } from "../lib/richtextprocessor"; import { RichTextProcessor } from "../lib/richtextprocessor";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
import { attachClickEvent, cancelEvent, detachClickEvent, findUpClassName } from "../helpers/dom"; import { attachClickEvent, cancelEvent, detachClickEvent, findUpClassName, replaceContent } from "../helpers/dom";
import { ripple } from "./ripple"; import { ripple } from "./ripple";
import appSidebarRight from "./sidebarRight"; import appSidebarRight from "./sidebarRight";
import AppPollResultsTab from "./sidebarRight/tabs/pollResults"; import AppPollResultsTab from "./sidebarRight/tabs/pollResults";
import { i18n, LangPackKey } from "../lib/langPack";
let lineTotalLength = 0; let lineTotalLength = 0;
const tailLength = 9; const tailLength = 9;
@ -200,7 +201,7 @@ export default class PollElement extends HTMLElement {
//console.log('pollElement poll:', poll, results); //console.log('pollElement poll:', poll, results);
let desc = ''; let descKey: LangPackKey = '';
if(poll.pFlags) { if(poll.pFlags) {
this.isPublic = !!poll.pFlags.public_voters; this.isPublic = !!poll.pFlags.public_voters;
this.isQuiz = !!poll.pFlags.quiz; this.isQuiz = !!poll.pFlags.quiz;
@ -208,11 +209,12 @@ export default class PollElement extends HTMLElement {
this.isMultiple = !!poll.pFlags.multiple_choice; this.isMultiple = !!poll.pFlags.multiple_choice;
if(this.isClosed) { if(this.isClosed) {
desc = 'Final results'; descKey = 'Chat.Poll.Type.Closed';
this.classList.add('is-closed'); this.classList.add('is-closed');
} else if(this.isQuiz) {
descKey = this.isPublic ? 'Chat.Poll.Type.Quiz' : 'Chat.Poll.Type.AnonymousQuiz';
} else { } else {
let type = this.isQuiz ? 'Quiz' : 'Poll'; descKey = this.isPublic ? 'Chat.Poll.Type.Public' : 'Chat.Poll.Type.Anonymous';
desc = (this.isPublic ? '' : 'Anonymous ') + type;
} }
} }
@ -240,20 +242,19 @@ export default class PollElement extends HTMLElement {
this.innerHTML = ` this.innerHTML = `
<div class="poll-title">${poll.rQuestion}</div> <div class="poll-title">${poll.rQuestion}</div>
<div class="poll-desc"> <div class="poll-desc">
<div class="poll-type">${desc}</div> <div class="poll-type"></div>
<div class="poll-avatars"></div> <div class="poll-avatars"></div>
</div> </div>
${votes} ${votes}`;
<div class="poll-footer">
<div class="poll-footer-button poll-view-results hide">View Results</div>
<div class="poll-votes-count"></div>
</div>
`;
this.descDiv = this.firstElementChild.nextElementSibling as HTMLElement; this.descDiv = this.firstElementChild.nextElementSibling as HTMLElement;
this.typeDiv = this.descDiv.firstElementChild as HTMLElement; this.typeDiv = this.descDiv.firstElementChild as HTMLElement;
this.avatarsDiv = this.descDiv.lastElementChild as HTMLElement; this.avatarsDiv = this.descDiv.lastElementChild as HTMLElement;
if(descKey) {
this.typeDiv.append(i18n(descKey));
}
if(this.isQuiz) { if(this.isQuiz) {
this.classList.add('is-quiz'); this.classList.add('is-quiz');
@ -332,9 +333,18 @@ export default class PollElement extends HTMLElement {
this.svgLines = Array.from(this.querySelectorAll('.poll-line')) as SVGSVGElement[]; this.svgLines = Array.from(this.querySelectorAll('.poll-line')) as SVGSVGElement[];
this.numberDivs = Array.from(this.querySelectorAll('.poll-answer-percents')) as HTMLDivElement[]; this.numberDivs = Array.from(this.querySelectorAll('.poll-answer-percents')) as HTMLDivElement[];
const footerDiv = this.lastElementChild; const footerDiv = document.createElement('div');
this.viewResults = footerDiv.firstElementChild as HTMLElement; footerDiv.classList.add('poll-footer');
this.votersCountDiv = footerDiv.lastElementChild as HTMLDivElement;
this.viewResults = document.createElement('div');
this.viewResults.className = 'poll-footer-button poll-view-results hide';
this.viewResults.append(i18n('Chat.Poll.ViewResults'));
this.votersCountDiv = document.createElement('div');
this.votersCountDiv.className = 'poll-votes-count';
footerDiv.append(this.viewResults, this.votersCountDiv);
this.append(footerDiv);
this.viewResults.addEventListener('click', (e) => { this.viewResults.addEventListener('click', (e) => {
cancelEvent(e); cancelEvent(e);
@ -348,7 +358,7 @@ export default class PollElement extends HTMLElement {
if(this.isMultiple) { if(this.isMultiple) {
this.sendVoteBtn = document.createElement('div'); this.sendVoteBtn = document.createElement('div');
this.sendVoteBtn.classList.add('poll-footer-button', 'poll-send-vote'); this.sendVoteBtn.classList.add('poll-footer-button', 'poll-send-vote');
this.sendVoteBtn.innerText = 'Vote'; this.sendVoteBtn.append(i18n('Chat.Poll.SubmitVote'));
ripple(this.sendVoteBtn); ripple(this.sendVoteBtn);
if(!poll.chosenIndexes.length) { if(!poll.chosenIndexes.length) {
@ -495,7 +505,7 @@ export default class PollElement extends HTMLElement {
if(this.isClosed) { if(this.isClosed) {
this.classList.add('is-closed'); this.classList.add('is-closed');
this.typeDiv.innerText = 'Final results'; replaceContent(this.typeDiv, i18n('Chat.Poll.Type.Closed'));
} }
// set chosen // set chosen
@ -534,7 +544,7 @@ export default class PollElement extends HTMLElement {
*/ */
results.recent_voters/* .slice().reverse() */.forEach((userId, idx) => { results.recent_voters/* .slice().reverse() */.forEach((userId, idx) => {
const style = idx === 0 ? '' : `style="transform: translateX(-${idx * 3}px);"`; const style = idx === 0 ? '' : `style="transform: translateX(-${idx * 3}px);"`;
html += `<avatar-element class="avatar-18" dialog="0" peer="${userId}" ${style}></avatar-element>`; html += `<avatar-element class="avatar-16" dialog="0" peer="${userId}" ${style}></avatar-element>`;
}); });
this.avatarsDiv.innerHTML = html; this.avatarsDiv.innerHTML = html;
} }
@ -612,9 +622,16 @@ export default class PollElement extends HTMLElement {
setVotersCount(results: PollResults) { setVotersCount(results: PollResults) {
const votersCount = results.total_voters || 0; const votersCount = results.total_voters || 0;
const votersOrAnswers = this.isQuiz ? (votersCount > 1 || !votersCount ? 'answers' : 'answer') : (votersCount > 1 || !votersCount ? 'votes' : 'vote'); let key: LangPackKey, args = [votersCount];
if(this.isClosed) {
this.votersCountDiv.innerText = `${results.total_voters ? results.total_voters + ' ' + votersOrAnswers : 'No ' + votersOrAnswers}`; if(this.isQuiz) key = votersCount ? 'Chat.Quiz.TotalVotes' : 'Chat.Quiz.TotalVotesResultEmpty';
else key = votersCount ? 'Chat.Poll.TotalVotes1' : 'Chat.Poll.TotalVotesResultEmpty';
} else {
if(this.isQuiz) key = votersCount ? 'Chat.Quiz.TotalVotes' : 'Chat.Quiz.TotalVotesEmpty';
else key = votersCount ? 'Chat.Poll.TotalVotes1' : 'Chat.Poll.TotalVotesEmpty';
}
replaceContent(this.votersCountDiv, i18n(key, args));
} }
setLineProgress(index: number, percents: number) { setLineProgress(index: number, percents: number) {
@ -632,4 +649,4 @@ export default class PollElement extends HTMLElement {
// у элемента могут быть ещё другие методы и свойства // у элемента могут быть ещё другие методы и свойства
} }
customElements.define("poll-element", PollElement); customElements.define("poll-element", PollElement);

View File

@ -1,11 +1,14 @@
import AvatarElement from "../avatar"; import AvatarElement from "../avatar";
import PopupElement, { PopupButton } from "."; import PopupElement, { PopupButton } from ".";
import { i18n, LangPackKey } from "../../lib/langPack";
export default class PopupPeer extends PopupElement { export default class PopupPeer extends PopupElement {
constructor(private className: string, options: Partial<{ constructor(private className: string, options: Partial<{
peerId: number, peerId: number,
title: string, title: string,
titleLangKey?: LangPackKey,
description: string, description: string,
descriptionLangKey?: LangPackKey,
buttons: Array<PopupButton> buttons: Array<PopupButton>
}> = {}) { }> = {}) {
super('popup-peer' + (className ? ' ' + className : ''), options.buttons, {overlayClosable: true}); super('popup-peer' + (className ? ' ' + className : ''), options.buttons, {overlayClosable: true});
@ -15,12 +18,14 @@ export default class PopupPeer extends PopupElement {
avatarEl.setAttribute('peer', '' + options.peerId); avatarEl.setAttribute('peer', '' + options.peerId);
avatarEl.classList.add('avatar-32'); avatarEl.classList.add('avatar-32');
this.title.innerText = options.title || ''; if(options.descriptionLangKey) this.title.append(i18n(options.titleLangKey));
else this.title.innerText = options.title || '';
this.header.prepend(avatarEl); this.header.prepend(avatarEl);
let p = document.createElement('p'); let p = document.createElement('p');
p.classList.add('popup-description'); p.classList.add('popup-description');
p.innerHTML = options.description; if(options.descriptionLangKey) p.append(i18n(options.descriptionLangKey));
else p.innerHTML = options.description;
this.container.insertBefore(p, this.header.nextElementSibling); this.container.insertBefore(p, this.header.nextElementSibling);
} }

View File

@ -6,10 +6,12 @@ import { wrapSticker } from "../wrappers";
import LazyLoadQueue from "../lazyLoadQueue"; import LazyLoadQueue from "../lazyLoadQueue";
import { putPreloader } from "../misc"; import { putPreloader } from "../misc";
import animationIntersector from "../animationIntersector"; import animationIntersector from "../animationIntersector";
import { findUpClassName } from "../../helpers/dom"; import { findUpClassName, toggleDisability } from "../../helpers/dom";
import appImManager from "../../lib/appManagers/appImManager"; import appImManager from "../../lib/appManagers/appImManager";
import { StickerSet } from "../../layer"; import { StickerSet } from "../../layer";
import mediaSizes from "../../helpers/mediaSizes"; import mediaSizes from "../../helpers/mediaSizes";
import { i18n } from "../../lib/langPack";
import Button from "../button";
const ANIMATION_GROUP = 'STICKERS-POPUP'; const ANIMATION_GROUP = 'STICKERS-POPUP';
@ -28,7 +30,7 @@ export default class PopupStickers extends PopupElement {
super('popup-stickers', null, {closable: true, overlayClosable: true, body: true}); super('popup-stickers', null, {closable: true, overlayClosable: true, body: true});
this.h6 = document.createElement('h6'); this.h6 = document.createElement('h6');
this.h6.innerText = 'Loading...'; this.h6.append(i18n('Loading'));
this.header.append(this.h6); this.header.append(this.h6);
@ -51,7 +53,7 @@ export default class PopupStickers extends PopupElement {
div.append(this.stickersDiv); div.append(this.stickersDiv);
this.stickersFooter.innerText = 'Loading...'; this.stickersFooter.append(i18n('Loading'));
this.body.append(div); this.body.append(div);
const scrollable = new Scrollable(this.body); const scrollable = new Scrollable(this.body);
@ -66,12 +68,12 @@ export default class PopupStickers extends PopupElement {
} }
onFooterClick = () => { onFooterClick = () => {
this.stickersFooter.setAttribute('disabled', 'true'); const toggle = toggleDisability([this.stickersFooter], true);
appStickersManager.toggleStickerSet(this.set).then(() => { appStickersManager.toggleStickerSet(this.set).then(() => {
this.btnClose.click(); this.hide();
}).catch(() => { }).catch(() => {
this.stickersFooter.removeAttribute('disabled'); toggle();
}); });
}; };
@ -81,7 +83,7 @@ export default class PopupStickers extends PopupElement {
const fileId = target.dataset.docId; const fileId = target.dataset.docId;
if(appImManager.chat.input.sendMessageWithDocument(fileId)) { if(appImManager.chat.input.sendMessageWithDocument(fileId)) {
this.btnClose.click(); this.hide();
} else { } else {
console.warn('got no doc by id:', fileId); console.warn('got no doc by id:', fileId);
} }
@ -97,9 +99,20 @@ export default class PopupStickers extends PopupElement {
this.h6.innerHTML = RichTextProcessor.wrapEmojiText(set.set.title); this.h6.innerHTML = RichTextProcessor.wrapEmojiText(set.set.title);
!set.set.installed_date ? this.stickersFooter.classList.add('add') : this.stickersFooter.classList.remove('add'); !set.set.installed_date ? this.stickersFooter.classList.add('add') : this.stickersFooter.classList.remove('add');
this.stickersFooter.innerHTML = set.set.hasOwnProperty('installed_date') ? '<div style="cursor: pointer; margin: 0 auto; width: 150px;">Remove stickers</div>' : `<button class="btn-primary btn-color-primary">ADD ${set.set.count} STICKERS</button>`;
this.stickersFooter.addEventListener('click', this.onFooterClick); let button: HTMLElement;
if(set.set.hasOwnProperty('installed_date')) {
button = Button('btn-primary btn-primary-transparent danger', {noRipple: true});
button.append(i18n('StickerPack.Remove', [set.set.count]));
} else {
button = Button('btn-primary btn-color-primary', {noRipple: true});
button.append(i18n('StickerPack.Add1', [set.set.count]));
}
this.stickersFooter.textContent = '';
this.stickersFooter.append(button);
button.addEventListener('click', this.onFooterClick);
if(set.documents.length) { if(set.documents.length) {
this.stickersDiv.addEventListener('click', this.onStickersClick); this.stickersDiv.addEventListener('click', this.onStickersClick);
@ -133,4 +146,4 @@ export default class PopupStickers extends PopupElement {
} }
}); });
} }
} }

View File

@ -54,7 +54,12 @@ export default class AppBlockedUsersTab extends SliderSuperTab {
}); });
const user = appUsersManager.getUser(peerId); const user = appUsersManager.getUser(peerId);
dom.lastMessageSpan.innerHTML = user.pFlags.bot ? ('@' + user.username) : user.rPhone || (user.username ? '@' + user.username : appUsersManager.getUserStatusString(peerId)); if(user.pFlags.bot) {
dom.lastMessageSpan.append('@' + user.username);
} else {
if(user.rPhone) dom.lastMessageSpan.innerHTML = user.rPhone;
else dom.lastMessageSpan.append(user.username ? '@' + user.username : appUsersManager.getUserStatusString(peerId));
}
//dom.titleSpan.innerHTML = 'Raaid El Syed'; //dom.titleSpan.innerHTML = 'Raaid El Syed';
//dom.lastMessageSpan.innerHTML = '+1 234 567891'; //dom.lastMessageSpan.innerHTML = '+1 234 567891';

View File

@ -100,7 +100,7 @@ export default class AppContactsTab extends SliderSuperTab {
}); });
let status = appUsersManager.getUserStatusString(user.id); let status = appUsersManager.getUserStatusString(user.id);
dom.lastMessageSpan.innerHTML = status === 'online' ? `<i>${status}</i>` : status; dom.lastMessageSpan.append(status);
}); });
if(!sorted.length) renderPage = undefined; if(!sorted.length) renderPage = undefined;

View File

@ -89,15 +89,7 @@ export default class AppNewGroupTab extends SliderSuperTab {
avatarSize: 48 avatarSize: 48
}); });
let subtitle = ''; dom.lastMessageSpan.append(appUsersManager.getUserStatusString(userId));
subtitle = appUsersManager.getUserStatusString(userId);
if(subtitle === 'online') {
subtitle = `<i>${subtitle}</i>`;
}
if(subtitle) {
dom.lastMessageSpan.innerHTML = subtitle;
}
}); });
this.searchGroup.nameEl.textContent = ''; this.searchGroup.nameEl.textContent = '';

View File

@ -6,32 +6,23 @@ import { MOUNT_CLASS_TO } from "../../config/debug";
export const RIGHT_COLUMN_ACTIVE_CLASSNAME = 'is-right-column-shown'; export const RIGHT_COLUMN_ACTIVE_CLASSNAME = 'is-right-column-shown';
const sharedMediaTab = new AppSharedMediaTab();
export class AppSidebarRight extends SidebarSlider { export class AppSidebarRight extends SidebarSlider {
public static SLIDERITEMSIDS = {
sharedMedia: 0,
};
public sharedMediaTab: AppSharedMediaTab; public sharedMediaTab: AppSharedMediaTab;
constructor() { constructor() {
super({ super({
sidebarEl: document.getElementById('column-right') as HTMLElement, sidebarEl: document.getElementById('column-right') as HTMLElement,
tabs: new Map([
[AppSidebarRight.SLIDERITEMSIDS.sharedMedia, sharedMediaTab],
] as any[]),
canHideFirst: true, canHideFirst: true,
navigationType: 'right' navigationType: 'right'
}); });
this.sharedMediaTab = sharedMediaTab;
mediaSizes.addEventListener('changeScreen', (from, to) => { mediaSizes.addEventListener('changeScreen', (from, to) => {
if(to === ScreenSize.medium && from !== ScreenSize.mobile) { if(to === ScreenSize.medium && from !== ScreenSize.mobile) {
this.toggleSidebar(false); this.toggleSidebar(false);
} }
}); });
this.sharedMediaTab = new AppSharedMediaTab(this);
} }
public onCloseTab(id: number, animate: boolean, isNavigation?: boolean) { public onCloseTab(id: number, animate: boolean, isNavigation?: boolean) {
@ -72,7 +63,8 @@ export class AppSidebarRight extends SidebarSlider {
if(!willChange) return Promise.resolve(); if(!willChange) return Promise.resolve();
if(!active && !this.historyTabIds.length) { if(!active && !this.historyTabIds.length) {
this.selectTab(AppSidebarRight.SLIDERITEMSIDS.sharedMedia); this.sharedMediaTab.open();
//this.selectTab(this.sharedMediaTab);
} }
const animationPromise = appImManager.selectTab(active ? 1 : 2, animate); const animationPromise = appImManager.selectTab(active ? 1 : 2, animate);

View File

@ -10,6 +10,8 @@ import appProfileManager from "../../../lib/appManagers/appProfileManager";
import { attachClickEvent, toggleDisability } from "../../../helpers/dom"; import { attachClickEvent, toggleDisability } from "../../../helpers/dom";
import PopupPeer from "../../popups/peer"; import PopupPeer from "../../popups/peer";
import { addCancelButton } from "../../popups"; import { addCancelButton } from "../../popups";
import { i18n } from "../../../lib/langPack";
import { numberThousandSplitter } from "../../../helpers/number";
export default class AppEditChannelTab extends SliderSuperTab { export default class AppEditChannelTab extends SliderSuperTab {
private nameInputField: InputField; private nameInputField: InputField;
@ -19,7 +21,7 @@ export default class AppEditChannelTab extends SliderSuperTab {
protected async init() { protected async init() {
this.container.classList.add('edit-peer-container', 'edit-channel-container'); this.container.classList.add('edit-peer-container', 'edit-channel-container');
this.title.innerHTML = 'Edit'; this.setTitle('Edit');
const chatFull = await appProfileManager.getChannelFull(-this.peerId, true); const chatFull = await appProfileManager.getChannelFull(-this.peerId, true);
@ -33,12 +35,12 @@ export default class AppEditChannelTab extends SliderSuperTab {
inputWrapper.classList.add('input-wrapper'); inputWrapper.classList.add('input-wrapper');
this.nameInputField = new InputField({ this.nameInputField = new InputField({
label: 'Name', label: 'Channel.ChannelNameHolder',
name: 'channel-name', name: 'channel-name',
maxLength: 255 maxLength: 255
}); });
this.descriptionInputField = new InputField({ this.descriptionInputField = new InputField({
label: 'Description', label: 'DescriptionPlaceholder',
name: 'channel-description', name: 'channel-description',
maxLength: 255 maxLength: 255
}); });
@ -89,8 +91,8 @@ export default class AppEditChannelTab extends SliderSuperTab {
if(appChatsManager.hasRights(-this.peerId, 'change_type')) { if(appChatsManager.hasRights(-this.peerId, 'change_type')) {
const channelTypeRow = new Row({ const channelTypeRow = new Row({
title: 'Channel Type', titleLangKey: 'ChannelType',
subtitle: 'Private', subtitleLangKey: 'TypePrivate',
clickable: true, clickable: true,
icon: 'lock' icon: 'lock'
}); });
@ -100,8 +102,8 @@ export default class AppEditChannelTab extends SliderSuperTab {
if(appChatsManager.hasRights(-this.peerId, 'change_info')) { if(appChatsManager.hasRights(-this.peerId, 'change_info')) {
const discussionRow = new Row({ const discussionRow = new Row({
title: 'Discussion', titleLangKey: 'PeerInfo.Discussion',
subtitle: 'Add', subtitleLangKey: 'PeerInfo.Discussion.Add',
clickable: true, clickable: true,
icon: 'message' icon: 'message'
}); });
@ -110,7 +112,7 @@ export default class AppEditChannelTab extends SliderSuperTab {
} }
const administratorsRow = new Row({ const administratorsRow = new Row({
title: 'Administrators', titleLangKey: 'PeerInfo.Administrators',
subtitle: '' + chatFull.admins_count, subtitle: '' + chatFull.admins_count,
icon: 'admin', icon: 'admin',
clickable: true clickable: true
@ -120,7 +122,7 @@ export default class AppEditChannelTab extends SliderSuperTab {
if(appChatsManager.hasRights(-this.peerId, 'change_info')) { if(appChatsManager.hasRights(-this.peerId, 'change_info')) {
const signMessagesCheckboxField = new CheckboxField({ const signMessagesCheckboxField = new CheckboxField({
text: 'Sign Messages', text: 'PeerInfo.SignMessages',
checked: false checked: false
}); });
@ -136,12 +138,13 @@ export default class AppEditChannelTab extends SliderSuperTab {
}); });
const subscribersRow = new Row({ const subscribersRow = new Row({
title: 'Subscribers', titleLangKey: 'PeerInfo.Subscribers',
subtitle: '335 356 subscribers',
icon: 'newgroup', icon: 'newgroup',
clickable: true clickable: true
}); });
subscribersRow.subtitle.append(i18n('Subscribers', [numberThousandSplitter(335356)]));
section.content.append(subscribersRow.container); section.content.append(subscribersRow.container);
this.scrollable.append(section.container); this.scrollable.append(section.container);
@ -152,15 +155,22 @@ export default class AppEditChannelTab extends SliderSuperTab {
}); });
const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'Delete Channel'}); const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'PeerInfo.DeleteChannel'});
attachClickEvent(btnDelete, () => { attachClickEvent(btnDelete, () => {
new PopupPeer('popup-delete-channel', { new PopupPeer('popup-delete-channel', {
peerId: this.peerId, peerId: this.peerId,
title: 'Delete Channel?', titleLangKey: 'ChannelDeleteMenu',
description: `Are you sure you want to delete this channel? All subscribers will be removed and all messages will be lost.`, descriptionLangKey: 'AreYouSureDeleteAndExitChannel',
buttons: addCancelButton([{ buttons: addCancelButton([{
text: 'DELETE', langKey: 'ChannelDeleteMenu',
callback: () => {
const toggle = toggleDisability([btnDelete], true);
},
isDanger: true
}, {
langKey: 'DeleteChannelForAll',
callback: () => { callback: () => {
const toggle = toggleDisability([btnDelete], true); const toggle = toggleDisability([btnDelete], true);

View File

@ -14,6 +14,7 @@ import rootScope from "../../../lib/rootScope";
import appPeersManager from "../../../lib/appManagers/appPeersManager"; import appPeersManager from "../../../lib/appManagers/appPeersManager";
import PopupPeer from "../../popups/peer"; import PopupPeer from "../../popups/peer";
import { addCancelButton } from "../../popups"; import { addCancelButton } from "../../popups";
import { i18n } from "../../../lib/langPack";
export default class AppEditContactTab extends SliderSuperTab { export default class AppEditContactTab extends SliderSuperTab {
private nameInputField: InputField; private nameInputField: InputField;
@ -23,7 +24,7 @@ export default class AppEditContactTab extends SliderSuperTab {
protected init() { protected init() {
this.container.classList.add('edit-peer-container', 'edit-contact-container'); this.container.classList.add('edit-peer-container', 'edit-contact-container');
this.title.innerHTML = 'Edit'; this.setTitle('Edit');
{ {
const section = new SettingSection({noDelimiter: true}); const section = new SettingSection({noDelimiter: true});
@ -33,12 +34,12 @@ export default class AppEditContactTab extends SliderSuperTab {
inputWrapper.classList.add('input-wrapper'); inputWrapper.classList.add('input-wrapper');
this.nameInputField = new InputField({ this.nameInputField = new InputField({
label: 'Name', label: 'EditProfile.FirstNameLabel',
name: 'contact-name', name: 'contact-name',
maxLength: 70 maxLength: 70
}); });
this.lastNameInputField = new InputField({ this.lastNameInputField = new InputField({
label: 'Last Name', label: 'Login.Register.LastName.Placeholder',
name: 'contact-lastname', name: 'contact-lastname',
maxLength: 70 maxLength: 70
}); });
@ -103,7 +104,7 @@ export default class AppEditContactTab extends SliderSuperTab {
const profileSubtitleDiv = document.createElement('div'); const profileSubtitleDiv = document.createElement('div');
profileSubtitleDiv.classList.add('profile-subtitle'); profileSubtitleDiv.classList.add('profile-subtitle');
profileSubtitleDiv.innerHTML = 'original name'; profileSubtitleDiv.append(i18n('EditContact.OriginalName'));
section.content.append(div, profileNameDiv, profileSubtitleDiv, inputWrapper, notificationsRow.container); section.content.append(div, profileNameDiv, profileSubtitleDiv, inputWrapper, notificationsRow.container);
@ -130,10 +131,10 @@ export default class AppEditContactTab extends SliderSuperTab {
attachClickEvent(btnDelete, () => { attachClickEvent(btnDelete, () => {
new PopupPeer('popup-delete-contact', { new PopupPeer('popup-delete-contact', {
peerId: this.peerId, peerId: this.peerId,
title: 'Delete Contact?', titleLangKey: 'DeleteContact',
description: `Are you sure you want to delete <b>${appPeersManager.getPeerTitle(this.peerId)}</b> from your contact list?`, descriptionLangKey: 'AreYouSureDeleteContact',
buttons: addCancelButton([{ buttons: addCancelButton([{
text: 'DELETE', langKey: 'Delete',
callback: () => { callback: () => {
const toggle = toggleDisability([btnDelete], true); const toggle = toggleDisability([btnDelete], true);

View File

@ -14,6 +14,7 @@ import { addCancelButton } from "../../popups";
import AppGroupTypeTab from "./groupType"; import AppGroupTypeTab from "./groupType";
import rootScope from "../../../lib/rootScope"; import rootScope from "../../../lib/rootScope";
import AppGroupPermissionsTab from "./groupPermissions"; import AppGroupPermissionsTab from "./groupPermissions";
import { i18n } from "../../../lib/langPack";
export default class AppEditGroupTab extends SliderSuperTab { export default class AppEditGroupTab extends SliderSuperTab {
private groupNameInputField: InputField; private groupNameInputField: InputField;
@ -27,7 +28,7 @@ export default class AppEditGroupTab extends SliderSuperTab {
this.scrollable.container.innerHTML = ''; this.scrollable.container.innerHTML = '';
this.container.classList.add('edit-peer-container', 'edit-group-container'); this.container.classList.add('edit-peer-container', 'edit-group-container');
this.title.innerHTML = 'Edit'; this.setTitle('Edit');
const chatFull = await appProfileManager.getChatFull(this.chatId, true); const chatFull = await appProfileManager.getChatFull(this.chatId, true);
@ -39,12 +40,12 @@ export default class AppEditGroupTab extends SliderSuperTab {
inputWrapper.classList.add('input-wrapper'); inputWrapper.classList.add('input-wrapper');
this.groupNameInputField = new InputField({ this.groupNameInputField = new InputField({
label: 'Group Name', label: 'CreateGroup.NameHolder',
name: 'group-name', name: 'group-name',
maxLength: 255 maxLength: 255
}); });
this.descriptionInputField = new InputField({ this.descriptionInputField = new InputField({
label: 'Description', label: 'DescriptionPlaceholder',
name: 'group-description', name: 'group-description',
maxLength: 255 maxLength: 255
}); });
@ -70,7 +71,7 @@ export default class AppEditGroupTab extends SliderSuperTab {
if(appChatsManager.hasRights(this.chatId, 'change_type')) { if(appChatsManager.hasRights(this.chatId, 'change_type')) {
const groupTypeRow = new Row({ const groupTypeRow = new Row({
title: 'Group Type', titleLangKey: 'GroupType',
clickable: () => { clickable: () => {
const tab = new AppGroupTypeTab(this.slider); const tab = new AppGroupTypeTab(this.slider);
tab.peerId = -this.chatId; tab.peerId = -this.chatId;
@ -83,7 +84,8 @@ export default class AppEditGroupTab extends SliderSuperTab {
}); });
const setGroupTypeSubtitle = () => { const setGroupTypeSubtitle = () => {
groupTypeRow.subtitle.innerHTML = chat.username ? 'Public' : 'Private'; groupTypeRow.subtitle.textContent = '';
groupTypeRow.subtitle.append(i18n(chat.username ? 'TypePublicGroup' : 'TypePrivateGroup'));
}; };
setGroupTypeSubtitle(); setGroupTypeSubtitle();
@ -103,7 +105,7 @@ export default class AppEditGroupTab extends SliderSuperTab {
] as ChatRights[]; ] as ChatRights[];
const permissionsRow = new Row({ const permissionsRow = new Row({
title: 'Permissions', titleLangKey: 'ChannelPermissions',
clickable: () => { clickable: () => {
const tab = new AppGroupPermissionsTab(this.slider); const tab = new AppGroupPermissionsTab(this.slider);
tab.chatId = this.chatId; tab.chatId = this.chatId;
@ -127,7 +129,7 @@ export default class AppEditGroupTab extends SliderSuperTab {
} }
const administratorsRow = new Row({ const administratorsRow = new Row({
title: 'Administrators', titleLangKey: 'PeerInfo.Administrators',
subtitle: '' + ((chatFull as ChatFull.channelFull).admins_count || 1), subtitle: '' + ((chatFull as ChatFull.channelFull).admins_count || 1),
icon: 'admin', icon: 'admin',
clickable: true clickable: true
@ -170,7 +172,7 @@ export default class AppEditGroupTab extends SliderSuperTab {
}); });
const membersRow = new Row({ const membersRow = new Row({
title: 'Members', titleLangKey: 'GroupMembers',
subtitle: '2 500', subtitle: '2 500',
icon: 'newgroup', icon: 'newgroup',
clickable: true clickable: true
@ -197,15 +199,21 @@ export default class AppEditGroupTab extends SliderSuperTab {
if(appChatsManager.isChannel(this.chatId) && appChatsManager.hasRights(this.chatId, 'delete_chat')) { if(appChatsManager.isChannel(this.chatId) && appChatsManager.hasRights(this.chatId, 'delete_chat')) {
const section = new SettingSection({}); const section = new SettingSection({});
const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'Delete Group'}); const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'DeleteMega'});
attachClickEvent(btnDelete, () => { attachClickEvent(btnDelete, () => {
new PopupPeer('popup-delete-group', { new PopupPeer('popup-delete-group', {
peerId: -this.chatId, peerId: -this.chatId,
title: 'Delete Group?', titleLangKey: 'DeleteMegaMenu',
description: `Are you sure you want to delete this group? All members will be removed, and all messages will be lost.`, descriptionLangKey: 'AreYouSureDeleteAndExit',
buttons: addCancelButton([{ buttons: addCancelButton([{
text: 'DELETE', langKey: 'DeleteMegaMenu',
callback: () => {
const toggle = toggleDisability([btnDelete], true);
},
isDanger: true
}, {
langKey: 'DeleteChat.DeleteGroupForAll',
callback: () => { callback: () => {
const toggle = toggleDisability([btnDelete], true); const toggle = toggleDisability([btnDelete], true);
@ -214,6 +222,12 @@ export default class AppEditGroupTab extends SliderSuperTab {
}, () => { }, () => {
toggle(); toggle();
}); });
/* appChatsManager.deleteChannel(this.chatId).then(() => {
this.close();
}, () => {
toggle();
}); */
}, },
isDanger: true isDanger: true
}]) }])

View File

@ -27,7 +27,7 @@ export default class AppGifsTab extends SliderSuperTab {
protected init() { protected init() {
this.container.id = 'search-gifs-container'; this.container.id = 'search-gifs-container';
this.inputSearch = new InputSearch('Search GIFs', (value) => { this.inputSearch = new InputSearch('SearchGifsTitle', (value) => {
this.reset(); this.reset();
this.search(value); this.search(value);
}); });

View File

@ -5,6 +5,7 @@ import { ChannelParticipant, Chat, ChatBannedRights, Update } from "../../../lay
import appChatsManager, { ChatRights } from "../../../lib/appManagers/appChatsManager"; import appChatsManager, { ChatRights } from "../../../lib/appManagers/appChatsManager";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import appProfileManager from "../../../lib/appManagers/appProfileManager"; import appProfileManager from "../../../lib/appManagers/appProfileManager";
import I18n, { i18n } from "../../../lib/langPack";
import rootScope from "../../../lib/rootScope"; import rootScope from "../../../lib/rootScope";
import CheckboxField from "../../checkboxField"; import CheckboxField from "../../checkboxField";
import PopupPickUser from "../../popups/pickUser"; import PopupPickUser from "../../popups/pickUser";
@ -29,14 +30,14 @@ export class ChatPermissions {
participant?: ChannelParticipant.channelParticipantBanned participant?: ChannelParticipant.channelParticipantBanned
}) { }) {
this.v = [ this.v = [
{flags: ['send_messages'], text: 'Send Messages'}, {flags: ['send_messages'], text: 'UserRestrictionsSend'},
{flags: ['send_media'], text: 'Send Media'}, {flags: ['send_media'], text: 'UserRestrictionsSendMedia'},
{flags: ['send_stickers', 'send_gifs'], text: 'Send Stickers & GIFs'}, {flags: ['send_stickers', 'send_gifs'], text: 'UserRestrictionsSendStickers'},
{flags: ['send_polls'], text: 'Send Polls'}, {flags: ['send_polls'], text: 'UserRestrictionsSendPolls'},
{flags: ['embed_links'], text: 'Send Links'}, {flags: ['embed_links'], text: 'UserRestrictionsEmbedLinks'},
{flags: ['invite_users'], text: 'Add Users'}, {flags: ['invite_users'], text: 'UserRestrictionsInviteUsers'},
{flags: ['pin_messages'], text: 'Pin Messages'}, {flags: ['pin_messages'], text: 'UserRestrictionsPinMessages'},
{flags: ['change_info'], text: 'Change Chat Info'} {flags: ['change_info'], text: 'UserRestrictionsChangeInfo'}
]; ];
this.toggleWith = { this.toggleWith = {
@ -71,7 +72,7 @@ export class ChatPermissions {
}); */ }); */
attachClickEvent(info.checkboxField.label, (e) => { attachClickEvent(info.checkboxField.label, (e) => {
toast('This option is disabled for all members in Group Permissions.'); toast(I18n.format('UserRestrictionsDisabled', true));
}, {listenerSetter: options.listenerSetter}); }, {listenerSetter: options.listenerSetter});
} }
@ -116,12 +117,12 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
protected async init() { protected async init() {
this.container.classList.add('edit-peer-container', 'group-permissions-container'); this.container.classList.add('edit-peer-container', 'group-permissions-container');
this.title.innerHTML = 'Permissions'; this.setTitle('ChannelPermissions');
let chatPermissions: ChatPermissions; let chatPermissions: ChatPermissions;
{ {
const section = new SettingSection({ const section = new SettingSection({
name: 'What can members of this group do?', name: 'ChannelPermissionsHeader',
}); });
chatPermissions = new ChatPermissions({ chatPermissions = new ChatPermissions({
@ -139,12 +140,12 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
{ {
const section = new SettingSection({ const section = new SettingSection({
name: 'Exceptions' name: 'PrivacyExceptions'
}); });
const addExceptionRow = new Row({ const addExceptionRow = new Row({
title: 'Add Exception', titleLangKey: 'ChannelAddException',
subtitle: 'Loading...', subtitleLangKey: 'Loading',
icon: 'adduser', icon: 'adduser',
clickable: () => { clickable: () => {
new PopupPickUser({ new PopupPickUser({
@ -177,8 +178,8 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
}; };
const removedUsersRow = new Row({ const removedUsersRow = new Row({
title: 'Removed Users', titleLangKey: 'ChannelBlockedUsers',
subtitle: 'No removed users', subtitleLangKey: 'NoBlockedUsers',
icon: 'deleteuser', icon: 'deleteuser',
clickable: true clickable: true
}); });
@ -277,7 +278,8 @@ export default class AppGroupPermissionsTab extends SliderSuperTabEventable {
}); });
const setLength = () => { const setLength = () => {
addExceptionRow.subtitle.innerHTML = exceptionsCount ? exceptionsCount + ' exceptions' : 'None'; addExceptionRow.subtitle.textContent = '';
addExceptionRow.subtitle.append(i18n(exceptionsCount ? 'Permissions.ExceptionsCount' : 'Permissions.NoExceptions', [exceptionsCount]));
}; };
let exceptionsCount = 0; let exceptionsCount = 0;

View File

@ -13,6 +13,7 @@ import { SettingSection } from "../../sidebarLeft";
import { toast } from "../../toast"; import { toast } from "../../toast";
import { UsernameInputField } from "../../usernameInputField"; import { UsernameInputField } from "../../usernameInputField";
import { SliderSuperTabEventable } from "../../sliderTab"; import { SliderSuperTabEventable } from "../../sliderTab";
import I18n from "../../../lib/langPack";
export default class AppGroupTypeTab extends SliderSuperTabEventable { export default class AppGroupTypeTab extends SliderSuperTabEventable {
public peerId: number; public peerId: number;
@ -20,28 +21,28 @@ export default class AppGroupTypeTab extends SliderSuperTabEventable {
protected init() { protected init() {
this.container.classList.add('edit-peer-container', 'group-type-container'); this.container.classList.add('edit-peer-container', 'group-type-container');
this.title.innerHTML = 'Group Type'; this.setTitle('GroupType');
const section = new SettingSection({ const section = new SettingSection({
name: 'Group Type' name: 'GroupType'
}); });
const random = randomLong(); const random = randomLong();
const privateRow = new Row({ const privateRow = new Row({
radioField: new RadioField({ radioField: new RadioField({
text: 'Private Group', langKey: 'MegaPrivate',
name: random, name: random,
value: 'private' value: 'private'
}), }),
subtitle: 'Private groups can only be joined if you were invited or have an invite link.' subtitleLangKey: 'MegaPrivateInfo'
}); });
const publicRow = new Row({ const publicRow = new Row({
radioField: new RadioField({ radioField: new RadioField({
text: 'Public Group', langKey: 'MegaPublic',
name: random, name: random,
value: 'public' value: 'public'
}), }),
subtitle: 'Public groups can be found in search, history is available to everyone and anyone can join.' subtitleLangKey: 'MegaPublicInfo'
}); });
const form = RadioFormFromRows([privateRow, publicRow], (value) => { const form = RadioFormFromRows([privateRow, publicRow], (value) => {
const a = [privateSection, publicSection]; const a = [privateSection, publicSection];
@ -62,18 +63,18 @@ export default class AppGroupTypeTab extends SliderSuperTabEventable {
//let revoked = false; //let revoked = false;
const linkRow = new Row({ const linkRow = new Row({
title: (this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link, title: (this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link,
subtitle: 'People can join your group by following this link. You can revoke the link at any time.', subtitleLangKey: 'MegaPrivateLinkHelp',
clickable: () => { clickable: () => {
copyTextToClipboard((this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link); copyTextToClipboard((this.chatFull.exported_invite as ExportedChatInvite.chatInviteExported).link);
toast('Invite link copied to clipboard.'); toast(I18n.format('LinkCopied', true));
} }
}); });
const btnRevoke = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'Revoke Link'}); const btnRevoke = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'RevokeLink'});
attachClickEvent(btnRevoke, () => { attachClickEvent(btnRevoke, () => {
new PopupConfirmAction('revoke-link', [{ new PopupConfirmAction('revoke-link', [{
text: 'OK', langKey: 'RevokeButton',
callback: () => { callback: () => {
const toggle = toggleDisability([btnRevoke], true); const toggle = toggleDisability([btnRevoke], true);
@ -85,15 +86,15 @@ export default class AppGroupTypeTab extends SliderSuperTabEventable {
}); });
} }
}], { }], {
title: 'Revoke Link?', title: 'RevokeLink',
text: 'Your previous link will be deactivated and we\'ll generate a new invite link for you.' text: 'RevokeAlert'
}).show(); }).show();
}, {listenerSetter: this.listenerSetter}); }, {listenerSetter: this.listenerSetter});
privateSection.content.append(linkRow.container, btnRevoke); privateSection.content.append(linkRow.container, btnRevoke);
const publicSection = new SettingSection({ const publicSection = new SettingSection({
caption: 'People can share this link with others and find your group using Telegram search.', caption: 'Channel.UsernameAboutGroup',
noDelimiter: true noDelimiter: true
}); });
@ -109,13 +110,13 @@ export default class AppGroupTypeTab extends SliderSuperTabEventable {
}; };
const linkInputField = new UsernameInputField({ const linkInputField = new UsernameInputField({
label: 'Link', label: 'SetUrlPlaceholder',
name: 'group-public-link', name: 'group-public-link',
plainText: true, plainText: true,
listenerSetter: this.listenerSetter, listenerSetter: this.listenerSetter,
availableText: 'Link is available', availableText: 'Link.Available',
invalidText: 'Link is invalid', invalidText: 'Link is invalid',
takenText: 'Link is already taken', takenText: 'Link.Taken',
onChange: onChange, onChange: onChange,
peerId: this.peerId, peerId: this.peerId,
head: placeholder head: placeholder

View File

@ -5,6 +5,7 @@ import { roundPercents } from "../../poll";
import { RichTextProcessor } from "../../../lib/richtextprocessor"; import { RichTextProcessor } from "../../../lib/richtextprocessor";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import { ripple } from "../../ripple"; import { ripple } from "../../ripple";
import { i18n } from "../../../lib/langPack";
export default class AppPollResultsTab extends SliderSuperTab { export default class AppPollResultsTab extends SliderSuperTab {
private resultsDiv: HTMLElement; private resultsDiv: HTMLElement;
@ -13,8 +14,6 @@ export default class AppPollResultsTab extends SliderSuperTab {
this.container.id = 'poll-results-container'; this.container.id = 'poll-results-container';
this.container.classList.add('chatlist-container'); this.container.classList.add('chatlist-container');
this.title.innerHTML = 'Results';
this.resultsDiv = document.createElement('div'); this.resultsDiv = document.createElement('div');
this.resultsDiv.classList.add('poll-results'); this.resultsDiv.classList.add('poll-results');
this.scrollable.append(this.resultsDiv); this.scrollable.append(this.resultsDiv);
@ -24,6 +23,8 @@ export default class AppPollResultsTab extends SliderSuperTab {
const ret = super.open(); const ret = super.open();
const poll = appPollsManager.getPoll(message.media.poll.id); const poll = appPollsManager.getPoll(message.media.poll.id);
this.setTitle(poll.poll.pFlags.quiz ? 'PollResults.Title.Quiz' : 'PollResults.Title.Poll');
const title = document.createElement('h3'); const title = document.createElement('h3');
title.innerHTML = poll.poll.rQuestion; title.innerHTML = poll.poll.rQuestion;
@ -82,7 +83,7 @@ export default class AppPollResultsTab extends SliderSuperTab {
if(offset) { if(offset) {
left -= votesList.votes.length; left -= votesList.votes.length;
(showMore.lastElementChild as HTMLElement).innerText = `Show ${Math.min(20, left)} more voter${left > 1 ? 's' : ''}`; (showMore.lastElementChild as HTMLElement).replaceWith(i18n('PollResults.LoadMore', [Math.min(20, left)]));
} }
offset = votesList.next_offset; offset = votesList.next_offset;
@ -101,11 +102,12 @@ export default class AppPollResultsTab extends SliderSuperTab {
if(left <= 0) return; if(left <= 0) return;
const showMore = document.createElement('div'); const showMore = document.createElement('div');
showMore.classList.add('poll-results-more', 'show-more'); showMore.classList.add('poll-results-more', 'show-more', 'rp-overflow');
showMore.addEventListener('click', load); showMore.addEventListener('click', load);
showMore.innerHTML = `<div class="tgico-down"></div><div>Show ${Math.min(20, left)} more voter${left > 1 ? 's' : ''}</div>`;
ripple(showMore); ripple(showMore);
const down = document.createElement('div');
down.classList.add('tgico-down');
showMore.append(down, i18n('PollResults.LoadMore', [Math.min(20, left)]));
fragment.append(showMore); fragment.append(showMore);
}); });

View File

@ -2,14 +2,14 @@ import appImManager from "../../../lib/appManagers/appImManager";
import appMessagesManager from "../../../lib/appManagers/appMessagesManager"; import appMessagesManager from "../../../lib/appManagers/appMessagesManager";
import appPeersManager from "../../../lib/appManagers/appPeersManager"; import appPeersManager from "../../../lib/appManagers/appPeersManager";
import appProfileManager from "../../../lib/appManagers/appProfileManager"; import appProfileManager from "../../../lib/appManagers/appProfileManager";
import appUsersManager from "../../../lib/appManagers/appUsersManager"; import appUsersManager, { User } from "../../../lib/appManagers/appUsersManager";
import { logger } from "../../../lib/logger"; import { logger } from "../../../lib/logger";
import { RichTextProcessor } from "../../../lib/richtextprocessor"; import { RichTextProcessor } from "../../../lib/richtextprocessor";
import rootScope from "../../../lib/rootScope"; import rootScope from "../../../lib/rootScope";
import AppSearchSuper, { SearchSuperType } from "../../appSearchSuper."; import AppSearchSuper, { SearchSuperType } from "../../appSearchSuper.";
import AvatarElement from "../../avatar"; import AvatarElement from "../../avatar";
import Scrollable from "../../scrollable"; import Scrollable from "../../scrollable";
import { SliderTab } from "../../slider"; import SidebarSlider, { SliderSuperTab, SliderTab } from "../../slider";
import CheckboxField from "../../checkboxField"; import CheckboxField from "../../checkboxField";
import { attachClickEvent } from "../../../helpers/dom"; import { attachClickEvent } from "../../../helpers/dom";
import appSidebarRight from ".."; import appSidebarRight from "..";
@ -19,27 +19,25 @@ import AppEditGroupTab from "./editGroup";
import PeerTitle from "../../peerTitle"; import PeerTitle from "../../peerTitle";
import AppEditChannelTab from "./editChannel"; import AppEditChannelTab from "./editChannel";
import AppEditContactTab from "./editContact"; import AppEditContactTab from "./editContact";
import appChatsManager from "../../../lib/appManagers/appChatsManager"; import appChatsManager, { Channel } from "../../../lib/appManagers/appChatsManager";
import { Chat } from "../../../layer"; import { Chat } from "../../../layer";
import Button from "../../button";
import ButtonIcon from "../../buttonIcon";
import I18n, { i18n } from "../../../lib/langPack";
import { SettingSection } from "../../sidebarLeft";
import Row from "../../row";
import { copyTextToClipboard } from "../../../helpers/clipboard";
import { toast } from "../../toast";
let setText = (text: string, el: HTMLDivElement) => { let setText = (text: string, row: Row) => {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
if(el.childElementCount > 1) { row.title.innerHTML = text;
el.firstElementChild.remove(); row.container.style.display = '';
}
let p = document.createElement('p');
p.innerHTML = text;
el.prepend(p);
el.style.display = '';
}); });
}; };
// TODO: отредактированное сообщение не изменится // TODO: отредактированное сообщение не изменится
export default class AppSharedMediaTab implements SliderTab { export default class AppSharedMediaTab extends SliderSuperTab {
public container: HTMLElement;
public closeBtn: HTMLButtonElement;
public editBtn: HTMLElement; public editBtn: HTMLElement;
private peerId = 0; private peerId = 0;
@ -50,12 +48,10 @@ export default class AppSharedMediaTab implements SliderTab {
avatar: AvatarElement, avatar: AvatarElement,
name: HTMLDivElement, name: HTMLDivElement,
subtitle: HTMLDivElement, subtitle: HTMLDivElement,
bio: HTMLDivElement, bio: Row,
username: HTMLDivElement, username: Row,
phone: HTMLDivElement, phone: Row,
notificationsRow: HTMLDivElement, notifications: Row
notificationsCheckbox: HTMLInputElement,
notificationsStatus: HTMLParagraphElement
} = {} as any; } = {} as any;
public historiesStorage: { public historiesStorage: {
@ -64,8 +60,6 @@ export default class AppSharedMediaTab implements SliderTab {
}> }>
} = {}; } = {};
public scroll: Scrollable = null;
private log = logger('SM'/* , LogLevels.error */); private log = logger('SM'/* , LogLevels.error */);
setPeerStatusInterval: number; setPeerStatusInterval: number;
cleaned: boolean; cleaned: boolean;
@ -73,44 +67,118 @@ export default class AppSharedMediaTab implements SliderTab {
private setBioTimeout: number; private setBioTimeout: number;
public init() { constructor(slider: SidebarSlider) {
this.container = document.getElementById('shared-media-container'); super(slider, false);
this.closeBtn = this.container.querySelector('.sidebar-header .btn-icon'); }
this.closeBtn.classList.add('sidebar-close-button');
this.editBtn = this.container.querySelector('.sidebar-header .tgico-edit');
this.profileContentEl = this.container.querySelector('.profile-content'); protected init() {
this.profileElements = { this.container.id = 'shared-media-container';
avatar: this.profileContentEl.querySelector('.profile-avatar'), this.container.classList.add('profile-container');
name: this.profileContentEl.querySelector('.profile-name'),
subtitle: this.profileContentEl.querySelector('.profile-subtitle'),
bio: this.profileContentEl.querySelector('.profile-row-bio'),
username: this.profileContentEl.querySelector('.profile-row-username'),
phone: this.profileContentEl.querySelector('.profile-row-phone'),
notificationsRow: this.profileContentEl.querySelector('.profile-row-notifications'),
notificationsCheckbox: null,
notificationsStatus: this.profileContentEl.querySelector('.profile-row-notifications > p')
};
const checkboxField = new CheckboxField({ // * header
text: 'Notifications', const newCloseBtn = Button('btn-icon sidebar-close-button', {noRipple: true});
name: 'notifications' this.closeBtn.replaceWith(newCloseBtn);
this.closeBtn = newCloseBtn;
const animatedCloseIcon = document.createElement('div');
animatedCloseIcon.classList.add('animated-close-icon');
newCloseBtn.append(animatedCloseIcon);
const transitionContainer = document.createElement('div');
transitionContainer.className = 'transition slide-fade';
const transitionFirstItem = document.createElement('div');
transitionFirstItem.classList.add('transition-item');
this.title.append(i18n('Telegram.PeerInfoController'));
this.editBtn = ButtonIcon('edit');
const moreBtn = ButtonIcon('more');
transitionFirstItem.append(this.title, this.editBtn, moreBtn);
const transitionLastItem = document.createElement('div');
transitionLastItem.classList.add('transition-item');
const secondTitle: HTMLElement = this.title.cloneNode() as any;
secondTitle.append(i18n('PeerInfo.SharedMedia'));
transitionLastItem.append(secondTitle);
transitionContainer.append(transitionFirstItem, transitionLastItem);
this.header.append(transitionContainer);
// * body
this.profileContentEl = document.createElement('div');
this.profileContentEl.classList.add('profile-content');
const section = new SettingSection({
noDelimiter: true
}); });
this.profileElements.notificationsCheckbox = checkboxField.input;
this.profileElements.notificationsCheckbox.checked = true;
this.profileElements.notificationsRow.prepend(checkboxField.label);
this.scroll = new Scrollable(this.container, 'SR', 400); this.profileElements.avatar = new AvatarElement();
this.profileElements.avatar.classList.add('profile-avatar', 'avatar-120');
this.profileElements.avatar.setAttribute('dialog', '1');
this.profileElements.avatar.setAttribute('clickable', '');
this.profileElements.name = document.createElement('div');
this.profileElements.name.classList.add('profile-name');
this.profileElements.subtitle = document.createElement('div');
this.profileElements.subtitle.classList.add('profile-subtitle');
this.profileElements.bio = new Row({
title: ' ',
subtitleLangKey: 'UserBio',
icon: 'info',
clickable: () => {
appProfileManager.getProfileByPeerId(this.peerId).then(full => {
copyTextToClipboard(full.about);
toast(I18n.format('BioCopied', true));
});
}
});
this.profileElements.username = new Row({
title: ' ',
subtitleLangKey: 'Username',
icon: 'username',
clickable: () => {
const peer: Channel | User = appPeersManager.getPeer(this.peerId);
copyTextToClipboard('@' + peer.username);
toast(I18n.format('UsernameCopied', true));
}
});
this.profileElements.phone = new Row({
title: ' ',
subtitleLangKey: 'Phone',
icon: 'phone',
clickable: () => {
const peer: User = appUsersManager.getUser(this.peerId);
copyTextToClipboard('+' + peer.phone);
toast(I18n.format('PhoneCopied', true));
}
});
this.profileElements.notifications = new Row({
checkboxField: new CheckboxField({text: 'Notifications'})
});
section.content.append(this.profileElements.avatar, this.profileElements.name, this.profileElements.subtitle,
this.profileElements.bio.container, this.profileElements.username.container, this.profileElements.phone.container, this.profileElements.notifications.container);
this.profileContentEl.append(section.container);
this.scrollable.append(this.profileContentEl);
const HEADER_HEIGHT = 56; const HEADER_HEIGHT = 56;
const closeIcon = this.closeBtn.firstElementChild as HTMLElement; this.scrollable.onAdditionalScroll = () => {
this.scroll.onAdditionalScroll = () => {
const rect = this.searchSuper.nav.getBoundingClientRect(); const rect = this.searchSuper.nav.getBoundingClientRect();
if(!rect.width) return; if(!rect.width) return;
const top = rect.top; const top = rect.top;
const isSharedMedia = top <= HEADER_HEIGHT; const isSharedMedia = top <= HEADER_HEIGHT;
closeIcon.classList.toggle('state-back', isSharedMedia); animatedCloseIcon.classList.toggle('state-back', isSharedMedia);
transition(+isSharedMedia); transition(+isSharedMedia);
if(!isSharedMedia) { if(!isSharedMedia) {
@ -118,16 +186,16 @@ export default class AppSharedMediaTab implements SliderTab {
} }
}; };
const transition = TransitionSlider(this.closeBtn.nextElementSibling as HTMLElement, 'slide-fade', 400, null, false); const transition = TransitionSlider(transitionContainer, 'slide-fade', 400, null, false);
transition(0); transition(0);
attachClickEvent(this.closeBtn, (e) => { attachClickEvent(this.closeBtn, (e) => {
if(this.closeBtn.firstElementChild.classList.contains('state-back')) { if(this.closeBtn.firstElementChild.classList.contains('state-back')) {
this.scroll.scrollIntoViewNew(this.scroll.container.firstElementChild as HTMLElement, 'start'); this.scrollable.scrollIntoViewNew(this.scrollable.container.firstElementChild as HTMLElement, 'start');
transition(0); transition(0);
closeIcon.classList.remove('state-back'); animatedCloseIcon.classList.remove('state-back');
} else if(!this.scroll.isHeavyAnimationInProgress) { } else if(!this.scrollable.isHeavyAnimationInProgress) {
appSidebarRight.onCloseBtnClick(); appSidebarRight.onCloseBtnClick();
} }
}); });
@ -153,9 +221,13 @@ export default class AppSharedMediaTab implements SliderTab {
} }
}); });
this.container.prepend(this.closeBtn.parentElement); //this.container.prepend(this.closeBtn.parentElement);
this.profileElements.notifications.checkboxField.input.addEventListener('change', (e) => {
if(!e.isTrusted) {
return;
}
this.profileElements.notificationsCheckbox.addEventListener('change', () => {
//let checked = this.profileElements.notificationsCheckbox.checked; //let checked = this.profileElements.notificationsCheckbox.checked;
appMessagesManager.mutePeer(this.peerId); appMessagesManager.mutePeer(this.peerId);
}); });
@ -163,8 +235,7 @@ export default class AppSharedMediaTab implements SliderTab {
rootScope.on('dialog_notify_settings', (dialog) => { rootScope.on('dialog_notify_settings', (dialog) => {
if(this.peerId === dialog.peerId) { if(this.peerId === dialog.peerId) {
const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false); const muted = appNotificationsManager.isPeerLocalMuted(this.peerId, false);
this.profileElements.notificationsCheckbox.checked = !muted; this.profileElements.notifications.checkboxField.checked = !muted;
this.profileElements.notificationsStatus.innerText = muted ? 'Disabled' : 'Enabled';
} }
}); });
@ -208,7 +279,7 @@ export default class AppSharedMediaTab implements SliderTab {
inputFilter: 'inputMessagesFilterMusic', inputFilter: 'inputMessagesFilterMusic',
name: 'SharedMusicTab2', name: 'SharedMusicTab2',
type: 'music' type: 'music'
}], this.scroll/* , undefined, undefined, false */); }], this.scrollable/* , undefined, undefined, false */);
this.profileContentEl.append(this.searchSuper.container); this.profileContentEl.append(this.searchSuper.container);
} }
@ -226,7 +297,8 @@ export default class AppSharedMediaTab implements SliderTab {
return; return;
} }
this.profileElements.subtitle.innerHTML = subtitle || ''; this.profileElements.subtitle.textContent = '';
this.profileElements.subtitle.append(subtitle || '');
}); });
}; };
@ -287,16 +359,15 @@ export default class AppSharedMediaTab implements SliderTab {
} }
} }
this.scroll.onScroll(); this.scrollable.onScroll();
} }
public cleanupHTML() { public cleanupHTML() {
this.profileElements.bio.style.display = 'none'; this.profileElements.bio.container.style.display = 'none';
this.profileElements.phone.style.display = 'none'; this.profileElements.phone.container.style.display = 'none';
this.profileElements.username.style.display = 'none'; this.profileElements.username.container.style.display = 'none';
this.profileElements.notificationsRow.style.display = ''; this.profileElements.notifications.container.style.display = '';
this.profileElements.notificationsCheckbox.checked = true; this.profileElements.notifications.checkboxField.checked = true;
this.profileElements.notificationsStatus.innerText = 'Enabled';
this.editBtn.style.display = 'none'; this.editBtn.style.display = 'none';
if(this.setBioTimeout) { if(this.setBioTimeout) {
window.clearTimeout(this.setBioTimeout); window.clearTimeout(this.setBioTimeout);
@ -351,11 +422,10 @@ export default class AppSharedMediaTab implements SliderTab {
} }
const muted = appNotificationsManager.isPeerLocalMuted(peerId, false); const muted = appNotificationsManager.isPeerLocalMuted(peerId, false);
this.profileElements.notificationsCheckbox.checked = !muted; this.profileElements.notifications.checkboxField.checked = !muted;
this.profileElements.notificationsStatus.innerText = muted ? 'Disabled' : 'Enabled';
} else { } else {
window.requestAnimationFrame(() => { window.requestAnimationFrame(() => {
this.profileElements.notificationsRow.style.display = 'none'; this.profileElements.notifications.container.style.display = 'none';
}); });
} }
@ -446,6 +516,6 @@ export default class AppSharedMediaTab implements SliderTab {
} }
onOpenAfterTimeout() { onOpenAfterTimeout() {
this.scroll.onScroll(); this.scrollable.onScroll();
} }
} }

View File

@ -11,6 +11,7 @@ import { wrapSticker } from "../../wrappers";
import appSidebarRight from ".."; import appSidebarRight from "..";
import { StickerSet, StickerSetCovered } from "../../../layer"; import { StickerSet, StickerSetCovered } from "../../../layer";
import { forEachReverse } from "../../../helpers/array"; import { forEachReverse } from "../../../helpers/array";
import { i18n } from "../../../lib/langPack";
export default class AppStickersTab extends SliderSuperTab { export default class AppStickersTab extends SliderSuperTab {
private inputSearch: InputSearch; private inputSearch: InputSearch;
@ -23,7 +24,7 @@ export default class AppStickersTab extends SliderSuperTab {
this.lazyLoadQueue = new LazyLoadQueue(); this.lazyLoadQueue = new LazyLoadQueue();
this.inputSearch = new InputSearch('Search Stickers', (value) => { this.inputSearch = new InputSearch('StickersTab.SearchPlaceholder', (value) => {
this.search(value); this.search(value);
}); });
@ -57,7 +58,8 @@ export default class AppStickersTab extends SliderSuperTab {
appStickersManager.getStickerSet({id, access_hash}).then(full => { appStickersManager.getStickerSet({id, access_hash}).then(full => {
appStickersManager.toggleStickerSet(full.set).then(changed => { appStickersManager.toggleStickerSet(full.set).then(changed => {
if(changed) { if(changed) {
button.innerText = full.set.installed_date ? 'Added' : 'Add'; button.textContent = '';
button.append(i18n(full.set.installed_date ? 'Stickers.SearchAdded' : 'Stickers.SearchAdd'));
button.classList.toggle('gray', !!full.set.installed_date); button.classList.toggle('gray', !!full.set.installed_date);
} }
}).finally(() => { }).finally(() => {
@ -91,12 +93,16 @@ export default class AppStickersTab extends SliderSuperTab {
details.classList.add('sticker-set-details'); details.classList.add('sticker-set-details');
details.innerHTML = ` details.innerHTML = `
<div class="sticker-set-name">${RichTextProcessor.wrapEmojiText(set.title)}</div> <div class="sticker-set-name">${RichTextProcessor.wrapEmojiText(set.title)}</div>
<div class="sticker-set-count">${set.count} stickers</div>
`; `;
const countDiv = document.createElement('div');
countDiv.classList.add('sticker-set-count');
countDiv.append(i18n('Stickers.Count', [set.count]));
details.append(countDiv);
const button = document.createElement('button'); const button = document.createElement('button');
button.classList.add('btn-primary', 'btn-color-primary', 'sticker-set-button'); button.classList.add('btn-primary', 'btn-color-primary', 'sticker-set-button');
button.innerText = set.installed_date ? 'Added' : 'Add'; button.append(i18n(set.installed_date ? 'Stickers.SearchAdded' : 'Stickers.SearchAdd'));
// button.style.width = set.installed_date ? '68px' : '52px'; // button.style.width = set.installed_date ? '68px' : '52px';
if(set.installed_date) { if(set.installed_date) {

View File

@ -19,13 +19,13 @@ export default class AppUserPermissionsTab extends SliderSuperTabEventable {
protected init() { protected init() {
this.container.classList.add('edit-peer-container', 'user-permissions-container'); this.container.classList.add('edit-peer-container', 'user-permissions-container');
this.title.innerHTML = 'User Permissions'; this.setTitle('UserRestrictions');
let destroyListener: () => void; let destroyListener: () => void;
{ {
const section = new SettingSection({ const section = new SettingSection({
name: 'What can this user do?', name: 'UserRestrictionsCanDo',
}); });
const div = document.createElement('div'); const div = document.createElement('div');
@ -43,7 +43,7 @@ export default class AppUserPermissionsTab extends SliderSuperTabEventable {
avatarSize: 48 avatarSize: 48
}); });
dom.lastMessageSpan.innerHTML = appUsersManager.getUserStatusString(this.userId); dom.lastMessageSpan.append(appUsersManager.getUserStatusString(this.userId));
const p = new ChatPermissions({ const p = new ChatPermissions({
chatId: this.chatId, chatId: this.chatId,
@ -71,7 +71,7 @@ export default class AppUserPermissionsTab extends SliderSuperTabEventable {
const section = new SettingSection({}); const section = new SettingSection({});
if(this.participant._ === 'channelParticipantBanned') { if(this.participant._ === 'channelParticipantBanned') {
const btnDeleteException = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'Delete Exception'}); const btnDeleteException = Button('btn-primary btn-transparent danger', {icon: 'delete', text: 'GroupPermission.Delete'});
attachClickEvent(btnDeleteException, () => { attachClickEvent(btnDeleteException, () => {
const toggle = toggleDisability([btnDeleteException], true); const toggle = toggleDisability([btnDeleteException], true);
@ -86,10 +86,15 @@ export default class AppUserPermissionsTab extends SliderSuperTabEventable {
section.content.append(btnDeleteException); section.content.append(btnDeleteException);
} }
const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'deleteuser', text: 'Ban and Remove From Group'}); const btnDelete = Button('btn-primary btn-transparent danger', {icon: 'deleteuser', text: 'UserRestrictionsBlock'});
attachClickEvent(btnDelete, () => { attachClickEvent(btnDelete, () => {
new PopupPeer('popup-group-kick-user', { const toggle = toggleDisability([btnDelete], true);
appChatsManager.kickFromChannel(this.chatId, this.participant).then(() => {
this.eventListener.removeEventListener('destroy', destroyListener);
this.close();
});
/* new PopupPeer('popup-group-kick-user', {
peerId: -this.chatId, peerId: -this.chatId,
title: 'Ban User?', title: 'Ban User?',
description: `Are you sure you want to ban <b>${appPeersManager.getPeerTitle(this.userId)}</b>`, description: `Are you sure you want to ban <b>${appPeersManager.getPeerTitle(this.userId)}</b>`,
@ -107,7 +112,7 @@ export default class AppUserPermissionsTab extends SliderSuperTabEventable {
}, },
isDanger: true isDanger: true
}]) }])
}).show(); }).show(); */
}, {listenerSetter: this.listenerSetter}); }, {listenerSetter: this.listenerSetter});
section.content.append(btnDelete); section.content.append(btnDelete);

View File

@ -2,7 +2,7 @@ const App = {
id: 1025907, id: 1025907,
hash: '452b0359b988148995f22ff0f4229750', hash: '452b0359b988148995f22ff0f4229750',
version: '0.4.0', version: '0.4.0',
langPackVersion: '0.0.4', langPackVersion: '0.0.5',
domains: [] as string[], domains: [] as string[],
baseDcId: 2 baseDcId: 2
}; };

View File

@ -811,3 +811,13 @@ export function htmlToSpan(html: string) {
span.innerHTML = html; span.innerHTML = html;
return span; return span;
} }
export function replaceContent(elem: HTMLElement, node: string | Node) {
if(elem.children.length === 1) {
elem.firstChild.remove();
} else {
elem.textContent = '';
}
elem.append(node);
}

View File

@ -1,4 +1,4 @@
export function numberThousandSplitter(x: number, joiner = ',') { export function numberThousandSplitter(x: number, joiner = ' ') {
const parts = x.toString().split("."); const parts = x.toString().split(".");
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, joiner); parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, joiner);
return parts.join("."); return parts.join(".");

View File

@ -118,47 +118,7 @@
</div> </div>
<div class="main-column" id="column-center"></div> <div class="main-column" id="column-center"></div>
<div class="sidebar sidebar-right main-column" id="column-right"> <div class="sidebar sidebar-right main-column" id="column-right">
<div class="sidebar-content sidebar-slider tabs-container"> <div class="sidebar-content sidebar-slider tabs-container"></div>
<div class="sidebar-slider-item profile-container" id="shared-media-container">
<div class="sidebar-header">
<button class="btn-icon">
<div class="animated-close-icon"></div>
</button>
<div class="transition slide-fade">
<div class="transition-item">
<div class="sidebar-header__title">Info</div>
<div class="btn-icon tgico-edit"></div>
<div class="btn-icon tgico-more"></div>
</div>
<div class="transition-item">
<div class="sidebar-header__title">Shared Media</div>
</div>
</div>
</div>
<div class="profile-content">
<div class="profile-content-wrapper">
<avatar-element class="profile-avatar avatar-120" dialog="1" clickable></avatar-element>
<div class="profile-name"></div>
<div class="profile-subtitle"></div>
<div class="profile-row profile-row-bio tgico-info">
<p></p>
<p class="profile-row-label">Bio</p>
</div>
<div class="profile-row profile-row-username tgico-username">
<p></p>
<p class="profile-row-label">Username</p>
</div>
<div class="profile-row profile-row-phone tgico-phone">
<p></p>
<p class="profile-row-label">Phone</p>
</div>
<div class="profile-row profile-row-notifications">
<p class="profile-row-label">Enabled</p>
</div>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
<div class="emoji-dropdown" id="emoji-dropdown" style="display: none;"> <div class="emoji-dropdown" id="emoji-dropdown" style="display: none;">

View File

@ -12,6 +12,7 @@ const lang = {
"FilterAllBots": "All Bots", "FilterAllBots": "All Bots",
"WordDelimiter": ", ", "WordDelimiter": ", ",
"WordDelimiterLast": " and ", "WordDelimiterLast": " and ",
"EditContact.OriginalName": "original name",
"EditProfile.FirstNameLabel": "Name", "EditProfile.FirstNameLabel": "Name",
"EditProfile.BioLabel": "Bio (optional)", "EditProfile.BioLabel": "Bio (optional)",
"EditProfile.Username.Label": "Username (optional)", "EditProfile.Username.Label": "Username (optional)",
@ -61,11 +62,25 @@ const lang = {
"one_value": "Send Album", "one_value": "Send Album",
"other_value": "Send %d Albums" "other_value": "Send %d Albums"
}, },
"Presence.YourChat": "chat with yourself",
"Privacy.Devices": { "Privacy.Devices": {
"one_value": "%1$d device", "one_value": "%1$d device",
"other_value": "%1$d devices" "other_value": "%1$d devices"
}, },
"PrivacyModal.Search.Placeholder": "Add Users or Groups...", "PrivacyModal.Search.Placeholder": "Add Users or Groups...",
"Permissions.NoExceptions": "No exceptions",
"Permissions.ExceptionsCount": {
"one_value": "%d exception",
"other_value": "%d exceptions",
},
"Link.Available": "Link is available",
"Link.Taken": "Link is already taken",
"Link.Invalid": "Link is invalid",
"StickersTab.SearchPlaceholder": "Search Stickers",
"StickerPack.Remove": {
"one_value": "Remove %d Sticker",
"other_value": "Remove %d Stickers"
},
// * android // * android
"ActionCreateChannel": "Channel created", "ActionCreateChannel": "Channel created",
@ -101,6 +116,7 @@ const lang = {
//"ChannelJoined": "You joined this channel", //"ChannelJoined": "You joined this channel",
"ChannelMegaJoined": "You joined this group", "ChannelMegaJoined": "You joined this group",
"Channel.DescriptionPlaceholder": "Description (optional)", "Channel.DescriptionPlaceholder": "Description (optional)",
"DescriptionPlaceholder": "Description",
"Draft": "Draft", "Draft": "Draft",
"FilterAlwaysShow": "Include Chats", "FilterAlwaysShow": "Include Chats",
"FilterNeverShow": "Exclude Chats", "FilterNeverShow": "Exclude Chats",
@ -238,6 +254,66 @@ const lang = {
"AskAQuestion": "Ask a Question", "AskAQuestion": "Ask a Question",
"AddAnExplanationInfo": "Users will see this text after choosing the wrong answer, good for educational purposes.", "AddAnExplanationInfo": "Users will see this text after choosing the wrong answer, good for educational purposes.",
"AccDescrQuizExplanation": "Explanation", "AccDescrQuizExplanation": "Explanation",
"PhoneCopied": "Phone copied to clipboard",
"UsernameCopied": "Username copied to clipboard.",
//"HashtagCopied": "Hashtag copied to clipboard.",
"BioCopied": "Bio copied to clipboard.",
"UserBio": "Bio",
"Username": "Username",
"Phone": "Phone",
"Notifications": "Notifications",
"AreYouSureDeleteContact": "Are you sure you want to delete this contact?",
"AreYouSureDeleteAndExit": "Are you sure you want to delete and leave the group?",
"AreYouSureDeleteAndExitChannel": "Do you want to delete and leave the channel?",
"DeleteContact": "Delete contact",
"GroupType": "Group Type",
"ChannelType": "Channel Type",
"TypePrivate": "Private",
"TypePublic": "Public",
"TypePrivateGroup": "Private",
"TypePublicGroup": "Public",
"GroupMembers": "Members",
"DeleteMega": "Delete Group",
"DeleteMegaMenu": "Delete group",
"ChannelDeleteMenu": "Delete channel",
"ChannelPermissions": "Permissions",
"ChannelPermissionsHeader": "What can members of this group do?",
"ChannelAddException": "Add Exception",
"ChannelBlockedUsers": "Removed users",
"NoBlockedUsers": "No removed users",
"UserRestrictions": "User Permissions",
"UserRestrictionsDisabled": "This option is disabled for all members in Group Permissions",
"UserRestrictionsCanDo": "What can this user do?",
"UserRestrictionsRead": "Read Messages",
"UserRestrictionsSend": "Send Messages",
"UserRestrictionsSendMedia": "Send Media",
"UserRestrictionsSendPolls": "Send Polls",
"UserRestrictionsSendStickers": "Send Stickers and GIFs",
"UserRestrictionsEmbedLinks": "Embed Links",
"UserRestrictionsChangeInfo": "Change Chat Info",
"UserRestrictionsPinMessages": "Pin Messages",
"UserRestrictionsInviteUsers": "Add Users",
"UserRestrictionsBlock": "Ban and remove from group",
"ChannelPublic": "Public Channel",
"MegaPublic": "Public Group",
"MegaLocation": "Location-based Group",
"ChannelPublicInfo": "Public channels can be found in search, anyone can join them.",
"MegaPublicInfo": "Public groups can be found in search, chat history is available to everyone and anyone can join.",
"ChannelPrivate": "Private Channel",
"MegaPrivate": "Private Group",
"ChannelPrivateInfo": "Private channels can only be joined via an invite link.",
"MegaPrivateInfo": "Private groups can only be joined if you were invited or have an invite link.",
"ChannelPrivateLinkHelp": "People can join your channel by following this link. You can revoke the link any time.",
"MegaPrivateLinkHelp": "People can join your group by following this link. You can revoke the link any time.",
"RevokeButton": "Revoke",
"RevokeLink": "Revoke Link",
"RevokeAlert": "Are you sure you want to revoke this link? Once the link is revoked, no one will be able to join using it.",
"SetUrlPlaceholder": "Link",
"Subscribers": {
"one_value": "%1$d subscriber",
"other_value": "%1$d subscribers"
},
"SearchGifsTitle": "Search GIFs",
// * macos // * macos
"AccountSettings.Filters": "Chat Folders", "AccountSettings.Filters": "Chat Folders",
@ -245,6 +321,8 @@ const lang = {
"AccountSettings.PrivacyAndSecurity": "Privacy and Security", "AccountSettings.PrivacyAndSecurity": "Privacy and Security",
"AccountSettings.Language": "Language", "AccountSettings.Language": "Language",
"Bio.Description": "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco", "Bio.Description": "Any details such as age, occupation or city.\nExample: 23 y.o. designer from San Francisco",
"Channel.UsernameAboutChannel": "People can share this link with others and can find your channel using Telegram search.",
"Channel.UsernameAboutGroup": "People can share this link with others and find your group using Telegram search.",
"Chat.CopySelectedText": "Copy Selected Text", "Chat.CopySelectedText": "Copy Selected Text",
"Chat.Date.ScheduledFor": "Scheduled for %@", "Chat.Date.ScheduledFor": "Scheduled for %@",
//"Chat.Date.ScheduledUntilOnline": "Scheduled until online", //"Chat.Date.ScheduledUntilOnline": "Scheduled until online",
@ -257,6 +335,25 @@ const lang = {
"Chat.Service.BotPermissionAllowed": "You allowed this bot to message you when you logged in on %@", "Chat.Service.BotPermissionAllowed": "You allowed this bot to message you when you logged in on %@",
"Chat.Poll.Unvote": "Retract Vote", "Chat.Poll.Unvote": "Retract Vote",
"Chat.Poll.Stop": "Stop Poll", "Chat.Poll.Stop": "Stop Poll",
"Chat.Poll.ViewResults": "View Results",
"Chat.Poll.SubmitVote": "Vote",
"Chat.Poll.Type.Anonymous": "Anonymous Poll",
"Chat.Poll.Type.Public": "Poll",
"Chat.Poll.Type.AnonymousQuiz": "Anonymous Quiz",
"Chat.Poll.Type.Quiz": "Quiz",
"Chat.Poll.Type.Closed": "Final Results",
"Chat.Poll.TotalVotes1": {
"one_value": "%d vote",
"other_value": "%d votes"
},
"Chat.Quiz.TotalVotes": {
"one_value": "%d answer",
"other_value": "%d answers"
},
"Chat.Poll.TotalVotesEmpty": "No votes yet",
"Chat.Poll.TotalVotesResultEmpty": "No votes",
"Chat.Quiz.TotalVotesEmpty": "No answers yet",
"Chat.Quiz.TotalVotesResultEmpty": "No answers",
// "Chat.Poll.Stop.Confirm.Header": "Stop Poll?", // "Chat.Poll.Stop.Confirm.Header": "Stop Poll?",
// "Chat.Poll.Stop.Confirm.Text": "If you stop this poll now, nobody will be able to vote in it anymore. This action cannot be undone.", // "Chat.Poll.Stop.Confirm.Text": "If you stop this poll now, nobody will be able to vote in it anymore. This action cannot be undone.",
// "Chat.Pinned.UnpinAll": { // "Chat.Pinned.UnpinAll": {
@ -297,16 +394,76 @@ const lang = {
"Channel.DescriptionHolderDescrpiton": "You can provide an optional description for your channel.", "Channel.DescriptionHolderDescrpiton": "You can provide an optional description for your channel.",
"CreateGroup.NameHolder": "Group Name", "CreateGroup.NameHolder": "Group Name",
"Date.Today": "Today", "Date.Today": "Today",
"DeleteChat.DeleteGroupForAll": "Delete for all members",
"DeleteChannelForAll": "Delete for all subscribers",
"EditAccount.Username": "Username", "EditAccount.Username": "Username",
"EditAccount.Title": "Edit Profile", "EditAccount.Title": "Edit Profile",
"EditAccount.Logout": "Log Out", "EditAccount.Logout": "Log Out",
"LastSeen.HoursAgo": {
"one_value": "last seen %d hour ago",
"other_value": "last seen %d hours ago"
},
"Login.Register.LastName.Placeholder": "Last Name", "Login.Register.LastName.Placeholder": "Last Name",
"Telegram.GeneralSettingsViewController": "General Settings", "Telegram.GeneralSettingsViewController": "General Settings",
"Telegram.InstalledStickerPacksController": "Stickers", "Telegram.InstalledStickerPacksController": "Stickers",
"Telegram.NotificationSettingsViewController": "Notifications", "Telegram.NotificationSettingsViewController": "Notifications",
"Telegram.PeerInfoController": "Info",
"StickerPack.Add1": {
"one_value": "Add %d Sticker",
"other_value": "Add %d Stickers"
},
"Stickers.Count": {
"one_value": "%d sticker",
"other_value": "%d stickers"
},
"Stickers.SearchAdd": "Add",
"Stickers.SearchAdded": "Added",
"Stickers.SuggestStickers": "Suggest Stickers by Emoji", "Stickers.SuggestStickers": "Suggest Stickers by Emoji",
"ShareModal.Search.ForwardPlaceholder": "Forward to...", "ShareModal.Search.ForwardPlaceholder": "Forward to...",
"InstalledStickers.LoopAnimated": "Loop Animated Stickers", "InstalledStickers.LoopAnimated": "Loop Animated Stickers",
// "Peer.Activity.User.PlayingGame": "playing a game",
"Peer.Activity.User.TypingText": "typing",
// "Peer.Activity.User.SendingPhoto": "sending a photo",
// "Peer.Activity.User.RecordingVideo": "recording video",
// "Peer.Activity.User.SendingVideo": "sending a video",
// "Peer.Activity.User.RecordingAudio": "recording voice",
// "Peer.Activity.User.SendingFile": "sending file",
"Peer.ServiceNotifications": "service notifications",
"Peer.RepliesNotifications": "Reply Notifications",
"Peer.Status.online": "online",
"Peer.Status.recently": "last seen recently",
"Peer.Status.justNow": "last seen just now",
"Peer.Status.lastWeek": "last seen within a week",
"Peer.Status.lastMonth": "last seen within a month",
"Peer.Status.longTimeAgo": "last seen a long time ago",
"Peer.Status.Today": "today",
"Peer.Status.Yesterday": "yesterday",
"Peer.Status.LastSeenAt": "last seen %@ at %@",
"Peer.Status.minAgo": {
"one_value": "last seen %d minute ago",
"other_value": "last seen %d minutes ago"
},
"Peer.Status.Member": {
"one_value": "%d member",
"other_value": "%d members"
},
"Peer.Status.Subscribers": {
"one_value": "%d subscriber",
"other_value": "%d subscribers"
},
"PeerInfo.Administrators": "Administrators",
"PeerInfo.DeleteChannel": "Delete Channel",
"PeerInfo.Discussion": "Discussion",
"PeerInfo.Discussion.Add": "Add",
"PeerInfo.SignMessages": "Sign Messages",
"PeerInfo.SharedMedia": "Shared Media",
"PeerInfo.Subscribers": "Subscribers",
"PollResults.Title.Poll": "Poll Results",
"PollResults.Title.Quiz": "Quiz Results",
"PollResults.LoadMore": {
"other_value": "Show More (%d)"
},
//"PeerInfo.Confirm.DeleteGroupConfirmation": "Wait! Deleting this group will remove all members and all messages will be lost. Delete the group anyway?",
"PreviewSender.CaptionPlaceholder": "Add a caption...", "PreviewSender.CaptionPlaceholder": "Add a caption...",
"PreviewSender.SendFile": { "PreviewSender.SendFile": {
"one_value": "Send File", "one_value": "Send File",
@ -320,6 +477,8 @@ const lang = {
"one_value": "Send Video", "one_value": "Send Video",
"other_value": "Send %d Videos" "other_value": "Send %d Videos"
}, },
"Presence.bot": "bot",
"Presence.Support": "support",
"PrivacyAndSecurity.Item.On": "On", "PrivacyAndSecurity.Item.On": "On",
"PrivacyAndSecurity.Item.Off": "Off", "PrivacyAndSecurity.Item.Off": "Off",
"PrivacySettings.VoiceCalls": "Calls", "PrivacySettings.VoiceCalls": "Calls",
@ -352,7 +511,8 @@ const lang = {
"NewPoll.Explanation.Placeholder": "Add a Comment (Optional)", "NewPoll.Explanation.Placeholder": "Add a Comment (Optional)",
"NewPoll.OptionsAddOption": "Add an Option", "NewPoll.OptionsAddOption": "Add an Option",
"NewPoll.MultipleChoice": "Multiple Answers", "NewPoll.MultipleChoice": "Multiple Answers",
"NewPoll.Quiz": "Quiz Mode" "NewPoll.Quiz": "Quiz Mode",
"GroupPermission.Delete": "Delete Exception",
}; };
export default lang; export default lang;

View File

@ -2,6 +2,7 @@ import { MOUNT_CLASS_TO } from "../../config/debug";
import { numberThousandSplitter } from "../../helpers/number"; import { numberThousandSplitter } from "../../helpers/number";
import { isObject, safeReplaceObject, copy, deepEqual } from "../../helpers/object"; import { isObject, safeReplaceObject, copy, deepEqual } from "../../helpers/object";
import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipant, ChatParticipants, InputChannel, InputChatPhoto, InputFile, InputPeer, SendMessageAction, Update, Updates } from "../../layer"; import { ChannelParticipant, Chat, ChatAdminRights, ChatBannedRights, ChatFull, ChatParticipant, ChatParticipants, InputChannel, InputChatPhoto, InputFile, InputPeer, SendMessageAction, Update, Updates } from "../../layer";
import { i18n, LangPackKey } from "../langPack";
import apiManagerProxy from "../mtproto/mtprotoworker"; import apiManagerProxy from "../mtproto/mtprotoworker";
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { RichTextProcessor } from "../richtextprocessor"; import { RichTextProcessor } from "../richtextprocessor";
@ -402,7 +403,9 @@ export class AppChatsManager {
const isChannel = this.isBroadcast(id); const isChannel = this.isBroadcast(id);
count = count || 1; count = count || 1;
return numberThousandSplitter(count, ' ') + ' ' + (isChannel ? (count > 1 ? 'subscribers' : 'subscriber') : (count > 1 ? 'members' : 'member'));
let key: LangPackKey = isChannel ? 'Peer.Status.Subscribers' : 'Peer.Status.Member';
return i18n(key, [numberThousandSplitter(count)]);
} }
public wrapForFull(id: number, fullChat: any) { public wrapForFull(id: number, fullChat: any) {

View File

@ -38,6 +38,7 @@ import { MOUNT_CLASS_TO } from '../../config/debug';
import appNavigationController from '../../components/appNavigationController'; import appNavigationController from '../../components/appNavigationController';
import appNotificationsManager from './appNotificationsManager'; import appNotificationsManager from './appNotificationsManager';
import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search'; import AppPrivateSearchTab from '../../components/sidebarRight/tabs/search';
import { i18n } from '../langPack';
//console.log('appImManager included33!'); //console.log('appImManager included33!');
@ -742,8 +743,8 @@ export class AppImManager {
} }
public async getPeerStatus(peerId: number) { public async getPeerStatus(peerId: number) {
let subtitle = ''; let subtitle: HTMLElement;
if(!peerId) return subtitle; if(!peerId) return '';
if(peerId < 0) { // not human if(peerId < 0) { // not human
const chat = appPeersManager.getPeer(peerId); const chat = appPeersManager.getPeer(peerId);
@ -756,10 +757,10 @@ export class AppImManager {
subtitle = appChatsManager.getChatMembersString(-peerId); subtitle = appChatsManager.getChatMembersString(-peerId);
if(participants_count < 2) return subtitle; if(participants_count < 2) return subtitle;
const onlines = await appChatsManager.getOnlines(chat.id); /* const onlines = await appChatsManager.getOnlines(chat.id);
if(onlines > 1) { if(onlines > 1) {
subtitle += ', ' + numberThousandSplitter(onlines, ' ') + ' online'; subtitle += ', ' + numberThousandSplitter(onlines) + ' online';
} } */
return subtitle; return subtitle;
//} //}
@ -774,15 +775,19 @@ export class AppImManager {
if(!appUsersManager.isBot(peerId)) { if(!appUsersManager.isBot(peerId)) {
const typings = appChatsManager.typingsInPeer[peerId]; const typings = appChatsManager.typingsInPeer[peerId];
if(typings && typings.length) { if(typings && typings.length) {
return '<span class="online">typing...</span>'; const span = document.createElement('span');
} else if(subtitle === 'online') { span.classList.add('online');
return `<span class="online">${subtitle}</span>`; span.append(i18n('Peer.Activity.User.TypingText'));
} else { return span;
return subtitle; } else if(user.status?._ === 'userStatusOnline') {
const span = document.createElement('span');
span.classList.add('online');
span.append(subtitle);
return span;
} }
} else {
return subtitle;
} }
return subtitle;
} }
} }
} }

View File

@ -3,6 +3,7 @@ import { MOUNT_CLASS_TO } from "../../config/debug";
import { tsNow } from "../../helpers/date"; import { tsNow } from "../../helpers/date";
import { safeReplaceObject, isObject } from "../../helpers/object"; import { safeReplaceObject, isObject } from "../../helpers/object";
import { InputUser, Update, User as MTUser, UserStatus } from "../../layer"; import { InputUser, Update, User as MTUser, UserStatus } from "../../layer";
import I18n, { i18n, LangPackKey } from "../langPack";
//import apiManager from '../mtproto/apiManager'; //import apiManager from '../mtproto/apiManager';
import apiManager from '../mtproto/mtprotoworker'; import apiManager from '../mtproto/mtprotoworker';
import { REPLIES_PEER_ID } from "../mtproto/mtproto_config"; import { REPLIES_PEER_ID } from "../mtproto/mtproto_config";
@ -386,79 +387,92 @@ export class AppUsersManager {
return this.getUser(rootScope.myId); return this.getUser(rootScope.myId);
} }
public getUserStatusString(userId: number) { public getUserStatusString(userId: number): HTMLElement {
let key: LangPackKey;
let args: any[];
switch(userId) { switch(userId) {
case REPLIES_PEER_ID: case REPLIES_PEER_ID:
return 'reply notifications'; key = 'Peer.RepliesNotifications';
break;
case 777000: case 777000:
return 'service notifications'; key = 'Peer.ServiceNotifications';
} break;
default: {
if(this.isBot(userId)) {
key = 'Presence.bot';
break;
}
if(this.isBot(userId)) { const user = this.getUser(userId);
return 'bot'; if(!user) {
} key = '';
break;
}
const user = this.getUser(userId); if(user.pFlags.support) {
if(!user) { key = 'Presence.Support';
return ''; break;
} }
if(user.pFlags.support) { switch(user.status?._) {
return 'support'; case 'userStatusRecently': {
key = 'Peer.Status.recently';
break;
}
case 'userStatusLastWeek': {
key = 'Peer.Status.lastWeek';
break;
}
case 'userStatusLastMonth': {
key = 'Peer.Status.lastMonth';
break;
}
case 'userStatusOffline': {
key = 'last seen ';
const date = user.status.was_online;
const now = Date.now() / 1000;
if((now - date) < 60) {
key = 'Peer.Status.justNow';
} else if((now - date) < 3600) {
key = 'Peer.Status.minAgo';
const c = (now - date) / 60 | 0;
args = [c];
} else if(now - date < 86400) {
key = 'LastSeen.HoursAgo';
const c = (now - date) / 3600 | 0;
args = [c];
} else {
key = 'Peer.Status.LastSeenAt';
const d = new Date(date * 1000);
args = [('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2),
('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2)];
}
break;
}
case 'userStatusOnline': {
key = 'Peer.Status.online';
break;
}
default: {
key = 'Peer.Status.longTimeAgo';
break;
}
}
break;
}
} }
let str = ''; return i18n(key, args);
switch(user.status?._) {
case 'userStatusRecently': {
str = 'last seen recently';
break;
}
case 'userStatusLastWeek': {
str = 'last seen last week';
break;
}
case 'userStatusLastMonth': {
str = 'last seen last month';
break;
}
case 'userStatusOffline': {
str = 'last seen ';
const date = user.status.was_online;
const now = Date.now() / 1000;
if((now - date) < 60) {
str += ' just now';
} else if((now - date) < 3600) {
const c = (now - date) / 60 | 0;
str += c + ' ' + (c === 1 ? 'minute' : 'minutes') + ' ago';
} else if(now - date < 86400) {
const c = (now - date) / 3600 | 0;
str += c + ' ' + (c === 1 ? 'hour' : 'hours') + ' ago';
} else {
const d = new Date(date * 1000);
str += ('0' + d.getDate()).slice(-2) + '.' + ('0' + (d.getMonth() + 1)).slice(-2) + ' at ' +
('0' + d.getHours()).slice(-2) + ':' + ('0' + d.getMinutes()).slice(-2);
}
break;
}
case 'userStatusOnline': {
str = 'online';
break;
}
default: {
str = 'last seen a long time ago';
break;
}
}
return str;
} }
public isBot(id: number) { public isBot(id: number) {

View File

@ -197,7 +197,8 @@ namespace I18n {
let input: string; let input: string;
if(str) { if(str) {
if(str._ === 'langPackStringPluralized' && args?.length) { if(str._ === 'langPackStringPluralized' && args?.length) {
const v = args[0] as number; let v = args[0] as number | string;
if(typeof(v) === 'string') v = +v.replace(/\D/g, '');
const s = pluralRules.select(v); const s = pluralRules.select(v);
// @ts-ignore // @ts-ignore
input = str[s + '_value'] || str['other_value']; input = str[s + '_value'] || str['other_value'];

View File

@ -172,4 +172,9 @@ avatar-element {
--size: 18px; --size: 18px;
--multiplier: 3; --multiplier: 3;
} }
}
&.avatar-16 {
--size: 16px;
--multiplier: 3.375;
}
}

View File

@ -245,6 +245,12 @@
background: hover-color($color-blue); background: hover-color($color-blue);
} }
&.danger {
@include hover() {
background: hover-color($color-red);
}
}
.preloader-circular .preloader-path { .preloader-circular .preloader-path {
stroke: $color-blue; stroke: $color-blue;
} }

View File

@ -2069,7 +2069,7 @@ poll-element {
font-size: 14px; font-size: 14px;
color: #707579; color: #707579;
margin-top: 2px; margin-top: 2px;
margin-bottom: 7px; margin-bottom: 5px;
display: flex; display: flex;
position: relative; position: relative;
@ -2078,6 +2078,10 @@ poll-element {
// } // }
} }
&-type {
margin-top: 2px;
}
&-hint { &-hint {
position: absolute; position: absolute;
font-size: 1.5rem; font-size: 1.5rem;
@ -2296,6 +2300,8 @@ poll-element {
avatar-element { avatar-element {
border: 1px solid #fff; border: 1px solid #fff;
cursor: pointer; cursor: pointer;
width: 18px;
height: 18px;
} }
.circle-hover { .circle-hover {

View File

@ -111,6 +111,10 @@
padding-top: 15px; padding-top: 15px;
} }
} }
.sidebar-left-section {
padding-bottom: 0;
}
} }
&-container { &-container {
@ -142,7 +146,7 @@
text-align: center; text-align: center;
color: $color-gray; color: $color-gray;
font-size: 14px; font-size: 14px;
margin-bottom: 2px; margin-bottom: .875rem;
margin-top: 1px; margin-top: 1px;
@include respond-to(handhelds) { @include respond-to(handhelds) {
@ -216,7 +220,8 @@
} }
&-avatar { &-avatar {
margin: 1px auto 10px; margin: .5rem auto 10px;
display: block;
//flex: 0 0 auto; //flex: 0 0 auto;
@include respond-to(handhelds) { @include respond-to(handhelds) {
@ -650,14 +655,12 @@
font-size: 15px; font-size: 15px;
border-radius: 16px; border-radius: 16px;
font-weight: 400; font-weight: 400;
width: 52px; width: auto;
//width: auto; //68 - Added //52 - Add
transition: width 0.2s; transition: width 0.2s;
&.gray { &.gray {
background: #F1F3F4; background: #F1F3F4;
color: #707579; color: #707579;
width: 68px;
} }
} }

View File

@ -46,4 +46,10 @@
} }
} }
} }
} }
.popup-peer, .popup-confirm-action {
.popup-container {
max-width: unquote('min(400px, 100%)');
}
}

View File

@ -129,7 +129,6 @@
margin-top: .5rem; margin-top: .5rem;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
max-width: 286px;
overflow: hidden; overflow: hidden;
} }
} }

View File

@ -11,18 +11,19 @@
} }
.sticker-set-footer { .sticker-set-footer {
padding: 19px 0 17px 0;
border-top: 1px solid $lightgrey; border-top: 1px solid $lightgrey;
text-align: center; text-align: center;
color: $color-blue; color: $color-blue;
.btn-primary { .btn-primary {
width: 164px; text-transform: uppercase;
width: auto;
padding: 0 1.0625rem;
height: 44px; height: 44px;
} }
} }
.sticker-set-footer.add { .sticker-set-footer {
padding: 8px 0; padding: 8px 0;
} }
@ -83,4 +84,4 @@
} }
} }
} }
} }