Top bar menu:
Add contact Block/unblock Fix Firefox scrollbar Fix selecting text in country input
This commit is contained in:
parent
f48ae2d013
commit
306478b7d5
@ -35,13 +35,14 @@ import blurActiveElement from "../../helpers/dom/blurActiveElement";
|
|||||||
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
||||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||||
import findUpTag from "../../helpers/dom/findUpTag";
|
import findUpTag from "../../helpers/dom/findUpTag";
|
||||||
import { toast } from "../toast";
|
import { toast, toastNew } from "../toast";
|
||||||
import replaceContent from "../../helpers/dom/replaceContent";
|
import replaceContent from "../../helpers/dom/replaceContent";
|
||||||
import { ChatFull } from "../../layer";
|
import { ChatFull } from "../../layer";
|
||||||
import PopupPickUser from "../popups/pickUser";
|
import PopupPickUser from "../popups/pickUser";
|
||||||
import PopupPeer from "../popups/peer";
|
import PopupPeer from "../popups/peer";
|
||||||
import generateVerifiedIcon from "../generateVerifiedIcon";
|
import generateVerifiedIcon from "../generateVerifiedIcon";
|
||||||
import { fastRaf } from "../../helpers/schedulers";
|
import { fastRaf } from "../../helpers/schedulers";
|
||||||
|
import AppEditContactTab from "../sidebarRight/tabs/editContact";
|
||||||
|
|
||||||
export default class ChatTopbar {
|
export default class ChatTopbar {
|
||||||
public container: HTMLDivElement;
|
public container: HTMLDivElement;
|
||||||
@ -273,6 +274,15 @@ export default class ChatTopbar {
|
|||||||
this.chat.selection.cancelSelection();
|
this.chat.selection.cancelSelection();
|
||||||
},
|
},
|
||||||
verify: () => this.chat.selection.isSelecting
|
verify: () => this.chat.selection.isSelecting
|
||||||
|
}, {
|
||||||
|
icon: 'adduser',
|
||||||
|
text: 'AddContact',
|
||||||
|
onClick: () => {
|
||||||
|
const tab = new AppEditContactTab(this.appSidebarRight);
|
||||||
|
tab.peerId = this.peerId;
|
||||||
|
tab.open();
|
||||||
|
},
|
||||||
|
verify: () => this.peerId > 0 && !this.appUsersManager.isContact(this.peerId)
|
||||||
}, {
|
}, {
|
||||||
icon: 'forward',
|
icon: 'forward',
|
||||||
text: 'ShareContact',
|
text: 'ShareContact',
|
||||||
@ -312,6 +322,46 @@ export default class ChatTopbar {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
verify: () => rootScope.myId !== this.peerId && this.peerId > 0 && this.appUsersManager.isContact(this.peerId)
|
verify: () => rootScope.myId !== this.peerId && this.peerId > 0 && this.appUsersManager.isContact(this.peerId)
|
||||||
|
}, {
|
||||||
|
icon: 'lock',
|
||||||
|
text: 'BlockUser',
|
||||||
|
onClick: () => {
|
||||||
|
new PopupPeer('', {
|
||||||
|
peerId: this.peerId,
|
||||||
|
titleLangKey: 'BlockUser',
|
||||||
|
descriptionLangKey: 'AreYouSureBlockContact2',
|
||||||
|
descriptionLangArgs: [new PeerTitle({peerId: this.peerId}).element],
|
||||||
|
buttons: [{
|
||||||
|
langKey: 'BlockUser',
|
||||||
|
isDanger: true,
|
||||||
|
callback: () => {
|
||||||
|
this.appUsersManager.toggleBlock(this.peerId, true).then(value => {
|
||||||
|
if(value) {
|
||||||
|
toastNew({langPackKey: 'UserBlocked'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}).show();
|
||||||
|
},
|
||||||
|
verify: () => {
|
||||||
|
const userFull = this.appProfileManager.usersFull[this.peerId];
|
||||||
|
return this.peerId > 0 && userFull && !userFull.pFlags?.blocked;
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
icon: 'lockoff',
|
||||||
|
text: 'Unblock',
|
||||||
|
onClick: () => {
|
||||||
|
this.appUsersManager.toggleBlock(this.peerId, false).then(value => {
|
||||||
|
if(value) {
|
||||||
|
toastNew({langPackKey: 'UserUnblocked'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
verify: () => {
|
||||||
|
const userFull = this.appProfileManager.usersFull[this.peerId];
|
||||||
|
return this.peerId > 0 && !!userFull?.pFlags?.blocked;
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
icon: 'delete danger',
|
icon: 'delete danger',
|
||||||
text: 'Delete',
|
text: 'Delete',
|
||||||
|
@ -8,6 +8,7 @@ import simulateEvent from "../helpers/dom/dispatchEvent";
|
|||||||
import findUpAttribute from "../helpers/dom/findUpAttribute";
|
import findUpAttribute from "../helpers/dom/findUpAttribute";
|
||||||
import getRichValue from "../helpers/dom/getRichValue";
|
import getRichValue from "../helpers/dom/getRichValue";
|
||||||
import isInputEmpty from "../helpers/dom/isInputEmpty";
|
import isInputEmpty from "../helpers/dom/isInputEmpty";
|
||||||
|
import selectElementContents from "../helpers/dom/selectElementContents";
|
||||||
import { i18n, LangPackKey, _i18n } from "../lib/langPack";
|
import { i18n, LangPackKey, _i18n } from "../lib/langPack";
|
||||||
import RichTextProcessor from "../lib/richtextprocessor";
|
import RichTextProcessor from "../lib/richtextprocessor";
|
||||||
|
|
||||||
@ -215,8 +216,14 @@ class InputField {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public select() {
|
public select() {
|
||||||
if((this.input as HTMLInputElement).value) { // * avoid selecting whole empty field on iOS devices
|
if(!this.value) { // * avoid selecting whole empty field on iOS devices
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.options.plainText) {
|
||||||
(this.input as HTMLInputElement).select(); // * select text
|
(this.input as HTMLInputElement).select(); // * select text
|
||||||
|
} else {
|
||||||
|
selectElementContents(this.input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,9 +285,7 @@ class InputField {
|
|||||||
(!this.required || !isInputEmpty(this.input));
|
(!this.required || !isInputEmpty(this.input));
|
||||||
}
|
}
|
||||||
|
|
||||||
public setOriginalValue(value: InputField['originalValue'] = '', silent = false) {
|
public setDraftValue(value = '', silent = false) {
|
||||||
this.originalValue = value;
|
|
||||||
|
|
||||||
if(!this.options.plainText) {
|
if(!this.options.plainText) {
|
||||||
value = RichTextProcessor.wrapDraftText(value);
|
value = RichTextProcessor.wrapDraftText(value);
|
||||||
}
|
}
|
||||||
@ -292,6 +297,11 @@ class InputField {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public setOriginalValue(value: InputField['originalValue'] = '', silent = false) {
|
||||||
|
this.originalValue = value;
|
||||||
|
this.setDraftValue(value, silent);
|
||||||
|
}
|
||||||
|
|
||||||
public setState(state: InputState, label?: LangPackKey) {
|
public setState(state: InputState, label?: LangPackKey) {
|
||||||
if(label) {
|
if(label) {
|
||||||
this.label.textContent = '';
|
this.label.textContent = '';
|
||||||
|
@ -31,7 +31,8 @@ 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.setTitle(this.peerId ? 'Edit' : 'AddContactTitle');
|
const isNew = !appUsersManager.isContact(this.peerId);
|
||||||
|
this.setTitle(isNew ? 'AddContactTitle' : 'Edit');
|
||||||
|
|
||||||
{
|
{
|
||||||
const section = new SettingSection({noDelimiter: true});
|
const section = new SettingSection({noDelimiter: true});
|
||||||
@ -41,12 +42,13 @@ 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: 'EditProfile.FirstNameLabel',
|
label: 'FirstName',
|
||||||
name: 'contact-name',
|
name: 'contact-name',
|
||||||
maxLength: 70
|
maxLength: 70,
|
||||||
|
required: true
|
||||||
});
|
});
|
||||||
this.lastNameInputField = new InputField({
|
this.lastNameInputField = new InputField({
|
||||||
label: 'Login.Register.LastName.Placeholder',
|
label: 'LastName',
|
||||||
name: 'contact-lastname',
|
name: 'contact-lastname',
|
||||||
maxLength: 70
|
maxLength: 70
|
||||||
});
|
});
|
||||||
@ -54,8 +56,13 @@ export default class AppEditContactTab extends SliderSuperTab {
|
|||||||
if(this.peerId) {
|
if(this.peerId) {
|
||||||
const user = appUsersManager.getUser(this.peerId);
|
const user = appUsersManager.getUser(this.peerId);
|
||||||
|
|
||||||
this.nameInputField.setOriginalValue(user.first_name);
|
if(isNew) {
|
||||||
this.lastNameInputField.setOriginalValue(user.last_name);
|
this.nameInputField.setDraftValue(user.first_name);
|
||||||
|
this.lastNameInputField.setDraftValue(user.last_name);
|
||||||
|
} else {
|
||||||
|
this.nameInputField.setOriginalValue(user.first_name);
|
||||||
|
this.lastNameInputField.setOriginalValue(user.last_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container);
|
inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container);
|
||||||
@ -97,13 +104,6 @@ export default class AppEditContactTab extends SliderSuperTab {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const notificationsRow = new Row({
|
|
||||||
checkboxField: notificationsCheckboxField
|
|
||||||
});
|
|
||||||
|
|
||||||
const enabled = !appNotificationsManager.isPeerLocalMuted(this.peerId, false);
|
|
||||||
notificationsCheckboxField.checked = enabled;
|
|
||||||
|
|
||||||
const profileNameDiv = document.createElement('div');
|
const profileNameDiv = document.createElement('div');
|
||||||
profileNameDiv.classList.add('profile-name');
|
profileNameDiv.classList.add('profile-name');
|
||||||
profileNameDiv.append(new PeerTitle({
|
profileNameDiv.append(new PeerTitle({
|
||||||
@ -115,7 +115,30 @@ export default class AppEditContactTab extends SliderSuperTab {
|
|||||||
profileSubtitleDiv.classList.add('profile-subtitle');
|
profileSubtitleDiv.classList.add('profile-subtitle');
|
||||||
profileSubtitleDiv.append(i18n('EditContact.OriginalName'));
|
profileSubtitleDiv.append(i18n('EditContact.OriginalName'));
|
||||||
|
|
||||||
section.content.append(div, profileNameDiv, profileSubtitleDiv, inputWrapper, notificationsRow.container);
|
section.content.append(div, profileNameDiv, profileSubtitleDiv, inputWrapper);
|
||||||
|
|
||||||
|
if(!isNew) {
|
||||||
|
const notificationsRow = new Row({
|
||||||
|
checkboxField: notificationsCheckboxField
|
||||||
|
});
|
||||||
|
|
||||||
|
const enabled = !appNotificationsManager.isPeerLocalMuted(this.peerId, false);
|
||||||
|
notificationsCheckboxField.checked = enabled;
|
||||||
|
|
||||||
|
section.content.append(notificationsRow.container);
|
||||||
|
} else {
|
||||||
|
const user = appUsersManager.getUser(this.peerId);
|
||||||
|
|
||||||
|
const phoneRow = new Row({
|
||||||
|
icon: 'phone',
|
||||||
|
titleLangKey: user.phone ? undefined : 'MobileHidden',
|
||||||
|
title: user.phone ? appUsersManager.formatUserPhone(user.phone) : undefined,
|
||||||
|
subtitleLangKey: user.phone ? 'Phone' : 'MobileHiddenExceptionInfo',
|
||||||
|
subtitleLangArgs: user.phone ? undefined : [new PeerTitle({peerId: this.peerId}).element]
|
||||||
|
});
|
||||||
|
|
||||||
|
section.content.append(phoneRow.container);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
section.content.append(inputWrapper);
|
section.content.append(inputWrapper);
|
||||||
}
|
}
|
||||||
@ -133,7 +156,7 @@ export default class AppEditContactTab extends SliderSuperTab {
|
|||||||
}, {listenerSetter: this.listenerSetter});
|
}, {listenerSetter: this.listenerSetter});
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.peerId) {
|
if(!isNew) {
|
||||||
const section = new SettingSection({
|
const section = new SettingSection({
|
||||||
|
|
||||||
});
|
});
|
||||||
|
8
src/helpers/dom/selectElementContents.ts
Normal file
8
src/helpers/dom/selectElementContents.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// https://stackoverflow.com/a/6150060
|
||||||
|
export default function selectElementContents(el: HTMLElement) {
|
||||||
|
const range = document.createRange();
|
||||||
|
range.selectNodeContents(el);
|
||||||
|
const sel = window.getSelection();
|
||||||
|
sel.removeAllRanges();
|
||||||
|
sel.addRange(range);
|
||||||
|
}
|
@ -575,6 +575,15 @@ const lang = {
|
|||||||
"DiscardVoiceMessageTitle": "Discard Voice Message",
|
"DiscardVoiceMessageTitle": "Discard Voice Message",
|
||||||
"DiscardVoiceMessageDescription": "Are you sure you want to stop recording and discard your voice message?",
|
"DiscardVoiceMessageDescription": "Are you sure you want to stop recording and discard your voice message?",
|
||||||
"DiscardVoiceMessageAction": "Discard",
|
"DiscardVoiceMessageAction": "Discard",
|
||||||
|
"AddContact": "Add to contacts",
|
||||||
|
"BlockUser": "Block user",
|
||||||
|
"MobileHidden": "Mobile hidden",
|
||||||
|
"MobileHiddenExceptionInfo": "Phone number will be visible once %1$s adds you as a contact.",
|
||||||
|
"FirstName": "First name (required)",
|
||||||
|
"LastName": "Last name (optional)",
|
||||||
|
"AreYouSureBlockContact2": "Are you sure you want to block **%1$s**?",
|
||||||
|
"UserBlocked": "User blocked",
|
||||||
|
"UserUnblocked": "User unblocked",
|
||||||
|
|
||||||
// * macos
|
// * macos
|
||||||
"AccountSettings.Filters": "Chat Folders",
|
"AccountSettings.Filters": "Chat Folders",
|
||||||
|
@ -37,13 +37,6 @@ const DialogColorsMap = [0, 7, 4, 1, 6, 3, 5];
|
|||||||
|
|
||||||
export type PeerType = 'channel' | 'chat' | 'megagroup' | 'group' | 'saved';
|
export type PeerType = 'channel' | 'chat' | 'megagroup' | 'group' | 'saved';
|
||||||
export class AppPeersManager {
|
export class AppPeersManager {
|
||||||
constructor() {
|
|
||||||
rootScope.addMultipleEventsListeners({
|
|
||||||
updatePeerBlocked: (update) => {
|
|
||||||
rootScope.dispatchEvent('peer_block', {peerId: this.getPeerId(update.peer_id), blocked: update.blocked});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/* public savePeerInstance(peerId: number, instance: any) {
|
/* public savePeerInstance(peerId: number, instance: any) {
|
||||||
if(peerId < 0) appChatsManager.saveApiChat(instance);
|
if(peerId < 0) appChatsManager.saveApiChat(instance);
|
||||||
else appUsersManager.saveApiUser(instance);
|
else appUsersManager.saveApiUser(instance);
|
||||||
|
@ -31,7 +31,7 @@ export type UserTyping = Partial<{userId: number, action: SendMessageAction, tim
|
|||||||
|
|
||||||
export class AppProfileManager {
|
export class AppProfileManager {
|
||||||
//private botInfos: any = {};
|
//private botInfos: any = {};
|
||||||
private usersFull: {[id: string]: UserFull.userFull} = {};
|
public usersFull: {[id: string]: UserFull.userFull} = {};
|
||||||
public chatsFull: {[id: string]: ChatFull} = {};
|
public chatsFull: {[id: string]: ChatFull} = {};
|
||||||
private fullPromises: {[peerId: string]: Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull>} = {};
|
private fullPromises: {[peerId: string]: Promise<ChatFull.chatFull | ChatFull.channelFull | UserFull>} = {};
|
||||||
|
|
||||||
@ -94,7 +94,9 @@ export class AppProfileManager {
|
|||||||
|
|
||||||
updateUserTyping: this.onUpdateUserTyping,
|
updateUserTyping: this.onUpdateUserTyping,
|
||||||
updateChatUserTyping: this.onUpdateUserTyping,
|
updateChatUserTyping: this.onUpdateUserTyping,
|
||||||
updateChannelUserTyping: this.onUpdateUserTyping
|
updateChannelUserTyping: this.onUpdateUserTyping,
|
||||||
|
|
||||||
|
updatePeerBlocked: this.onUpdatePeerBlocked
|
||||||
});
|
});
|
||||||
|
|
||||||
rootScope.addEventListener('chat_update', (chatId) => {
|
rootScope.addEventListener('chat_update', (chatId) => {
|
||||||
@ -639,6 +641,19 @@ export class AppProfileManager {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private onUpdatePeerBlocked = (update: Update.updatePeerBlocked) => {
|
||||||
|
const peerId = appPeersManager.getPeerId(update.peer_id);
|
||||||
|
if(peerId > 0) {
|
||||||
|
const userFull = this.usersFull[peerId];
|
||||||
|
if(userFull) {
|
||||||
|
if(update.blocked) userFull.pFlags.blocked = true;
|
||||||
|
else delete userFull.pFlags.blocked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootScope.dispatchEvent('peer_block', {peerId, blocked: update.blocked});
|
||||||
|
};
|
||||||
|
|
||||||
public getPeerTypings(peerId: number) {
|
public getPeerTypings(peerId: number) {
|
||||||
return this.typingsInPeer[peerId];
|
return this.typingsInPeer[peerId];
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,6 @@ import appChatsManager from "./appChatsManager";
|
|||||||
import appPeersManager from "./appPeersManager";
|
import appPeersManager from "./appPeersManager";
|
||||||
import appStateManager from "./appStateManager";
|
import appStateManager from "./appStateManager";
|
||||||
|
|
||||||
// TODO: updateUserBlocked
|
|
||||||
|
|
||||||
export type User = MTUser.user;
|
export type User = MTUser.user;
|
||||||
export type TopPeerType = 'correspondents' | 'bots_inline';
|
export type TopPeerType = 'correspondents' | 'bots_inline';
|
||||||
export type MyTopPeer = {id: number, rating: number};
|
export type MyTopPeer = {id: number, rating: number};
|
||||||
|
@ -80,14 +80,14 @@ html:not(.is-safari):not(.is-ios) {
|
|||||||
|
|
||||||
&.scrollable-x {
|
&.scrollable-x {
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
scrollbar-width: none;
|
scrollbar-width: thin; // Firefox only
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.scrollable-y {
|
&.scrollable-y {
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
overflow-y: overlay;
|
overflow-y: overlay;
|
||||||
scrollbar-width: none;
|
scrollbar-width: thin; // Firefox only
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
|
|
||||||
/* html.is-safari & {
|
/* html.is-safari & {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user