Touch fixes

This commit is contained in:
Eduard Kuzmenko 2022-02-11 18:36:00 +04:00
parent e74ac65ca4
commit 72479fc179
15 changed files with 91 additions and 37 deletions

View File

@ -6,7 +6,7 @@
import MEDIA_MIME_TYPES_SUPPORTED from "../environment/mediaMimeTypesSupport";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import { attachClickEvent } from "../helpers/dom/clickEvent";
import { attachClickEvent, detachClickEvent } from "../helpers/dom/clickEvent";
import setInnerHTML from "../helpers/dom/setInnerHTML";
import mediaSizes from "../helpers/mediaSizes";
import SearchListLoader from "../helpers/searchListLoader";
@ -123,8 +123,8 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
protected setListeners() {
super.setListeners();
this.buttons.forward.addEventListener('click', this.onForwardClick);
this.author.container.addEventListener('click', this.onAuthorClick);
attachClickEvent(this.buttons.forward, this.onForwardClick);
attachClickEvent(this.author.container, this.onAuthorClick);
const onCaptionClick = (e: MouseEvent) => {
if(e.target instanceof HTMLAnchorElement) { // close viewer if it's t.me/ redirect
@ -136,14 +136,15 @@ export default class AppMediaViewer extends AppMediaViewerBase<'caption', 'delet
cancelEvent(e);
this.close().then(() => {
this.content.caption.removeEventListener('click', onCaptionClick, {capture: true});
detachClickEvent(this.content.caption, onCaptionClick, {capture: true});
(e.target as HTMLAnchorElement).click();
});
return false;
}
};
this.content.caption.addEventListener('click', onCaptionClick, {capture: true});
attachClickEvent(this.content.caption, onCaptionClick, {capture: true});
}
/* public close(e?: MouseEvent) {

View File

@ -43,6 +43,7 @@ import { MyMessage } from "../lib/appManagers/appMessagesManager";
import RichTextProcessor from "../lib/richtextprocessor";
import { NULL_PEER_ID } from "../lib/mtproto/mtproto_config";
import { isFullScreen } from "../helpers/dom/fullScreen";
import { attachClickEvent } from "../helpers/dom/clickEvent";
const ZOOM_STEP = 0.5;
const ZOOM_INITIAL_VALUE = 1;
@ -190,9 +191,9 @@ export default class AppMediaViewerBase<
this.zoomElements.container.classList.add('zoom-container');
this.zoomElements.btnOut = ButtonIcon('zoomout', {noRipple: true});
this.zoomElements.btnOut.addEventListener('click', () => this.changeZoom(false));
attachClickEvent(this.zoomElements.btnOut, () => this.changeZoom(false));
this.zoomElements.btnIn = ButtonIcon('zoomin', {noRipple: true});
this.zoomElements.btnIn.addEventListener('click', () => this.changeZoom(true));
attachClickEvent(this.zoomElements.btnIn, () => this.changeZoom(true));
this.zoomElements.rangeSelector = new RangeSelector({
step: ZOOM_STEP,
@ -254,13 +255,13 @@ export default class AppMediaViewerBase<
}
protected setListeners() {
this.buttons.download.addEventListener('click', this.onDownloadClick);
attachClickEvent(this.buttons.download, this.onDownloadClick);
[this.buttons.close, this.buttons['mobile-close'], this.preloaderStreamable.preloader].forEach(el => {
el.addEventListener('click', this.close.bind(this));
attachClickEvent(el, this.close.bind(this));
});
([[-1, this.buttons.prev], [1, this.buttons.next]] as [number, HTMLElement][]).forEach(([moveLength, button]) => {
button.addEventListener('click', (e) => {
attachClickEvent(button, (e) => {
cancelEvent(e);
if(this.setMoverPromise) return;
@ -268,14 +269,14 @@ export default class AppMediaViewerBase<
});
});
this.buttons.zoom.addEventListener('click', () => {
attachClickEvent(this.buttons.zoom, () => {
if(this.isZooming()) this.toggleZoom(false);
else {
this.changeZoom(true);
}
});
this.wholeDiv.addEventListener('click', this.onClick);
attachClickEvent(this.wholeDiv, this.onClick);
this.listLoader.onJump = (item, older) => {
if(older) this.onNextClick(item);
@ -1359,7 +1360,14 @@ export default class AppMediaViewerBase<
// const play = useController ? appMediaPlaybackController.willBePlayedMedia === video : true;
const play = true;
const player = this.videoPlayer = new VideoPlayer(video, play, supportsStreaming);
const player = this.videoPlayer = new VideoPlayer({
video,
play,
streamable: supportsStreaming,
onPlaybackRackMenuToggle: (open) => {
this.wholeDiv.classList.toggle('hide-caption', !!open);
}
});
player.addEventListener('toggleControls', (show) => {
this.wholeDiv.classList.toggle('has-video-controls', show);
});

View File

@ -1100,7 +1100,7 @@ export default class AppSearchSuper {
});
showMore.append(intlElement.element);
this.searchGroups.globalContacts.nameEl.append(showMore);
showMore.addEventListener('click', () => {
attachClickEvent(showMore, () => {
const isShort = this.searchGroups.globalContacts.container.classList.toggle('is-short');
intlElement.key = isShort ? 'Separator.ShowMore' : 'Separator.ShowLess';
intlElement.update();
@ -1194,7 +1194,7 @@ export default class AppSearchSuper {
if(!this.membersList) {
this.membersList = new SortedUserList({lazyLoadQueue: this.lazyLoadQueue, rippleEnabled: false});
this.membersList.list.addEventListener('click', (e) => {
attachClickEvent(this.membersList.list, (e) => {
const li = findUpTag(e.target, 'LI');
if(!li) {
return;

View File

@ -25,6 +25,7 @@ import debounce from "../helpers/schedulers/debounce";
import windowSize from "../helpers/windowSize";
import appPeersManager, { IsPeerType } from "../lib/appManagers/appPeersManager";
import { generateDelimiter, SettingSection } from "./sidebarLeft";
import { attachClickEvent } from "../helpers/dom/clickEvent";
type SelectSearchPeerType = 'contacts' | 'dialogs' | 'channelParticipants';
@ -157,7 +158,7 @@ export default class AppSelectPeers {
// let delimiter = document.createElement('hr');
this.selectedContainer.addEventListener('click', (e) => {
attachClickEvent(this.selectedContainer, (e) => {
if(this.freezed) return;
let target = e.target as HTMLElement;
target = findUpClassName(target, 'selector-user');
@ -188,7 +189,7 @@ export default class AppSelectPeers {
this.scrollable = new Scrollable(this.chatsContainer);
this.scrollable.setVirtualContainer(this.list);
this.chatsContainer.addEventListener('click', (e) => {
attachClickEvent(this.chatsContainer, (e) => {
const target = findUpAttribute(e.target, 'data-peer-id') as HTMLElement;
cancelEvent(e);

View File

@ -5,6 +5,7 @@
*/
import type { CancellablePromise } from "../helpers/cancellablePromise";
import { attachClickEvent } from "../helpers/dom/clickEvent";
import type { InputFile } from "../layer";
import PopupAvatar from "./popups/avatar";
@ -25,7 +26,7 @@ export default class AvatarEdit {
this.container.append(this.canvas, this.icon);
this.container.addEventListener('click', () => {
attachClickEvent(this.container, () => {
new PopupAvatar().open(this.canvas, onChange);
});
}

View File

@ -23,7 +23,7 @@ const ButtonMenuToggle = (options: Partial<{noRipple: true, onlyMobile: true, li
};
// TODO: refactor for attachClickEvent, because if move finger after touchstart, it will start anyway
const ButtonMenuToggleHandler = (el: HTMLElement, onOpen?: (e: Event) => void, options?: AttachClickOptions) => {
const ButtonMenuToggleHandler = (el: HTMLElement, onOpen?: (e: Event) => void, options?: AttachClickOptions, onClose?: () => void) => {
const add = options?.listenerSetter ? options.listenerSetter.add(el) : el.addEventListener.bind(el);
//console.trace('ButtonMenuToggleHandler attach', el, onOpen, options);
@ -39,7 +39,7 @@ const ButtonMenuToggleHandler = (el: HTMLElement, onOpen?: (e: Event) => void, o
closeBtnMenu();
} else {
onOpen && onOpen(e);
openBtnMenu(openedMenu);
openBtnMenu(openedMenu, onClose);
}
});
};

View File

@ -522,9 +522,6 @@ export default class ChatBubbles {
});
});
// attachClickEvent(this.bubblesContainer, this.onBubblesClick, {listenerSetter: this.listenerSetter});
this.listenerSetter.add(this.bubblesContainer)('click', this.onBubblesClick/* , {capture: true, passive: false} */);
if(IS_TOUCH_SUPPORTED) {
const className = 'is-gesturing-reply';
const MAX = 64;
@ -593,6 +590,9 @@ export default class ChatBubbles {
});
}
attachClickEvent(this.bubblesContainer, this.onBubblesClick, {listenerSetter: this.listenerSetter});
// this.listenerSetter.add(this.bubblesContainer)('click', this.onBubblesClick/* , {capture: true, passive: false} */);
if(DEBUG) {
this.listenerSetter.add(this.bubblesContainer)('dblclick', (e) => {
const bubble = findUpClassName(e.target, 'grouped-item') || findUpClassName(e.target, 'bubble');

View File

@ -42,6 +42,7 @@ import AppPrivateSearchTab from "../sidebarRight/tabs/search";
import renderImageFromUrl from "../../helpers/dom/renderImageFromUrl";
import mediaSizes from "../../helpers/mediaSizes";
import ChatSearch from "./search";
import { IS_TOUCH_SUPPORTED } from "../../environment/touchSupport";
export type ChatType = 'chat' | 'pinned' | 'replies' | 'discussion' | 'scheduled';
@ -216,7 +217,7 @@ export default class Chat extends EventListenerBase<{
this.input.constructPeerHelpers();
}
if(this.type !== 'scheduled') {
if(this.type !== 'scheduled' && !IS_TOUCH_SUPPORTED) {
this.bubbles.setReactionsHoverListeners();
}

View File

@ -18,6 +18,7 @@ import sessionStorage from '../lib/sessionStorage';
import { ConnectionStatus } from "../lib/mtproto/connectionStatus";
import { cancelEvent } from "../helpers/dom/cancelEvent";
import apiManager from "../lib/mtproto/mtprotoworker";
import { attachClickEvent } from "../helpers/dom/clickEvent";
export default class ConnectionStatusComponent {
public static CHANGE_STATE_DELAY = 1000;
@ -133,7 +134,7 @@ export default class ConnectionStatusComponent {
const a = document.createElement('a');
a.classList.add('force-reconnect');
a.append(i18n(langPackKey));
a.addEventListener('click', (e) => {
attachClickEvent(a, (e) => {
cancelEvent(e);
callback();
});

View File

@ -45,7 +45,7 @@ export function attachClickEvent(elem: HTMLElement | Window, callback: (e: /* To
add(CLICK_EVENT_NAME, callback, options);
}
export function detachClickEvent(elem: HTMLElement, callback: (e: TouchEvent | MouseEvent) => void, options?: AddEventListenerOptions) {
export function detachClickEvent(elem: HTMLElement, callback: (e: /* TouchEvent | */MouseEvent) => void, options?: AddEventListenerOptions) {
// if(CLICK_EVENT_NAME === 'touchend') {
// elem.removeEventListener('touchstart', callback, options);
// } else {

View File

@ -20,6 +20,7 @@ export default class ControlsHover extends EventListenerBase<{
protected element: HTMLElement;
protected listenerSetter: ListenerSetter;
protected showOnLeaveToClassName: string;
protected ignoreClickClassName: string;
constructor() {
super(false);
@ -30,14 +31,19 @@ export default class ControlsHover extends EventListenerBase<{
element: HTMLElement,
listenerSetter: ListenerSetter,
canHideControls?: () => boolean,
showOnLeaveToClassName?: string
showOnLeaveToClassName?: string,
ignoreClickClassName?: string
}) {
safeAssign(this, options);
const {listenerSetter, element} = this;
if(IS_TOUCH_SUPPORTED) {
listenerSetter.add(element)('click', () => {
listenerSetter.add(element)('click', (e) => {
if(this.ignoreClickClassName && findUpClassName(e.target, this.ignoreClickClassName)) {
return;
}
this.toggleControls();
});

View File

@ -266,6 +266,7 @@ export default class VideoPlayer extends ControlsHover {
private static PLAYBACK_RATES = [0.5, 1, 1.5, 2];
private static PLAYBACK_RATES_ICONS = ['playback_05', 'playback_1x', 'playback_15', 'playback_2x'];
protected video: HTMLVideoElement;
protected wrapper: HTMLDivElement;
protected progress: MediaProgressLine;
protected skin: 'default';
@ -276,12 +277,23 @@ export default class VideoPlayer extends ControlsHover {
/* protected videoParent: HTMLElement;
protected videoWhichChild: number; */
constructor(protected video: HTMLVideoElement, play = false, streamable = false, duration?: number) {
protected onPlaybackRackMenuToggle?: (open: boolean) => void;
constructor({video, play = false, streamable = false, duration, onPlaybackRackMenuToggle}: {
video: HTMLVideoElement,
play?: boolean,
streamable?: boolean,
duration?: number,
onPlaybackRackMenuToggle?: (open: boolean) => void
}) {
super();
this.video = video;
this.wrapper = document.createElement('div');
this.wrapper.classList.add('ckin__player');
this.onPlaybackRackMenuToggle = onPlaybackRackMenuToggle;
this.listenerSetter = new ListenerSetter();
this.setup({
@ -290,7 +302,8 @@ export default class VideoPlayer extends ControlsHover {
canHideControls: () => {
return !this.video.paused && (!this.playbackRateButton || !this.playbackRateButton.classList.contains('menu-open'));
},
showOnLeaveToClassName: 'media-viewer-caption'
showOnLeaveToClassName: 'media-viewer-caption',
ignoreClickClassName: 'ckin__controls'
});
video.parentNode.insertBefore(this.wrapper, video);
@ -423,9 +436,11 @@ export default class VideoPlayer extends ControlsHover {
listenerSetter.add(video)('play', () => {
wrapper.classList.add('played');
if(!IS_TOUCH_SUPPORTED) {
listenerSetter.add(video)('play', () => {
this.hideControls(true);
});
}
}, {once: true});
listenerSetter.add(video)('pause', () => {
@ -495,7 +510,16 @@ export default class VideoPlayer extends ControlsHover {
});
const btnMenu = ButtonMenu(buttons);
btnMenu.classList.add('top-left');
ButtonMenuToggleHandler(this.playbackRateButton);
ButtonMenuToggleHandler(
this.playbackRateButton,
this.onPlaybackRackMenuToggle ? () => {
this.onPlaybackRackMenuToggle(true);
} : undefined,
undefined,
this.onPlaybackRackMenuToggle ? () => {
this.onPlaybackRackMenuToggle(false);
} : undefined
);
this.playbackRateButton.append(btnMenu);
this.setPlaybackRateIcon();
@ -572,5 +596,6 @@ export default class VideoPlayer extends ControlsHover {
super.cleanup();
this.listenerSetter.removeAll();
this.progress.removeListeners();
this.onPlaybackRackMenuToggle = undefined;
}
}

View File

@ -92,7 +92,10 @@
left: 50%;
transform: translate3d(-50%, -50%, 0) scale(1);
font-size: 4rem;
@include respond-to(not-handhelds) {
pointer-events: none;
}
@include animation-level(2) {
transition: visibility var(--layer-transition), opacity var(--layer-transition);

View File

@ -533,7 +533,7 @@ $inactive-opacity: .4;
transition: opacity var(--open-duration) 0s, visibility 0s var(--open-duration);
} */
.btn-menu-toggle {
.btn-menu-toggle:not(.playback-rate) {
color: rgba(255, 255, 255, $inactive-opacity);
opacity: 1;
@ -542,6 +542,13 @@ $inactive-opacity: .4;
background-color: rgba(112, 117, 121, .2) !important;
}
}
&.hide-caption {
.media-viewer-caption {
opacity: 0 !important;
pointer-events: none;
}
}
}
&.highlight-switchers {

View File

@ -44,7 +44,7 @@
&.has-animation {
> .media-sticker {
visibility: hidden;
opacity: 0;
}
}