Browse Source

Import contact popup

master
morethanwords 3 years ago
parent
commit
ac1865f678
  1. 83
      src/components/editPeer.ts
  2. 20
      src/components/inputField.ts
  3. 88
      src/components/popups/createContact.ts
  4. 8
      src/components/popups/index.ts
  5. 14
      src/components/sidebarLeft/tabs/addContact.ts
  6. 13
      src/components/sidebarLeft/tabs/contacts.ts
  7. 89
      src/components/sidebarRight/tabs/editContact.ts
  8. 110
      src/components/telInputField.ts
  9. 1
      src/lang.ts
  10. 1
      src/langSign.ts
  11. 93
      src/lib/appManagers/appUsersManager.ts
  12. 126
      src/pages/pageSignIn.ts
  13. 23
      src/scss/partials/popups/_mediaAttacher.scss

83
src/components/editPeer.ts

@ -24,37 +24,94 @@ export default class EditPeer {
private peerId: number; private peerId: number;
private _disabled = false;
private avatarSize = 120;
constructor(options: { constructor(options: {
peerId: number, peerId?: number,
inputFields: EditPeer['inputFields'], inputFields: EditPeer['inputFields'],
listenerSetter: ListenerSetter, listenerSetter: ListenerSetter,
doNotEditAvatar?: boolean, doNotEditAvatar?: boolean,
withoutAvatar?: boolean,
nextBtn?: HTMLButtonElement,
avatarSize?: number
}) { }) {
safeAssign(this, options); safeAssign(this, options);
this.nextBtn = ButtonCorner({icon: 'check'}); if(!this.nextBtn) {
this.nextBtn = ButtonCorner({icon: 'check'});
} else if(!this.nextBtn.classList.contains('btn-corner')) {
this.handleChange = () => {
this.nextBtn.toggleAttribute('disabled', !this.isChanged() || this.disabled);
};
}
this.avatarElem = document.createElement('avatar-element') as AvatarElement; if(!options.withoutAvatar) {
this.avatarElem.classList.add('avatar-placeholder', 'avatar-120'); this.avatarElem = document.createElement('avatar-element') as AvatarElement;
this.avatarElem.setAttribute('peer', '' + this.peerId); this.avatarElem.classList.add('avatar-placeholder', 'avatar-' + this.avatarSize);
this.avatarElem.setAttribute('peer', '' + this.peerId);
if(!options.doNotEditAvatar) { if(!options.doNotEditAvatar) {
this.avatarEdit = new AvatarEdit((_upload) => { this.avatarEdit = new AvatarEdit((_upload) => {
this.uploadAvatar = _upload; this.uploadAvatar = _upload;
this.handleChange(); this.handleChange();
this.avatarElem.remove(); this.avatarElem.remove();
}); });
this.avatarEdit.container.append(this.avatarElem); this.avatarEdit.container.append(this.avatarElem);
}
} }
this.inputFields.forEach(inputField => { this.inputFields.forEach(inputField => {
this.listenerSetter.add(inputField.input)('input', this.handleChange); this.listenerSetter.add(inputField.input)('input', this.handleChange);
}); });
this.handleChange();
}
public get disabled() {
return this._disabled;
}
public set disabled(value) {
this._disabled = value;
this.inputFields.forEach(inputField => inputField.input.toggleAttribute('disabled', value));
this.handleChange();
}
public lockWithPromise(promise: Promise<any>, unlockOnSuccess = false) {
this.disabled = true;
promise.then(() => {
if(unlockOnSuccess) {
this.disabled = false;
}
}, () => {
this.disabled = false;
});
} }
public isChanged = () => { public isChanged = () => {
return !!this.uploadAvatar || !!this.inputFields.find(inputField => inputField.isValid()); if(this.uploadAvatar) {
return true;
}
let validLength = 0, requiredLength = 0, requiredValidLength = 0;
this.inputFields.forEach(inputField => {
const isValid = inputField.isValid();
if(isValid) {
++validLength;
if(inputField.required) {
++requiredValidLength;
}
}
if(inputField.required) {
++requiredLength;
}
});
return requiredLength === requiredValidLength && validLength > 0;
}; };
public handleChange = () => { public handleChange = () => {

20
src/components/inputField.ts

@ -75,7 +75,9 @@ export type InputFieldOptions = {
maxLength?: number, maxLength?: number,
showLengthOn?: number, showLengthOn?: number,
plainText?: true, plainText?: true,
animate?: true animate?: true,
required?: boolean,
validate?: () => boolean
}; };
class InputField { class InputField {
@ -86,6 +88,9 @@ class InputField {
public originalValue: string; public originalValue: string;
public required: boolean;
public validate: () => boolean;
//public onLengthChange: (length: number, isOverflow: boolean) => void; //public onLengthChange: (length: number, isOverflow: boolean) => void;
protected wasInputFakeClientHeight: number; protected wasInputFakeClientHeight: number;
// protected showScrollDebounced: () => void; // protected showScrollDebounced: () => void;
@ -94,6 +99,13 @@ class InputField {
this.container = document.createElement('div'); this.container = document.createElement('div');
this.container.classList.add('input-field'); this.container.classList.add('input-field');
this.required = options.required;
this.validate = options.validate;
if(this.required) {
this.originalValue = '';
}
if(options.maxLength) { if(options.maxLength) {
options.showLengthOn = Math.min(40, Math.round(options.maxLength / 3)); options.showLengthOn = Math.min(40, Math.round(options.maxLength / 3));
} }
@ -259,8 +271,12 @@ class InputField {
} }
} }
public isChanged() {
return this.value !== this.originalValue;
}
public isValid() { public isValid() {
return !this.input.classList.contains('error') && this.value !== this.originalValue; return !this.input.classList.contains('error') && this.isChanged() && (!this.validate || this.validate());
} }
public setOriginalValue(value: InputField['originalValue'] = '', silent = false) { public setOriginalValue(value: InputField['originalValue'] = '', silent = false) {

88
src/components/popups/createContact.ts

@ -0,0 +1,88 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import InputField from "../inputField";
import PopupElement from ".";
import { attachClickEvent } from "../../helpers/dom/clickEvent";
import EditPeer from "../editPeer";
import { _i18n } from "../../lib/langPack";
import TelInputField from "../telInputField";
import appUsersManager from "../../lib/appManagers/appUsersManager";
import { formatPhoneNumber } from "../../helpers/formatPhoneNumber";
import { toastNew } from "../toast";
export default class PopupCreateContact extends PopupElement {
constructor() {
super('popup-create-contact popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Add'});
_i18n(this.title, 'AddContactTitle');
attachClickEvent(this.btnConfirm, () => {
const promise = appUsersManager.importContact(nameInputField.value, lastNameInputField.value, telInputField.value);
promise.then(() => {
this.hide();
}, (err) => {
if(err.type === 'NO_USER') {
toastNew({langPackKey: 'Contacts.PhoneNumber.NotRegistred'});
editPeer.disabled = false;
}
});
editPeer.lockWithPromise(promise);
}, {listenerSetter: this.listenerSetter});
const inputFields: InputField[] = [];
const div = document.createElement('div');
div.classList.add('name-fields');
const nameInputField = new InputField({
label: 'FirstName',
name: 'create-contact-name',
maxLength: 70,
required: true
});
const lastNameInputField = new InputField({
label: 'LastName',
name: 'create-contact-lastname',
maxLength: 70
});
const telInputField = new TelInputField({required: true});
inputFields.push(nameInputField, lastNameInputField, telInputField);
const onInput = () => {
const name = nameInputField.value + ' ' + lastNameInputField.value;
// const abbr = RichTextProcessor.getAbbreviation(name);
editPeer.avatarElem.setAttribute('peer-title', name);
editPeer.avatarElem.update();
};
this.listenerSetter.add(nameInputField.input)('input', onInput);
this.listenerSetter.add(lastNameInputField.input)('input', onInput);
const user = appUsersManager.getSelf();
const formatted = formatPhoneNumber(user.phone);
if(formatted) {
telInputField.validate = () => {
return !!telInputField.value.match(/\d/);
};
telInputField.value = '+' + formatted.code.country_code;
}
const editPeer = new EditPeer({
inputFields,
listenerSetter: this.listenerSetter,
doNotEditAvatar: true,
nextBtn: this.btnConfirm,
avatarSize: 100
});
div.append(nameInputField.container, lastNameInputField.container, editPeer.avatarElem);
this.container.append(div, telInputField.container);
this.show();
}
}

8
src/components/popups/index.ts

@ -11,6 +11,7 @@ import appNavigationController, { NavigationItem } from "../appNavigationControl
import { i18n, LangPackKey } from "../../lib/langPack"; import { i18n, LangPackKey } from "../../lib/langPack";
import findUpClassName from "../../helpers/dom/findUpClassName"; import findUpClassName from "../../helpers/dom/findUpClassName";
import blurActiveElement from "../../helpers/dom/blurActiveElement"; import blurActiveElement from "../../helpers/dom/blurActiveElement";
import ListenerSetter from "../../helpers/listenerSetter";
export type PopupButton = { export type PopupButton = {
text?: string, text?: string,
@ -34,7 +35,7 @@ export default class PopupElement {
protected header = document.createElement('div'); protected header = document.createElement('div');
protected title = document.createElement('div'); protected title = document.createElement('div');
protected btnClose: HTMLElement; protected btnClose: HTMLElement;
protected btnConfirm: HTMLElement; protected btnConfirm: HTMLButtonElement;
protected body: HTMLElement; protected body: HTMLElement;
protected buttons: HTMLElement; protected buttons: HTMLElement;
@ -44,6 +45,8 @@ export default class PopupElement {
protected navigationItem: NavigationItem; protected navigationItem: NavigationItem;
protected listenerSetter: ListenerSetter;
constructor(className: string, buttons?: Array<PopupButton>, options: PopupOptions = {}) { constructor(className: string, buttons?: Array<PopupButton>, options: PopupOptions = {}) {
this.element.classList.add('popup'); this.element.classList.add('popup');
this.element.className = 'popup' + (className ? ' ' + className : ''); this.element.className = 'popup' + (className ? ' ' + className : '');
@ -54,6 +57,8 @@ export default class PopupElement {
this.header.append(this.title); this.header.append(this.title);
this.listenerSetter = new ListenerSetter();
if(options.closable) { if(options.closable) {
this.btnClose = document.createElement('span'); this.btnClose = document.createElement('span');
this.btnClose.classList.add('btn-icon', 'popup-close', 'tgico-close'); this.btnClose.classList.add('btn-icon', 'popup-close', 'tgico-close');
@ -157,6 +162,7 @@ export default class PopupElement {
this.onClose && this.onClose(); this.onClose && this.onClose();
this.element.classList.add('hiding'); this.element.classList.add('hiding');
this.element.classList.remove('active'); this.element.classList.remove('active');
this.listenerSetter.removeAll();
if(this.btnClose) this.btnClose.removeEventListener('click', this.hide); if(this.btnClose) this.btnClose.removeEventListener('click', this.hide);
rootScope.isOverlayActive = false; rootScope.isOverlayActive = false;

14
src/components/sidebarLeft/tabs/addContact.ts

@ -1,14 +0,0 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import { SliderSuperTab } from "../../slider";
export default class AppAddContactTab extends SliderSuperTab {
protected init() {
this.container.classList.add('add-contact-container');
this.setTitle('AddContactTitle');
}
}

13
src/components/sidebarLeft/tabs/contacts.ts

@ -7,11 +7,13 @@
import { SliderSuperTab } from "../../slider"; import { SliderSuperTab } from "../../slider";
import appDialogsManager from "../../../lib/appManagers/appDialogsManager"; import appDialogsManager from "../../../lib/appManagers/appDialogsManager";
import appUsersManager from "../../../lib/appManagers/appUsersManager"; import appUsersManager from "../../../lib/appManagers/appUsersManager";
import appPhotosManager from "../../../lib/appManagers/appPhotosManager";
import InputSearch from "../../inputSearch"; import InputSearch from "../../inputSearch";
import { isMobile } from "../../../helpers/userAgent"; import { isMobile } from "../../../helpers/userAgent";
import { canFocus } from "../../../helpers/dom/canFocus"; import { canFocus } from "../../../helpers/dom/canFocus";
import windowSize from "../../../helpers/windowSize"; import windowSize from "../../../helpers/windowSize";
import ButtonCorner from "../../buttonCorner";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import PopupCreateContact from "../../popups/createContact";
// TODO: поиск по людям глобальный, если не нашло в контактах никого // TODO: поиск по людям глобальный, если не нашло в контактах никого
@ -29,8 +31,15 @@ export default class AppContactsTab extends SliderSuperTab {
this.list.id = 'contacts'; this.list.id = 'contacts';
this.list.classList.add('contacts-container'); this.list.classList.add('contacts-container');
const btnAdd = ButtonCorner({icon: 'add', className: 'is-visible'});
this.content.append(btnAdd);
attachClickEvent(btnAdd, () => {
new PopupCreateContact();
}, {listenerSetter: this.listenerSetter});
appDialogsManager.setListClickListener(this.list, () => { appDialogsManager.setListClickListener(this.list, () => {
(this.container.querySelector('.sidebar-close-button') as HTMLElement).click(); this.close();
}, undefined, true); }, undefined, true);
this.inputSearch = new InputSearch('Search', (value) => { this.inputSearch = new InputSearch('Search', (value) => {

89
src/components/sidebarRight/tabs/editContact.ts

@ -31,7 +31,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.setTitle('Edit'); this.setTitle(this.peerId ? 'Edit' : 'AddContactTitle');
{ {
const section = new SettingSection({noDelimiter: true}); const section = new SettingSection({noDelimiter: true});
@ -51,13 +51,14 @@ export default class AppEditContactTab extends SliderSuperTab {
maxLength: 70 maxLength: 70
}); });
const user = appUsersManager.getUser(this.peerId); if(this.peerId) {
const user = appUsersManager.getUser(this.peerId);
this.nameInputField.setOriginalValue(user.first_name); this.nameInputField.setOriginalValue(user.first_name);
this.lastNameInputField.setOriginalValue(user.last_name); this.lastNameInputField.setOriginalValue(user.last_name);
}
inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container); inputWrapper.append(this.nameInputField.container, this.lastNameInputField.container);
inputFields.push(this.nameInputField, this.lastNameInputField); inputFields.push(this.nameInputField, this.lastNameInputField);
this.editPeer = new EditPeer({ this.editPeer = new EditPeer({
@ -68,52 +69,56 @@ export default class AppEditContactTab extends SliderSuperTab {
}); });
this.content.append(this.editPeer.nextBtn); this.content.append(this.editPeer.nextBtn);
const div = document.createElement('div'); if(this.peerId) {
div.classList.add('avatar-edit'); const div = document.createElement('div');
div.append(this.editPeer.avatarElem); div.classList.add('avatar-edit');
div.append(this.editPeer.avatarElem);
const notificationsCheckboxField = new CheckboxField({ const notificationsCheckboxField = new CheckboxField({
text: 'Notifications' text: 'Notifications'
}); });
notificationsCheckboxField.input.addEventListener('change', (e) => { notificationsCheckboxField.input.addEventListener('change', (e) => {
if(!e.isTrusted) { if(!e.isTrusted) {
return; return;
} }
appMessagesManager.mutePeer(this.peerId); appMessagesManager.mutePeer(this.peerId);
}); });
this.listenerSetter.add(rootScope)('notify_settings', (update) => { this.listenerSetter.add(rootScope)('notify_settings', (update) => {
if(update.peer._ !== 'notifyPeer') return; if(update.peer._ !== 'notifyPeer') return;
const peerId = appPeersManager.getPeerId(update.peer.peer); const peerId = appPeersManager.getPeerId(update.peer.peer);
if(this.peerId === peerId) { if(this.peerId === peerId) {
const enabled = !appNotificationsManager.isMuted(update.notify_settings); const enabled = !appNotificationsManager.isMuted(update.notify_settings);
if(enabled !== notificationsCheckboxField.checked) { if(enabled !== notificationsCheckboxField.checked) {
notificationsCheckboxField.checked = enabled; notificationsCheckboxField.checked = enabled;
}
} }
} });
});
const notificationsRow = new Row({ const notificationsRow = new Row({
checkboxField: notificationsCheckboxField checkboxField: notificationsCheckboxField
}); });
const enabled = !appNotificationsManager.isPeerLocalMuted(this.peerId, false); const enabled = !appNotificationsManager.isPeerLocalMuted(this.peerId, false);
notificationsCheckboxField.checked = enabled; 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({
peerId: this.peerId peerId: this.peerId
}).element); }).element);
//profileNameDiv.innerHTML = 'Karen Stanford'; //profileNameDiv.innerHTML = 'Karen Stanford';
const profileSubtitleDiv = document.createElement('div'); const profileSubtitleDiv = document.createElement('div');
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, notificationsRow.container);
} else {
section.content.append(inputWrapper);
}
this.scrollable.append(section.container); this.scrollable.append(section.container);
@ -128,7 +133,7 @@ export default class AppEditContactTab extends SliderSuperTab {
}, {listenerSetter: this.listenerSetter}); }, {listenerSetter: this.listenerSetter});
} }
{ if(this.peerId) {
const section = new SettingSection({ const section = new SettingSection({
}); });

110
src/components/telInputField.ts

@ -0,0 +1,110 @@
/*
* https://github.com/morethanwords/tweb
* Copyright (C) 2019-2021 Eduard Kuzmenko
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import placeCaretAtEnd from "../helpers/dom/placeCaretAtEnd";
import { formatPhoneNumber } from "../helpers/formatPhoneNumber";
import { isApple, isAndroid, isAppleMobile } from "../helpers/userAgent";
import { HelpCountry, HelpCountryCode } from "../layer";
import InputField, { InputFieldOptions } from "./inputField";
export default class TelInputField extends InputField {
private pasted = false;
public lastValue = '';
constructor(options: InputFieldOptions & {
onInput?: (formatted: ReturnType<typeof formatPhoneNumber>) => void
} = {}) {
super({
label: 'Contacts.PhoneNumber.Placeholder',
//plainText: true,
name: 'phone',
...options
});
this.container.classList.add('input-field-phone');
let telEl = this.input;
if(telEl instanceof HTMLInputElement) {
telEl.type = 'tel';
telEl.autocomplete = 'rr55RandomRR55';
} else {
telEl.inputMode = 'decimal';
const pixelRatio = window.devicePixelRatio;
if(pixelRatio > 1) {
let letterSpacing: number;
if(isApple) {
letterSpacing = pixelRatio * -.16;
} else if(isAndroid) {
letterSpacing = 0;
}
telEl.style.setProperty('--letter-spacing', letterSpacing + 'px');
}
const originalFunc = this.setValueSilently.bind(this);
this.setValueSilently = (value) => {
originalFunc(value);
placeCaretAtEnd(this.input, true);
};
}
telEl.addEventListener('input', () => {
//console.log('input', this.value);
telEl.classList.remove('error');
const value = this.value;
const diff = Math.abs(value.length - this.lastValue.length);
if(diff > 1 && !this.pasted && isAppleMobile) {
this.setValueSilently(this.lastValue + value);
}
this.pasted = false;
this.setLabel();
let formattedPhoneNumber: ReturnType<typeof formatPhoneNumber>;
let formatted: string, country: HelpCountry, countryCode: HelpCountryCode, leftPattern = '';
if(this.value.replace(/\++/, '+') === '+') {
this.setValueSilently('+');
} else {
formattedPhoneNumber = formatPhoneNumber(this.value);
formatted = formattedPhoneNumber.formatted;
country = formattedPhoneNumber.country;
leftPattern = formattedPhoneNumber.leftPattern;
countryCode = formattedPhoneNumber.code;
this.setValueSilently(this.lastValue = formatted ? '+' + formatted : '');
}
telEl.dataset.leftPattern = leftPattern/* .replace(/X/g, '0') */;
//console.log(formatted, country);
options.onInput && options.onInput(formattedPhoneNumber);
});
telEl.addEventListener('paste', () => {
this.pasted = true;
//console.log('paste', telEl.value);
});
/* telEl.addEventListener('change', (e) => {
console.log('change', telEl.value);
}); */
telEl.addEventListener('keypress', (e) => {
//console.log('keypress', this.value);
if(/\D/.test(e.key) && !(e.metaKey || e.ctrlKey) && e.key !== 'Backspace' && !(e.key === '+' && e.shiftKey/* && !this.value */)) {
e.preventDefault();
return false;
}
});
/* telEl.addEventListener('focus', function(this: typeof telEl, e) {
this.removeAttribute('readonly'); // fix autocomplete
});*/
}
}

1
src/lang.ts

@ -570,6 +570,7 @@ const lang = {
"Alert.UserDoesntExists": "Sorry, this user doesn't seem to exist.", "Alert.UserDoesntExists": "Sorry, this user doesn't seem to exist.",
"Appearance.Reset": "Reset to Defaults", "Appearance.Reset": "Reset to Defaults",
"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",
"Contacts.PhoneNumber.NotRegistred": "The person with this phone number is not registered on Telegram yet.",
"Channel.UsernameAboutChannel": "People can share this link with others and can find your channel using Telegram search.", "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.", "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",

1
src/langSign.ts

@ -23,6 +23,7 @@ const lang = {
"StartMessaging": "Start Messaging", "StartMessaging": "Start Messaging",
// * macos // * macos
"Contacts.PhoneNumber.Placeholder": "Phone Number",
"Login.Next": "Next", "Login.Next": "Next",
"Login.ContinueOnLanguage": "Continue in English", "Login.ContinueOnLanguage": "Continue in English",
"Login.QR.Title": "Log in to Telegram by QR Code", "Login.QR.Title": "Log in to Telegram by QR Code",

93
src/lib/appManagers/appUsersManager.ts

@ -17,7 +17,7 @@ import cleanUsername from "../../helpers/cleanUsername";
import { tsNow } from "../../helpers/date"; import { tsNow } from "../../helpers/date";
import { formatPhoneNumber } from "../../helpers/formatPhoneNumber"; import { formatPhoneNumber } from "../../helpers/formatPhoneNumber";
import { safeReplaceObject, isObject } from "../../helpers/object"; import { safeReplaceObject, isObject } from "../../helpers/object";
import { Chat, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer"; import { Chat, InputContact, InputUser, User as MTUser, UserProfilePhoto, UserStatus } from "../../layer";
import I18n, { i18n, LangPackKey } from "../langPack"; 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';
@ -680,75 +680,50 @@ export class AppUsersManager {
} }
} }
/* function importContact (phone, firstName, lastName) { public importContact(first_name: string, last_name: string, phone: string) {
return MtpApiManager.invokeApi('contacts.importContacts', { return this.importContacts([{
contacts: [{ first_name,
_: 'inputPhoneContact', last_name,
client_id: '1', phones: [phone]
phone: phone, }]).then(userIds => {
first_name: firstName, if(!userIds.length) {
last_name: lastName const error = new Error();
}], (error as any).type = 'NO_USER';
replace: false throw error;
}).then(function (importedContactsResult) { }
saveApiUsers(importedContactsResult.users)
return userIds[0];
var foundUserID = false });
angular.forEach(importedContactsResult.imported, function (importedContact) {
onContactUpdated(foundUserID = importedContact.user_id, true)
})
return foundUserID || false
})
} }
function importContacts (contacts) { public importContacts(contacts: {phones: string[], first_name: string, last_name: string}[]) {
var inputContacts = [], const inputContacts: InputContact[] = [];
i
var j
for (i = 0; i < contacts.length; i++) { for(let i = 0; i < contacts.length; ++i) {
for (j = 0; j < contacts[i].phones.length; j++) { for(let j = 0; j < contacts[i].phones.length; ++j) {
inputContacts.push({ inputContacts.push({
_: 'inputPhoneContact', _: 'inputPhoneContact',
client_id: (i << 16 | j).toString(10), client_id: (i << 16 | j).toString(10),
phone: contacts[i].phones[j], phone: contacts[i].phones[j],
first_name: contacts[i].first_name, first_name: contacts[i].first_name,
last_name: contacts[i].last_name last_name: contacts[i].last_name
}) });
} }
} }
return MtpApiManager.invokeApi('contacts.importContacts', { return apiManager.invokeApi('contacts.importContacts', {
contacts: inputContacts, contacts: inputContacts
replace: false }).then((importedContactsResult) => {
}).then(function (importedContactsResult) { this.saveApiUsers(importedContactsResult.users);
saveApiUsers(importedContactsResult.users)
var result = []
angular.forEach(importedContactsResult.imported, function (importedContact) {
onContactUpdated(importedContact.user_id, true)
result.push(importedContact.user_id)
})
return result const userIds = importedContactsResult.imported.map((importedContact) => {
}) this.onContactUpdated(importedContact.user_id, true);
} */ return importedContact.user_id;
/* public deleteContacts(userIds: number[]) {
var ids: any[] = [];
userIds.forEach((userId) => {
ids.push(this.getUserInput(userId));
})
return apiManager.invokeApi('contacts.deleteContacts', {
id: ids
}).then(() => {
userIds.forEach((userId) => {
this.onContactUpdated(userId, false);
}); });
return userIds;
}); });
} */ }
public getTopPeers(type: TopPeerType) { public getTopPeers(type: TopPeerType) {
if(this.getTopPeersPromises[type]) return this.getTopPeersPromises[type]; if(this.getTopPeersPromises[type]) return this.getTopPeersPromises[type];
@ -889,6 +864,14 @@ export class AppUsersManager {
} }
public addContact(userId: number, first_name: string, last_name: string, phone: string, showPhone?: true) { public addContact(userId: number, first_name: string, last_name: string, phone: string, showPhone?: true) {
/* if(!userId) {
return this.importContacts([{
first_name,
last_name,
phones: [phone]
}]);
} */
return apiManager.invokeApi('contacts.addContact', { return apiManager.invokeApi('contacts.addContact', {
id: this.getUserInput(userId), id: this.getUserInput(userId),
first_name, first_name,

126
src/pages/pageSignIn.ts

@ -40,6 +40,7 @@ import { getCountryEmoji } from "../vendor/emoji";
import simulateEvent from "../helpers/dom/dispatchEvent"; import simulateEvent from "../helpers/dom/dispatchEvent";
import stateStorage from "../lib/stateStorage"; import stateStorage from "../lib/stateStorage";
import rootScope from "../lib/rootScope"; import rootScope from "../lib/rootScope";
import TelInputField from "../components/telInputField";
//import _countries from '../countries_pretty.json'; //import _countries from '../countries_pretty.json';
let btnNext: HTMLButtonElement = null, btnQr: HTMLButtonElement; let btnNext: HTMLButtonElement = null, btnQr: HTMLButtonElement;
@ -163,7 +164,7 @@ let onFirstMount = () => {
lastCountrySelected = countries.find(c => c.default_name === defaultName); lastCountrySelected = countries.find(c => c.default_name === defaultName);
lastCountryCodeSelected = lastCountrySelected.country_codes.find(_countryCode => _countryCode.country_code === countryCode); lastCountryCodeSelected = lastCountrySelected.country_codes.find(_countryCode => _countryCode.country_code === countryCode);
telInputField.value = lastValue = phoneCode; telInputField.value = telInputField.lastValue = phoneCode;
hidePicker(); hidePicker();
setTimeout(() => { setTimeout(() => {
telEl.focus(); telEl.focus();
@ -269,114 +270,41 @@ let onFirstMount = () => {
else countryInput.focus(); else countryInput.focus();
}); });
let pasted = false; const telInputField = new TelInputField({
let lastValue = ''; onInput: (formatted) => {
lottieLoader.loadLottieWorkers();
const telInputField = new InputField({
label: 'Login.PhoneLabel', const {country, code} = formatted;
//plainText: true, let countryName = country ? country.name || country.default_name : ''/* 'Unknown' */;
name: 'phone' if(countryName !== countryInputField.value && (
}); !lastCountrySelected ||
!country ||
telInputField.container.classList.add('input-field-phone'); !code || (
lastCountrySelected !== country &&
let telEl = telInputField.input; lastCountryCodeSelected.country_code !== code.country_code
if(telEl instanceof HTMLInputElement) { )
telEl.type = 'tel';
telEl.autocomplete = 'rr55RandomRR55';
} else {
telEl.inputMode = 'decimal';
const pixelRatio = window.devicePixelRatio;
if(pixelRatio > 1) {
let letterSpacing: number;
if(isApple) {
letterSpacing = pixelRatio * -.16;
} else if(isAndroid) {
letterSpacing = 0;
}
telEl.style.setProperty('--letter-spacing', letterSpacing + 'px');
}
const originalFunc = telInputField.setValueSilently.bind(telInputField);
telInputField.setValueSilently = (value) => {
originalFunc(value);
placeCaretAtEnd(telInputField.input, true);
};
}
telEl.addEventListener('input', () => {
//console.log('input', this.value);
telEl.classList.remove('error');
lottieLoader.loadLottieWorkers();
const value = telInputField.value;
const diff = Math.abs(value.length - lastValue.length);
if(diff > 1 && !pasted && isAppleMobile) {
telInputField.setValueSilently(lastValue + value);
}
pasted = false;
telInputField.setLabel();
let formatted: string, country: HelpCountry, countryCode: HelpCountryCode, leftPattern = '';
if(telInputField.value.replace(/\++/, '+') === '+') {
telInputField.setValueSilently('+');
} else {
const o = formatPhoneNumber(telInputField.value);
formatted = o.formatted;
country = o.country;
leftPattern = o.leftPattern;
countryCode = o.code;
telInputField.setValueSilently(lastValue = formatted ? '+' + formatted : '');
}
telEl.dataset.leftPattern = leftPattern/* .replace(/X/g, '0') */;
//console.log(formatted, country);
let countryName = country ? country.name || country.default_name : ''/* 'Unknown' */;
if(countryName !== countryInputField.value && (
!lastCountrySelected ||
!country ||
!countryCode || (
lastCountrySelected !== country &&
lastCountryCodeSelected.country_code !== countryCode.country_code
) )
) ) {
) { replaceContent(countryInput, country ? i18n(country.default_name as any) : countryName);
replaceContent(countryInput, country ? i18n(country.default_name as any) : countryName); lastCountrySelected = country;
lastCountrySelected = country; lastCountryCodeSelected = code;
lastCountryCodeSelected = countryCode; }
}
//if(country && (telInputField.value.length - 1) >= (country.pattern ? country.pattern.length : 9)) { //if(country && (telInputField.value.length - 1) >= (country.pattern ? country.pattern.length : 9)) {
if(country || (telInputField.value.length - 1) > 1) { if(country || (telInputField.value.length - 1) > 1) {
btnNext.style.visibility = ''; btnNext.style.visibility = '';
} else { } else {
btnNext.style.visibility = 'hidden'; btnNext.style.visibility = 'hidden';
}
} }
}); });
telEl.addEventListener('paste', () => { const telEl = telInputField.input;
pasted = true;
//console.log('paste', telEl.value);
});
/* telEl.addEventListener('change', (e) => {
console.log('change', telEl.value);
}); */
telEl.addEventListener('keypress', (e) => { telEl.addEventListener('keypress', (e) => {
//console.log('keypress', this.value); //console.log('keypress', this.value);
if(!btnNext.style.visibility &&/* this.value.length >= 9 && */ e.key === 'Enter') { if(!btnNext.style.visibility &&/* this.value.length >= 9 && */ e.key === 'Enter') {
return onSubmit(); return onSubmit();
} else if(/\D/.test(e.key) && !(e.metaKey || e.ctrlKey) && e.key !== 'Backspace' && !(e.key === '+' && e.shiftKey/* && !this.value */)) {
e.preventDefault();
return false;
} }
}); });

23
src/scss/partials/popups/_mediaAttacher.scss

@ -147,7 +147,7 @@
font-size: 1rem; font-size: 1rem;
border-radius: $border-radius-medium; border-radius: $border-radius-medium;
&:not(:focus):empty ~ label { &[data-placeholder]:not(:focus):empty ~ label {
opacity: 0; opacity: 0;
} }
} }
@ -189,3 +189,24 @@
margin-top: .5rem; margin-top: .5rem;
} }
} }
.popup-create-contact {
.name-fields {
display: flex;
flex-direction: column;
position: relative;
padding-left: 116px;
margin-top: 1rem;
.input-field:first-child {
margin-top: 0;
}
}
.avatar-placeholder {
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
}
}

Loading…
Cancel
Save