Refactor global shortcuts, simplify debug consoles

- Move out all shortcuts from their central file to the component they
  actually belong to

- Get rid of DebugConsoleLoader and the multiple consoles handling mess,
  have only one global console
This commit is contained in:
miruka 2020-03-28 07:18:00 -04:00
parent af2d5f8cba
commit 1038678a2f
24 changed files with 268 additions and 401 deletions

View File

@ -2,9 +2,6 @@
## Refactoring
- Put keybindings in the components they belong to instead of shoving them
all in one central file
- Rewrite account settings using `HTabbedContainer`
- Get rid of all `currentSpacing` stuff
- Use new default/reset controls system
@ -13,8 +10,6 @@
- Split `HScrollableTextArea` into `HTextArea` and `HScrollView` components
- Refactor `Composer`
- Make sure we don't store any state in delegates
- Drop the `HBox` `buttonModel`/`buttonCallbacks` `HBox` approach,
be more declarative

View File

@ -3,9 +3,6 @@
import QtQuick 2.12
HPage {
focusTarget: column
default property alias columnData: column.data

View File

@ -1,11 +1,9 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import "../ShortcutBundles"
HPage {
focusTarget: column
property alias flickable: flickable
default property alias columnData: column.data
@ -17,6 +15,10 @@ HPage {
contentWidth: parent.width
contentHeight: column.childrenRect.height
FlickShortcuts {
flickable: flickable
}
HColumnLayout {
id: column
width: flickable.width

View File

@ -8,16 +8,10 @@ Page {
rightPadding: leftPadding
background: null
Component.onCompleted:
if (becomeKeyboardFlickableTarget) shortcuts.flickTarget = focusTarget
property int currentSpacing:
Math.min(theme.spacing * width / 400, theme.spacing)
property Item focusTarget: this
property bool becomeKeyboardFlickableTarget: true
Behavior on leftPadding { HNumberAnimation {} }
}

View File

@ -0,0 +1,7 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
QtObject {
default property list<QtObject> data
}

View File

@ -2,10 +2,12 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import "../ShortcutBundles"
SwipeView {
id: swipeView
Component.onCompleted: if (! changed) {
if (becomeKeyboardTabsTarget) shortcuts.tabsTarget = this
setCurrentIndex(window.getState(this, "currentIndex", defaultIndex))
saveEnabled = true
}
@ -20,10 +22,14 @@ SwipeView {
// Prevent onCurrentIndexChanged from running before Component.onCompleted
property bool saveEnabled: false
property bool becomeKeyboardTabsTarget: true
property int defaultIndex: 0
property bool changed: currentIndex !== defaultIndex
function reset() { setCurrentIndex(defaultIndex) }
TabShortcuts {
container: swipeView
}
}

View File

@ -2,8 +2,10 @@
import QtQuick 2.12
import QtQuick.Controls 2.12
import "../ShortcutBundles"
TabBar {
id: tabBar
spacing: 0
position: TabBar.Header
@ -15,4 +17,9 @@ TabBar {
color: theme.controls.tab.bottomLine
}
}
TabShortcuts {
container: tabBar
}
}

View File

@ -16,7 +16,6 @@ HColumnLayout {
HTabBar {
id: tabBar
Component.onCompleted: shortcuts.tabsTarget = this
Layout.fillWidth: true

View File

@ -17,41 +17,7 @@ HDrawer {
z: 9999
position: 0
property Item previouslyFocused: null
property QtObject target: null
property alias t: debugConsole.target
property var history: window.history.console
property alias his: debugConsole.history
property int historyEntry: -1
property int maxHistoryLength: 4096
property string help: qsTr(
`Javascript debugging console
Useful variables:
window, theme, settings, shortcuts, utils, mainUI, pageLoader
py Python interpreter
this The console itself
t Target item to debug for which this console was opened
his History, list of commands entered
Special commands:
.j OBJECT, .json OBJECT Print OBJECT as human-readable JSON
.t, .top Attach the console to the parent window's top
.b, .bottom Attach the console to the parent window's bottom
.l, .left Attach the console to the parent window's left
.r, .right Attach the console to the parent window's right
.h, .help Show this help`.replace(/^ {8}/gm, "")
)
readonly property alias commandsView: commandsView
Component.onCompleted: {
position = 1
onTargetChanged: {
commandsView.model.insert(0, {
input: "t = " + String(target),
output: "",
@ -73,8 +39,41 @@ HDrawer {
historyEntry === -1 ? "" : history.slice(-historyEntry - 1)[0]
function runJS(input) {
if (history.slice(-1)[0] !== input) {
property Item previouslyFocused: null
property QtObject target: null
property alias t: debugConsole.target
property var history: window.history.console
property alias his: debugConsole.history
property int historyEntry: -1
property int maxHistoryLength: 4096
property string help: qsTr(
`Javascript debugging console
Useful variables:
window, theme, settings, utils, mainUI, pageLoader
py Python interpreter
this The console itself
t Target item to debug for which this console was opened
his History, list of commands entered
Special commands:
.j OBJECT, .json OBJECT Print OBJECT as human-readable JSON
.t, .top Attach the console to the parent window's top
.b, .bottom Attach the console to the parent window's bottom
.l, .left Attach the console to the parent window's left
.r, .right Attach the console to the parent window's right
.h, .help Show this help`.replace(/^ {8}/gm, "")
)
readonly property alias commandsView: commandsView
function runJS(input, addToHistory=true) {
if (addToHistory && history.slice(-1)[0] !== input) {
history.push(input)
while (history.length > maxHistoryLength) history.shift()
window.historyChanged()
@ -117,11 +116,14 @@ HDrawer {
}
HShortcut {
sequences: settings.keys.toggleDebugConsole
onActivated: debugConsole.visible = ! debugConsole.visible
}
HColumnLayout {
anchors.fill: parent
Keys.onEscapePressed: debugConsole.visible = false
HListView {
id: commandsView
spacing: theme.spacing

View File

@ -1,43 +0,0 @@
import QtQuick 2.12
import "Base"
HLoader {
id: loader
onLoaded: {
if (! isDefault)
shortcuts.defaultDebugConsoleLoader.active = false
if (shortcuts.debugConsoleLoader)
shortcuts.debugConsoleLoader.active = false
shortcuts.debugConsoleLoader = this
}
onActiveChanged: if (! active) shortcuts.debugConsoleLoader = null
Component.onDestruction: shortcuts.debugConsoleLoader = null
sourceComponent: DebugConsole {
target: loader.target
property HLoader parentLoader: loader
}
property QtObject target: parent
readonly property bool isDefault:
shortcuts.defaultDebugConsoleLoader &&
shortcuts.defaultDebugConsoleLoader === this
function toggle() {
if (! loader.active) {
loader.active = true
return
}
loader.item.visible = ! loader.item.visible
}
}

View File

@ -1,278 +0,0 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import QtQuick.Controls 2.12
import Clipboard 0.1
import "Base"
Item {
visible: false
// Flickable or ListView that should be affected by scroll shortcuts
property Item flickTarget
// A QQC Container that should be affected by tab navigation shortcuts
property Container tabsTarget
// DebugConsoleLoader that should be affected by console shortcuts
property DebugConsoleLoader debugConsoleLoader
// DebugConsoleLoader to activate if no other loader is active and the
// shortcut to bring up a console is pressed
property DebugConsoleLoader defaultDebugConsoleLoader
readonly property DebugConsole debugConsole:
debugConsoleLoader ? debugConsoleLoader.item : null
readonly property DebugConsole defaultDebugConsole:
defaultDebugConsoleLoader ? defaultDebugConsoleLoader.item : null
readonly property Item toFlick:
debugConsole && debugConsole.activeFocus ?
debugConsole.commandsView :
flickTarget
function toggleConsole() {
if (debugConsole) {
debugConsole.visible = ! debugConsole.visible
} else if (! defaultDebugConsoleLoader.active) {
defaultDebugConsoleLoader.active = true
} else {
defaultDebugConsole.visible = ! defaultDebugConsole.visible
}
}
// App
HShortcut {
sequences: settings.keys.startPythonDebugger
onActivated: py.call("BRIDGE.pdb")
}
HShortcut {
sequences: settings.keys.toggleDebugConsole
onActivated: toggleConsole()
}
HShortcut {
sequences: settings.keys.reloadConfig
onActivated: mainUI.reloadSettings()
}
HShortcut {
sequences: settings.keys.zoomIn
onActivated: theme.uiScale += 0.1
}
HShortcut {
sequences: settings.keys.zoomOut
onActivated: theme.uiScale = Math.max(0.1, theme.uiScale - 0.1)
}
HShortcut {
sequences: settings.keys.zoomReset
onActivated: theme.uiScale = 1
}
HShortcut {
sequences: settings.keys.toggleCompactMode
onActivated: {
settings.compactMode = ! settings.compactMode
settingsChanged()
}
}
// Pages
HShortcut {
sequences: settings.keys.goToLastPage
onActivated: mainUI.pageLoader.showPrevious()
}
// Page scrolling
HShortcut {
enabled: toFlick
sequences: settings.keys.scrollUp
onActivated: utils.flickPages(toFlick, -1 / 10)
}
HShortcut {
enabled: toFlick
sequences: settings.keys.scrollDown
onActivated: utils.flickPages(toFlick, 1 / 10)
}
HShortcut {
enabled: toFlick
sequences: settings.keys.scrollPageUp
onActivated: utils.flickPages(toFlick, -1)
}
HShortcut {
enabled: toFlick
sequences: settings.keys.scrollPageDown
onActivated: utils.flickPages(toFlick, 1)
}
HShortcut {
enabled: toFlick
sequences: settings.keys.scrollToTop
onActivated: utils.flickToTop(toFlick)
}
HShortcut {
enabled: toFlick
sequences: settings.keys.scrollToBottom
onActivated: utils.flickToBottom(toFlick)
}
// Tab navigation
HShortcut {
enabled: tabsTarget
sequences: settings.keys.previousTab
onActivated: tabsTarget.setCurrentIndex(
utils.numberWrapAt(tabsTarget.currentIndex - 1, tabsTarget.count),
)
}
HShortcut {
enabled: tabsTarget
sequences: settings.keys.nextTab
onActivated: tabsTarget.setCurrentIndex(
utils.numberWrapAt(tabsTarget.currentIndex + 1, tabsTarget.count),
)
}
// MainPane
HShortcut {
enabled: mainUI.accountsPresent
sequences: settings.keys.toggleFocusMainPane
onActivated: mainUI.mainPane.toggleFocus()
context: Qt.ApplicationShortcut
}
HShortcut {
enabled: mainUI.accountsPresent
sequences: settings.keys.clearRoomFilter
onActivated: mainUI.mainPane.bottomBar.roomFilter = ""
}
HShortcut {
enabled: mainUI.accountsPresent
sequences: settings.keys.addNewAccount
onActivated: mainUI.mainPane.bottomBar.addAccountButton.clicked()
}
HShortcut {
enabled: mainUI.accountsPresent
sequences: settings.keys.addNewChat
onActivated: mainUI.mainPane.mainPaneList.addNewChat()
}
HShortcut {
enabled: mainUI.accountsPresent
sequences: settings.keys.accountSettings
onActivated: mainUI.mainPane.mainPaneList.accountSettings()
}
HShortcut {
enabled: mainUI.accountsPresent
sequences: settings.keys.toggleCollapseAccount
onActivated: mainUI.mainPane.mainPaneList.toggleCollapseAccount()
}
HShortcut {
enabled: mainUI.accountsPresent
sequences: settings.keys.goToPreviousRoom
onActivated: {
mainUI.mainPane.mainPaneList.previous()
mainUI.mainPane.mainPaneList.requestActivate()
}
}
HShortcut {
enabled: mainUI.accountsPresent
sequences: settings.keys.goToNextRoom
onActivated: {
mainUI.mainPane.mainPaneList.next()
mainUI.mainPane.mainPaneList.requestActivate()
}
}
Repeater {
model: Object.keys(settings.keys.focusRoomAtIndex)
Item {
HShortcut {
enabled: mainUI.accountsPresent
sequence: settings.keys.focusRoomAtIndex[modelData]
onActivated: mainUI.mainPane.mainPaneList.goToRoom(
parseInt(modelData - 1, 10),
)
}
}
}
// Chat
HShortcut {
enabled: window.uiState.page === "Pages/Chat/Chat.qml"
sequences: settings.keys.clearRoomMessages
onActivated: utils.makePopup(
"Popups/ClearMessagesPopup.qml",
mainUI,
{
userId: window.uiState.pageProperties.userId,
roomId: window.uiState.pageProperties.roomId,
}
)
}
HShortcut {
enabled: window.uiState.page === "Pages/Chat/Chat.qml"
sequences: settings.keys.sendFile
onActivated: utils.makeObject(
"Dialogs/SendFilePicker.qml",
mainUI,
{
userId: window.uiState.pageProperties.userId,
roomId: window.uiState.pageProperties.roomId,
destroyWhenDone: true,
},
picker => { picker.dialog.open() }
)
}
HShortcut {
enabled: window.uiState.page === "Pages/Chat/Chat.qml"
sequences: settings.keys.sendFileFromPathInClipboard
onActivated: utils.sendFile(
window.uiState.pageProperties.userId,
window.uiState.pageProperties.roomId,
Clipboard.text.trim(),
)
}
// RoomPane
HShortcut {
enabled: window.uiState.page === "Pages/Chat/Chat.qml"
sequences: settings.keys.toggleFocusRoomPane
onActivated: mainUI.pageLoader.item.roomPane.toggleFocus()
context: Qt.ApplicationShortcut
}
}

View File

@ -184,6 +184,8 @@ HListView {
function goToRoom(index) {
if (! currentItem) next()
if (! currentItem) return
const room = currentItem.roomList.contentItem.children[index]
if (room && room.activated) room.activated()
}
@ -194,6 +196,7 @@ HListView {
function activate() {
if (! currentItem) next()
if (! currentItem) return
selectedRoom ?
currentItem.roomList.currentItem.activated() :
@ -204,6 +207,7 @@ HListView {
function accountSettings() {
if (! currentItem) next()
if (! currentItem) return
currentItem.account.activated()
detachedCurrentIndex = false
@ -211,6 +215,7 @@ HListView {
function addNewChat() {
if (! currentItem) next()
if (! currentItem) return
currentItem.account.addChat.clicked()
detachedCurrentIndex = false
@ -237,6 +242,42 @@ HListView {
when: ! detachedCurrentIndex
}
HShortcut {
sequences: window.settings.keys.addNewChat
onActivated: addNewChat()
}
HShortcut {
sequences: window.settings.keys.accountSettings
onActivated: accountSettings()
}
HShortcut {
sequences: window.settings.keys.toggleCollapseAccount
onActivated: toggleCollapseAccount()
}
HShortcut {
sequences: window.settings.keys.goToPreviousRoom
onActivated: { previous(); requestActivate() }
}
HShortcut {
sequences: window.settings.keys.goToNextRoom
onActivated: { next(); requestActivate() }
}
Repeater {
model: Object.keys(window.settings.keys.focusRoomAtIndex)
Item {
HShortcut {
sequence: window.settings.keys.focusRoomAtIndex[modelData]
onActivated: goToRoom(parseInt(modelData - 1, 10))
}
}
}
Timer {
id: activateLimiter
interval: 200

View File

@ -27,6 +27,11 @@ Rectangle {
onClicked: pageLoader.showPage("AddAccount/AddAccount")
Layout.fillHeight: true
HShortcut {
sequences: window.settings.keys.addNewAccount
onActivated: addAccountButton.clicked()
}
}
HTextField {
@ -65,6 +70,11 @@ Rectangle {
}
Behavior on opacity { HNumberAnimation {} }
HShortcut {
sequences: window.settings.keys.clearRoomFilter
onActivated: filterField.text = ""
}
}
}
}

View File

@ -47,6 +47,12 @@ HDrawer {
when: ! mainUI.accountsPresent
}
HShortcut {
enabled: mainUI.accountsPresent
sequences: window.settings.keys.toggleFocusMainPane
onActivated: toggleFocus()
}
HColumnLayout {
anchors.fill: parent

View File

@ -95,4 +95,9 @@ HLoader {
easing.type: Easing.OutBack
duration: theme.animationDuration * 1.5
}
HShortcut {
sequences: window.settings.keys.goToLastPage
onActivated: showPrevious()
}
}

View File

@ -12,9 +12,6 @@ HColumnPage {
leftPadding: 0
rightPadding: 0
// The target will be our EventList, not the page itself
becomeKeyboardFlickableTarget: false
onLoadEventListChanged: if (loadEventList) loadedOnce = true

View File

@ -243,10 +243,22 @@ Rectangle {
Layout.fillHeight: true
HShortcut {
sequences: window.settings.keys.sendFileFromPathInClipboard
onActivated: utils.sendFile(
chat.userId, chat.roomId, Clipboard.text.trim(),
)
}
SendFilePicker {
id: sendFilePicker
userId: chat.userId
roomId: chat.roomId
HShortcut {
sequences: window.settings.keys.sendFile
onActivated: sendFilePicker.dialog.open()
}
}
}
}

View File

@ -77,4 +77,9 @@ MultiviewPane {
MemberView {}
SettingsView { fillAvailableHeight: true }
HShortcut {
sequences: window.settings.keys.toggleFocusRoomPane
onActivated: toggleFocus()
}
}

View File

@ -65,17 +65,9 @@ HRowLayout {
// ~600px max with a 16px font
readonly property int maxMessageWidth: theme.fontSize.normal * 0.5 * 75
readonly property alias debugConsoleLoader: debugConsoleLoader
readonly property alias selectedText: contentLabel.selectedText
DebugConsoleLoader {
id: debugConsoleLoader
active: false
onLoaded: item.runJS("json()")
}
Item {
id: avatarWrapper
opacity: collapseAvatar ? 0 : 1

View File

@ -221,7 +221,11 @@ HColumnLayout {
HMenuItem {
icon.name: "debug"
text: qsTr("Debug this event")
onTriggered: eventContent.debugConsoleLoader.toggle()
onTriggered: {
mainUI.debugConsole.visible = true
mainUI.debugConsole.target = eventContent
mainUI.debugConsole.runJS("t.parent.json()", false)
}
}
HMenuItemPopupSpawner {

View File

@ -6,6 +6,7 @@ import QtQuick.Window 2.12
import Clipboard 0.1
import "../../.."
import "../../../Base"
import "../../../ShortcutBundles"
Rectangle {
color: theme.chat.eventList.background
@ -56,6 +57,23 @@ Rectangle {
eventList.currentItem.eventContent.debugConsoleLoader.toggle()
}
HShortcut {
sequences: window.settings.keys.clearRoomMessages
onActivated: utils.makePopup(
"Popups/ClearMessagesPopup.qml",
mainUI,
{
userId: window.uiState.pageProperties.userId,
roomId: window.uiState.pageProperties.roomId,
}
)
}
FlickShortcuts {
flickable: eventList
}
HListView {
id: eventList
clip: true
@ -109,8 +127,6 @@ Rectangle {
// fetch past events.
onInviterChanged: canLoad = true
Component.onCompleted: shortcuts.flickTarget = eventList
property string inviter: chat.roomInfo.inviter || ""
property real yPos: visibleArea.yPosition

View File

@ -0,0 +1,39 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import "../Base"
HQtObject {
property Item flickable: parent
HShortcut {
sequences: window.settings.keys.scrollUp
onActivated: utils.flickPages(flickable, -1 / 10)
}
HShortcut {
sequences: window.settings.keys.scrollDown
onActivated: utils.flickPages(flickable, 1 / 10)
}
HShortcut {
sequences: window.settings.keys.scrollPageUp
onActivated: utils.flickPages(flickable, -1)
}
HShortcut {
sequences: window.settings.keys.scrollPageDown
onActivated: utils.flickPages(flickable, 1)
}
HShortcut {
sequences: window.settings.keys.scrollToTop
onActivated: utils.flickToTop(flickable)
}
HShortcut {
sequences: window.settings.keys.scrollToBottom
onActivated: utils.flickToBottom(flickable)
}
}

View File

@ -0,0 +1,23 @@
// SPDX-License-Identifier: LGPL-3.0-or-later
import QtQuick 2.12
import "../Base"
HQtObject {
property Item container: parent
HShortcut {
sequences: window.settings.keys.previousTab
onActivated: container.setCurrentIndex(
utils.numberWrapAt(container.currentIndex - 1, container.count),
)
}
HShortcut {
sequences: window.settings.keys.nextTab
onActivated: container.setCurrentIndex(
utils.numberWrapAt(container.currentIndex + 1, container.count),
)
}
}

View File

@ -18,7 +18,7 @@ Item {
property bool accountsPresent:
ModelStore.get("accounts").count > 0 || py.startupAnyAccountsSaved
readonly property alias shortcuts: shortcuts
readonly property alias debugConsole: debugConsole
readonly property alias mainPane: mainPane
readonly property alias pageLoader: pageLoader
readonly property alias pressAnimation: pressAnimation
@ -39,14 +39,43 @@ Item {
}
}
GlobalShortcuts {
id: shortcuts
defaultDebugConsoleLoader: debugConsoleLoader
HShortcut {
sequences: window.settings.keys.startPythonDebugger
onActivated: py.call("BRIDGE.pdb")
}
DebugConsoleLoader {
id: debugConsoleLoader
active: false
HShortcut {
sequences: window.settings.keys.reloadConfig
onActivated: reloadSettings()
}
HShortcut {
sequences: window.settings.keys.zoomIn
onActivated: theme.uiScale += 0.1
}
HShortcut {
sequences: window.settings.keys.zoomOut
onActivated: theme.uiScale = Math.max(0.1, theme.uiScale - 0.1)
}
HShortcut {
sequences: window.settings.keys.zoomReset
onActivated: theme.uiScale = 1
}
HShortcut {
sequences: window.settings.keys.toggleCompactMode
onActivated: {
settings.compactMode = ! settings.compactMode
settingsChanged()
}
}
DebugConsole {
id: debugConsole
target: mainUI
visible: false
}
LinearGradient {