diff --git a/res/css/views/settings/tabs/user/_KeyboardUserSettingsTab.scss b/res/css/views/settings/tabs/user/_KeyboardUserSettingsTab.scss index 1ba3a8599b8..c7251826750 100644 --- a/res/css/views/settings/tabs/user/_KeyboardUserSettingsTab.scss +++ b/res/css/views/settings/tabs/user/_KeyboardUserSettingsTab.scss @@ -18,7 +18,16 @@ limitations under the License. .mx_KeyboardUserSettingsTab .mx_SettingsTab_section { .mx_KeyboardShortcut_shortcutRow { display: flex; - justify-content: space-between; align-items: center; + + .mx_KeyboardShortcut_shortcutRow_displayName { + margin-right: auto; + } + + .mx_AccessibleButton { + margin: 0 4px; + } + + margin: 4px 0; } } diff --git a/src/components/views/settings/tabs/user/ChangeKeyboardShortcutDialog.tsx b/src/components/views/settings/tabs/user/ChangeKeyboardShortcutDialog.tsx new file mode 100644 index 00000000000..2c22c1bce97 --- /dev/null +++ b/src/components/views/settings/tabs/user/ChangeKeyboardShortcutDialog.tsx @@ -0,0 +1,80 @@ +/* +Copyright 2022 Šimon Brandner + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { KeyboardEvent, useState } from "react"; + +import { KeyCombo } from "../../../../../KeyBindingsManager"; +import { Key } from "../../../../../Keyboard"; +import { _t } from "../../../../../languageHandler"; +import BaseDialog from "../../../dialogs/BaseDialog"; +import { IDialogProps } from "../../../dialogs/IDialogProps"; +import DialogButtons from "../../../elements/DialogButtons"; +import KeyboardShortcut from "../../KeyboardShortcut"; + +const eventIntoKeyCombo = (event: KeyboardEvent): KeyCombo | null => { + const hasModifier = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; + const isKeyAModifier = [Key.ALT, Key.CONTROL, Key.META, Key.SHIFT].includes(event.key); + // Don't allow KeyCombos without modifiers + if (!hasModifier) return null; + // Don't allow KeyCombos without a key pressed + if (isKeyAModifier || !event.key) return null; + + return { + key: event.key, + altKey: event.altKey, + ctrlKey: event.ctrlKey, + metaKey: event.metaKey, + shiftKey: event.shiftKey, + }; +}; + +export interface IProps extends IDialogProps { + value: KeyCombo; +} + +export const ChangeKeyboardShortcutDialog: React.FC = ({ onFinished, value }) => { + const [currentValue, setValue] = useState(value); + + const onDialogFinished = () => { + onFinished(currentValue); + }; + + const onKeyDown = (event: KeyboardEvent): void => { + event.preventDefault(); + event.stopPropagation(); + + const key = event.key; + if (!key) return; + + setValue(eventIntoKeyCombo(event)); + }; + + const onCancel = (): void => { + onFinished(null); + }; + + const onPrimaryButtonClick = (): void => { + if (!currentValue) return; + onFinished(currentValue); + }; + + return + + + ; +}; + +export default ChangeKeyboardShortcutDialog; diff --git a/src/components/views/settings/tabs/user/KeyboardUserSettingsTab.tsx b/src/components/views/settings/tabs/user/KeyboardUserSettingsTab.tsx index 0327e07ccc8..aaadac2b21d 100644 --- a/src/components/views/settings/tabs/user/KeyboardUserSettingsTab.tsx +++ b/src/components/views/settings/tabs/user/KeyboardUserSettingsTab.tsx @@ -25,41 +25,80 @@ import { import SdkConfig from "../../../../../SdkConfig"; import { _t } from "../../../../../languageHandler"; import { - getKeyboardShortcutDisplayName, getKeyboardShortcutValue, + getKeyboardShortcutDisplayName, + getKeyboardShortcutHideEditUI, + getKeyboardShortcutValue, } from "../../../../../accessibility/KeyboardShortcutUtils"; import { KeyboardShortcut } from "../../KeyboardShortcut"; +import AccessibleButton from "../../../elements/AccessibleButton"; +import SettingsStore from "../../../../../settings/SettingsStore"; +import { SettingLevel } from "../../../../../settings/SettingLevel"; +import Modal from "../../../../../Modal"; +import { + ChangeKeyboardShortcutDialog, + IProps as IChangeKeyboardShortcutDialogProps, +} from "./ChangeKeyboardShortcutDialog"; interface IKeyboardShortcutRowProps { name: string; + allowCustomization: boolean; } // Filter out the labs section if labs aren't enabled. const visibleCategories = Object.entries(CATEGORIES).filter(([categoryName]) => categoryName !== CategoryName.LABS || SdkConfig.get("show_labs_settings")); -const KeyboardShortcutRow: React.FC = ({ name }) => { +const KeyboardShortcutRow: React.FC = ({ name, allowCustomization }) => { const displayName = getKeyboardShortcutDisplayName(name); + const hideEditUI = getKeyboardShortcutHideEditUI(name); const value = getKeyboardShortcutValue(name); if (!displayName || !value) return null; + const onEditClick = async (): Promise => { + const { finished } = Modal.createDialog(ChangeKeyboardShortcutDialog, { + value, + } as IChangeKeyboardShortcutDialogProps); + const [newValue] = await finished; + if (!newValue) return; + + //SettingsStore.setValue(name, null, SettingLevel.DEVICE, newValue); + }; + + const onResetClick = (): void => { + SettingsStore.setValue(name, null, SettingLevel.DEVICE, SettingsStore.getDefaultValue(name)); + }; + return
- { displayName } +
+ { displayName } +
+ { allowCustomization && + { _t("Edit") } + { _t("Reset") } + }
; }; interface IKeyboardShortcutSectionProps { categoryName: CategoryName; category: ICategory; + allowCustomization: boolean; } -const KeyboardShortcutSection: React.FC = ({ categoryName, category }) => { +const KeyboardShortcutSection: React.FC = ( + { categoryName, category, allowCustomization }, +) => { if (!category.categoryLabel) return null; return
{ _t(category.categoryLabel) }
{ category.settingNames.map((shortcutName) => { - return ; + return ; }) }
; }; @@ -68,7 +107,12 @@ const KeyboardUserSettingsTab: React.FC = () => { return
{ _t("Keyboard") }
{ visibleCategories.map(([categoryName, category]: [CategoryName, ICategory]) => { - return ; + return ; }) }
; };