Rewrite SidePane using QQC Drawer

Cleaner approach, gets rid of the HPage swipe view hack, better
performances, a lot less complex
This commit is contained in:
miruka 2019-12-08 14:43:41 -04:00
parent 5326726c4f
commit 06a6a4c08d
13 changed files with 250 additions and 260 deletions

View File

@ -1,3 +1,7 @@
- make pageup/down not slippery again
- rename all setfocus() to takefocus()
- refactor roomsidepane too
- better pane minsize
- better cancel for all boxes - better cancel for all boxes
- Media - Media
- Confirmation box after picking file to upload - Confirmation box after picking file to upload

72
src/qml/Base/HDrawer.qml Normal file
View File

@ -0,0 +1,72 @@
import QtQuick 2.13
import QtQuick.Controls 2.13
import "../utils.js" as Utils
Drawer {
id: drawer
implicitWidth: calculatedWidth
implicitHeight: parent.height
// FIXME: https://bugreports.qt.io/browse/QTBUG-59141
// dragMargin: parent.width / 2
interactive: collapse
position: 1
visible: ! collapse
modal: false
closePolicy: Popup.CloseOnEscape
background: Rectangle { id: bg; color: theme.colors.strongBackground }
signal userResized(int newWidth)
property int normalWidth: 300
property int minNormalWidth: resizeAreaWidth
property int maxNormalWidth: parent.width
property bool collapse: window.width < 400
property int collapseExpandedWidth: parent.width
property alias color: bg.color
property alias resizeAreaWidth: resizeArea.width
readonly property int calculatedWidth:
collapse ?
collapseExpandedWidth :
Math.max(minNormalWidth, Math.min(normalWidth, maxNormalWidth))
Behavior on width {
enabled: ! resizeMouseHandler.drag.active
NumberAnimation { duration: 100 }
}
Item {
id: resizeArea
anchors.right: parent.right
width: theme.spacing / 2
height: parent.height
z: 9999
MouseArea {
id: resizeMouseHandler
anchors.fill: parent
enabled: ! drawer.collapse
acceptedButtons: Qt.LeftButton
hoverEnabled: true
cursorShape:
containsMouse || drag.active ?
Qt.SizeHorCursor : Qt.ArrowCursor
onPressed: canResize = true
onReleased: { canResize = false; userResized(drawer.normalWidth) }
onMouseXChanged:
if (canResize)
drawer.normalWidth = drawer.calculatedWidth + mouseX
property bool canResize: false
}
}
}

View File

@ -3,14 +3,13 @@ import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12 import QtQuick.Layouts 1.12
import "../SidePane" import "../SidePane"
SwipeView { Page {
id: innerPage
default property alias columnChildren: contentColumn.children default property alias columnChildren: contentColumn.children
property alias page: innerPage
property alias header: innerPage.header
property alias footer: innerPage.header
property alias flickable: innerFlickable property alias flickable: innerFlickable
property alias headerLabel: innerHeaderLabel property alias headerLabel: innerHeaderLabel
property var hideHeaderUnderHeight: null property var hideHeaderUnderHeight: null
@ -19,22 +18,7 @@ SwipeView {
property bool becomeKeyboardFlickableTarget: true property bool becomeKeyboardFlickableTarget: true
id: swipeView
clip: true
interactive: sidePane.reduce
currentIndex: 1
SidePane {
implicitWidth: swipeView.width
animateWidth: false // Without this, the SidePane gets auto-focused
collapse: false
reduce: false
visible: swipeView.interactive
onVisibleChanged: if (currentIndex != 1) swipeView.setCurrentIndex(1)
}
Page {
id: innerPage
background: null background: null
header: Rectangle { header: Rectangle {
@ -86,5 +70,4 @@ SwipeView {
height: innerFlickable.height height: innerFlickable.height
} }
} }
}
} }

View File

