Browse Source

Fix audio player content overflow with sidebar

Always display .gif as video
Restrict jumping from webpage media to regular
Fix displaying round video in webpage
master
morethanwords 3 years ago
parent
commit
1a39932068
  1. 4
      src/components/appMediaPlaybackController.ts
  2. 28
      src/components/audio.ts
  3. 24
      src/components/chat/bubbles.ts
  4. 15
      src/components/chat/pinnedContainer.ts
  5. 2
      src/components/chat/topbar.ts
  6. 13
      src/components/wrappers.ts
  7. 11
      src/lib/appManagers/appDocsManager.ts
  8. 2
      src/lib/appManagers/appMessagesManager.ts
  9. 17
      src/scss/partials/_chatBubble.scss
  10. 6
      src/scss/partials/_chatPinned.scss

4
src/components/appMediaPlaybackController.ts

@ -360,7 +360,7 @@ class AppMediaPlaybackController { @@ -360,7 +360,7 @@ class AppMediaPlaybackController {
private async setNewMediadata(message: Message.message, playingMedia = this.playingMedia) {
await onMediaLoad(playingMedia, undefined, false); // have to wait for load, otherwise on macOS won't set
const doc = (message.media as MessageMedia.messageMediaDocument).document as MyDocument;
const doc = appMessagesManager.getMediaFromMessage(message) as MyDocument;
const artwork: MediaImage[] = [];
@ -624,7 +624,7 @@ class AppMediaPlaybackController { @@ -624,7 +624,7 @@ class AppMediaPlaybackController {
public previous = () => {
const media = this.playingMedia;
if(media && media.currentTime > 5) {
if(media && (media.currentTime > 5 || !this.listLoader.previous.length)) {
media.currentTime = 0;
this.toggle(true);
return;

28
src/components/audio.ts

@ -28,6 +28,7 @@ import htmlToSpan from "../helpers/dom/htmlToSpan"; @@ -28,6 +28,7 @@ import htmlToSpan from "../helpers/dom/htmlToSpan";
import { formatFullSentTime } from "../helpers/date";
import { clamp, formatBytes } from "../helpers/number";
import throttleWithRaf from "../helpers/schedulers/throttleWithRaf";
import { NULL_PEER_ID } from "../lib/mtproto/mtproto_config";
rootScope.addEventListener('messages_media_read', ({mids, peerId}) => {
mids.forEach(mid => {
@ -340,20 +341,28 @@ function constructDownloadPreloader(tryAgainOnFail = true) { @@ -340,20 +341,28 @@ function constructDownloadPreloader(tryAgainOnFail = true) {
return preloader;
}
export const findAudioTargets = (anchor: HTMLElement, useSearch: boolean) => {
export const findMediaTargets = (anchor: HTMLElement/* , useSearch: boolean */) => {
let prev: MediaItem[], next: MediaItem[];
// if(anchor.classList.contains('search-super-item') || !useSearch) {
const container = findUpClassName(anchor, anchor.classList.contains('search-super-item') ? 'tabs-tab' : 'bubbles-inner');
const isBubbles = !anchor.classList.contains('search-super-item');
const container = findUpClassName(anchor, !isBubbles ? 'tabs-tab' : 'bubbles-inner');
if(container) {
const attr = `:not([data-is-outgoing="1"])`;
const justAudioSelector = `.audio:not(.is-voice)${attr}`;
let selector: string;
let selectors: string[];
if(!anchor.matches(justAudioSelector)) {
selector = `.audio.is-voice${attr}, .media-round${attr}`;
selectors = [`.audio.is-voice${attr}`, `.media-round${attr}`];
} else {
selector = justAudioSelector;
selectors = [justAudioSelector];
}
if(isBubbles) {
const prefix = '.bubble:not(.webpage) ';
selectors = selectors.map(s => prefix + s);
}
const selector = selectors.join(', ');
const elements = Array.from(container.querySelectorAll(selector)) as HTMLElement[];
const idx = elements.indexOf(anchor);
@ -454,8 +463,13 @@ export default class AudioElement extends HTMLElement { @@ -454,8 +463,13 @@ export default class AudioElement extends HTMLElement {
e && cancelEvent(e);
if(paused) {
if(appMediaPlaybackController.setSearchContext(this.searchContext)) {
const [prev, next] = findAudioTargets(this, this.searchContext.useSearch);
const hadSearchContext = !!this.searchContext;
if(appMediaPlaybackController.setSearchContext(this.searchContext || {
peerId: NULL_PEER_ID,
inputFilter: {_: 'inputMessagesFilterEmpty'},
useSearch: false
})) {
const [prev, next] = !hadSearchContext ? [] : findMediaTargets(this/* , this.searchContext.useSearch */);
appMediaPlaybackController.setTargets({peerId: this.message.peerId, mid: this.message.mid}, prev, next);
}

24
src/components/chat/bubbles.ts

@ -1042,6 +1042,9 @@ export default class ChatBubbles { @@ -1042,6 +1042,9 @@ export default class ChatBubbles {
return;
}
const SINGLE_MEDIA_CLASSNAME = 'webpage';
const isSingleMedia = bubble.classList.contains(SINGLE_MEDIA_CLASSNAME);
const f = documentDiv ? (media: any) => {
return AppMediaViewer.isMediaCompatibleForDocumentViewer(media);
} : (media: any) => {
@ -1049,7 +1052,10 @@ export default class ChatBubbles { @@ -1049,7 +1052,10 @@ export default class ChatBubbles {
};
const targets: {element: HTMLElement, mid: number, peerId: PeerId}[] = [];
const ids = Object.keys(this.bubbles).map(k => +k).filter(id => {
const ids = isSingleMedia ? [messageId] : Object.keys(this.bubbles).map(k => +k).filter(id => {
/* if(isSingleMedia && !this.bubbles[id].classList.contains(SINGLE_MEDIA_CLASSNAME)) {
return false;
} */
//if(!this.scrollable.visibleElements.find(e => e.element === this.bubbles[id])) return false;
const message = this.chat.getMessage(id);
@ -1117,7 +1123,7 @@ export default class ChatBubbles { @@ -1117,7 +1123,7 @@ export default class ChatBubbles {
threadId: this.chat.threadId,
peerId: this.peerId,
inputFilter: {_: documentDiv ? 'inputMessagesFilterDocument' : 'inputMessagesFilterPhotoVideo'},
useSearch: this.chat.type !== 'scheduled',
useSearch: this.chat.type !== 'scheduled' && !isSingleMedia,
isScheduled: this.chat.type === 'scheduled'
})
.openMedia(message, targets[idx].element, 0, true, targets.slice(0, idx), targets.slice(idx + 1));
@ -2707,15 +2713,21 @@ export default class ChatBubbles { @@ -2707,15 +2713,21 @@ export default class ChatBubbles {
const doc = webpage.document as MyDocument;
if(doc) {
if(doc.type === 'gif' || doc.type === 'video') {
if(doc.type === 'gif' || doc.type === 'video' || doc.type === 'round') {
//if(doc.size <= 20e6) {
bubble.classList.add('video');
const mediaSize = doc.type === 'round' ? mediaSizes.active.round : mediaSizes.active.webpage;
if(doc.type === 'round') {
bubble.classList.add('round');
preview.classList.add('is-round');
} else {
bubble.classList.add('video');
}
wrapVideo({
doc,
container: preview,
message,
boxWidth: mediaSizes.active.webpage.width,
boxHeight: mediaSizes.active.webpage.height,
boxWidth: mediaSize.width,
boxHeight: mediaSize.height,
lazyLoadQueue: this.lazyLoadQueue,
middleware: this.getMiddleware(),
isOut,

15
src/components/chat/pinnedContainer.ts

@ -89,10 +89,10 @@ export default class PinnedContainer { @@ -89,10 +89,10 @@ export default class PinnedContainer {
return;
}
const scrollable = this.chat.bubbles.scrollable;
// const scrollable = this.chat.bubbles.scrollable;
const isFloating = (this.floating || mediaSizes.isMobile) && !hide;
const scrollTop = isFloating || this.divAndCaption.container.classList.contains('is-floating') ? scrollable.scrollTop : undefined;
// const scrollTop = isFloating || this.divAndCaption.container.classList.contains('is-floating') ? scrollable.scrollTop : undefined;
this.divAndCaption.container.classList.toggle('is-floating', isFloating);
this.divAndCaption.container.classList.toggle('hide', hide);
@ -100,12 +100,13 @@ export default class PinnedContainer { @@ -100,12 +100,13 @@ export default class PinnedContainer {
this.topbar.container.classList.toggle('is-pinned-floating', isFloating);
this.topbar.container.classList.toggle(`is-pinned-${this.className}-shown`, !hide);
const active = classNames.filter(className => this.topbar.container.classList.contains(className));
const maxActive = hide ? 0 : 1;
// const active = classNames.filter(className => this.topbar.container.classList.contains(className));
// const maxActive = hide ? 0 : 1;
if(scrollTop !== undefined && active.length <= maxActive/* && !scrollable.isScrolledDown */) {
scrollable.scrollTop = scrollTop + ((hide ? -1 : 1) * HEIGHT);
}
// * not sure when it became unneeded
// if(scrollTop !== undefined && active.length <= maxActive/* && !scrollable.isScrolledDown */) {
// scrollable.scrollTop = scrollTop + ((hide ? -1 : 1) * HEIGHT);
// }
this.topbar.setFloating();
this.topbar.setUtilsWidth();

2
src/components/chat/topbar.ts

@ -728,7 +728,7 @@ export default class ChatTopbar { @@ -728,7 +728,7 @@ export default class ChatTopbar {
void this.chatInfo.offsetLeft; // reflow */
const width = /* chatUtils.scrollWidth */this.chatUtils.getBoundingClientRect().width;
this.chat.log('utils width:', width);
this.chatInfo.style.setProperty('--utils-width', width + 'px');
this.container.style.setProperty('--utils-width', width + 'px');
//this.chatInfo.classList.toggle('have-utils-width', !!width);
//}, 0);

13
src/components/wrappers.ts

@ -20,7 +20,7 @@ import LottieLoader from '../lib/lottieLoader'; @@ -20,7 +20,7 @@ import LottieLoader from '../lib/lottieLoader';
import webpWorkerController from '../lib/webp/webpWorkerController';
import animationIntersector from './animationIntersector';
import appMediaPlaybackController, { MediaSearchContext } from './appMediaPlaybackController';
import AudioElement, { findAudioTargets as findMediaTargets } from './audio';
import AudioElement, { findMediaTargets } from './audio';
import ReplyContainer from './chat/replyContainer';
import { Layouter, RectPart } from './groupedLayout';
import LazyLoadQueue from './lazyLoadQueue';
@ -29,7 +29,6 @@ import ProgressivePreloader from './preloader'; @@ -29,7 +29,6 @@ import ProgressivePreloader from './preloader';
import './middleEllipsis';
import RichTextProcessor from '../lib/richtextprocessor';
import appImManager from '../lib/appManagers/appImManager';
import { SearchSuperContext } from './appSearchSuper.';
import rootScope from '../lib/rootScope';
import { onMediaLoad } from '../helpers/files';
import { animateSingle } from '../helpers/animation';
@ -49,6 +48,7 @@ import MEDIA_MIME_TYPES_SUPPORTED from '../environment/mediaMimeTypesSupport'; @@ -49,6 +48,7 @@ import MEDIA_MIME_TYPES_SUPPORTED from '../environment/mediaMimeTypesSupport';
import { MiddleEllipsisElement } from './middleEllipsis';
import { joinElementsWith } from '../lib/langPack';
import throttleWithRaf from '../helpers/schedulers/throttleWithRaf';
import { NULL_PEER_ID } from '../lib/mtproto/mtproto_config';
const MAX_VIDEO_AUTOPLAY_SIZE = 50 * 1024 * 1024; // 50 MB
@ -305,8 +305,13 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai @@ -305,8 +305,13 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
} */
if(globalVideo.paused) {
if(appMediaPlaybackController.setSearchContext(searchContext)) {
const [prev, next] = findMediaTargets(divRound, searchContext.useSearch);
const hadSearchContext = !!searchContext;
if(appMediaPlaybackController.setSearchContext(searchContext || {
peerId: NULL_PEER_ID,
inputFilter: {_: 'inputMessagesFilterEmpty'},
useSearch: false
})) {
const [prev, next] = !hadSearchContext ? [] : findMediaTargets(divRound/* , searchContext.useSearch */);
appMediaPlaybackController.setTargets({peerId: message.peerId, mid: message.mid}, prev, next);
}

11
src/lib/appManagers/appDocsManager.ts

@ -28,8 +28,10 @@ export type MyDocument = Document.document; @@ -28,8 +28,10 @@ export type MyDocument = Document.document;
// TODO: если залить картинку файлом, а потом перезайти в диалог - превьюшка заново скачается
const EXTENSION_MIME_TYPE_MAP: {[key: string]: string} = {
mov: 'video/quicktime'
const EXTENSION_MIME_TYPE_MAP = {
mov: 'video/quicktime',
gif: 'image/gif',
pdf: 'application/pdf',
};
export class AppDocsManager {
@ -163,6 +165,7 @@ export class AppDocsManager { @@ -163,6 +165,7 @@ export class AppDocsManager {
if(!doc.mime_type) {
const ext = (doc.file_name || '').split('.').pop();
// @ts-ignore
const mappedMimeType = ext && EXTENSION_MIME_TYPE_MAP[ext.toLowerCase()];
if(mappedMimeType) {
doc.mime_type = mappedMimeType;
@ -187,8 +190,10 @@ export class AppDocsManager { @@ -187,8 +190,10 @@ export class AppDocsManager {
break;
}
}
} else if(doc.mime_type === 'application/pdf') {
} else if(doc.mime_type === EXTENSION_MIME_TYPE_MAP.pdf) {
doc.type = 'pdf';
} else if(doc.mime_type === EXTENSION_MIME_TYPE_MAP.gif) {
doc.type = 'gif';
}
if(doc.type === 'voice' || doc.type === 'round') {

2
src/lib/appManagers/appMessagesManager.ts

@ -3696,7 +3696,7 @@ export class AppMessagesManager { @@ -3696,7 +3696,7 @@ export class AppMessagesManager {
const foundCount: number = searchResult.count || (foundMsgs.length + searchResult.messages.length);
searchResult.messages.forEach((message: any) => {
searchResult.messages.forEach((message: MyMessage) => {
const peerId = this.getMessagePeer(message);
if(peerId.isAnyChat()) {
const chat: Chat.chat = appChatsManager.getChat(peerId.toChatId());

17
src/scss/partials/_chatBubble.scss

@ -597,12 +597,12 @@ $bubble-beside-button-width: 38px; @@ -597,12 +597,12 @@ $bubble-beside-button-width: 38px;
max-height: var(--round-video-size) !important;
width: var(--round-video-size) !important;
height: var(--round-video-size) !important;
}
.media-photo,
.media-video {
border-radius: 50%;
pointer-events: none;
}
.media-photo,
.media-video {
border-radius: 50%;
pointer-events: none;
}
}
@ -922,6 +922,13 @@ $bubble-beside-button-width: 38px; @@ -922,6 +922,13 @@ $bubble-beside-button-width: 38px;
}
}
}
&.is-round {
.media-photo,
.media-video {
border-radius: 50%;
}
}
}
&.no-text {

6
src/scss/partials/_chatPinned.scss

@ -285,6 +285,12 @@ @@ -285,6 +285,12 @@
.pinned-container-content {
margin-right: .5rem;
@include respond-to(medium-screens) {
body.is-right-column-shown & {
padding-right: var(--right-column-width);
}
}
}
/* &:before {

Loading…
Cancel
Save