diff --git a/src/components/sidebarLeft/tabs/chatFolders.ts b/src/components/sidebarLeft/tabs/chatFolders.ts index 3886e94f..5197cf3b 100644 --- a/src/components/sidebarLeft/tabs/chatFolders.ts +++ b/src/components/sidebarLeft/tabs/chatFolders.ts @@ -121,7 +121,7 @@ export default class AppChatFoldersTab extends SliderSuperTab { caption.classList.add('caption'); i18n_({element: caption, key: 'ChatList.Filter.Header'}); - this.createFolderBtn = Button('btn-primary btn-color-primary btn-create-folder', { + this.createFolderBtn = Button('btn-primary btn-color-primary btn-control tgico', { text: 'ChatList.Filter.NewTitle', icon: 'add' }); diff --git a/src/components/wrappers.ts b/src/components/wrappers.ts index 07b1901b..32f8473d 100644 --- a/src/components/wrappers.ts +++ b/src/components/wrappers.ts @@ -39,6 +39,7 @@ import renderImageFromUrl from '../helpers/dom/renderImageFromUrl'; import sequentialDom from '../helpers/sequentialDom'; import { fastRaf } from '../helpers/schedulers'; import appDownloadManager from '../lib/appManagers/appDownloadManager'; +import appStickersManager from '../lib/appManagers/appStickersManager'; const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB @@ -1097,6 +1098,35 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o return loadPromise; } +export function wrapLocalSticker({emoji, width, height}: { + doc?: MyDocument, + url?: string, + emoji?: string, + width: number, + height: number, +}) { + const container = document.createElement('div'); + + const doc = appStickersManager.getAnimatedEmojiSticker(emoji); + if(doc) { + wrapSticker({ + doc, + div: container, + loop: false, + play: true, + width, + height, + emoji + }).then(() => { + // this.animation = player; + }); + } else { + container.classList.add('media-sticker-wrapper'); + } + + return {container}; +} + export function wrapReply(title: string, subtitle: string, message?: any) { const replyContainer = new ReplyContainer('reply'); replyContainer.fill(title, subtitle, message); diff --git a/src/lang.ts b/src/lang.ts index 49e195b3..1c7128ff 100644 --- a/src/lang.ts +++ b/src/lang.ts @@ -406,6 +406,8 @@ const lang = { "Open": "Open", "OpenUrlTitle": "Open Link", "OpenUrlAlert2": "Do you want to open %1$s?", + "FilterNoChatsToDisplay": "Folder is empty", + "FilterNoChatsToDisplayInfo": "No chats currently belong to this folder.", // * macos "AccountSettings.Filters": "Chat Folders", diff --git a/src/lib/appManagers/appDialogsManager.ts b/src/lib/appManagers/appDialogsManager.ts index c59636b5..f9351b45 100644 --- a/src/lib/appManagers/appDialogsManager.ts +++ b/src/lib/appManagers/appDialogsManager.ts @@ -16,7 +16,7 @@ import { isSafari } from "../../helpers/userAgent"; import { logger, LogTypes } from "../logger"; import { RichTextProcessor } from "../richtextprocessor"; import rootScope from "../rootScope"; -import { positionElementByIndex, replaceContent } from "../../helpers/dom"; +import { attachClickEvent, positionElementByIndex, replaceContent } from "../../helpers/dom"; import apiUpdatesManager from "./apiUpdatesManager"; import appPeersManager from './appPeersManager'; import appImManager from "./appImManager"; @@ -33,9 +33,13 @@ import App from "../../config/app"; import DEBUG, { MOUNT_CLASS_TO } from "../../config/debug"; import appNotificationsManager from "./appNotificationsManager"; import PeerTitle from "../../components/peerTitle"; -import { i18n } from "../langPack"; +import { i18n, _i18n } from "../langPack"; import findUpTag from "../../helpers/dom/findUpTag"; import { LazyLoadQueueIntersector } from "../../components/lazyLoadQueue"; +import lottieLoader from "../lottieLoader"; +import { wrapLocalSticker } from "../../components/wrappers"; +import AppEditFolderTab from "../../components/sidebarLeft/tabs/editFolder"; +import appSidebarLeft from "../../components/sidebarLeft"; export type DialogDom = { avatarEl: AvatarElement, @@ -343,14 +347,9 @@ export class AppDialogsManager { }); rootScope.on('dialog_drop', (e) => { - const {peerId, dialog} = e; - - const dom = this.getDialogDom(peerId); - if(dom) { - dom.listEl.remove(); - delete this.doms[peerId]; - } + const {peerId} = e; + this.deleteDialog(peerId); this.setFiltersUnreadCount(); }); @@ -537,6 +536,8 @@ export class AppDialogsManager { new ConnectionStatusComponent(this.chatsContainer); this.chatsContainer.append(bottomPart); + + lottieLoader.loadLottieWorkers(); } private getOffset(side: 'top' | 'bottom'): {index: number, pos: number} { @@ -565,6 +566,20 @@ export class AppDialogsManager { return (!topOffset.index || index <= topOffset.index) && (!bottomOffset.index || index >= bottomOffset.index); } + private deleteDialog(peerId: number) { + const dom = this.getDialogDom(peerId); + if(dom) { + dom.listEl.remove(); + delete this.doms[peerId]; + + this.onListLengthChange(); + + return true; + } + + return false; + } + private updateDialog(dialog: Dialog) { if(!dialog) { return; @@ -576,17 +591,13 @@ export class AppDialogsManager { if(ret) { const idx = appMessagesManager.getDialogByPeerId(dialog.peerId)[1]; positionElementByIndex(ret.dom.listEl, this.chatList, idx); + this.onListLengthChange(); } else { return; } } } else { - const dom = this.getDialogDom(dialog.peerId); - if(dom) { - dom.listEl.remove(); - delete this.doms[dialog.peerId]; - } - + this.deleteDialog(dialog.peerId); return; } @@ -668,9 +679,7 @@ export class AppDialogsManager { // если больше не подходит по фильтру, удаляем if(folder.findIndex((dialog) => dialog.peerId === peerId) === -1) { - const listEl = this.doms[peerId].listEl; - listEl.remove(); - delete this.doms[peerId]; + this.deleteDialog(peerId); } } } @@ -806,6 +815,8 @@ export class AppDialogsManager { }); }); } + + this.onListLengthChange(); this.log.debug('getDialogs ' + loadCount + ' dialogs by offset:', offsetIndex, result, this.chatList.childElementCount); @@ -825,6 +836,48 @@ export class AppDialogsManager { }); } + private onListLengthChange = () => { + const emptyFolder = this.chatList.parentElement.querySelector('.empty-folder'); + if(this.scroll.loadedAll.bottom && !this.chatList.childElementCount) { + if(emptyFolder) { + return; + } + + const BASE_CLASS = 'empty-folder'; + const div = document.createElement('div'); + div.classList.add(BASE_CLASS); + + div.append(wrapLocalSticker({ + emoji: '📂', + width: 128, + height: 128 + }).container); + + const header = document.createElement('div'); + header.classList.add(BASE_CLASS + '-header'); + _i18n(header, 'FilterNoChatsToDisplay'); + + const subtitle = document.createElement('div'); + subtitle.classList.add(BASE_CLASS + '-subtitle'); + _i18n(subtitle, 'FilterNoChatsToDisplayInfo'); + + const button = Button('btn-primary btn-color-primary btn-control tgico', { + text: 'FilterHeaderEdit', + icon: 'settings' + }); + + attachClickEvent(button, () => { + new AppEditFolderTab(appSidebarLeft).open(appMessagesManager.filtersStorage.filters[this.filterId]); + }); + + div.append(header, subtitle, button); + + this.chatList.parentElement.append(div); + } else if(emptyFolder) { + emptyFolder.remove(); + } + }; + public onChatsRegularScroll = () => { if(this.sliceTimeout) clearTimeout(this.sliceTimeout); this.sliceTimeout = window.setTimeout(() => { @@ -900,9 +953,8 @@ export class AppDialogsManager { sliced.push(...sliceFromEnd); sliced.forEach(el => { - el.remove(); const peerId = +el.dataset.peerId; - delete this.doms[peerId]; + this.deleteDialog(peerId); }); //this.log('[slicer] elements', firstElement, lastElement, rect, sliced, sliceFromStart.length, sliceFromEnd.length); @@ -1024,8 +1076,7 @@ export class AppDialogsManager { const needIndex = index - offset; if(needIndex > currentOrder.length) { - dom.listEl.remove(); - delete this.doms[dialog.peerId]; + this.deleteDialog(dialog.peerId); return; } diff --git a/src/lib/appManagers/appMessagesManager.ts b/src/lib/appManagers/appMessagesManager.ts index 9e9594b2..dd5d76b9 100644 --- a/src/lib/appManagers/appMessagesManager.ts +++ b/src/lib/appManagers/appMessagesManager.ts @@ -1540,7 +1540,7 @@ export class AppMessagesManager { } public async refreshConversations() { - const limit = 100, outDialogs: Dialog[] = []; + const limit = 200, outDialogs: Dialog[] = []; for(let folderId = 0; folderId < 2; ++folderId) { let offsetDate = 0; for(;;) { @@ -1575,7 +1575,7 @@ export class AppMessagesManager { } public async getConversationsAll(query = '', folderId = 0) { - const limit = 100, outDialogs: Dialog[] = []; + const limit = 200, outDialogs: Dialog[] = []; for(; folderId < 2; ++folderId) { let offsetIndex = 0; for(;;) { diff --git a/src/scss/partials/_button.scss b/src/scss/partials/_button.scss index eeac8582..94920949 100644 --- a/src/scss/partials/_button.scss +++ b/src/scss/partials/_button.scss @@ -300,6 +300,21 @@ } } +.btn-control { + width: auto; + height: 40px; + align-items: center; + margin: 15px auto 1rem; + border-radius: 30px; + padding: 0 24px 0 12px; + display: flex; + + &.tgico:before { + font-size: 1.5rem; + margin-right: .375rem; + } +} + // ! example: multiselect input, button in pinned messages chat, settings, chat background tab .btn-transparent { color: var(--primary-text-color); diff --git a/src/scss/partials/_leftSidebar.scss b/src/scss/partials/_leftSidebar.scss index f99678b2..4a055684 100644 --- a/src/scss/partials/_leftSidebar.scss +++ b/src/scss/partials/_leftSidebar.scss @@ -606,21 +606,6 @@ } */ } - .btn-primary { - width: auto; - height: 40px; - align-items: center; - margin: 15px auto 1rem; - border-radius: 30px; - padding: 0 24px 0 12px; - display: flex; - } - - .tgico-add:before { - font-size: 24px; - margin-right: 6px; - } - .row { .btn-primary { height: 30px; @@ -1159,3 +1144,38 @@ padding-bottom: .5rem; } } + +.empty-folder { + top: 40%; + transform: translateY(-50%); + text-align: center; + line-height: var(--line-height); + user-select: none; + + .media-sticker-wrapper { + width: 128px; + height: 128px; + margin: 0 auto 1.9375rem; + position: relative; + } + + &-header { + font-size: 1.25rem; + font-weight: 500; + } + + &-subtitle { + color: var(--secondary-text-color); + font-size: .875rem; + margin-top: .3125rem; + } + + .btn-control { + margin-top: 1.75rem; + padding: 0 1.0625rem 0 .8125rem; + + &:before { + margin-right: .625rem; + } + } +}