Search by date & peer (beta)
This commit is contained in:
parent
d9cd7b217e
commit
294099e8b7
@ -199,7 +199,7 @@ class AppMediaPlaybackController {
|
||||
const media = this.playingMedia;
|
||||
this.prevMid = this.nextMid = 0;
|
||||
|
||||
return appMessagesManager.getSearchNew({
|
||||
return appMessagesManager.getSearch({
|
||||
peerId,
|
||||
query: '',
|
||||
inputFilter: {
|
||||
|
@ -1244,7 +1244,7 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
|
||||
if(anchor) maxId = anchor.mid;
|
||||
if(!older) maxId = appMessagesManager.incrementMessageId(maxId, 1);
|
||||
|
||||
const promise = appMessagesManager.getSearchNew({
|
||||
const promise = appMessagesManager.getSearch({
|
||||
peerId: this.searchContext.peerId,
|
||||
query: this.searchContext.query,
|
||||
inputFilter: {
|
||||
|
@ -150,7 +150,7 @@ export default class AppSearch {
|
||||
|
||||
const maxId = this.minMsgId || 0;
|
||||
|
||||
return this.searchPromise = appMessagesManager.getSearchNew({
|
||||
return this.searchPromise = appMessagesManager.getSearch({
|
||||
peerId: this.peerId,
|
||||
query,
|
||||
inputFilter: {_: 'inputMessagesFilterEmpty'},
|
||||
|
@ -19,7 +19,7 @@ import { horizontalMenu } from "./horizontalMenu";
|
||||
import LazyLoadQueue from "./lazyLoadQueue";
|
||||
import { renderImageFromUrl, putPreloader, formatPhoneNumber } from "./misc";
|
||||
import { ripple } from "./ripple";
|
||||
import Scrollable from "./scrollable";
|
||||
import Scrollable, { ScrollableX } from "./scrollable";
|
||||
import { wrapDocument } from "./wrappers";
|
||||
|
||||
const testScroll = false;
|
||||
@ -33,7 +33,9 @@ export type SearchSuperContext = {
|
||||
folderId?: number,
|
||||
threadId?: number,
|
||||
date?: number,
|
||||
nextRate?: number
|
||||
nextRate?: number,
|
||||
minDate?: number,
|
||||
maxDate?: number
|
||||
};
|
||||
|
||||
export default class AppSearchSuper {
|
||||
@ -43,6 +45,7 @@ export default class AppSearchSuper {
|
||||
public tabSelected: HTMLElement;
|
||||
|
||||
public container: HTMLElement;
|
||||
public nav: HTMLElement;
|
||||
private tabsContainer: HTMLElement;
|
||||
private tabsMenu: HTMLUListElement;
|
||||
private prevTabId = -1;
|
||||
@ -74,15 +77,24 @@ export default class AppSearchSuper {
|
||||
}
|
||||
}> = {};
|
||||
|
||||
private searchGroupMedia: SearchGroup;
|
||||
|
||||
constructor(public types: {inputFilter: SearchSuperType, name: string}[], public scrollable: Scrollable, public searchGroups?: {[group in SearchGroupType]: SearchGroup}, public asChatList = false) {
|
||||
this.container = document.createElement('div');
|
||||
this.container.classList.add('search-super');
|
||||
|
||||
const nav = document.createElement('nav');
|
||||
const navScrollableContainer = document.createElement('div');
|
||||
navScrollableContainer.classList.add('search-super-tabs-scrollable', 'menu-horizontal-scrollable');
|
||||
|
||||
const navScrollable = new ScrollableX(navScrollableContainer);
|
||||
|
||||
const nav = this.nav = document.createElement('nav');
|
||||
nav.classList.add('search-super-tabs', 'menu-horizontal');
|
||||
this.tabsMenu = document.createElement('ul');
|
||||
nav.append(this.tabsMenu);
|
||||
|
||||
navScrollable.container.append(nav);
|
||||
|
||||
for(const type of types) {
|
||||
const li = document.createElement('li');
|
||||
const span = document.createElement('span');
|
||||
@ -115,10 +127,12 @@ export default class AppSearchSuper {
|
||||
this.tabs[type.inputFilter] = content;
|
||||
}
|
||||
|
||||
this.container.append(nav, this.tabsContainer);
|
||||
this.container.append(navScrollableContainer, this.tabsContainer);
|
||||
|
||||
// * construct end
|
||||
|
||||
this.searchGroupMedia = new SearchGroup('', 'messages', true);
|
||||
|
||||
this.scrollable.onScrolledBottom = () => {
|
||||
if(this.tabSelected && this.tabSelected.childElementCount/* && false */) {
|
||||
//this.log('onScrolledBottom will load media');
|
||||
@ -296,10 +310,19 @@ export default class AppSearchSuper {
|
||||
|
||||
public async performSearchResult(messages: any[], type: SearchSuperType, append = true) {
|
||||
const elemsToAppend: {element: HTMLElement, message: any}[] = [];
|
||||
const sharedMediaDiv: HTMLElement = this.tabs[type];
|
||||
const promises: Promise<any>[] = [];
|
||||
const sharedMediaDiv: HTMLElement = type === 'inputMessagesFilterEmpty' ? this.searchGroups.messages.list : this.tabs[type];
|
||||
|
||||
const middleware = this.getMiddleware();
|
||||
|
||||
let searchGroup: SearchGroup;
|
||||
if(type === 'inputMessagesFilterPhotoVideo' && !!this.searchContext.query.trim()) {
|
||||
type = 'inputMessagesFilterEmpty';
|
||||
searchGroup = this.searchGroupMedia;
|
||||
sharedMediaDiv.append(searchGroup.container);
|
||||
} else if(type === 'inputMessagesFilterEmpty') {
|
||||
searchGroup = this.searchGroups.messages;
|
||||
}
|
||||
|
||||
|
||||
// https://core.telegram.org/type/MessagesFilter
|
||||
switch(type) {
|
||||
@ -307,14 +330,14 @@ export default class AppSearchSuper {
|
||||
for(const message of messages) {
|
||||
const {dialog, dom} = appDialogsManager.addDialogNew({
|
||||
dialog: message.peerId,
|
||||
container: sharedMediaDiv as HTMLUListElement/* searchGroup.list */,
|
||||
container: searchGroup.list,
|
||||
drawStatus: false,
|
||||
avatarSize: 54
|
||||
});
|
||||
appDialogsManager.setLastMessage(dialog, message, dom, this.searchContext.query);
|
||||
}
|
||||
|
||||
this.searchGroups.messages.setActive();
|
||||
searchGroup.setActive();
|
||||
break;
|
||||
}
|
||||
|
||||
@ -689,7 +712,24 @@ export default class AppSearchSuper {
|
||||
.then((contacts) => {
|
||||
if(contacts) {
|
||||
setResults(contacts.my_results, this.searchGroups.contacts, true);
|
||||
setResults(contacts.results, this.searchGroups.globalContacts);
|
||||
setResults(contacts.results/* .concat(contacts.results, contacts.results, contacts.results) */, this.searchGroups.globalContacts);
|
||||
|
||||
if(this.searchGroups.globalContacts.nameEl.lastElementChild) {
|
||||
this.searchGroups.globalContacts.nameEl.lastElementChild.remove();
|
||||
}
|
||||
|
||||
this.searchGroups.globalContacts.container.classList.add('is-short');
|
||||
|
||||
if(this.searchGroups.globalContacts.list.childElementCount > 3) {
|
||||
const showMore = document.createElement('div');
|
||||
showMore.classList.add('search-group__show-more');
|
||||
showMore.innerText = 'Show more';
|
||||
this.searchGroups.globalContacts.nameEl.append(showMore);
|
||||
showMore.addEventListener('click', () => {
|
||||
const isShort = this.searchGroups.globalContacts.container.classList.toggle('is-short');
|
||||
showMore.innerText = isShort ? 'Show more' : 'Show less';
|
||||
});
|
||||
}
|
||||
}
|
||||
}),
|
||||
|
||||
@ -835,7 +875,7 @@ export default class AppSearchSuper {
|
||||
//this.log(logStr + 'search house of glass pre', type, maxId);
|
||||
|
||||
//let loadCount = history.length ? 50 : 15;
|
||||
return this.loadPromises[type] = appMessagesManager.getSearchNew({
|
||||
return this.loadPromises[type] = appMessagesManager.getSearch({
|
||||
peerId,
|
||||
query: this.searchContext.query,
|
||||
inputFilter: {_: type},
|
||||
@ -843,7 +883,9 @@ export default class AppSearchSuper {
|
||||
limit: loadCount,
|
||||
nextRate: this.nextRates[type] ?? (this.nextRates[type] = 0),
|
||||
threadId: this.searchContext.threadId,
|
||||
folderId: this.searchContext.folderId
|
||||
folderId: this.searchContext.folderId,
|
||||
minDate: this.searchContext.minDate,
|
||||
maxDate: this.searchContext.maxDate
|
||||
}).then(value => {
|
||||
history.push(...value.history.map(m => ({mid: m.mid, peerId: m.peerId})));
|
||||
|
||||
@ -870,13 +912,15 @@ export default class AppSearchSuper {
|
||||
this.usedFromHistory[type] = history.length;
|
||||
|
||||
if(!this.loaded[type]) {
|
||||
this.loadPromises[type].then(() => {
|
||||
(this.loadPromises[type] || Promise.resolve()).then(() => {
|
||||
setTimeout(() => {
|
||||
if(!middleware()) return;
|
||||
//this.log('will preload more');
|
||||
if(this.type === type) {
|
||||
const promise = this.load(true, true);
|
||||
if(promise) {
|
||||
promise.then(() => {
|
||||
if(!middleware()) return;
|
||||
//this.log('preloaded more');
|
||||
setTimeout(() => {
|
||||
this.scrollable.checkForTriggers();
|
||||
@ -988,6 +1032,7 @@ export default class AppSearchSuper {
|
||||
});
|
||||
|
||||
this.monthContainers = {};
|
||||
this.searchGroupMedia.clear();
|
||||
|
||||
if(testScroll) {
|
||||
for(let i = 0; i < 1500; ++i) {
|
||||
@ -1016,19 +1061,23 @@ export default class AppSearchSuper {
|
||||
return context;
|
||||
}
|
||||
|
||||
public setQuery({peerId, query, threadId, historyStorage, folderId}: {
|
||||
public setQuery({peerId, query, threadId, historyStorage, folderId, minDate, maxDate}: {
|
||||
peerId: number,
|
||||
query?: string,
|
||||
threadId?: number,
|
||||
historyStorage?: AppSearchSuper['historyStorage'],
|
||||
folderId?: number
|
||||
folderId?: number,
|
||||
minDate?: number,
|
||||
maxDate?: number
|
||||
}) {
|
||||
this.searchContext = {
|
||||
peerId: peerId || 0,
|
||||
query: query || '',
|
||||
inputFilter: this.type,
|
||||
threadId,
|
||||
folderId
|
||||
folderId,
|
||||
minDate,
|
||||
maxDate
|
||||
};
|
||||
|
||||
this.historyStorage = historyStorage ?? {};
|
||||
|
@ -290,7 +290,7 @@ function wrapAudio(audioEl: AudioElement) {
|
||||
const html = `
|
||||
<div class="audio-details">
|
||||
<div class="audio-title"><middle-ellipsis-element data-font-weight="${audioEl.dataset.fontWeight}">${title}</middle-ellipsis-element>${titleAdditionHTML}</div>
|
||||
<div class="audio-subtitle"><div class="audio-time"></div>${subtitle}</div>
|
||||
<div class="audio-subtitle"><div class="audio-time"></div>${subtitle || '<div></div>'}</div>
|
||||
</div>`;
|
||||
|
||||
audioEl.insertAdjacentHTML('beforeend', html);
|
||||
@ -356,7 +356,8 @@ export default class AudioElement extends HTMLElement {
|
||||
this.classList.add('audio');
|
||||
|
||||
const doc = this.message.media.document || this.message.media.webpage.document;
|
||||
const isVoice = !this.voiceAsMusic && doc.type == 'voice';
|
||||
const isRealVoice = doc.type == 'voice';
|
||||
const isVoice = !this.voiceAsMusic && isRealVoice;
|
||||
const uploading = this.message.pFlags.is_outgoing;
|
||||
|
||||
const durationStr = String(doc.duration | 0).toHHMMSS();
|
||||
@ -429,7 +430,7 @@ export default class AudioElement extends HTMLElement {
|
||||
if(!uploading) {
|
||||
let preloader: ProgressivePreloader = this.preloader;
|
||||
|
||||
if(isVoice) {
|
||||
if(isRealVoice) {
|
||||
let download: Download;
|
||||
|
||||
const onClick = (e: Event) => {
|
||||
|
@ -52,7 +52,7 @@ export default class AvatarElement extends HTMLElement {
|
||||
if(peerId < 0) {
|
||||
const maxId = Number.MAX_SAFE_INTEGER;
|
||||
const inputFilter = 'inputMessagesFilterChatPhotos';
|
||||
let message: any = await appMessagesManager.getSearchNew({
|
||||
let message: any = await appMessagesManager.getSearch({
|
||||
peerId,
|
||||
inputFilter: {_: inputFilter},
|
||||
maxId,
|
||||
|
@ -2350,7 +2350,7 @@ export default class ChatBubbles {
|
||||
if(this.chat.type === 'chat' || this.chat.type === 'discussion') {
|
||||
return this.appMessagesManager.getHistory(this.peerId, maxId, loadCount, backLimit, this.chat.threadId);
|
||||
} else if(this.chat.type === 'pinned') {
|
||||
const promise = this.appMessagesManager.getSearchNew({
|
||||
const promise = this.appMessagesManager.getSearch({
|
||||
peerId: this.peerId,
|
||||
inputFilter: {_: 'inputMessagesFilterPinned'},
|
||||
maxId,
|
||||
|
@ -410,7 +410,7 @@ export default class ChatPinnedMessage {
|
||||
try {
|
||||
let gotRest = false;
|
||||
const promises = [
|
||||
this.appMessagesManager.getSearchNew({
|
||||
this.appMessagesManager.getSearch({
|
||||
peerId: this.topbar.peerId,
|
||||
inputFilter: {_: 'inputMessagesFilterPinned'},
|
||||
maxId: mid,
|
||||
|
@ -10,6 +10,7 @@ export default class InputSearch {
|
||||
public prevValue = '';
|
||||
public timeout = 0;
|
||||
public onChange: (value: string) => void;
|
||||
public onClear: () => void;
|
||||
|
||||
constructor(placeholder: string, onChange?: (value: string) => void) {
|
||||
this.inputField = new InputField({
|
||||
@ -57,6 +58,7 @@ export default class InputSearch {
|
||||
onClearClick = () => {
|
||||
this.value = '';
|
||||
this.onChange && this.onChange('');
|
||||
this.onClear && this.onClear();
|
||||
};
|
||||
|
||||
get value() {
|
||||
|
@ -1,7 +1,5 @@
|
||||
//import { logger } from "../polyfill";
|
||||
import { formatNumber } from "../../helpers/number";
|
||||
import appChatsManager from "../../lib/appManagers/appChatsManager";
|
||||
import appDialogsManager from "../../lib/appManagers/appDialogsManager";
|
||||
import appImManager from "../../lib/appManagers/appImManager";
|
||||
import appPeersManager from "../../lib/appManagers/appPeersManager";
|
||||
import appStateManager from "../../lib/appManagers/appStateManager";
|
||||
@ -29,6 +27,7 @@ import AppSettingsTab from "./tabs/settings";
|
||||
import appMessagesManager from "../../lib/appManagers/appMessagesManager";
|
||||
import apiManagerProxy from "../../lib/mtproto/mtprotoworker";
|
||||
import AppSearchSuper from "../appSearchSuper.";
|
||||
import { DateData, fillTipDates } from "../../helpers/date";
|
||||
|
||||
const newChannelTab = new AppNewChannelTab();
|
||||
const addMembersTab = new AppAddMembersTab();
|
||||
@ -213,21 +212,157 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
|
||||
scrollable.container.append(searchSuper.container);
|
||||
|
||||
searchSuper.setQuery({
|
||||
peerId: 0,
|
||||
folderId: 0
|
||||
const resetSearch = () => {
|
||||
searchSuper.setQuery({
|
||||
peerId: 0,
|
||||
folderId: 0
|
||||
});
|
||||
searchSuper.selectTab(0);
|
||||
searchSuper.load(true);
|
||||
};
|
||||
|
||||
resetSearch();
|
||||
|
||||
let pickedElements: HTMLElement[] = [];
|
||||
let selectedPeerId = 0;
|
||||
let selectedMinDate = 0;
|
||||
let selectedMaxDate = 0;
|
||||
const updatePicked = () => {
|
||||
(this.inputSearch.input as HTMLInputElement).placeholder = pickedElements.length ? 'Search' : 'Telegram Search';
|
||||
this.inputSearch.container.classList.toggle('is-picked-twice', pickedElements.length === 2);
|
||||
this.inputSearch.container.classList.toggle('is-picked', !!pickedElements.length);
|
||||
|
||||
if(pickedElements.length) {
|
||||
this.inputSearch.input.style.setProperty('--paddingLeft', (pickedElements[pickedElements.length - 1].getBoundingClientRect().right - this.inputSearch.input.getBoundingClientRect().left) + 'px');
|
||||
} else {
|
||||
this.inputSearch.input.style.removeProperty('--paddingLeft');
|
||||
}
|
||||
};
|
||||
|
||||
const helper = document.createElement('div');
|
||||
helper.classList.add('search-helper');
|
||||
helper.addEventListener('click', (e) => {
|
||||
const target = findUpClassName(e.target, 'selector-user');
|
||||
if(!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
const key = target.dataset.key;
|
||||
if(key.indexOf('date_') === 0) {
|
||||
const [_, minDate, maxDate] = key.split('_');
|
||||
selectedMinDate = +minDate;
|
||||
selectedMaxDate = +maxDate;
|
||||
} else {
|
||||
selectedPeerId = +key;
|
||||
}
|
||||
|
||||
target.addEventListener('click', () => {
|
||||
unselectEntity(target);
|
||||
});
|
||||
|
||||
this.inputSearch.container.append(target);
|
||||
this.inputSearch.onChange(this.inputSearch.value = '');
|
||||
pickedElements.push(target);
|
||||
updatePicked();
|
||||
});
|
||||
searchSuper.selectTab(0);
|
||||
searchSuper.load(true);
|
||||
|
||||
searchSuper.nav.parentElement.append(helper);
|
||||
|
||||
const renderEntity = (peerId: any, title?: string) => {
|
||||
const div = document.createElement('div');
|
||||
div.classList.add('selector-user'/* , 'scale-in' */);
|
||||
|
||||
const avatarEl = document.createElement('avatar-element');
|
||||
avatarEl.classList.add('selector-user-avatar', 'tgico');
|
||||
avatarEl.setAttribute('dialog', '1');
|
||||
avatarEl.classList.add('avatar-30');
|
||||
|
||||
div.dataset.key = '' + peerId;
|
||||
if(typeof(peerId) === 'number') {
|
||||
if(title === undefined) {
|
||||
title = peerId == rootScope.myId ? 'Saved' : appPeersManager.getPeerTitle(peerId, false, true);
|
||||
}
|
||||
|
||||
avatarEl.setAttribute('peer', '' + peerId);
|
||||
} else {
|
||||
avatarEl.classList.add('tgico-calendarfilter');
|
||||
}
|
||||
|
||||
if(title) {
|
||||
div.innerHTML = title;
|
||||
}
|
||||
|
||||
div.insertAdjacentElement('afterbegin', avatarEl);
|
||||
|
||||
return div;
|
||||
};
|
||||
|
||||
const unselectEntity = (target: HTMLElement) => {
|
||||
const key = target.dataset.key;
|
||||
if(key.indexOf('date_') === 0) {
|
||||
selectedMinDate = selectedMaxDate = 0;
|
||||
} else {
|
||||
selectedPeerId = 0;
|
||||
}
|
||||
|
||||
target.remove();
|
||||
pickedElements.findAndSplice(t => t === target);
|
||||
|
||||
setTimeout(() => {
|
||||
updatePicked();
|
||||
this.inputSearch.onChange(this.inputSearch.value);
|
||||
}, 0);
|
||||
};
|
||||
|
||||
this.inputSearch.onClear = () => {
|
||||
pickedElements.forEach(el => {
|
||||
unselectEntity(el);
|
||||
});
|
||||
};
|
||||
|
||||
this.inputSearch.onChange = (value) => {
|
||||
searchSuper.cleanupHTML();
|
||||
searchSuper.setQuery({
|
||||
peerId: 0,
|
||||
folderId: 0,
|
||||
query: value
|
||||
peerId: selectedPeerId,
|
||||
folderId: selectedPeerId ? undefined : 0,
|
||||
query: value,
|
||||
minDate: selectedMinDate,
|
||||
maxDate: selectedMaxDate
|
||||
});
|
||||
searchSuper.load(true);
|
||||
|
||||
helper.innerHTML = '';
|
||||
searchSuper.nav.classList.remove('hide');
|
||||
if(!value) {
|
||||
}
|
||||
|
||||
if(!selectedPeerId && value.trim()) {
|
||||
const middleware = searchSuper.getMiddleware();
|
||||
Promise.all([
|
||||
appMessagesManager.getConversationsAll(value).then(dialogs => dialogs.map(d => d.peerId)),
|
||||
appUsersManager.getContacts(value, true)
|
||||
]).then(results => {
|
||||
if(!middleware()) return;
|
||||
const peerIds = new Set(results[0].concat(results[1]));
|
||||
|
||||
peerIds.forEach(peerId => {
|
||||
helper.append(renderEntity(peerId));
|
||||
});
|
||||
|
||||
searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);
|
||||
//console.log('got peerIds by value:', value, [...peerIds]);
|
||||
});
|
||||
}
|
||||
|
||||
if(!selectedMinDate && value.trim()) {
|
||||
const dates: DateData[] = [];
|
||||
fillTipDates(value, dates);
|
||||
dates.forEach(dateData => {
|
||||
helper.append(renderEntity('date_' + dateData.minDate + '_' + dateData.maxDate, dateData.title));
|
||||
});
|
||||
|
||||
searchSuper.nav.classList.toggle('hide', !!helper.innerHTML);
|
||||
}
|
||||
};
|
||||
|
||||
searchSuper.tabs.inputMessagesFilterEmpty.addEventListener('click', (e) => {
|
||||
@ -272,6 +407,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
|
||||
if(id === 0) {
|
||||
this.inputSearch.onClearClick();
|
||||
resetSearch();
|
||||
hideNewBtnMenuTimeout = window.setTimeout(() => {
|
||||
hideNewBtnMenuTimeout = 0;
|
||||
this.newBtnMenu.classList.remove('is-hidden');
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { MOUNT_CLASS_TO } from "../lib/mtproto/mtproto_config";
|
||||
|
||||
export const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
||||
export const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
|
||||
|
||||
@ -49,4 +51,289 @@ export const getFullDate = (date: Date, options: Partial<{
|
||||
export function tsNow(seconds?: true) {
|
||||
const t = Date.now();
|
||||
return seconds ? Math.floor(t / 1000) : t;
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/DrKLO/Telegram/blob/d52b2c921abd3c1e8d6368858313ad0cb0468c07/TMessagesProj/src/main/java/org/telegram/ui/Adapters/FiltersView.java
|
||||
const minYear = 2013;
|
||||
const yearPattern = new RegExp("20[0-9]{1,2}");
|
||||
const monthYearOrDayPattern = new RegExp("(\\w{3,}) ([0-9]{0,4})", 'i');
|
||||
const yearOrDayAndMonthPattern = new RegExp("([0-9]{0,4}) (\\w{2,})", 'i');
|
||||
const shortDate = new RegExp("^([0-9]{1,4})(\\.| |/|\\-)([0-9]{1,4})$", 'i');
|
||||
const longDate = new RegExp("^([0-9]{1,2})(\\.| |/|\\-)([0-9]{1,2})(\\.| |/|\\-)([0-9]{1,4})$", 'i');
|
||||
const numberOfDaysEachMonth = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
|
||||
export type DateData = {
|
||||
title: string,
|
||||
minDate: number,
|
||||
maxDate: number,
|
||||
};
|
||||
export function fillTipDates(query: string, dates: DateData[]) {
|
||||
const q = query.trim();
|
||||
|
||||
if(q.length < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
let matches: any[];
|
||||
if((matches = shortDate.exec(q)) !== null) {
|
||||
const g1 = matches[1];
|
||||
const g2 = matches[3];
|
||||
const k = parseInt(g1);
|
||||
const k1 = parseInt(g2);
|
||||
if(k > 0 && k <= 31) {
|
||||
if(k1 >= minYear && k <= 12) {
|
||||
const selectedYear = k1;
|
||||
const month = k - 1;
|
||||
createForMonthYear(dates, month, selectedYear);
|
||||
return;
|
||||
} else if (k1 <= 12) {
|
||||
const day = k - 1;
|
||||
const month = k1 - 1;
|
||||
createForDayMonth(dates, day, month);
|
||||
}
|
||||
} else if (k >= minYear && k1 <= 12) {
|
||||
const selectedYear = k;
|
||||
const month = k1 - 1;
|
||||
createForMonthYear(dates, month, selectedYear);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if((matches = longDate.exec(q)) !== null) {
|
||||
const g1 = matches[1];
|
||||
const g2 = matches[3];
|
||||
const g3 = matches[5];
|
||||
if(!matches[2] == matches[4]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const day = parseInt(g1);
|
||||
const month = parseInt(g2) - 1;
|
||||
let year = parseInt(g3);
|
||||
if(year >= 10 && year <= 99) {
|
||||
year += 2000;
|
||||
}
|
||||
|
||||
const currentYear = new Date().getFullYear();
|
||||
if(validDateForMonth(day - 1, month) && year >= minYear && year <= currentYear) {
|
||||
const date = new Date();
|
||||
date.setFullYear(year, month, day);
|
||||
date.setHours(0, 0, 0);
|
||||
|
||||
const minDate = date.getTime();
|
||||
date.setFullYear(year, month, day + 1);
|
||||
date.setHours(0, 0, 0);
|
||||
|
||||
const maxDate = date.getTime() - 1;
|
||||
dates.push({
|
||||
title: formatterYearMax(minDate),
|
||||
minDate,
|
||||
maxDate
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if((matches = yearPattern.exec(q)) !== null) {
|
||||
let selectedYear = +q;
|
||||
const currentYear = new Date().getFullYear();
|
||||
if(selectedYear < minYear) {
|
||||
selectedYear = minYear;
|
||||
for(let i = currentYear; i >= selectedYear; i--) {
|
||||
const date = new Date();
|
||||
date.setFullYear(i, 0, 1);
|
||||
date.setHours(0, 0, 0);
|
||||
|
||||
const minDate = date.getTime();
|
||||
date.setFullYear(i + 1, 0, 1);
|
||||
date.setHours(0, 0, 0);
|
||||
|
||||
const maxDate = date.getTime() - 1;
|
||||
dates.push({
|
||||
title: '' + i,
|
||||
minDate,
|
||||
maxDate
|
||||
});
|
||||
}
|
||||
} else if(selectedYear <= currentYear) {
|
||||
const date = new Date();
|
||||
date.setFullYear(selectedYear, 0, 1);
|
||||
date.setHours(0, 0, 0);
|
||||
|
||||
const minDate = date.getTime();
|
||||
date.setFullYear(selectedYear + 1, 0, 1);
|
||||
date.setHours(0, 0, 0);
|
||||
|
||||
const maxDate = date.getTime() - 1;
|
||||
dates.push({
|
||||
title: '' + selectedYear,
|
||||
minDate,
|
||||
maxDate
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if((matches = monthYearOrDayPattern.exec(q)) !== null) {
|
||||
const g1 = matches[1];
|
||||
const g2 = matches[2];
|
||||
const month = getMonth(g1);
|
||||
if(month >= 0) {
|
||||
const k = +g2;
|
||||
if(k > 0 && k <= 31) {
|
||||
const day = k - 1;
|
||||
createForDayMonth(dates, day, month);
|
||||
return;
|
||||
} else if(k >= minYear) {
|
||||
const selectedYear = k;
|
||||
createForMonthYear(dates, month, selectedYear);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if((matches = yearOrDayAndMonthPattern.exec(q)) !== null) {
|
||||
const g1 = matches[1];
|
||||
const g2 = matches[2];
|
||||
const month = getMonth(g2);
|
||||
if(month >= 0) {
|
||||
const k = +g1;
|
||||
if(k > 0 && k <= 31) {
|
||||
const day = k - 1;
|
||||
createForDayMonth(dates, day, month);
|
||||
return;
|
||||
} else if (k >= minYear) {
|
||||
const selectedYear = k;
|
||||
createForMonthYear(dates, month, selectedYear);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createForMonthYear(dates: DateData[], month: number, selectedYear: number) {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const today = Date.now();
|
||||
if(selectedYear >= minYear && selectedYear <= currentYear) {
|
||||
const date = new Date();
|
||||
date.setFullYear(selectedYear, month, 1);
|
||||
date.setHours(0, 0, 0);
|
||||
const minDate = date.getTime();
|
||||
if(minDate > today) {
|
||||
return;
|
||||
}
|
||||
date.setMonth(date.getMonth() + 1);
|
||||
const maxDate = date.getTime() - 1;
|
||||
|
||||
dates.push({
|
||||
title: formatterMonthYear(minDate),
|
||||
minDate,
|
||||
maxDate
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function createForDayMonth(dates: DateData[], day: number, month: number) {
|
||||
if(validDateForMonth(day, month)) {
|
||||
const currentYear = new Date().getFullYear();
|
||||
const today = Date.now();
|
||||
|
||||
for(let i = currentYear; i >= minYear; i--) {
|
||||
if(month == 1 && day == 28 && !isLeapYear(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const date = new Date();
|
||||
date.setFullYear(i, month, day + 1);
|
||||
date.setHours(0, 0, 0);
|
||||
|
||||
const minDate = date.getTime();
|
||||
if(minDate > today) {
|
||||
continue;
|
||||
}
|
||||
|
||||
date.setFullYear(i, month, day + 2);
|
||||
date.setHours(0, 0, 0);
|
||||
const maxDate = date.getTime() - 1;
|
||||
if(i == currentYear) {
|
||||
dates.push({
|
||||
title: formatterDayMonth(minDate),
|
||||
minDate,
|
||||
maxDate
|
||||
});
|
||||
} else {
|
||||
dates.push({
|
||||
title: formatterYearMax(minDate),
|
||||
minDate,
|
||||
maxDate
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function formatterMonthYear(timestamp: number) {
|
||||
const date = new Date(timestamp);
|
||||
return months[date.getMonth()].slice(0, 3) + ' ' + date.getFullYear();
|
||||
}
|
||||
|
||||
function formatterDayMonth(timestamp: number) {
|
||||
const date = new Date(timestamp);
|
||||
return months[date.getMonth()].slice(0, 3) + ' ' + date.getDate();
|
||||
}
|
||||
|
||||
function formatterYearMax(timestamp: number) {
|
||||
const date = new Date(timestamp);
|
||||
return ('0' + date.getDate()).slice(-2) + '.' + ('0' + (date.getMonth() + 1)).slice(-2) + '.' + date.getFullYear();
|
||||
}
|
||||
|
||||
function validDateForMonth(day: number, month: number) {
|
||||
if(month >= 0 && month < 12) {
|
||||
if(day >= 0 && day < numberOfDaysEachMonth[month]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function isLeapYear(year: number) {
|
||||
return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
|
||||
}
|
||||
|
||||
function getMonth(q: string) {
|
||||
/* String[] months = new String[]{
|
||||
LocaleController.getString("January", R.string.January).toLowerCase(),
|
||||
LocaleController.getString("February", R.string.February).toLowerCase(),
|
||||
LocaleController.getString("March", R.string.March).toLowerCase(),
|
||||
LocaleController.getString("April", R.string.April).toLowerCase(),
|
||||
LocaleController.getString("May", R.string.May).toLowerCase(),
|
||||
LocaleController.getString("June", R.string.June).toLowerCase(),
|
||||
LocaleController.getString("July", R.string.July).toLowerCase(),
|
||||
LocaleController.getString("August", R.string.August).toLowerCase(),
|
||||
LocaleController.getString("September", R.string.September).toLowerCase(),
|
||||
LocaleController.getString("October", R.string.October).toLowerCase(),
|
||||
LocaleController.getString("November", R.string.November).toLowerCase(),
|
||||
LocaleController.getString("December", R.string.December).toLowerCase()
|
||||
}; */
|
||||
|
||||
/* String[] monthsEng = new String[12];
|
||||
Calendar c = Calendar.getInstance();
|
||||
for (int i = 1; i <= 12; i++) {
|
||||
c.set(0, 0, 0, 0, 0, 0);
|
||||
c.set(Calendar.MONTH, i);
|
||||
monthsEng[i - 1] = c.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.ENGLISH).toLowerCase();
|
||||
} */
|
||||
|
||||
q = q.toLowerCase();
|
||||
for(let i = 0; i < 12; i++) {
|
||||
const month = months[i].toLowerCase();
|
||||
if(month.indexOf(q) === 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
MOUNT_CLASS_TO && (MOUNT_CLASS_TO.fillTipDates = fillTipDates);
|
@ -143,7 +143,7 @@
|
||||
</div>
|
||||
<div class="sidebar-content transition zoom-fade">
|
||||
<div class="transition-item active" id="chatlist-container">
|
||||
<div class="folders-tabs-scrollable hide">
|
||||
<div class="folders-tabs-scrollable menu-horizontal-scrollable hide">
|
||||
<nav class="menu-horizontal" id="folders-tabs">
|
||||
<ul>
|
||||
<li class="rp"><span>All<span class="badge badge-20 badge-blue"></span><i></i></span></li>
|
||||
|
@ -1887,7 +1887,7 @@ export class AppMessagesManager {
|
||||
if(p.promise) return p.promise;
|
||||
else if(p.maxId) return Promise.resolve(p);
|
||||
|
||||
return p.promise = this.getSearchNew({
|
||||
return p.promise = this.getSearch({
|
||||
peerId,
|
||||
inputFilter: {_: 'inputMessagesFilterPinned'},
|
||||
maxId: 0,
|
||||
@ -2887,7 +2887,7 @@ export class AppMessagesManager {
|
||||
});
|
||||
}
|
||||
|
||||
public getSearchNew({peerId, query, inputFilter, maxId, limit, nextRate, backLimit, threadId, folderId}: {
|
||||
public getSearch({peerId, query, inputFilter, maxId, limit, nextRate, backLimit, threadId, folderId, minDate, maxDate}: {
|
||||
peerId?: number,
|
||||
maxId?: number,
|
||||
limit?: number,
|
||||
@ -2899,18 +2899,24 @@ export class AppMessagesManager {
|
||||
inputFilter?: {
|
||||
_: MyInputMessagesFilter
|
||||
},
|
||||
}) {
|
||||
return this.getSearch(peerId, query, inputFilter, maxId, limit, nextRate, backLimit, threadId, folderId);
|
||||
}
|
||||
|
||||
public getSearch(peerId = 0, query: string = '', inputFilter: {
|
||||
_: MyInputMessagesFilter
|
||||
} = {_: 'inputMessagesFilterEmpty'}, maxId: number, limit = 20, nextRate = 0, backLimit = 0, threadId?: number, folderId?: number): Promise<{
|
||||
minDate?: number,
|
||||
maxDate?: number
|
||||
}): Promise<{
|
||||
count: number,
|
||||
next_rate: number,
|
||||
offset_id_offset: number,
|
||||
history: MyMessage[]
|
||||
}> {
|
||||
if(!peerId) peerId = 0;
|
||||
if(!query) query = '';
|
||||
if(!inputFilter) inputFilter = {_: 'inputMessagesFilterEmpty'};
|
||||
if(!limit) limit = 20;
|
||||
if(!nextRate) nextRate = 0;
|
||||
if(!backLimit) backLimit = 0;
|
||||
|
||||
minDate = minDate ? minDate / 1000 | 0 : 0;
|
||||
maxDate = maxDate ? maxDate / 1000 | 0 : 0;
|
||||
|
||||
const foundMsgs: Message.message[] = [];
|
||||
|
||||
//this.log('search', maxId);
|
||||
@ -3077,8 +3083,8 @@ export class AppMessagesManager {
|
||||
peer: appPeersManager.getInputPeerById(peerId),
|
||||
q: query || '',
|
||||
filter: inputFilter as any as MessagesFilter,
|
||||
min_date: 0,
|
||||
max_date: 0,
|
||||
min_date: minDate,
|
||||
max_date: maxDate,
|
||||
limit,
|
||||
offset_id: this.getLocalMessageId(maxId) || 0,
|
||||
add_offset: backLimit ? -backLimit : 0,
|
||||
@ -3105,8 +3111,8 @@ export class AppMessagesManager {
|
||||
apiPromise = apiManager.invokeApi('messages.searchGlobal', {
|
||||
q: query,
|
||||
filter: inputFilter as any as MessagesFilter,
|
||||
min_date: 0,
|
||||
max_date: 0,
|
||||
min_date: minDate,
|
||||
max_date: maxDate,
|
||||
offset_rate: nextRate,
|
||||
offset_peer: appPeersManager.getInputPeerById(offsetPeerId),
|
||||
offset_id: offsetId,
|
||||
|
@ -21,6 +21,10 @@ avatar-element {
|
||||
&.tgico-avatar_deletedaccount:before {
|
||||
font-size: calc(56px / var(--multiplier));
|
||||
}
|
||||
|
||||
&.tgico-calendarfilter:before {
|
||||
font-size: calc(32px / var(--multiplier));
|
||||
}
|
||||
|
||||
/* kostil */
|
||||
display: flex;
|
||||
@ -113,6 +117,11 @@ avatar-element {
|
||||
--multiplier: 1.6875;
|
||||
}
|
||||
|
||||
&.avatar-30 {
|
||||
--size: 30px;
|
||||
--multiplier: 1.8;
|
||||
}
|
||||
|
||||
&.avatar-18 {
|
||||
--size: 18px;
|
||||
--multiplier: 3;
|
||||
|
@ -232,7 +232,7 @@ input:focus, button:focus {
|
||||
}
|
||||
}
|
||||
|
||||
.tgico {
|
||||
> .tgico {
|
||||
position: absolute;
|
||||
left: 12px;
|
||||
top: 50%;
|
||||
|
@ -47,7 +47,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
.folders-tabs-scrollable {
|
||||
.menu-horizontal-scrollable {
|
||||
z-index: 1;
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #dadce0;
|
||||
@ -60,6 +60,7 @@
|
||||
|
||||
.menu-horizontal {
|
||||
border-bottom: none;
|
||||
position: relative !important;
|
||||
|
||||
ul {
|
||||
justify-content: flex-start;
|
||||
@ -101,6 +102,49 @@
|
||||
}
|
||||
}
|
||||
|
||||
.item-main {
|
||||
.input-search {
|
||||
/* &-input {
|
||||
--paddingLeft: 0px;
|
||||
padding-left: calc(42px - var(--border-width) + var(--paddingLeft));
|
||||
} */
|
||||
|
||||
.selector-user {
|
||||
height: 30px;
|
||||
position: absolute!important;
|
||||
left: 5px;
|
||||
top: 5px;
|
||||
background: #f1f3f4;
|
||||
z-index: 1;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
&.is-picked {
|
||||
.input-search-input {
|
||||
padding-left: calc(var(--paddingLeft) + 12px - var(--border-width));
|
||||
}
|
||||
|
||||
.tgico-close {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-picked-twice {
|
||||
.selector-user:first-of-type {
|
||||
width: 30px;
|
||||
}
|
||||
|
||||
.selector-user:last-of-type {
|
||||
left: 38px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.search-helper {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
#chatlist-container {
|
||||
max-height: 100%;
|
||||
overflow: hidden;
|
||||
|
@ -267,6 +267,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-tabs-scrollable {
|
||||
.scrollable {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
&-tabs-container {
|
||||
//min-height: 100%;
|
||||
min-height: calc(100% - 49px);
|
||||
@ -524,6 +530,12 @@
|
||||
flex: 0 0 auto;
|
||||
margin-left: .5rem;
|
||||
}
|
||||
|
||||
.search-group.is-short {
|
||||
li:nth-child(n + 4) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#stickers-container {
|
||||
|
Loading…
x
Reference in New Issue
Block a user