diff --git a/ts/background.ts b/ts/background.ts index 82755ff3926..d1412ea62c1 100644 --- a/ts/background.ts +++ b/ts/background.ts @@ -1565,18 +1565,7 @@ export async function startApp(): Promise { // Send in expanded composer - handled by component // Attach file - if ( - conversation && - commandOrCtrl && - !shiftKey && - (key === 'u' || key === 'U') - ) { - conversation.trigger('attach-file'); - - event.preventDefault(); - event.stopPropagation(); - return; - } + // hooks/useKeyboardShorcuts useAttachFileShortcut // Remove draft link preview if ( diff --git a/ts/components/CompositionArea.tsx b/ts/components/CompositionArea.tsx index 80969d837c6..acc74335a77 100644 --- a/ts/components/CompositionArea.tsx +++ b/ts/components/CompositionArea.tsx @@ -50,6 +50,10 @@ import { MediaQualitySelector } from './MediaQualitySelector'; import { Quote, Props as QuoteProps } from './conversation/Quote'; import { StagedLinkPreview } from './conversation/StagedLinkPreview'; import { countStickers } from './stickers/lib'; +import { + useAttachFileShortcut, + useKeyboardShortcuts, +} from '../hooks/useKeyboardShortcuts'; export type CompositionAPIType = | { @@ -269,7 +273,7 @@ export const CompositionArea = ({ [draftAttachments, onSendMessage, setLarge] ); - const launchAttachmentPicker = () => { + const launchAttachmentPicker = useCallback(() => { const fileInput = fileInputRef.current; if (fileInput) { // Setting the value to empty so that onChange always fires in case @@ -277,7 +281,10 @@ export const CompositionArea = ({ fileInput.value = ''; fileInput.click(); } - }; + }, []); + + const attachFileShortcut = useAttachFileShortcut(launchAttachmentPicker); + useKeyboardShortcuts(attachFileShortcut); const focusInput = useCallback(() => { if (inputApiRef.current) { diff --git a/ts/components/conversation/AudioCapture.tsx b/ts/components/conversation/AudioCapture.tsx index d7e2e32756b..cc67ba2ce9e 100644 --- a/ts/components/conversation/AudioCapture.tsx +++ b/ts/components/conversation/AudioCapture.tsx @@ -1,7 +1,7 @@ // Copyright 2016-2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import React, { useCallback, useEffect, useMemo, useState } from 'react'; +import React, { useCallback, useEffect, useState } from 'react'; import * as moment from 'moment'; import { noop } from 'lodash'; @@ -13,7 +13,7 @@ import { ToastVoiceNoteLimit } from '../ToastVoiceNoteLimit'; import { ToastVoiceNoteMustBeOnlyAttachment } from '../ToastVoiceNoteMustBeOnlyAttachment'; import { useEscapeHandling } from '../../hooks/useEscapeHandling'; import { - getStartRecordingShortcut, + useStartRecordingShortcut, useKeyboardShortcuts, } from '../../hooks/useKeyboardShortcuts'; @@ -94,10 +94,7 @@ export const AudioCapture = ({ useEscapeHandling(escapeRecording); - const startRecordingShortcut = useMemo(() => { - return getStartRecordingShortcut(startRecording); - }, [startRecording]); - + const startRecordingShortcut = useStartRecordingShortcut(startRecording); useKeyboardShortcuts(startRecordingShortcut); // Update timestamp regularly, then timeout if recording goes over five minutes diff --git a/ts/hooks/useKeyboardShortcuts.tsx b/ts/hooks/useKeyboardShortcuts.tsx index c1fe15bff60..a64b1ae547e 100644 --- a/ts/hooks/useKeyboardShortcuts.tsx +++ b/ts/hooks/useKeyboardShortcuts.tsx @@ -1,7 +1,7 @@ // Copyright 2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { useEffect } from 'react'; +import { useCallback, useEffect } from 'react'; import { get } from 'lodash'; import * as KeyboardLayout from '../services/keyboardLayout'; @@ -15,24 +15,48 @@ function isCmdOrCtrl(ev: KeyboardEvent): boolean { return commandKey || controlKey; } -export function getStartRecordingShortcut( +export function useStartRecordingShortcut( startAudioRecording: () => unknown ): KeyboardShortcutHandlerType { - return ev => { - const { shiftKey } = ev; + return useCallback( + ev => { + const { shiftKey } = ev; + const key = KeyboardLayout.lookup(ev); - const key = KeyboardLayout.lookup(ev); + if (isCmdOrCtrl(ev) && shiftKey && (key === 'v' || key === 'V')) { + ev.preventDefault(); + ev.stopPropagation(); - if (isCmdOrCtrl(ev) && shiftKey && (key === 'v' || key === 'V')) { - startAudioRecording(); - ev.preventDefault(); - ev.stopPropagation(); + startAudioRecording(); + return true; + } - return true; - } + return false; + }, + [startAudioRecording] + ); +} + +export function useAttachFileShortcut( + attachFile: () => unknown +): KeyboardShortcutHandlerType { + return useCallback( + ev => { + const { shiftKey } = ev; + const key = KeyboardLayout.lookup(ev); + + if (isCmdOrCtrl(ev) && !shiftKey && (key === 'u' || key === 'U')) { + ev.preventDefault(); + ev.stopPropagation(); + + attachFile(); + return true; + } - return false; - }; + return false; + }, + [attachFile] + ); } export function useKeyboardShortcuts( diff --git a/ts/views/conversation_view.ts b/ts/views/conversation_view.ts index 42049684ef4..715da3792ce 100644 --- a/ts/views/conversation_view.ts +++ b/ts/views/conversation_view.ts @@ -287,7 +287,6 @@ export class ConversationView extends window.Backbone.View { // These are triggered by background.ts for keyboard handling this.listenTo(this.model, 'focus-composer', this.focusMessageField); this.listenTo(this.model, 'open-all-media', this.showAllMedia); - this.listenTo(this.model, 'attach-file', this.onChooseAttachment); this.listenTo(this.model, 'escape-pressed', this.resetPanel); this.listenTo(this.model, 'show-message-details', this.showMessageDetail); this.listenTo(this.model, 'show-contact-modal', this.showContactModal); @@ -1288,20 +1287,6 @@ export class ConversationView extends window.Backbone.View { }); } - onChooseAttachment(): void { - // TODO: DESKTOP-2425 - this.$('input.file-input').click(); - } - - async onChoseAttachment(): Promise { - const fileField = this.$('input.file-input'); - const files: Array = Array.from(fileField.prop('files')); - - fileField.val([]); - - await this.processAttachments(files); - } - // TODO DESKTOP-2426 async processAttachments(files: Array): Promise { const {