Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

[Labs] Refresh UI for keybindings and prep for customisable keybindings #5758

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
72e5226
Add labs keybinding setting
SimonBrandner Mar 5, 2021
cd17a45
Convert Key into an enum
SimonBrandner Mar 5, 2021
8a5fd95
Add Modifiers
SimonBrandner Mar 5, 2021
f62f423
Add styling for KeyboardShortcut
SimonBrandner Mar 5, 2021
66c935f
Use styling for KeyboardShortcut
SimonBrandner Mar 5, 2021
01b3e71
AddKeyboardShortcut
SimonBrandner Mar 5, 2021
b8bc251
Add keyboard icon
SimonBrandner Mar 5, 2021
e5f5001
Merge remote-tracking branch 'czeidler/key-bindings' into new-keybind…
SimonBrandner Mar 12, 2021
0306365
Merge branch 'develop' into new-keybinding-ui
SimonBrandner Mar 12, 2021
dbfbce5
Add styling for KeybindingUserSettingsTab
SimonBrandner Mar 13, 2021
93f3f06
Add keybinding settings
SimonBrandner Mar 13, 2021
f3707dd
Add KeybindingsUserSettingsTab
SimonBrandner Mar 13, 2021
5165113
Use KeybindingsUserSettingsTab
SimonBrandner Mar 13, 2021
fe6771b
Credit Material design icons
SimonBrandner Mar 13, 2021
f734caa
i18n
SimonBrandner Mar 13, 2021
77cb01d
Add missing newline
SimonBrandner Mar 13, 2021
74ce690
Merge branch 'develop' into new-keybinding-ui
SimonBrandner Mar 26, 2021
6aa6d0c
Don't export Keybinding
SimonBrandner Mar 26, 2021
f400208
British spelling
SimonBrandner Apr 9, 2021
c0faa20
Remove unnecessary CSS
SimonBrandner Apr 9, 2021
85b63ff
i18n
SimonBrandner Apr 9, 2021
94d97a0
Rework KeyboardShortcut
SimonBrandner Apr 9, 2021
d8c59be
Use Map instead of Record so that we can use Key
SimonBrandner Apr 13, 2021
c261a3c
Merge branch 'develop' into new-keybinding-ui
SimonBrandner Apr 13, 2021
31c33e5
Make private
SimonBrandner Apr 13, 2021
0536b47
Merge branch 'develop' into new-keybinding-ui
SimonBrandner May 22, 2021
a97ee2c
Fix indent
SimonBrandner May 22, 2021
615c020
i18n
SimonBrandner May 22, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions res/css/_components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
@import "./views/dialogs/_WidgetCapabilitiesPromptDialog.scss";
@import "./views/dialogs/_WidgetOpenIDPermissionsDialog.scss";
@import "./views/dialogs/security/_AccessSecretStorageDialog.scss";
@import "./views/elements/_KeyboardShortcut.scss";
@import "./views/dialogs/security/_CreateCrossSigningDialog.scss";
@import "./views/dialogs/security/_CreateKeyBackupDialog.scss";
@import "./views/dialogs/security/_CreateSecretStorageDialog.scss";
Expand Down Expand Up @@ -240,6 +241,7 @@
@import "./views/settings/tabs/user/_AppearanceUserSettingsTab.scss";
@import "./views/settings/tabs/user/_GeneralUserSettingsTab.scss";
@import "./views/settings/tabs/user/_HelpUserSettingsTab.scss";
@import "./views/settings/tabs/user/_KeybindingsUserSettingsTab.scss";
@import "./views/settings/tabs/user/_LabsUserSettingsTab.scss";
@import "./views/settings/tabs/user/_MjolnirUserSettingsTab.scss";
@import "./views/settings/tabs/user/_NotificationUserSettingsTab.scss";
Expand Down
4 changes: 4 additions & 0 deletions res/css/views/dialogs/_UserSettingsDialog.scss
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/settings/help.svg');
}

.mx_UserSettingsDialog_keyboardIcon::before {
mask-image: url('$(res)/img/element-icons/settings/keyboard.svg');
}

.mx_UserSettingsDialog_labsIcon::before {
mask-image: url('$(res)/img/element-icons/settings/lab-flags.svg');
}
Expand Down
35 changes: 35 additions & 0 deletions res/css/views/elements/_KeyboardShortcut.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>

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.
*/

