Added video messages to voice tab
Some fixes
This commit is contained in:
parent
ce715fa09f
commit
1e4b34aca3
@ -267,22 +267,24 @@ class AppMediaPlaybackController {
|
||||
} else if(isVoice) {
|
||||
const peerId = message.fromId || message.peerId;
|
||||
const peerPhoto = appPeersManager.getPeerPhoto(peerId);
|
||||
const result = appAvatarsManager.loadAvatar(peerId, peerPhoto, 'photo_small');
|
||||
if(result.cached) {
|
||||
const url = await result.loadPromise;
|
||||
artwork.push({
|
||||
src: url,
|
||||
sizes: '160x160',
|
||||
type: 'image/jpeg'
|
||||
});
|
||||
} else {
|
||||
result.loadPromise.then((url) => {
|
||||
if(this.playingMedia !== playingMedia || !url) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setNewMediadata(message);
|
||||
});
|
||||
if(peerPhoto) {
|
||||
const result = appAvatarsManager.loadAvatar(peerId, peerPhoto, 'photo_small');
|
||||
if(result.cached) {
|
||||
const url = await result.loadPromise;
|
||||
artwork.push({
|
||||
src: url,
|
||||
sizes: '160x160',
|
||||
type: 'image/jpeg'
|
||||
});
|
||||
} else {
|
||||
result.loadPromise.then((url) => {
|
||||
if(this.playingMedia !== playingMedia || !url) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setNewMediadata(message);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
title = appPeersManager.getPeerTitle(peerId, true, false);
|
||||
|
@ -28,7 +28,7 @@ import ProgressivePreloader from "./preloader";
|
||||
import Scrollable from "./scrollable";
|
||||
import appSidebarRight from "./sidebarRight";
|
||||
import SwipeHandler from "./swipeHandler";
|
||||
import { ONE_DAY } from "../helpers/date";
|
||||
import { formatFullSentTime, formatTime, ONE_DAY } from "../helpers/date";
|
||||
import { SearchSuperContext } from "./appSearchSuper.";
|
||||
import appNavigationController from "./appNavigationController";
|
||||
import { Message } from "../layer";
|
||||
@ -1185,46 +1185,7 @@ class AppMediaViewerBase<ContentAdditionType extends string, ButtonsAdditionType
|
||||
}
|
||||
|
||||
protected setAuthorInfo(fromId: number, timestamp: number) {
|
||||
const date = new Date();
|
||||
const time = new Date(timestamp * 1000);
|
||||
const now = date.getTime() / 1000;
|
||||
|
||||
const timeEl = new I18n.IntlDateElement({
|
||||
date: time,
|
||||
options: {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit'
|
||||
}
|
||||
}).element;
|
||||
|
||||
let dateEl: Node | string;
|
||||
if((now - timestamp) < ONE_DAY && date.getDate() === time.getDate()) { // if the same day
|
||||
dateEl = i18n('Date.Today');
|
||||
} else if((now - timestamp) < (ONE_DAY * 2) && (date.getDate() - 1) === time.getDate()) { // yesterday
|
||||
dateEl = capitalizeFirstLetter(I18n.format('Yesterday', true));
|
||||
} else if(date.getFullYear() !== time.getFullYear()) { // different year
|
||||
dateEl = new I18n.IntlDateElement({
|
||||
date: time,
|
||||
options: {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric'
|
||||
}
|
||||
}).element;
|
||||
// dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate() + ', ' + time.getFullYear();
|
||||
} else {
|
||||
dateEl = new I18n.IntlDateElement({
|
||||
date: time,
|
||||
options: {
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
}
|
||||
}).element;
|
||||
// dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate();
|
||||
}
|
||||
|
||||
this.author.date.innerHTML = '';
|
||||
this.author.date.append(dateEl, ' ', i18n('ScheduleController.at'), ' ', timeEl);
|
||||
this.author.date.append(formatFullSentTime(timestamp));
|
||||
|
||||
replaceContent(this.author.nameEl, new PeerTitle({
|
||||
peerId: fromId,
|
||||
|
@ -4,7 +4,7 @@
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import { formatDateAccordingToToday, months } from "../helpers/date";
|
||||
import { months } from "../helpers/date";
|
||||
import { copy, getObjectKeysAndSort, safeAssign } from "../helpers/object";
|
||||
import { escapeRegExp, limitSymbols } from "../helpers/string";
|
||||
import appChatsManager from "../lib/appManagers/appChatsManager";
|
||||
@ -26,7 +26,7 @@ import { ripple } from "./ripple";
|
||||
import Scrollable, { ScrollableX } from "./scrollable";
|
||||
import { wrapDocument, wrapPhoto, wrapVideo } from "./wrappers";
|
||||
import useHeavyAnimationCheck, { getHeavyAnimationPromise } from "../hooks/useHeavyAnimationCheck";
|
||||
import { LangPackKey, i18n } from "../lib/langPack";
|
||||
import I18n, { LangPackKey, i18n } from "../lib/langPack";
|
||||
import findUpClassName from "../helpers/dom/findUpClassName";
|
||||
import { getMiddleware } from "../helpers/middleware";
|
||||
import appProfileManager from "../lib/appManagers/appProfileManager";
|
||||
@ -50,6 +50,7 @@ import htmlToDocumentFragment from "../helpers/dom/htmlToDocumentFragment";
|
||||
import { SearchSelection } from "./chat/selection";
|
||||
import { cancelEvent } from "../helpers/dom/cancelEvent";
|
||||
import { attachClickEvent, simulateClickEvent } from "../helpers/dom/clickEvent";
|
||||
import { MyDocument } from "../lib/appManagers/appDocsManager";
|
||||
|
||||
//const testScroll = false;
|
||||
|
||||
@ -599,6 +600,18 @@ export default class AppSearchSuper {
|
||||
break;
|
||||
}
|
||||
|
||||
case 'inputMessagesFilterRoundVoice': {
|
||||
for(let message of messages) {
|
||||
if(!message.media.document || !(['voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
filtered.push(message);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -695,21 +708,22 @@ export default class AppSearchSuper {
|
||||
}
|
||||
|
||||
case 'inputMessagesFilterVoice':
|
||||
case 'inputMessagesFilterRoundVoice':
|
||||
case 'inputMessagesFilterMusic':
|
||||
case 'inputMessagesFilterDocument': {
|
||||
for(const message of messages) {
|
||||
const showSender = this.showSender || message.media.document.type === 'voice';
|
||||
const showSender = this.showSender || (['voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type);
|
||||
const div = wrapDocument({
|
||||
message,
|
||||
withTime: !showSender,
|
||||
fontWeight: 400,
|
||||
voiceAsMusic: true,
|
||||
showSender: showSender,
|
||||
showSender,
|
||||
searchContext: this.copySearchContext(inputFilter),
|
||||
lazyLoadQueue: this.lazyLoadQueue
|
||||
});
|
||||
|
||||
if(['audio', 'voice'].includes(message.media.document.type)) {
|
||||
if((['audio', 'voice', 'round'] as MyDocument['type'][]).includes(message.media.document.type)) {
|
||||
div.classList.add('audio-48');
|
||||
}
|
||||
|
||||
@ -810,22 +824,19 @@ export default class AppSearchSuper {
|
||||
}
|
||||
|
||||
subtitleFragment.append(a);
|
||||
|
||||
if(this.showSender) {
|
||||
subtitleFragment.append('\n', appMessagesManager.wrapSenderToPeer(message));
|
||||
}
|
||||
|
||||
if(!title) {
|
||||
//title = new URL(webpage.url).hostname;
|
||||
title = RichTextProcessor.wrapPlainText(webpage.display_url.split('/', 1)[0]);
|
||||
}
|
||||
|
||||
let sender = this.showSender ? `<div class="subtitle sender">${appMessagesManager.getSenderToPeerText(message)}</div>` : '';
|
||||
|
||||
let titleAdditionHTML = '';
|
||||
if(this.showSender) {
|
||||
titleAdditionHTML = `<div class="sent-time">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;
|
||||
}
|
||||
|
||||
const row = new Row({
|
||||
title,
|
||||
titleRight: titleAdditionHTML,
|
||||
titleRight: appMessagesManager.wrapSentTime(message),
|
||||
subtitle: subtitleFragment,
|
||||
havePadding: true,
|
||||
clickable: true,
|
||||
@ -1257,7 +1268,7 @@ export default class AppSearchSuper {
|
||||
}
|
||||
|
||||
// ! Фикс случая, когда не загружаются документы при открытой панели разработчиков (происходит из-за того, что не совпадают критерии отбора документов в getSearch)
|
||||
if(value.history.length < loadCount) {
|
||||
if(value.history.length < loadCount || (this.searchContext.folderId !== undefined && !value.next_rate) || value.history.length === value.count) {
|
||||
//if((value.count || history.length === value.count) && history.length >= value.count) {
|
||||
//this.log(logStr + 'loaded all media', value, loadCount);
|
||||
this.loaded[type] = true;
|
||||
@ -1401,14 +1412,26 @@ export default class AppSearchSuper {
|
||||
const dateTimestamp = date.getTime();
|
||||
const containers = this.monthContainers[type] ?? (this.monthContainers[type] = {});
|
||||
if(!(dateTimestamp in containers)) {
|
||||
const str = months[date.getMonth()] + ' ' + date.getFullYear();
|
||||
|
||||
const container = document.createElement('div');
|
||||
container.className = 'search-super-month';
|
||||
|
||||
const name = document.createElement('div');
|
||||
name.classList.add('search-super-month-name');
|
||||
name.innerText = str;
|
||||
|
||||
const options: Intl.DateTimeFormatOptions = {
|
||||
month: 'long'
|
||||
};
|
||||
|
||||
if(date.getFullYear() !== new Date().getFullYear()) {
|
||||
options.year = 'numeric';
|
||||
}
|
||||
|
||||
const dateElement = new I18n.IntlDateElement({
|
||||
date,
|
||||
options
|
||||
}).element;
|
||||
name.append(dateElement);
|
||||
|
||||
container.append(name);
|
||||
|
||||
const items = document.createElement('div');
|
||||
|
@ -5,8 +5,7 @@
|
||||
*/
|
||||
|
||||
import appDocsManager, {MyDocument} from "../lib/appManagers/appDocsManager";
|
||||
import { RichTextProcessor } from "../lib/richtextprocessor";
|
||||
import { formatDate, wrapPhoto } from "./wrappers";
|
||||
import { wrapPhoto } from "./wrappers";
|
||||
import ProgressivePreloader from "./preloader";
|
||||
import { MediaProgressLine } from "../lib/mediaPlayer";
|
||||
import appMediaPlaybackController, { MediaItem } from "./appMediaPlaybackController";
|
||||
@ -17,7 +16,6 @@ import appMessagesManager from "../lib/appManagers/appMessagesManager";
|
||||
import rootScope from "../lib/rootScope";
|
||||
import './middleEllipsis';
|
||||
import { SearchSuperContext } from "./appSearchSuper.";
|
||||
import { formatDateAccordingToToday } from "../helpers/date";
|
||||
import { cancelEvent } from "../helpers/dom/cancelEvent";
|
||||
import { attachClickEvent, detachClickEvent } from "../helpers/dom/clickEvent";
|
||||
import LazyLoadQueue from "./lazyLoadQueue";
|
||||
@ -25,6 +23,11 @@ import { CancellablePromise, deferredPromise } from "../helpers/cancellablePromi
|
||||
import ListenerSetter, { Listener } from "../helpers/listenerSetter";
|
||||
import noop from "../helpers/noop";
|
||||
import findUpClassName from "../helpers/dom/findUpClassName";
|
||||
import { joinElementsWith } from "../lib/langPack";
|
||||
import { MiddleEllipsisElement } from "./middleEllipsis";
|
||||
import htmlToSpan from "../helpers/dom/htmlToSpan";
|
||||
import { formatFullSentTime } from "../helpers/date";
|
||||
import { formatBytes } from "../helpers/number";
|
||||
|
||||
rootScope.addEventListener('messages_media_read', ({mids, peerId}) => {
|
||||
mids.forEach(mid => {
|
||||
@ -273,43 +276,56 @@ function wrapAudio(audioEl: AudioElement) {
|
||||
const message = audioEl.message;
|
||||
const doc: MyDocument = message.media.document || message.media.webpage.document;
|
||||
|
||||
const senderTitle = audioEl.showSender ? appMessagesManager.getSenderToPeerText(message) : '';
|
||||
|
||||
let title = doc.type === 'voice' ? senderTitle : (doc.audioTitle || doc.fileName);
|
||||
let subtitle: string;
|
||||
const isVoice = doc.type === 'voice' || doc.type === 'round';
|
||||
const descriptionEl = document.createElement('div');
|
||||
descriptionEl.classList.add('audio-description');
|
||||
|
||||
if(doc.type === 'voice') {
|
||||
subtitle = '';
|
||||
} else {
|
||||
subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : '';
|
||||
if(!isVoice) {
|
||||
const parts: (Node | string)[] = [];
|
||||
if(doc.audioPerformer) {
|
||||
parts.push(htmlToSpan(doc.audioPerformer));
|
||||
}
|
||||
|
||||
if(withTime) {
|
||||
subtitle += (subtitle ? ' • ' : '') + formatDate(doc.date);
|
||||
} else if(!subtitle) {
|
||||
subtitle = 'Unknown Artist';
|
||||
parts.push(formatFullSentTime(doc.date));
|
||||
} else if(!parts.length) {
|
||||
parts.push(formatBytes(doc.size));
|
||||
}
|
||||
|
||||
if(audioEl.showSender) {
|
||||
subtitle += ' • ' + senderTitle;
|
||||
} else {
|
||||
subtitle = ' • ' + subtitle;
|
||||
parts.push(appMessagesManager.wrapSenderToPeer(message));
|
||||
}
|
||||
}
|
||||
|
||||
let titleAdditionHTML = '';
|
||||
if(audioEl.showSender) {
|
||||
titleAdditionHTML = `<div class="sent-time">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;
|
||||
descriptionEl.append(...joinElementsWith(parts, ' • '));
|
||||
}
|
||||
|
||||
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>'}</div>
|
||||
<div class="audio-title"></div>
|
||||
<div class="audio-subtitle"><div class="audio-time"></div></div>
|
||||
</div>`;
|
||||
|
||||
audioEl.insertAdjacentHTML('beforeend', html);
|
||||
|
||||
const titleEl = audioEl.querySelector('.audio-title') as HTMLElement;
|
||||
|
||||
const middleEllipsisEl = new MiddleEllipsisElement();
|
||||
middleEllipsisEl.dataset.fontWeight = audioEl.dataset.fontWeight;
|
||||
if(isVoice) {
|
||||
middleEllipsisEl.append(appMessagesManager.wrapSenderToPeer(message));
|
||||
} else {
|
||||
middleEllipsisEl.innerHTML = doc.audioTitle || doc.fileName;
|
||||
}
|
||||
|
||||
titleEl.append(middleEllipsisEl);
|
||||
|
||||
if(audioEl.showSender) {
|
||||
titleEl.append(appMessagesManager.wrapSentTime(message));
|
||||
}
|
||||
|
||||
const subtitleDiv = audioEl.querySelector('.audio-subtitle') as HTMLDivElement;
|
||||
subtitleDiv.append(descriptionEl);
|
||||
|
||||
const onLoad = () => {
|
||||
const subtitleDiv = audioEl.querySelector('.audio-subtitle') as HTMLDivElement;
|
||||
let launched = false;
|
||||
|
||||
let progressLine = new MediaProgressLine(audioEl.audio, doc.supportsStreaming);
|
||||
@ -317,7 +333,7 @@ function wrapAudio(audioEl: AudioElement) {
|
||||
audioEl.addAudioListener('ended', () => {
|
||||
audioEl.classList.remove('audio-show-progress');
|
||||
// Reset subtitle
|
||||
subtitleDiv.lastChild.replaceWith(subtitle);
|
||||
subtitleDiv.lastChild.replaceWith(descriptionEl);
|
||||
launched = false;
|
||||
});
|
||||
|
||||
@ -519,9 +535,9 @@ export default class AudioElement extends HTMLElement {
|
||||
onClick();
|
||||
}
|
||||
} else {
|
||||
if(doc.supportsStreaming) {
|
||||
// if(doc.supportsStreaming) {
|
||||
onLoad(false);
|
||||
}
|
||||
// }
|
||||
|
||||
if(doc.thumbs) {
|
||||
const imgs: HTMLImageElement[] = [];
|
||||
@ -606,6 +622,8 @@ export default class AudioElement extends HTMLElement {
|
||||
this.listenerSetter.remove(pauseListener);
|
||||
});
|
||||
} else {
|
||||
preloader = constructDownloadPreloader();
|
||||
|
||||
const load = () => {
|
||||
const download = getDownloadPromise();
|
||||
preloader.attach(downloadDiv, false, download);
|
||||
@ -619,7 +637,10 @@ export default class AudioElement extends HTMLElement {
|
||||
|
||||
this.append(downloadDiv);
|
||||
|
||||
this.classList.add('downloading');
|
||||
|
||||
this.readyPromise.then(() => {
|
||||
this.classList.remove('downloading');
|
||||
downloadDiv.classList.add('downloaded');
|
||||
setTimeout(() => {
|
||||
downloadDiv.remove();
|
||||
|
@ -6,30 +6,40 @@
|
||||
|
||||
import type { AppMessagesManager } from "../../lib/appManagers/appMessagesManager";
|
||||
import type ChatTopbar from "./topbar";
|
||||
import { RichTextProcessor } from "../../lib/richtextprocessor";
|
||||
import rootScope from "../../lib/rootScope";
|
||||
import appMediaPlaybackController from "../appMediaPlaybackController";
|
||||
import DivAndCaption from "../divAndCaption";
|
||||
import { formatDate } from "../wrappers";
|
||||
import PinnedContainer from "./pinnedContainer";
|
||||
import Chat from "./chat";
|
||||
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||
import replaceContent from "../../helpers/dom/replaceContent";
|
||||
import PeerTitle from "../peerTitle";
|
||||
import { i18n } from "../../lib/langPack";
|
||||
import { formatFullSentTime } from "../../helpers/date";
|
||||
|
||||
export default class ChatAudio extends PinnedContainer {
|
||||
private toggleEl: HTMLElement;
|
||||
|
||||
constructor(protected topbar: ChatTopbar, protected chat: Chat, protected appMessagesManager: AppMessagesManager) {
|
||||
super(topbar, chat, topbar.listenerSetter, 'audio', new DivAndCaption('pinned-audio', (title: string | HTMLElement, subtitle: string | HTMLElement) => {
|
||||
replaceContent(this.divAndCaption.title, title);
|
||||
replaceContent(this.divAndCaption.subtitle, subtitle);
|
||||
}), () => {
|
||||
if(this.toggleEl.classList.contains('flip-icon')) {
|
||||
appMediaPlaybackController.toggle();
|
||||
super(
|
||||
topbar,
|
||||
chat,
|
||||
topbar.listenerSetter,
|
||||
'audio',
|
||||
new DivAndCaption(
|
||||
'pinned-audio',
|
||||
(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment) => {
|
||||
replaceContent(this.divAndCaption.title, title);
|
||||
replaceContent(this.divAndCaption.subtitle, subtitle);
|
||||
}
|
||||
),
|
||||
() => {
|
||||
if(this.toggleEl.classList.contains('flip-icon')) {
|
||||
appMediaPlaybackController.toggle();
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
|
||||
this.divAndCaption.border.remove();
|
||||
|
||||
@ -45,16 +55,16 @@ export default class ChatAudio extends PinnedContainer {
|
||||
this.topbar.listenerSetter.add(rootScope)('audio_play', (e) => {
|
||||
const {doc, mid, peerId} = e;
|
||||
|
||||
let title: string | HTMLElement, subtitle: string;
|
||||
let title: string | HTMLElement, subtitle: string | HTMLElement | DocumentFragment;
|
||||
const message = appMessagesManager.getMessageByPeer(peerId, mid);
|
||||
if(doc.type === 'voice' || doc.type === 'round') {
|
||||
title = new PeerTitle({peerId: message.fromId}).element;
|
||||
|
||||
//subtitle = 'Voice message';
|
||||
subtitle = formatDate(message.date, false, false);
|
||||
subtitle = formatFullSentTime(message.date);
|
||||
} else {
|
||||
title = doc.audioTitle || doc.fileName;
|
||||
subtitle = doc.audioPerformer ? RichTextProcessor.wrapPlainText(doc.audioPerformer) : 'Unknown Artist';
|
||||
subtitle = doc.audioPerformer || i18n('AudioUnknownArtist');
|
||||
}
|
||||
|
||||
this.fill(title, subtitle, message);
|
||||
|
@ -22,7 +22,14 @@ export default class PinnedContainer {
|
||||
private close: HTMLElement;
|
||||
protected wrapper: HTMLElement;
|
||||
|
||||
constructor(protected topbar: ChatTopbar, protected chat: Chat, public listenerSetter: ListenerSetter, protected className: string, public divAndCaption: DivAndCaption<(title: string | HTMLElement, subtitle: string | HTMLElement, message?: any) => void>, onClose?: () => void | Promise<boolean>) {
|
||||
constructor(
|
||||
protected topbar: ChatTopbar,
|
||||
protected chat: Chat,
|
||||
public listenerSetter: ListenerSetter,
|
||||
protected className: string,
|
||||
public divAndCaption: DivAndCaption<(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message?: any) => void>,
|
||||
onClose?: () => void | Promise<boolean>
|
||||
) {
|
||||
/* const prev = this.divAndCaption.fill;
|
||||
this.divAndCaption.fill = (mid, title, subtitle) => {
|
||||
this.divAndCaption.container.dataset.mid = '' + mid;
|
||||
@ -87,7 +94,7 @@ export default class PinnedContainer {
|
||||
this.topbar.setUtilsWidth();
|
||||
}
|
||||
|
||||
public fill(title: string | HTMLElement, subtitle: string | HTMLElement, message: any) {
|
||||
public fill(title: string | HTMLElement | DocumentFragment, subtitle: string | HTMLElement | DocumentFragment, message: any) {
|
||||
this.divAndCaption.container.dataset.peerId = '' + message.peerId;
|
||||
this.divAndCaption.container.dataset.mid = '' + message.mid;
|
||||
this.divAndCaption.fill(title, subtitle, message);
|
||||
|
@ -297,7 +297,7 @@ export class AppSidebarLeft extends SidebarSlider {
|
||||
name: 'SharedMusicTab2',
|
||||
type: 'music'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterVoice',
|
||||
inputFilter: 'inputMessagesFilterRoundVoice',
|
||||
name: 'SharedVoiceTab2',
|
||||
type: 'voice'
|
||||
}],
|
||||
|
@ -9,7 +9,7 @@ import { SettingSection } from "..";
|
||||
import Button from "../../button";
|
||||
import Row from "../../row";
|
||||
import { Authorization } from "../../../layer";
|
||||
import { formatDateAccordingToToday } from "../../../helpers/date";
|
||||
import { formatDateAccordingToTodayNew } from "../../../helpers/date";
|
||||
import { attachContextMenuListener, openBtnMenu, positionMenu } from "../../misc";
|
||||
import ButtonMenu from "../../buttonMenu";
|
||||
import apiManager from "../../../lib/mtproto/mtprotoworker";
|
||||
@ -35,7 +35,7 @@ export default class AppActiveSessionsTab extends SliderSuperTab {
|
||||
title: [auth.app_name, auth.app_version].join(' '),
|
||||
subtitle: [auth.ip, auth.country].join(' - '),
|
||||
clickable: true,
|
||||
titleRight: auth.pFlags.current ? undefined : formatDateAccordingToToday(new Date(Math.max(auth.date_active, auth.date_created) * 1000))
|
||||
titleRight: auth.pFlags.current ? undefined : formatDateAccordingToTodayNew(new Date(Math.max(auth.date_active, auth.date_created) * 1000))
|
||||
});
|
||||
|
||||
row.container.dataset.hash = auth.hash;
|
||||
|
@ -862,7 +862,7 @@ export default class AppSharedMediaTab extends SliderSuperTab {
|
||||
name: 'SharedMusicTab2',
|
||||
type: 'music'
|
||||
}, {
|
||||
inputFilter: 'inputMessagesFilterVoice',
|
||||
inputFilter: 'inputMessagesFilterRoundVoice',
|
||||
name: 'SharedVoiceTab2',
|
||||
type: 'voice'
|
||||
}],
|
||||
|
@ -8,7 +8,7 @@ import type Chat from './chat/chat';
|
||||
import { getEmojiToneIndex } from '../vendor/emoji';
|
||||
import { readBlobAsText } from '../helpers/blob';
|
||||
import { deferredPromise } from '../helpers/cancellablePromise';
|
||||
import { formatDateAccordingToToday, months } from '../helpers/date';
|
||||
import { formatFullSentTime } from '../helpers/date';
|
||||
import mediaSizes, { ScreenSize } from '../helpers/mediaSizes';
|
||||
import { formatBytes } from '../helpers/number';
|
||||
import { IS_SAFARI } from '../environment/userAgent';
|
||||
@ -46,6 +46,8 @@ import { clearBadCharsAndTrim } from '../helpers/cleanSearchText';
|
||||
import blur from '../helpers/blur';
|
||||
import IS_WEBP_SUPPORTED from '../environment/webpSupport';
|
||||
import MEDIA_MIME_TYPES_SUPPORTED from '../environment/mediaMimeTypesSupport';
|
||||
import { MiddleEllipsisElement } from './middleEllipsis';
|
||||
import { joinElementsWith } from '../lib/langPack';
|
||||
|
||||
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
|
||||
|
||||
@ -487,20 +489,6 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
return res;
|
||||
}
|
||||
|
||||
export const formatDate = (timestamp: number, monthShort = false, withYear = true) => {
|
||||
const date = new Date(timestamp * 1000);
|
||||
|
||||
let month = months[date.getMonth()];
|
||||
if(monthShort) month = month.slice(0, 3);
|
||||
|
||||
let str = month + ' ' + date.getDate();
|
||||
if(withYear) {
|
||||
str += ', ' + date.getFullYear();
|
||||
}
|
||||
|
||||
return str + ' at ' + date.getHours() + ':' + ('0' + date.getMinutes()).slice(-2);
|
||||
};
|
||||
|
||||
rootScope.addEventListener('download_start', (docId) => {
|
||||
const elements = Array.from(document.querySelectorAll(`.document[data-doc-id="${docId}"]`)) as HTMLElement[];
|
||||
elements.forEach(element => {
|
||||
@ -525,7 +513,7 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
||||
|
||||
const doc = (message.media.document || message.media.webpage.document) as MyDocument;
|
||||
const uploading = message.pFlags.is_outgoing && message.media?.preloader;
|
||||
if(doc.type === 'audio' || doc.type === 'voice') {
|
||||
if(doc.type === 'audio' || doc.type === 'voice' || doc.type === 'round') {
|
||||
const audioElement = new AudioElement();
|
||||
audioElement.dataset.mid = '' + message.mid;
|
||||
audioElement.dataset.peerId = '' + message.peerId;
|
||||
@ -589,27 +577,38 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
||||
|
||||
//let fileName = stringMiddleOverflow(doc.file_name || 'Unknown.file', 26);
|
||||
let fileName = doc.fileName || 'Unknown.file';
|
||||
let size = formatBytes(doc.size);
|
||||
const descriptionEl = document.createElement('div');
|
||||
descriptionEl.classList.add('document-description');
|
||||
const descriptionParts: (HTMLElement | string | DocumentFragment)[] = [formatBytes(doc.size)];
|
||||
|
||||
if(withTime) {
|
||||
size += ' · ' + formatDate(doc.date);
|
||||
descriptionParts.push(formatFullSentTime(doc.date));
|
||||
}
|
||||
|
||||
if(showSender) {
|
||||
size += ' · ' + appMessagesManager.getSenderToPeerText(message);
|
||||
descriptionParts.push(appMessagesManager.wrapSenderToPeer(message));
|
||||
}
|
||||
|
||||
let titleAdditionHTML = '';
|
||||
if(showSender) {
|
||||
titleAdditionHTML = `<div class="sent-time">${formatDateAccordingToToday(new Date(message.date * 1000))}</div>`;
|
||||
}
|
||||
|
||||
docDiv.innerHTML = `
|
||||
${cacheContext.downloaded && !uploading ? '' : `<div class="document-download"></div>`}
|
||||
<div class="document-name"><middle-ellipsis-element data-font-weight="${fontWeight}">${fileName}</middle-ellipsis-element>${titleAdditionHTML}</div>
|
||||
<div class="document-size">${size}</div>
|
||||
<div class="document-name"></div>
|
||||
<div class="document-size"></div>
|
||||
`;
|
||||
|
||||
const nameDiv = docDiv.querySelector('.document-name') as HTMLElement;
|
||||
const middleEllipsisEl = new MiddleEllipsisElement();
|
||||
middleEllipsisEl.dataset.fontWeight = '' + fontWeight;
|
||||
middleEllipsisEl.innerHTML = fileName;
|
||||
|
||||
nameDiv.append(middleEllipsisEl);
|
||||
|
||||
if(showSender) {
|
||||
nameDiv.append(appMessagesManager.wrapSentTime(message));
|
||||
}
|
||||
|
||||
const sizeDiv = docDiv.querySelector('.document-size') as HTMLElement;
|
||||
sizeDiv.append(...joinElementsWith(descriptionParts, ' · '));
|
||||
|
||||
docDiv.prepend(icoDiv);
|
||||
|
||||
if(!uploading && message.pFlags.is_outgoing) {
|
||||
|
@ -5,7 +5,8 @@
|
||||
*/
|
||||
|
||||
import { MOUNT_CLASS_TO } from "../config/debug";
|
||||
import I18n from "../lib/langPack";
|
||||
import I18n, { i18n } from "../lib/langPack";
|
||||
import { capitalizeFirstLetter } from "./string";
|
||||
|
||||
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'];
|
||||
@ -21,25 +22,6 @@ export const getWeekNumber = (date: Date) => {
|
||||
return Math.ceil((((d.getTime() - yearStart.getTime()) / ONE_DAY) + 1) / 7);
|
||||
};
|
||||
|
||||
export const formatDateAccordingToToday = (time: Date) => {
|
||||
const date = new Date();
|
||||
const now = date.getTime() / 1000 | 0;
|
||||
const timestamp = time.getTime() / 1000 | 0;
|
||||
|
||||
let timeStr: string;
|
||||
if((now - timestamp) < ONE_DAY && date.getDate() === time.getDate()) { // if the same day
|
||||
timeStr = ('0' + time.getHours()).slice(-2) + ':' + ('0' + time.getMinutes()).slice(-2);
|
||||
} else if(date.getFullYear() !== time.getFullYear()) { // different year
|
||||
timeStr = time.getDate() + '.' + ('0' + (time.getMonth() + 1)).slice(-2) + '.' + ('' + time.getFullYear()).slice(-2);
|
||||
} else if((now - timestamp) < (ONE_DAY * 7) && getWeekNumber(date) === getWeekNumber(time)) { // current week
|
||||
timeStr = days[time.getDay()].slice(0, 3);
|
||||
} else { // same year
|
||||
timeStr = months[time.getMonth()].slice(0, 3) + ' ' + ('0' + time.getDate()).slice(-2);
|
||||
}
|
||||
|
||||
return timeStr;
|
||||
};
|
||||
|
||||
export function formatDateAccordingToTodayNew(time: Date) {
|
||||
const today = new Date();
|
||||
const now = today.getTime() / 1000 | 0;
|
||||
@ -64,6 +46,44 @@ export function formatDateAccordingToTodayNew(time: Date) {
|
||||
}).element;
|
||||
}
|
||||
|
||||
export function formatFullSentTime(timestamp: number) {
|
||||
const date = new Date();
|
||||
const time = new Date(timestamp * 1000);
|
||||
const now = date.getTime() / 1000;
|
||||
|
||||
const timeEl = formatTime(time);
|
||||
|
||||
let dateEl: Node | string;
|
||||
if((now - timestamp) < ONE_DAY && date.getDate() === time.getDate()) { // if the same day
|
||||
dateEl = i18n('Date.Today');
|
||||
} else if((now - timestamp) < (ONE_DAY * 2) && (date.getDate() - 1) === time.getDate()) { // yesterday
|
||||
dateEl = capitalizeFirstLetter(I18n.format('Yesterday', true));
|
||||
} else if(date.getFullYear() !== time.getFullYear()) { // different year
|
||||
dateEl = new I18n.IntlDateElement({
|
||||
date: time,
|
||||
options: {
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
year: 'numeric'
|
||||
}
|
||||
}).element;
|
||||
// dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate() + ', ' + time.getFullYear();
|
||||
} else {
|
||||
dateEl = new I18n.IntlDateElement({
|
||||
date: time,
|
||||
options: {
|
||||
month: 'short',
|
||||
day: 'numeric'
|
||||
}
|
||||
}).element;
|
||||
// dateStr = months[time.getMonth()].slice(0, 3) + ' ' + time.getDate();
|
||||
}
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
fragment.append(dateEl, ' ', i18n('ScheduleController.at'), ' ', timeEl);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
export function formatTime(date: Date) {
|
||||
return new I18n.IntlDateElement({
|
||||
date,
|
||||
|
@ -584,6 +584,8 @@ const lang = {
|
||||
"AreYouSureBlockContact2": "Are you sure you want to block **%1$s**?",
|
||||
"UserBlocked": "User blocked",
|
||||
"UserUnblocked": "User unblocked",
|
||||
"AudioUnknownArtist": "Unknown artist",
|
||||
"AudioUnknownTitle": "Unknown title",
|
||||
|
||||
// * macos
|
||||
"AccountSettings.Filters": "Chat Folders",
|
||||
|
@ -12,7 +12,7 @@
|
||||
import { LazyLoadQueueBase } from "../../components/lazyLoadQueue";
|
||||
import ProgressivePreloader from "../../components/preloader";
|
||||
import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePromise";
|
||||
import { formatTime, tsNow } from "../../helpers/date";
|
||||
import { formatDateAccordingToTodayNew, formatTime, tsNow } from "../../helpers/date";
|
||||
import { createPosterForVideo } from "../../helpers/files";
|
||||
import { copy, getObjectKeysAndSort } from "../../helpers/object";
|
||||
import { randomLong } from "../../helpers/random";
|
||||
@ -2721,21 +2721,36 @@ export class AppMessagesManager {
|
||||
}
|
||||
}
|
||||
|
||||
public getSenderToPeerText(message: MyMessage) {
|
||||
let senderTitle = '', peerTitle: string;
|
||||
public wrapSenderToPeer(message: MyMessage) {
|
||||
const senderTitle: HTMLElement = document.createElement('span');
|
||||
senderTitle.classList.add('sender-title');
|
||||
|
||||
senderTitle = message.pFlags.out ? 'You' : appPeersManager.getPeerTitle(message.fromId, false, false);
|
||||
peerTitle = appPeersManager.isAnyGroup(message.peerId) || (message.pFlags.out && message.peerId !== rootScope.myId) ?
|
||||
appPeersManager.getPeerTitle(message.peerId, false, false) :
|
||||
'';
|
||||
const fromMe = message.fromId === rootScope.myId && message.peerId !== rootScope.myId;
|
||||
senderTitle.append(
|
||||
fromMe ?
|
||||
i18n('FromYou') :
|
||||
new PeerTitle({
|
||||
peerId: message.fromId,
|
||||
dialog: message.peerId === rootScope.myId
|
||||
}).element
|
||||
);
|
||||
|
||||
if(peerTitle) {
|
||||
senderTitle += ' ➝ ' + peerTitle;
|
||||
if(appPeersManager.isAnyGroup(message.peerId) || fromMe) {
|
||||
const peerTitle = new PeerTitle({peerId: message.peerId}).element;
|
||||
senderTitle.append(' ➝ ', peerTitle);
|
||||
}
|
||||
|
||||
return senderTitle;
|
||||
}
|
||||
|
||||
public wrapSentTime(message: MyMessage) {
|
||||
const el: HTMLElement = document.createElement('span');
|
||||
el.classList.add('sent-time');
|
||||
el.append(formatDateAccordingToTodayNew(new Date(message.date * 1000)));
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
public wrapMessageActionTextNew(message: any, plain: true): string;
|
||||
public wrapMessageActionTextNew(message: any, plain?: false): HTMLElement;
|
||||
public wrapMessageActionTextNew(message: any, plain: boolean): HTMLElement | string;
|
||||
|
@ -448,16 +448,19 @@ export {i18n_};
|
||||
const _i18n = I18n._i18n;
|
||||
export {_i18n};
|
||||
|
||||
export function join(elements: (Node | string)[], useLast = true) {
|
||||
export function joinElementsWith(elements: (Node | string)[], joiner: typeof elements[0] | ((isLast: boolean) => typeof elements[0])) {
|
||||
const arr = elements.slice(0, 1);
|
||||
for(let i = 1; i < elements.length; ++i) {
|
||||
const isLast = (elements.length - 1) === i;
|
||||
const delimiterKey: LangPackKey = isLast && useLast ? 'WordDelimiterLast' : 'WordDelimiter';
|
||||
arr.push(i18n(delimiterKey));
|
||||
arr.push(typeof(joiner) === 'function' ? joiner(isLast) : joiner);
|
||||
arr.push(elements[i]);
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
export function join(elements: (Node | string)[], useLast = true) {
|
||||
return joinElementsWith(elements, (isLast) => i18n(isLast && useLast ? 'WordDelimiterLast' : 'WordDelimiter'));
|
||||
}
|
||||
|
||||
MOUNT_CLASS_TO.I18n = I18n;
|
||||
|
@ -454,9 +454,6 @@
|
||||
&-subtitle {
|
||||
font-size: .875rem;
|
||||
color: var(--secondary-text-color);
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
|
||||
@include respond-to(handhelds) {
|
||||
@ -464,6 +461,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
&-title,
|
||||
&-time,
|
||||
&-subtitle {
|
||||
@include text-overflow();
|
||||
}
|
||||
|
||||
// * for audio
|
||||
&-subtitle {
|
||||
align-items: center;
|
||||
@ -483,12 +486,9 @@
|
||||
// * for audio
|
||||
&-title,
|
||||
&:not(.audio-show-progress) &-subtitle {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
|
||||
&.is-voice {
|
||||
.audio-time {
|
||||
line-height: 1;
|
||||
@ -535,9 +535,10 @@
|
||||
.audio-play-icon {
|
||||
z-index: 1;
|
||||
background-color: transparent;
|
||||
opacity: 1;
|
||||
|
||||
@include animation-level(2) {
|
||||
transition: transform .25 ease-in-out, background-color .2s ease-in-out;
|
||||
transition: transform .25s ease-in-out, background-color .2s ease-in-out, opacity .2s ease-in-out;
|
||||
}
|
||||
|
||||
.part {
|
||||
@ -555,5 +556,17 @@
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
&:not(.corner-download) {
|
||||
.audio-download {
|
||||
background-color: rgba(0, 0, 0, .3);
|
||||
}
|
||||
|
||||
&.downloading {
|
||||
.audio-play-icon {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1691,6 +1691,10 @@ $bubble-margin: .25rem;
|
||||
.replies {
|
||||
user-select: none;
|
||||
|
||||
.c-ripple__circle {
|
||||
background-color: var(--light-primary-color);
|
||||
}
|
||||
|
||||
.rp {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -189,6 +189,10 @@
|
||||
//transform: scale(0);
|
||||
}
|
||||
}
|
||||
|
||||
&-description {
|
||||
@include text-overflow();
|
||||
}
|
||||
|
||||
&:not(.corner-download) .preloader-container:not(.preloader-streamable) {
|
||||
transform: scale(1) !important;
|
||||
|
@ -514,16 +514,17 @@
|
||||
white-space: pre-wrap;
|
||||
text-overflow: ellipsis;
|
||||
word-break: break-word;
|
||||
|
||||
&.sender {
|
||||
margin-top: .125rem;
|
||||
}
|
||||
}
|
||||
|
||||
.sent-time {
|
||||
margin: 1px 0 0;
|
||||
}
|
||||
|
||||
.sender-title {
|
||||
display: block;
|
||||
margin-top: .25rem;
|
||||
}
|
||||
|
||||
.checkbox-field {
|
||||
padding: 0 !important;
|
||||
margin: 2rem 0 0 -1.75rem !important;
|
||||
|
Loading…
Reference in New Issue
Block a user