@ -5,6 +5,9 @@ import "../utils.js" as Utils
HPage { HPage {
id: chatPage id: chatPage
leftPadding: 0
rightPadding: 0
// The target will be our EventList, not the page itself // The target will be our EventList, not the page itself
becomeKeyboardFlickableTarget: false becomeKeyboardFlickableTarget: false
@ -49,9 +52,6 @@ HPage {
Behavior on height { HNumberAnimation {} } Behavior on height { HNumberAnimation {} }
} }
page.leftPadding: 0
page.rightPadding: 0
HLoader { HLoader {
source: ready ? "ChatSplitView.qml" : "../Base/HBusyIndicator.qml" source: ready ? "ChatSplitView.qml" : "../Base/HBusyIndicator.qml"

View File

@ -8,7 +8,7 @@ import "FileTransfer"
HSplitView { HSplitView {
id: chatSplitView id: chatSplitView
Component.onCompleted: composer.setFocus() Component.onCompleted: composer.takeFocus()
HColumnLayout { HColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true

View File

@ -5,8 +5,6 @@ import "../Dialogs"
import "../utils.js" as Utils import "../utils.js" as Utils
Rectangle { Rectangle {
function setFocus() { areaScrollView.forceActiveFocus() }
property string indent: " " property string indent: " "
property var aliases: window.settings.writeAliases property var aliases: window.settings.writeAliases
@ -40,6 +38,8 @@ Rectangle {
lineTextUntilCursor.match(/ {1,4}/g).slice(-1)[0].length : lineTextUntilCursor.match(/ {1,4}/g).slice(-1)[0].length :
1 1
function takeFocus() { areaScrollView.forceActiveFocus() }
// property var pr: lineTextUntilCursor // property var pr: lineTextUntilCursor
// onPrChanged: print( // onPrChanged: print(
// "y", cursorY, "x", cursorX, // "y", cursorY, "x", cursorX,

View File

@ -6,7 +6,7 @@ import "../utils.js" as Utils
HTileDelegate { HTileDelegate {
id: accountDelegate id: accountDelegate
spacing: 0 spacing: 0
topPadding: model.index > 0 ? sidePane.currentSpacing / 2 : 0 topPadding: model.index > 0 ? theme.spacing / 2 : 0
bottomPadding: topPadding bottomPadding: topPadding
backgroundColor: theme.sidePane.account.background backgroundColor: theme.sidePane.account.background
opacity: collapsed && ! forceExpand ? opacity: collapsed && ! forceExpand ?
@ -54,7 +54,7 @@ HTileDelegate {
title.color: theme.sidePane.account.name title.color: theme.sidePane.account.name
title.text: model.data.display_name || model.data.user_id title.text: model.data.display_name || model.data.user_id
title.font.pixelSize: theme.fontSize.big title.font.pixelSize: theme.fontSize.big
title.leftPadding: sidePane.currentSpacing title.leftPadding: theme.spacing
HButton { HButton {
id: addChat id: addChat
@ -112,7 +112,7 @@ HTileDelegate {
text: qsTr("Sign out") text: qsTr("Sign out")
onTriggered: Utils.makePopup( onTriggered: Utils.makePopup(
"Popups/SignOutPopup.qml", "Popups/SignOutPopup.qml",
mainUI, window,
{ "userId": model.data.user_id }, { "userId": model.data.user_id },
popup => { popup.ok.connect(() => { disconnecting = true }) }, popup => { popup.ok.connect(() => { disconnecting = true }) },
) )

View File

@ -5,7 +5,7 @@ import "../utils.js" as Utils
HTileDelegate { HTileDelegate {
id: roomDelegate id: roomDelegate
spacing: sidePane.currentSpacing spacing: theme.spacing
backgroundColor: theme.sidePane.room.background backgroundColor: theme.sidePane.room.background
opacity: model.data.left ? theme.sidePane.room.leftRoomOpacity : 1 opacity: model.data.left ? theme.sidePane.room.leftRoomOpacity : 1
@ -110,7 +110,7 @@ HTileDelegate {
onTriggered: Utils.makePopup( onTriggered: Utils.makePopup(
"Popups/LeaveRoomPopup.qml", "Popups/LeaveRoomPopup.qml",
sidePane, window,
{ {
userId: model.user_id, userId: model.user_id,
roomId: model.data.room_id, roomId: model.data.room_id,
@ -126,7 +126,7 @@ HTileDelegate {
onTriggered: Utils.makePopup( onTriggered: Utils.makePopup(
"Popups/ForgetRoomPopup.qml", "Popups/ForgetRoomPopup.qml",
sidePane, window,
{ {
userId: model.user_id, userId: model.user_id,
roomId: model.data.room_id, roomId: model.data.room_id,

View File

@ -3,107 +3,36 @@ import QtQuick.Layouts 1.12
import "../Base" import "../Base"
import "../utils.js" as Utils import "../utils.js" as Utils
Rectangle { HDrawer {
id: sidePane id: sidePane
clip: true clip: true
opacity: mainUI.accountsPresent && ! reduce ? 1 : 0 opacity: mainUI.accountsPresent ? 1 : 0
visible: opacity > 0
color: theme.sidePane.background color: theme.sidePane.background
normalWidth: window.uiState.sidePaneManualWidth
onUserResized: {
window.uiState.sidePaneManualWidth = newWidth
window.uiStateChanged()
}
property bool hasFocus: toolBar.filterField.activeFocus property bool hasFocus: toolBar.filterField.activeFocus
property alias sidePaneList: sidePaneList property alias sidePaneList: sidePaneList
property alias toolBar: toolBar property alias toolBar: toolBar
property real autoWidthRatio: theme.sidePane.autoWidthRatio
property bool manuallyResizing: false
property bool manuallyResized: false
property int manualWidth: 0
property bool animateWidth: true
Component.onCompleted: { function toggleFocus() {
if (window.uiState.sidePaneManualWidth) { if (toolBar.filterField.activeFocus) {
manualWidth = window.uiState.sidePaneManualWidth pageLoader.takeFocus()
manuallyResized = true return
}
} }
onFocusChanged: if (focus) toolBar.filterField.forceActiveFocus() sidePane.open()
toolBar.filterField.forceActiveFocus()
onManualWidthChanged: {
window.uiState.sidePaneManualWidth = manualWidth
window.uiStateChanged()
}
property int maximumCalculatedWidth: Math.min(
manuallyResized ? manualWidth : theme.sidePane.maximumAutoWidth,
window.width - theme.minimumSupportedWidthPlusSpacing
)
property int parentWidth: parent.width
// Needed for SplitView since it breaks the binding when user manual sizes
onParentWidthChanged: width = Qt.binding(() => implicitWidth)
property int calculatedWidth: Math.min(
manuallyResized ? manualWidth * theme.uiScale :
parentWidth * autoWidthRatio,
maximumCalculatedWidth
)
property bool collapse:
(manuallyResizing ? width : calculatedWidth) <
(manuallyResized ?
(theme.sidePane.collapsedWidth + theme.spacing * 2) :
theme.sidePane.autoCollapseBelowWidth)
property bool reduce:
window.width < theme.sidePane.autoReduceBelowWindowWidth
property int implicitWidth:
reduce ? 0 :
collapse ? theme.sidePane.collapsedWidth :
calculatedWidth
property int currentSpacing:
width <= theme.sidePane.collapsedWidth + theme.spacing * 2 ?
0 : theme.spacing
Behavior on currentSpacing { HNumberAnimation {} }
Behavior on implicitWidth {
HNumberAnimation { factor: animateWidth ? 1 : 0 }
} }
function setFocus() { Behavior on opacity { HOpacityAnimator {} }
forceActiveFocus()
if (reduce) {
pageLoader.item.currentIndex = 0
}
}
Keys.enabled: sidePane.hasFocus
Keys.onUpPressed: sidePaneList.previous(false) // do not activate
Keys.onDownPressed: sidePaneList.next(false)
Keys.onEnterPressed: Keys.onReturnPressed(event)
Keys.onReturnPressed: if (event.modifiers & Qt.ShiftModifier) {
sidePaneList.toggleCollapseAccount()
} else {
if (window.settings.clearRoomFilterOnEnter) {
mainUI.sidePane.toolBar.roomFilter = ""
}
sidePaneList.activate()
}
Keys.onEscapePressed: {
if (window.settings.clearRoomFilterOnEscape) {
mainUI.sidePane.toolBar.roomFilter = ""
}
mainUI.pageLoader.forceActiveFocus()
}
HColumnLayout { HColumnLayout {
anchors.fill: parent anchors.fill: parent
@ -118,6 +47,7 @@ Rectangle {
SidePaneToolBar { SidePaneToolBar {
id: toolBar id: toolBar
sidePaneList: sidePaneList
} }
} }
} }

View File

@ -108,7 +108,6 @@ HListView {
{ {
currentIndex = i currentIndex = i
currentItem.item.toggleCollapse() currentItem.item.toggleCollapse()
activate()
} }
} }
} }

View File

@ -5,6 +5,7 @@ import "../Base"
HRowLayout { HRowLayout {
id: toolBar id: toolBar
property SidePaneList sidePaneList
readonly property alias addAccountButton: addAccountButton readonly property alias addAccountButton: addAccountButton
readonly property alias filterField: filterField readonly property alias filterField: filterField
property alias roomFilter: filterField.text property alias roomFilter: filterField.text
@ -29,8 +30,7 @@ HRowLayout {
backgroundColor: theme.sidePane.filterRooms.background backgroundColor: theme.sidePane.filterRooms.background
bordered: false bordered: false
Layout.fillWidth: true Component.onCompleted: filterField.text = uiState.sidePaneFilter
Layout.fillHeight: true
onTextChanged: { onTextChanged: {
if (window.uiState.sidePaneFilter == text) return if (window.uiState.sidePaneFilter == text) return
@ -38,12 +38,26 @@ HRowLayout {
window.uiStateChanged() window.uiStateChanged()
} }
Connections { Layout.fillWidth: true
target: window Layout.fillHeight: true
// Keep multiple instances of SidePaneToolBar in sync.
// This also sets the text on startup. Keys.onUpPressed: sidePaneList.previous(false) // do not activate
onUiStateChanged: filterField.text = uiState.sidePaneFilter Keys.onDownPressed: sidePaneList.next(false)
Keys.onEnterPressed: Keys.onReturnPressed(event)
Keys.onReturnPressed: {
if (event.modifiers & Qt.ShiftModifier) {
sidePaneList.toggleCollapseAccount()
return
} }
if (window.settings.clearRoomFilterOnEnter) text = ""
sidePaneList.activate()
}
Keys.onEscapePressed: {
if (window.settings.clearRoomFilterOnEscape) text = ""
mainUI.pageLoader.forceActiveFocus()
}
} }
} }

View File

@ -11,7 +11,6 @@ Item {
id: mainUI id: mainUI
focus: true focus: true
Component.onCompleted: window.mainUI = mainUI Component.onCompleted: window.mainUI = mainUI
Keys.forwardTo: [shortcuts]
readonly property alias shortcuts: shortcuts readonly property alias shortcuts: shortcuts
readonly property alias sidePane: sidePane readonly property alias sidePane: sidePane
@ -55,32 +54,19 @@ Item {
} }
HSplitView {
id: uiSplitView
anchors.fill: parent
onAnyResizingChanged: if (anyResizing) {
sidePane.manuallyResizing = true
} else {
sidePane.manuallyResizing = false
sidePane.manuallyResized = true
sidePane.manualWidth = sidePane.width
}
SidePane { SidePane {
id: sidePane id: sidePane
maxNormalWidth: parent.width - theme.minimumSupportedWidth
// Initial width until user manually resizes
width: implicitWidth
Layout.minimumWidth: reduce ? 0 : theme.sidePane.collapsedWidth
Layout.maximumWidth:
window.width - theme.minimumSupportedWidthPlusSpacing
Behavior on Layout.minimumWidth { HNumberAnimation {} }
} }
HLoader { HLoader {
id: pageLoader id: pageLoader
anchors.fill: parent
anchors.leftMargin: sidePane.width * sidePane.position
visible: ! sidePane.hidden || anchors.leftMargin < width
// onSourceChanged: if (sidePane.collapse) sidePane.close()
property bool isWide: width > theme.contentIsWideAbove property bool isWide: width > theme.contentIsWideAbove
@ -142,8 +128,14 @@ Item {
return true return true
} }
function takeFocus() {
pageLoader.item.forceActiveFocus()
if (sidePane.collapse) sidePane.close()
}
onStatusChanged: if (status == Loader.Ready) { onStatusChanged: if (status == Loader.Ready) {
item.forceActiveFocus() pageLoader.takeFocus()
appearAnimation.start() appearAnimation.start()
} }
@ -157,7 +149,6 @@ Item {
duration: theme.animationDuration * 2 duration: theme.animationDuration * 2
} }
} }
}
HPopup { HPopup {
id: fullScreenPopup id: fullScreenPopup

View File

@ -261,9 +261,6 @@ ui:
sidePane: sidePane:
real autoWidthRatio: 0.33 * uiScale
int maximumAutoWidth: 320 * uiScale
int autoCollapseBelowWidth: 128 * uiScale int autoCollapseBelowWidth: 128 * uiScale
int collapsedWidth: controls.avatar.size int collapsedWidth: controls.avatar.size