.mx_KeyboardShortcut {
.mx_KeyboardShortcut_key {
padding: 5px;
border-radius: 4px;
background-color: $reaction-row-button-bg-color;
margin-right: 5px;
min-width: 20px;
text-align: center;
display: inline-block;
border: 1px solid $kbd-border-color;
box-shadow: 0 2px $kbd-border-color;
margin-bottom: 4px;
text-transform: capitalize;

& + kbd {
margin-left: 5px;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>

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.
*/

.mx_KeybindingUserSettingsTab {
.mx_SettingsTab_section {
margin-bottom: 30px;
}

.mx_KeybindingUserSettingsTab_keybind {
display: flex;
justify-content: space-between;
align-items: center;
padding-bottom: 3px;


.mx_KeybindingUserSettingsTab_keybind_buttons {
display: flex;
align-items: center;
}
}
}
1 change: 1 addition & 0 deletions res/img/element-icons/settings/keyboard.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
115 changes: 60 additions & 55 deletions src/Keyboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,62 +16,67 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

export const Key = {
HOME: "Home",
END: "End",
PAGE_UP: "PageUp",
PAGE_DOWN: "PageDown",
BACKSPACE: "Backspace",
DELETE: "Delete",
ARROW_UP: "ArrowUp",
ARROW_DOWN: "ArrowDown",
ARROW_LEFT: "ArrowLeft",
ARROW_RIGHT: "ArrowRight",
TAB: "Tab",
ESCAPE: "Escape",
ENTER: "Enter",
ALT: "Alt",
CONTROL: "Control",
META: "Meta",
SHIFT: "Shift",
CONTEXT_MENU: "ContextMenu",
export enum Key {
HOME = "Home",
END = "End",
PAGE_UP = "PageUp",
PAGE_DOWN = "PageDown",
BACKSPACE = "Backspace",
DELETE = "Delete",
ARROW_UP = "ArrowUp",
ARROW_DOWN = "ArrowDown",
ARROW_LEFT = "ArrowLeft",
ARROW_RIGHT = "ArrowRight",
TAB = "Tab",
ESCAPE = "Escape",
ENTER = "Enter",
ALT = "Alt",
CONTROL = "Control",
META = "Meta",
SHIFT = "Shift",
CONTEXT_MENU = "ContextMenu",

COMMA: ",",
PERIOD: ".",
LESS_THAN: "<",
GREATER_THAN: ">",
BACKTICK: "`",
SPACE: " ",
SLASH: "/",
SQUARE_BRACKET_LEFT: "[",
SQUARE_BRACKET_RIGHT: "]",
A: "a",
B: "b",
C: "c",
D: "d",
E: "e",
F: "f",
G: "g",
H: "h",
I: "i",
J: "j",
K: "k",
L: "l",
M: "m",
N: "n",
O: "o",
P: "p",
Q: "q",
R: "r",
S: "s",
T: "t",
U: "u",
V: "v",
W: "w",
X: "x",
Y: "y",
Z: "z",
};
COMMA = ",",
PERIOD = ".",
LESS_THAN = "<",
GREATER_THAN = ">",
BACKTICK = "`",
SPACE = " ",
SLASH = "/",
SQUARE_BRACKET_LEFT = "[",
SQUARE_BRACKET_RIGHT = "]",
A = "a",
B = "b",
C = "c",
D = "d",
E = "e",
F = "f",
G = "g",
H = "h",
I = "i",
J = "j",
K = "k",
L = "l",
M = "m",
N = "n",
O = "o",
P = "p",
Q = "q",
R = "r",
S = "s",
T = "t",
U = "u",
V = "v",
W = "w",
X = "x",
Y = "y",
Z = "z",
}

/**
* An array of modifiers
*/
export const Modifiers = ["Control", "Meta", "Shift", "Alt"];

export const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;

Expand Down
12 changes: 11 additions & 1 deletion src/components/structures/LoggedInView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ import { getKeyBindingsManager, NavigationAction, RoomAction } from '../../KeyBi
import { IOpts } from "../../createRoom";
import SpacePanel from "../views/spaces/SpacePanel";
import {replaceableComponent} from "../../utils/replaceableComponent";
import { USER_KEYBINDINGS_TAB } from "../views/dialogs/UserSettingsDialog"
import { OpenToTabPayload } from "../../dispatcher/payloads/OpenToTabPayload";
import CallHandler, { CallHandlerEvent } from '../../CallHandler';
import { MatrixCall } from 'matrix-js-sdk/src/webrtc/call';
import AudioFeedArrayForCall from '../views/voip/AudioFeedArrayForCall';
Expand Down Expand Up @@ -477,7 +479,15 @@ class LoggedInView extends React.Component<IProps, IState> {
handled = true;
break;
case NavigationAction.ToggleShortCutDialog:
KeyboardShortcuts.toggleDialog();
if (SettingsStore.getValue("feature_keybindings")) {
const payload: OpenToTabPayload = {
action: Action.ViewUserSettings,
initialTabId: USER_KEYBINDINGS_TAB,
};
dis.dispatch(payload);
} else {
KeyboardShortcuts.toggleDialog();
}
handled = true;
break;
case NavigationAction.GoToHome:
Expand Down
10 changes: 10 additions & 0 deletions src/components/views/dialogs/UserSettingsDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import AppearanceUserSettingsTab from "../settings/tabs/user/AppearanceUserSetti
import SecurityUserSettingsTab from "../settings/tabs/user/SecurityUserSettingsTab";
import NotificationUserSettingsTab from "../settings/tabs/user/NotificationUserSettingsTab";
import PreferencesUserSettingsTab from "../settings/tabs/user/PreferencesUserSettingsTab";
import KeybindingsUserSettingsTab from "../settings/tabs/user/KeybindingsUserSettingsTab";
import VoiceUserSettingsTab from "../settings/tabs/user/VoiceUserSettingsTab";
import HelpUserSettingsTab from "../settings/tabs/user/HelpUserSettingsTab";
import FlairUserSettingsTab from "../settings/tabs/user/FlairUserSettingsTab";
Expand All @@ -40,6 +41,7 @@ export const USER_APPEARANCE_TAB = "USER_APPEARANCE_TAB";
export const USER_FLAIR_TAB = "USER_FLAIR_TAB";
export const USER_NOTIFICATIONS_TAB = "USER_NOTIFICATIONS_TAB";
export const USER_PREFERENCES_TAB = "USER_PREFERENCES_TAB";
export const USER_KEYBINDINGS_TAB = "USER_KEYBINDINGS_TAB";
export const USER_VOICE_TAB = "USER_VOICE_TAB";
export const USER_SECURITY_TAB = "USER_SECURITY_TAB";
export const USER_LABS_TAB = "USER_LABS_TAB";
Expand Down Expand Up @@ -110,6 +112,14 @@ export default class UserSettingsDialog extends React.Component {
<PreferencesUserSettingsTab />,
));

if (SettingsStore.getValue("feature_keybindings")) {
germain-gg marked this conversation as resolved.
Show resolved Hide resolved
tabs.push(new Tab(
USER_KEYBINDINGS_TAB,
_td("Keybindings"),
"mx_UserSettingsDialog_keyboardIcon",
<KeybindingsUserSettingsTab />,
));
}
if (SettingsStore.getValue(UIFeature.Voip)) {
tabs.push(new Tab(
USER_VOICE_TAB,
Expand Down
112 changes: 112 additions & 0 deletions src/components/views/elements/KeyboardShortcut.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
Copyright 2021 Šimon Brandner <simon.bra.ag@gmail.com>

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 * as React from "react";
import { _td } from "../../../languageHandler";
import {isMac, Key, Modifiers} from "../../../Keyboard";
import {KeyCombo} from "../../../KeyBindingsManager";

const keyName: Map<Key, string> = new Map([
[Key.PAGE_UP, _td("Page Up")],
[Key.PAGE_DOWN, _td("Page Down")],
[Key.ESCAPE, _td("Esc")],
[Key.ENTER, _td("Enter")],
[Key.SPACE, _td("Space")],
[Key.HOME, _td("Home")],
[Key.END, _td("End")],
[Key.ALT, _td("Alt")],
[Key.CONTROL, _td("Ctrl")],
[Key.SHIFT, _td("Shift")],
]);

const keyIcon: Map<Key, string> = new Map([
[Key.ARROW_UP, "↑"],
[Key.ARROW_DOWN, "↓"],
[Key.ARROW_LEFT, "←"],
[Key.ARROW_RIGHT, "→"],
]);

if (isMac) {
keyIcon[Key.META] = "⌘";
keyIcon[Key.SHIFT] = "⌥";
}

interface IProps {
keyCombo: KeyCombo | KeyboardEvent;
}

function keyDisplayValue(key: string | Key) {
const newKey = Key[key] || key;
return keyIcon.get(newKey) || keyName.get(newKey) || newKey;
}

export default class KeyboardShortcut extends React.Component<IProps> {
private renderKey(key: string, text: string) {
return (
<React.Fragment key={key}>
<kbd className="mx_KeyboardShortcut_key">
{text}
</kbd>+
</React.Fragment>
);
}

render() {
const key = this.props.keyCombo.key;

const modifiersElement = [];
// We have to use hasOwnProperty here, see https://stackoverflow.com/a/43496627/10822785
if (this.props.keyCombo.hasOwnProperty("ctrlOrCmdKey")) {
const text = isMac ? keyDisplayValue(Key.META) : keyDisplayValue(Key.CONTROL);
const key = this.renderKey("ctrlOrCmdKey", text)
modifiersElement.push(key);
} else if (this.props.keyCombo.ctrlKey) {
const text = keyDisplayValue(Key.CONTROL);
const key = this.renderKey("ctrlKey", text)
modifiersElement.push(key);
} else if (this.props.keyCombo.metaKey) {
const text = keyDisplayValue(Key.META);
const key = this.renderKey("metaKey", text)
modifiersElement.push(key);
}
if (this.props.keyCombo.altKey) {
const text = keyDisplayValue(Key.ALT);
const key = this.renderKey("altKey", text)
modifiersElement.push(key);
}
if (this.props.keyCombo.shiftKey) {
const text = keyDisplayValue(Key.SHIFT);
const key = this.renderKey("shiftKey", text)
modifiersElement.push(key);
}

let keyElement;
if (key && !Modifiers.includes(key)) {
keyElement = (
<kbd className="mx_KeyboardShortcut_key">
{ keyDisplayValue(key) }
</kbd>
);
}

return (
<kbd className="mx_KeyboardShortcut">
{modifiersElement}
{keyElement}
</kbd>
);
}
}
Loading