Browse Source

Clear recent stickers button

master
Eduard Kuzmenko 2 years ago
parent
commit
43adba8845
  1. 159
      src/components/emoticonsDropdown/tabs/stickers.ts
  2. 5
      src/helpers/dropdownHover.ts
  3. 2
      src/lang.ts
  4. 11
      src/lib/appManagers/appStickersManager.ts
  5. 2
      src/lib/rootScope.ts
  6. 15
      src/scss/partials/_emojiDropdown.scss

159
src/components/emoticonsDropdown/tabs/stickers.ts

@ -25,6 +25,9 @@ import ButtonIcon from "../../buttonIcon";
import positionElementByIndex from "../../../helpers/dom/positionElementByIndex"; import positionElementByIndex from "../../../helpers/dom/positionElementByIndex";
import VisibilityIntersector, { OnVisibilityChange } from "../../visibilityIntersector"; import VisibilityIntersector, { OnVisibilityChange } from "../../visibilityIntersector";
import findAndSplice from "../../../helpers/array/findAndSplice"; import findAndSplice from "../../../helpers/array/findAndSplice";
import { attachClickEvent } from "../../../helpers/dom/clickEvent";
import confirmationPopup from "../../confirmationPopup";
import noop from "../../../helpers/noop";
export class SuperStickerRenderer { export class SuperStickerRenderer {
public lazyLoadQueue: LazyLoadQueueRepeat; public lazyLoadQueue: LazyLoadQueueRepeat;
@ -213,35 +216,47 @@ export default class StickersTab implements EmoticonsTab {
this.categoriesMap.set(container, category); this.categoriesMap.set(container, category);
this.categoriesIntersector.observe(container); this.categoriesIntersector.observe(container);
this.stickyIntersector.observeStickyHeaderChanges(container);
return category; return category;
} }
private categoryPush( private categoryAppendStickers(
category: StickersTabCategory, category: StickersTabCategory,
promise: Promise<MyDocument[]> promise: Promise<MyDocument[]>
) { ) {
const {container, items} = category.elements; const {container} = category.elements;
this.stickyIntersector.observeStickyHeaderChanges(container);
promise.then((documents) => { promise.then((documents) => {
const isVisible = this.isCategoryVisible(category);
documents.forEach((document) => { documents.forEach((document) => {
const element = this.superStickerRenderer.renderSticker(document); const element = this.superStickerRenderer.renderSticker(document);
category.items.push({document, element}); category.items.push({document, element});
// items.append(element);
if(isVisible) {
category.elements.items.append(element);
}
}); });
const containerWidth = 410; this.setCategoryItemsHeight(category);
const stickerSize = mediaSizes.active.esgSticker.width; container.classList.remove('hide');
});
}
private isCategoryVisible(category: StickersTabCategory) {
return this.categoriesIntersector.getVisible().includes(category.elements.container);
}
const itemsPerRow = Math.floor(containerWidth / stickerSize); private setCategoryItemsHeight(category: StickersTabCategory) {
const rows = Math.ceil(documents.length / itemsPerRow); const containerWidth = this.content.getBoundingClientRect().width - 10;
const height = rows * stickerSize; const stickerSize = mediaSizes.active.esgSticker.width;
items.style.height = height + 'px'; const itemsPerRow = Math.floor(containerWidth / stickerSize);
const rows = Math.ceil(category.items.length / itemsPerRow);
const height = rows * stickerSize;
container.classList.remove('hide'); category.elements.items.style.minHeight = height + 'px';
});
} }
private async renderStickerSet(set: StickerSet.stickerSet, prepend = false) { private async renderStickerSet(set: StickerSet.stickerSet, prepend = false) {
@ -251,7 +266,7 @@ export default class StickersTab implements EmoticonsTab {
positionElementByIndex(menuTab, this.menu, prepend ? 1 : 0xFFFF); positionElementByIndex(menuTab, this.menu, prepend ? 1 : 0xFFFF);
const promise = this.managers.appStickersManager.getStickerSet(set); const promise = this.managers.appStickersManager.getStickerSet(set);
this.categoryPush( this.categoryAppendStickers(
category, category,
promise.then((stickerSet) => stickerSet.documents as MyDocument[]) promise.then((stickerSet) => stickerSet.documents as MyDocument[])
); );
@ -313,29 +328,21 @@ export default class StickersTab implements EmoticonsTab {
const intersectionOptions: IntersectionObserverInit = {root: emoticonsDropdown.getElement()}; const intersectionOptions: IntersectionObserverInit = {root: emoticonsDropdown.getElement()};
this.categoriesIntersector = new VisibilityIntersector(onCategoryVisibility, intersectionOptions); this.categoriesIntersector = new VisibilityIntersector(onCategoryVisibility, intersectionOptions);
rootScope.addEventListener('stickers_installed', (set) => { const clearCategoryItems = (category: StickersTabCategory) => {
if(!this.categories[set.id] && this.mounted) { category.elements.items.textContent = '';
this.renderStickerSet(set, true); category.items.forEach(({element}) => this.superStickerRenderer.unobserveAnimated(element));
} category.items.length = 0;
}); };
rootScope.addEventListener('stickers_deleted', ({id}) => {
const set = this.categories[id];
if(set && this.mounted) {
set.elements.container.remove();
set.elements.menuTab.remove();
this.categoriesIntersector.unobserve(set.elements.container);
set.items.forEach(({element}) => this.superStickerRenderer.unobserveAnimated(element));
delete this.categories[id];
this.categoriesMap.delete(set.elements.container);
}
});
this.scroll.container.addEventListener('click', (e) => { this.scroll.container.addEventListener('click', (e) => {
const target = e.target as HTMLElement; const target = e.target as HTMLElement;
if(findUpClassName(target, 'category-title')) { if(findUpClassName(target, 'category-title')) {
const container = findUpClassName(target, 'emoji-category'); const container = findUpClassName(target, 'emoji-category');
const category = this.categoriesMap.get(container); const category = this.categoriesMap.get(container);
if(category.set.id === 'recent') {
return;
}
new PopupStickers({id: category.set.id, access_hash: category.set.access_hash}).show(); new PopupStickers({id: category.set.id, access_hash: category.set.access_hash}).show();
return; return;
} }
@ -355,7 +362,8 @@ export default class StickersTab implements EmoticonsTab {
setTyping(); setTyping();
}); });
this.stickyIntersector = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll).stickyIntersector; const {stickyIntersector, setActive} = EmoticonsDropdown.menuOnClick(this.menu, this.scroll, menuScroll);
this.stickyIntersector = stickyIntersector;
const preloader = putPreloader(this.content, true); const preloader = putPreloader(this.content, true);
@ -363,15 +371,34 @@ export default class StickersTab implements EmoticonsTab {
recentCategory.elements.title.classList.add('disable-hover'); recentCategory.elements.title.classList.add('disable-hover');
recentCategory.elements.menuTab.classList.add('tgico-recent', 'active'); recentCategory.elements.menuTab.classList.add('tgico-recent', 'active');
recentCategory.elements.menuTabPadding.remove(); recentCategory.elements.menuTabPadding.remove();
positionElementByIndex(recentCategory.elements.container, this.scroll.container, 0); this.toggleRecentCategory(recentCategory, false);
positionElementByIndex(recentCategory.elements.menuTab, this.menu, 0);
const clearButton = ButtonIcon('close', {noRipple: true});
recentCategory.elements.title.append(clearButton);
attachClickEvent(clearButton, () => {
confirmationPopup({
titleLangKey: 'ClearRecentStickersAlertTitle',
descriptionLangKey: 'ClearRecentStickersAlertMessage',
button: {
langKey: 'Clear'
}
}).then(() => {
this.managers.appStickersManager.clearRecentStickers();
}, noop);
});
const onRecentStickers = (stickers: MyDocument[]) => {
const sliced = stickers.slice(0, RECENT_STICKERS_COUNT) as MyDocument[];
clearCategoryItems(recentCategory);
this.toggleRecentCategory(recentCategory, !!sliced.length);
this.categoryAppendStickers(recentCategory, Promise.resolve(sliced));
};
Promise.all([ Promise.all([
this.managers.appStickersManager.getRecentStickers().then((stickers) => { this.managers.appStickersManager.getRecentStickers().then((stickers) => {
const sliced = stickers.stickers.slice(0, RECENT_STICKERS_COUNT) as MyDocument[];
preloader.remove(); preloader.remove();
this.categoryPush(recentCategory, Promise.resolve(sliced)); onRecentStickers(stickers.stickers as MyDocument[]);
}), }),
this.managers.appStickersManager.getAllStickers().then((res) => { this.managers.appStickersManager.getAllStickers().then((res) => {
@ -384,6 +411,7 @@ export default class StickersTab implements EmoticonsTab {
]).finally(() => { ]).finally(() => {
this.mounted = true; this.mounted = true;
setTyping(); setTyping();
setActive(0);
}); });
this.superStickerRenderer = new SuperStickerRenderer(EmoticonsDropdown.lazyLoadQueue, EMOTICONSSTICKERGROUP, this.managers, intersectionOptions); this.superStickerRenderer = new SuperStickerRenderer(EmoticonsDropdown.lazyLoadQueue, EMOTICONSSTICKERGROUP, this.managers, intersectionOptions);
@ -417,19 +445,65 @@ export default class StickersTab implements EmoticonsTab {
// ); // );
// }, .25e3); // }, .25e3);
rootScope.addEventListener('stickers_installed', (set) => {
if(!this.categories[set.id] && this.mounted) {
this.renderStickerSet(set, true);
}
});
rootScope.addEventListener('stickers_deleted', ({id}) => {
const category = this.categories[id];
if(category && this.mounted) {
category.elements.container.remove();
category.elements.menuTab.remove();
this.categoriesIntersector.unobserve(category.elements.container);
clearCategoryItems(category);
delete this.categories[id];
this.categoriesMap.delete(category.elements.container);
}
});
rootScope.addEventListener('stickers_recent', (stickers) => {
if(this.mounted) {
onRecentStickers(stickers);
}
});
const resizeCategories = () => {
for(const [container, category] of this.categoriesMap) {
this.setCategoryItemsHeight(category);
}
};
mediaSizes.addEventListener('resize', resizeCategories);
emoticonsDropdown.addEventListener('opened', resizeCategories);
this.init = null; this.init = null;
} }
private toggleRecentCategory(category: StickersTabCategory, visible: boolean) {
if(!visible) {
category.elements.menuTab.remove();
category.elements.container.remove();
} else {
positionElementByIndex(category.elements.menuTab, this.menu, 0);
positionElementByIndex(category.elements.container, this.scroll.container, 0);
}
// category.elements.container.classList.toggle('hide', !visible);
}
public pushRecentSticker(doc: MyDocument) { public pushRecentSticker(doc: MyDocument) {
this.managers.appStickersManager.pushRecentSticker(doc.id); this.managers.appStickersManager.pushRecentSticker(doc.id);
const set = this.categories['recent']; const category = this.categories['recent'];
if(!set) { if(!category) {
return; return;
} }
const items = set.elements.items; const items = category.elements.items;
let item = findAndSplice(set.items, (item) => item.document.id === doc.id); let item = findAndSplice(category.items, (item) => item.document.id === doc.id);
if(!item) { if(!item) {
item = { item = {
element: this.superStickerRenderer.renderSticker(doc), element: this.superStickerRenderer.renderSticker(doc),
@ -437,11 +511,14 @@ export default class StickersTab implements EmoticonsTab {
}; };
} }
set.items.unshift(item); category.items.unshift(item);
if(items.childElementCount) items.prepend(item.element); if(items.childElementCount) items.prepend(item.element);
if(items.childElementCount > RECENT_STICKERS_COUNT) { if(items.childElementCount > RECENT_STICKERS_COUNT) {
(Array.from(items.children) as HTMLElement[]).slice(RECENT_STICKERS_COUNT).forEach((el) => el.remove()); (Array.from(items.children) as HTMLElement[]).slice(RECENT_STICKERS_COUNT).forEach((el) => el.remove());
} }
this.setCategoryItemsHeight(category);
this.toggleRecentCategory(category, true);
} }
onClose() { onClose() {

5
src/helpers/dropdownHover.ts

@ -48,7 +48,10 @@ export default class DropdownHover extends EventListenerBase<{
listenerSetter.add(button)('mouseover', (e) => { listenerSetter.add(button)('mouseover', (e) => {
//console.log('onmouseover button'); //console.log('onmouseover button');
if(firstTime) { if(firstTime) {
listenerSetter.add(button)('mouseout', this.onMouseOut); listenerSetter.add(button)('mouseout', (e) => {
clearTimeout(this.displayTimeout);
this.onMouseOut(e);
});
firstTime = false; firstTime = false;
} }

2
src/lang.ts

@ -750,6 +750,8 @@ const lang = {
"Clear": "Clear", "Clear": "Clear",
"Save": "Save", "Save": "Save",
"PaymentCheckoutName": "Name", "PaymentCheckoutName": "Name",
"ClearRecentStickersAlertTitle": "Clear recent stickers",
"ClearRecentStickersAlertMessage": "Do you want to clear all your recent stickers?",
// * macos // * macos
"AccountSettings.Filters": "Chat Folders", "AccountSettings.Filters": "Chat Folders",

11
src/lib/appManagers/appStickersManager.ts

@ -72,6 +72,12 @@ export class AppStickersManager extends AppManager {
const stickerSet = update.stickerset as MyMessagesStickerSet; const stickerSet = update.stickerset as MyMessagesStickerSet;
this.saveStickerSet(stickerSet, stickerSet.set.id); this.saveStickerSet(stickerSet, stickerSet.set.id);
this.rootScope.dispatchEvent('stickers_installed', stickerSet.set); this.rootScope.dispatchEvent('stickers_installed', stickerSet.set);
},
updateRecentStickers: () => {
this.getRecentStickers().then(({stickers}) => {
this.rootScope.dispatchEvent('stickers_recent', stickers as MyDocument[]);
});
} }
}); });
} }
@ -576,4 +582,9 @@ export class AppStickersManager extends AppManager {
}); });
} }
} }
public clearRecentStickers() {
this.rootScope.dispatchEvent('stickers_recent', []);
return this.apiManager.invokeApi('messages.clearRecentStickers');
}
} }

2
src/lib/rootScope.ts

@ -16,6 +16,7 @@ import type { AppManagers } from "./appManagers/managers";
import type { State } from "../config/state"; import type { State } from "../config/state";
import type { Progress } from "./appManagers/appDownloadManager"; import type { Progress } from "./appManagers/appDownloadManager";
import type { CallId } from "./appManagers/appCallsManager"; import type { CallId } from "./appManagers/appCallsManager";
import type { MyDocument } from "./appManagers/appDocsManager";
import { NULL_PEER_ID, UserAuth } from "./mtproto/mtproto_config"; import { NULL_PEER_ID, UserAuth } from "./mtproto/mtproto_config";
import EventListenerBase from "../helpers/eventListenerBase"; import EventListenerBase from "../helpers/eventListenerBase";
import { MOUNT_CLASS_TO } from "../config/debug"; import { MOUNT_CLASS_TO } from "../config/debug";
@ -85,6 +86,7 @@ export type BroadcastEvents = {
'stickers_installed': StickerSet.stickerSet, 'stickers_installed': StickerSet.stickerSet,
'stickers_deleted': StickerSet.stickerSet, 'stickers_deleted': StickerSet.stickerSet,
'stickers_recent': MyDocument[],
'state_cleared': void, 'state_cleared': void,
'state_synchronized': ChatId | void, 'state_synchronized': ChatId | void,

15
src/scss/partials/_emojiDropdown.scss

@ -84,6 +84,17 @@
color: var(--secondary-text-color); color: var(--secondary-text-color);
padding: .8125rem .875rem .6875rem; padding: .8125rem .875rem .6875rem;
width: 100%; width: 100%;
position: relative;
.btn-icon {
position: absolute;
right: 0.5rem;
top: 50%;
transform: translateY(-50%);
font-size: 1.25rem;
z-index: 1;
pointer-events: all;
}
} }
.tabs-container { .tabs-container {
@ -152,10 +163,6 @@
} }
.category-items { .category-items {
width: 100%;
display: grid;
grid-template-columns: repeat(auto-fill, var(--esg-sticker-size)); // 64px
justify-content: space-between;
padding: 0 .3125rem; padding: 0 .3125rem;
} }

Loading…
Cancel
Save