diff --git a/src/components/appNavigationController.ts b/src/components/appNavigationController.ts index cbe8b8a9..97012cde 100644 --- a/src/components/appNavigationController.ts +++ b/src/components/appNavigationController.ts @@ -13,7 +13,7 @@ import { cancelEvent } from "../helpers/dom/cancelEvent"; export type NavigationItem = { type: 'left' | 'right' | 'im' | 'chat' | 'popup' | 'media' | 'menu' | - 'esg' | 'multiselect' | 'input-helper' | 'autocomplete-helper' | 'markup' | 'global-search', + 'esg' | 'multiselect' | 'input-helper' | 'autocomplete-helper' | 'markup' | 'global-search' | 'voice', onPop: (canAnimate: boolean) => boolean | void, onEscape?: () => boolean, noHistory?: boolean, diff --git a/src/components/chat/input.ts b/src/components/chat/input.ts index 3c10601f..7fb74432 100644 --- a/src/components/chat/input.ts +++ b/src/components/chat/input.ts @@ -43,7 +43,7 @@ import SendMenu from './sendContextMenu'; import rootScope from '../../lib/rootScope'; import PopupPinMessage from '../popups/unpinMessage'; import { tsNow } from '../../helpers/date'; -import appNavigationController from '../appNavigationController'; +import appNavigationController, { NavigationItem } from '../appNavigationController'; import { isMobile, isMobileSafari } from '../../helpers/userAgent'; import I18n, { i18n, join, LangPackKey } from '../../lib/langPack'; import { generateTail } from './bubbles'; @@ -132,6 +132,8 @@ export default class ChatInput { private recordTimeEl: HTMLElement; private recordRippleEl: HTMLElement; private recordStartTime = 0; + private recordingOverlayListener: Listener; + private recordingNavigationItem: NavigationItem; // private scrollTop = 0; // private scrollOffsetTop = 0; @@ -174,8 +176,6 @@ export default class ChatInput { private previousQuery: string; - private recordingOverlayListener: Listener; - constructor(private chat: Chat, private appMessagesManager: AppMessagesManager, private appMessagesIdsManager: AppMessagesIdsManager, @@ -583,6 +583,11 @@ export default class ChatInput { this.recordingOverlayListener = undefined; } + if(this.recordingNavigationItem) { + appNavigationController.removeItem(this.recordingNavigationItem); + this.recordingNavigationItem = undefined; + } + if(this.recordCanceled) { return; } @@ -1460,26 +1465,41 @@ export default class ChatInput { this.recording = true; this.updateSendBtn(); opusDecodeController.setKeepAlive(true); + + const showDiscardPopup = () => { + new PopupPeer('popup-cancel-record', { + titleLangKey: 'DiscardVoiceMessageTitle', + descriptionLangKey: 'DiscardVoiceMessageDescription', + buttons: [{ + langKey: 'DiscardVoiceMessageAction', + callback: () => { + simulateClickEvent(this.btnCancelRecord); + } + }, { + langKey: 'Continue', + isCancel: true + }] + }).show(); + }; this.recordingOverlayListener = this.listenerSetter.add(document.body)('mousedown', (e) => { if(!findUpClassName(e.target, 'chat-input') && !findUpClassName(e.target, 'popup-cancel-record')) { cancelEvent(e); - new PopupPeer('popup-cancel-record', { - titleLangKey: 'DiscardVoiceMessageTitle', - descriptionLangKey: 'DiscardVoiceMessageDescription', - buttons: [{ - langKey: 'DiscardVoiceMessageAction', - callback: () => { - simulateClickEvent(this.btnCancelRecord); - } - }, { - langKey: 'Continue', - isCancel: true - }] - }).show(); + showDiscardPopup(); } }, {capture: true, passive: false}) as any; + appNavigationController.pushItem(this.recordingNavigationItem = { + type: 'voice', + onPop: () => { + setTimeout(() => { + showDiscardPopup(); + }, 0); + + return false; + } + }); + this.recordStartTime = Date.now(); const sourceNode: MediaStreamAudioSourceNode = this.recorder.sourceNode; diff --git a/src/components/chat/selection.ts b/src/components/chat/selection.ts index 76a8f953..6b2cbf7f 100644 --- a/src/components/chat/selection.ts +++ b/src/components/chat/selection.ts @@ -64,6 +64,7 @@ class AppSelection { protected getElementFromTarget: (target: HTMLElement) => HTMLElement; protected verifyTarget: (e: MouseEvent, target: HTMLElement) => boolean; protected verifyMouseMoveTarget: (e: MouseEvent, element: HTMLElement, selecting: boolean) => boolean; + protected verifyTouchLongPress: () => boolean; protected targetLookupClassName: string; protected lookupBetweenParentClassName: string; protected lookupBetweenElementsQuery: string; @@ -75,6 +76,7 @@ class AppSelection { getElementFromTarget: AppSelection['getElementFromTarget'], verifyTarget?: AppSelection['verifyTarget'], verifyMouseMoveTarget?: AppSelection['verifyMouseMoveTarget'], + verifyTouchLongPress?: AppSelection['verifyTouchLongPress'], targetLookupClassName: string, lookupBetweenParentClassName: string, lookupBetweenElementsQuery: string @@ -90,7 +92,7 @@ class AppSelection { }); attachContextMenuListener(this.listenElement, (e) => { - if(this.isSelecting) return; + if(this.isSelecting || (this.verifyTouchLongPress && !this.verifyTouchLongPress())) return; // * these two lines will fix instant text selection on iOS Safari document.body.classList.add('no-select'); // * need no-select on body because chat-input transforms in channels @@ -685,6 +687,7 @@ export default class ChatSelection extends AppSelection { !this.selectedMids.size; return !bad; }, + verifyTouchLongPress: () => !this.chat.input.recording, targetLookupClassName: 'bubble', lookupBetweenParentClassName: 'bubbles-inner', lookupBetweenElementsQuery: '.bubble:not(.is-multiple-documents), .grouped-item'