Browse Source

Empty chatlist placeholder

Fix pinned container on mobiles
master
Eduard Kuzmenko 3 years ago
parent
commit
935e0a3714
  1. 21
      src/components/sortedUserList.ts
  2. 94
      src/lib/appManagers/appDialogsManager.ts
  3. 23
      src/lib/mtproto/authorizer.ts
  4. 12
      src/scss/partials/_chatPinned.scss
  5. 3
      src/scss/partials/pages/_pages.scss

21
src/components/sortedUserList.ts

@ -21,8 +21,8 @@ type SortedUser = {
}; };
export default class SortedUserList { export default class SortedUserList {
protected static SORT_INTERVAL = 30e3; protected static SORT_INTERVAL = 30e3;
protected users: Map<number, SortedUser>; public users: Map<number, SortedUser>;
protected sorted: Array<SortedUser>; public sorted: Array<SortedUser>;
public list: HTMLUListElement; public list: HTMLUListElement;
protected lazyLoadQueue: LazyLoadQueueIntersector; protected lazyLoadQueue: LazyLoadQueueIntersector;
@ -78,8 +78,12 @@ export default class SortedUserList {
return true; return true;
} }
public has(peerId: number) {
return this.users.has(peerId);
}
public add(peerId: number) { public add(peerId: number) {
if(this.users.has(peerId)) { if(this.has(peerId)) {
return; return;
} }
@ -104,6 +108,17 @@ export default class SortedUserList {
this.update(peerId); this.update(peerId);
} }
public delete(peerId: number) {
const user = this.users.get(peerId);
if(!user) {
return;
}
user.dom.listEl.remove();
this.users.delete(peerId);
this.sorted.findAndSplice(_user => _user === user);
}
public update(peerId: number, batch = false) { public update(peerId: number, batch = false) {
const sortedUser = this.users.get(peerId); const sortedUser = this.users.get(peerId);
sortedUser.status = appUsersManager.getUserStatusForSort(peerId); sortedUser.status = appUsersManager.getUserStatusForSort(peerId);

94
src/lib/appManagers/appDialogsManager.ts

@ -108,7 +108,9 @@ export class AppDialogsManager {
private lastActiveElements: Set<HTMLElement> = new Set(); private lastActiveElements: Set<HTMLElement> = new Set();
private offsets: {top: number, bottom: number} = {top: 0, bottom: 0}; private offsets: {top: number, bottom: number} = {top: 0, bottom: 0};
loadContacts: () => void;
private loadContacts: () => void;
private processContact: (peerId: number) => void;
constructor() { constructor() {
this.chatsPreloader = putPreloader(null, true); this.chatsPreloader = putPreloader(null, true);
@ -190,8 +192,7 @@ export class AppDialogsManager {
this.setFiltersUnreadCount(); this.setFiltersUnreadCount();
}); */ }); */
rootScope.addEventListener('dialog_flush', (e) => { rootScope.addEventListener('dialog_flush', ({peerId}) => {
const peerId: number = e.peerId;
const dialog = appMessagesManager.getDialogOnly(peerId); const dialog = appMessagesManager.getDialogOnly(peerId);
if(dialog) { if(dialog) {
this.setLastMessage(dialog); this.setLastMessage(dialog);
@ -200,29 +201,31 @@ export class AppDialogsManager {
} }
}); });
rootScope.addEventListener('dialogs_multiupdate', (e) => { rootScope.addEventListener('dialogs_multiupdate', (dialogs) => {
const dialogs = e;
for(const id in dialogs) { for(const id in dialogs) {
const dialog = dialogs[id]; const dialog = dialogs[id];
this.updateDialog(dialog); this.updateDialog(dialog);
if(this.processContact) {
this.processContact(+id);
}
} }
this.validateForFilter(); this.validateForFilter();
this.setFiltersUnreadCount(); this.setFiltersUnreadCount();
}); });
rootScope.addEventListener('dialog_drop', (e) => { rootScope.addEventListener('dialog_drop', ({peerId}) => {
const {peerId} = e;
this.deleteDialog(peerId); this.deleteDialog(peerId);
this.setFiltersUnreadCount(); this.setFiltersUnreadCount();
});
rootScope.addEventListener('dialog_unread', (e) => { if(this.processContact) {
const info = e; this.processContact(peerId);
}
});
const dialog = appMessagesManager.getDialogOnly(info.peerId); rootScope.addEventListener('dialog_unread', ({peerId}) => {
const dialog = appMessagesManager.getDialogOnly(peerId);
if(dialog) { if(dialog) {
this.setUnreadMessages(dialog); this.setUnreadMessages(dialog);
this.validateForFilter(); this.validateForFilter();
@ -234,16 +237,18 @@ export class AppDialogsManager {
this.setUnreadMessages(dialog); // возможно это не нужно, но нужно менять is-muted this.setUnreadMessages(dialog); // возможно это не нужно, но нужно менять is-muted
}); });
rootScope.addEventListener('dialog_draft', (e) => { rootScope.addEventListener('dialog_draft', ({peerId}) => {
const dialog = appMessagesManager.getDialogOnly(e.peerId); const dialog = appMessagesManager.getDialogOnly(peerId);
if(dialog) { if(dialog) {
this.updateDialog(dialog); this.updateDialog(dialog);
if(this.processContact) {
this.processContact(peerId);
}
} }
}); });
rootScope.addEventListener('peer_changed', (e) => { rootScope.addEventListener('peer_changed', (peerId) => {
const peerId = e;
//const perf = performance.now(); //const perf = performance.now();
for(const element of this.lastActiveElements) { for(const element of this.lastActiveElements) {
if(+element.dataset.peerId !== peerId) { if(+element.dataset.peerId !== peerId) {
@ -260,8 +265,7 @@ export class AppDialogsManager {
//this.log('peer_changed total time:', performance.now() - perf); //this.log('peer_changed total time:', performance.now() - perf);
}); });
rootScope.addEventListener('filter_update', (e) => { rootScope.addEventListener('filter_update', (filter) => {
const filter: DialogFilter = e;
if(!this.filtersRendered[filter.id]) { if(!this.filtersRendered[filter.id]) {
this.addFilter(filter); this.addFilter(filter);
return; return;
@ -280,8 +284,7 @@ export class AppDialogsManager {
elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title); elements.title.innerHTML = RichTextProcessor.wrapEmojiText(filter.title);
}); });
rootScope.addEventListener('filter_delete', (e) => { rootScope.addEventListener('filter_delete', (filter) => {
const filter: DialogFilter = e;
const elements = this.filtersRendered[filter.id]; const elements = this.filtersRendered[filter.id];
if(!elements) return; if(!elements) return;
@ -301,9 +304,7 @@ export class AppDialogsManager {
} }
}); });
rootScope.addEventListener('filter_order', (e) => { rootScope.addEventListener('filter_order', (order) => {
const order = e;
const containerToAppend = this.folders.menu as HTMLElement; const containerToAppend = this.folders.menu as HTMLElement;
order.forEach((filterId) => { order.forEach((filterId) => {
const filter = appMessagesManager.filtersStorage.filters[filterId]; const filter = appMessagesManager.filtersStorage.filters[filterId];
@ -319,9 +320,7 @@ export class AppDialogsManager {
} */ } */
}); });
rootScope.addEventListener('peer_typings', (e) => { rootScope.addEventListener('peer_typings', ({peerId, typings}) => {
const {peerId, typings} = e;
const dialog = appMessagesManager.getDialogOnly(peerId); const dialog = appMessagesManager.getDialogOnly(peerId);
if(!dialog) return; if(!dialog) return;
@ -888,16 +887,27 @@ export class AppDialogsManager {
} }
private onListLengthChange = () => { private onListLengthChange = () => {
return;
this.checkIfPlaceholderNeeded(); this.checkIfPlaceholderNeeded();
if(this.filterId > 0) return; if(this.filterId > 0) return;
const count = this.chatList.childElementCount;
const parts = this.chatList.parentElement.parentElement;
const bottom = this.chatList.parentElement.nextElementSibling as HTMLElement; const bottom = this.chatList.parentElement.nextElementSibling as HTMLElement;
const hasContacts = !!bottom.childElementCount;
if(count >= 10) {
if(hasContacts) {
parts.classList.remove('with-contacts');
bottom.innerHTML = '';
this.loadContacts = undefined;
this.processContact = undefined;
}
if(bottom.childElementCount) return; return;
} else if(hasContacts) return;
bottom.parentElement.classList.add('with-contacts'); parts.classList.add('with-contacts');
const section = new SettingSection({ const section = new SettingSection({
name: 'Contacts', name: 'Contacts',
@ -911,7 +921,7 @@ export class AppDialogsManager {
const sortedUserList = new SortedUserList({avatarSize: 42, new: true}); const sortedUserList = new SortedUserList({avatarSize: 42, new: true});
this.loadContacts = () => { this.loadContacts = () => {
const pageCount = appPhotosManager.windowH / 60 | 0; const pageCount = appPhotosManager.windowH / 60 | 0;
const arr = contacts.splice(0, pageCount); const arr = contacts.splice(0, pageCount).filter(this.verifyUserIdForContacts);
arr.forEach((peerId) => { arr.forEach((peerId) => {
sortedUserList.add(peerId); sortedUserList.add(peerId);
@ -924,6 +934,17 @@ export class AppDialogsManager {
this.loadContacts(); this.loadContacts();
this.processContact = (peerId) => {
if(peerId < 0) {
return;
}
const good = this.verifyUserIdForContacts(peerId);
const added = sortedUserList.has(peerId);
if(!added && good) sortedUserList.add(peerId);
else if(added && !good) sortedUserList.delete(peerId);
};
const list = sortedUserList.list; const list = sortedUserList.list;
list.classList.add('chatlist-new'); list.classList.add('chatlist-new');
this.setListClickListener(list); this.setListClickListener(list);
@ -934,6 +955,11 @@ export class AppDialogsManager {
bottom.append(section.container); bottom.append(section.container);
}; };
private verifyUserIdForContacts = (peerId: number) => {
const dialog = appMessagesManager.getDialogOnly(peerId);
return !dialog;
};
public onChatsRegularScroll = () => { public onChatsRegularScroll = () => {
if(this.sliceTimeout) clearTimeout(this.sliceTimeout); if(this.sliceTimeout) clearTimeout(this.sliceTimeout);
this.sliceTimeout = window.setTimeout(() => { this.sliceTimeout = window.setTimeout(() => {
@ -944,7 +970,7 @@ export class AppDialogsManager {
return; return;
} }
if(!this.chatList.childElementCount) { if(!this.chatList.childElementCount || this.processContact) {
return; return;
} }

23
src/lib/mtproto/authorizer.ts

@ -64,7 +64,9 @@ type AuthOptions = {
serverSalt?: Uint8Array, serverSalt?: Uint8Array,
localTime?: number, localTime?: number,
serverTime?: any serverTime?: any,
localTry?: number
}; };
type ResPQ = { type ResPQ = {
@ -122,8 +124,7 @@ export class Authorizer {
const transport = dcConfigurator.chooseServer(dcId); const transport = dcConfigurator.chooseServer(dcId);
const baseError = { const baseError = {
code: 406, code: 406,
type: 'NETWORK_BAD_RESPONSE', type: 'NETWORK_BAD_RESPONSE'
transport
}; };
if(DEBUG) { if(DEBUG) {
@ -245,7 +246,7 @@ export class Authorizer {
return this.sendReqDhParams(auth); return this.sendReqDhParams(auth);
} }
private async sendReqDhParams(auth: AuthOptions) { private async sendReqDhParams(auth: AuthOptions): Promise<AuthOptions> {
auth.newNonce = new Uint8Array(32).randomize(); auth.newNonce = new Uint8Array(32).randomize();
const p_q_inner_data_dc: P_Q_inner_data = { const p_q_inner_data_dc: P_Q_inner_data = {
@ -578,16 +579,26 @@ export class Authorizer {
MTProto.secureRandom.nextBytes(nonce); */ MTProto.secureRandom.nextBytes(nonce); */
if(!dcConfigurator.chooseServer(dcId)) { if(!dcConfigurator.chooseServer(dcId)) {
return Promise.reject(new Error('[MT] No server found for dc ' + dcId)); throw new Error('[MT] No server found for dc ' + dcId);
} }
// await new Promise((resolve) => setTimeout(resolve, 2e3)); // await new Promise((resolve) => setTimeout(resolve, 2e3));
const auth: AuthOptions = {dcId, nonce, localTry: 1};
try { try {
const promise = this.sendReqPQ({dcId, nonce}); const promise = this.sendReqPQ(auth);
this.cached[dcId] = promise; this.cached[dcId] = promise;
return await promise; return await promise;
} catch(err) { } catch(err) {
if(err.originalError === -404 && auth.localTry <= 3) {
return this.sendReqPQ({
dcId: auth.dcId,
nonce: new Uint8Array(16).randomize(),
localTry: auth.localTry + 1
});
}
delete this.cached[dcId]; delete this.cached[dcId];
throw err; throw err;
} }

12
src/scss/partials/_chatPinned.scss

@ -249,12 +249,14 @@
&.is-floating { &.is-floating {
position: absolute !important; position: absolute !important;
top: 100%; top: 3.5rem;
width: 100% !important; right: 0;
background: var(--surface-color) !important;
left: 0; left: 0;
max-height: 100% !important; margin: 0;
height: 52px; width: auto;
height: 3.25rem;
max-height: 3.25rem;
background: var(--surface-color) !important;
.pinned-container-close { .pinned-container-close {
position: absolute; position: absolute;

3
src/scss/partials/pages/_pages.scss

@ -91,12 +91,13 @@
flex-direction: row; flex-direction: row;
} */ } */
> div { .container {
height: 810px; height: 810px;
padding: 0; padding: 0;
flex: 1 1 auto; flex: 1 1 auto;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%;
@media screen and (max-height: 810px) { @media screen and (max-height: 810px) {
height: 760px; height: 760px;

Loading…
Cancel
Save