From fe18b725a50d885b3f6656b058f407dc40dd02fb Mon Sep 17 00:00:00 2001 From: miruka Date: Wed, 13 May 2020 07:37:39 -0400 Subject: [PATCH] Use an horizontal bar for accounts --- TODO.md | 2 + src/gui/Base/HGridView.qml | 140 ++++++++++++++++++++++++++ src/gui/Base/HListView.qml | 2 - src/gui/MainPane/Account.qml | 6 +- src/gui/MainPane/AccountsBar.qml | 116 ++++++++++----------- src/gui/MainPane/FilterRoomsField.qml | 2 +- src/gui/MainPane/MainPane.qml | 47 +++++---- src/gui/MainPane/Room.qml | 2 + src/gui/MainPane/TopBar.qml | 63 ++++++++++++ src/themes/Midnight.qpl | 7 +- 10 files changed, 301 insertions(+), 86 deletions(-) create mode 100644 src/gui/Base/HGridView.qml create mode 100644 src/gui/MainPane/TopBar.qml diff --git a/TODO.md b/TODO.md index 14e4b1eb..0c763523 100644 --- a/TODO.md +++ b/TODO.md @@ -5,6 +5,8 @@ - fix left rooms opacity - fix escape keybinds (filter rooms, message selection) - fix python getting stuck when loading large room +- fix accounts in room list not getting their profile updated if mirage starts + with a filter - account delegates refactor - lag when switching accounts diff --git a/src/gui/Base/HGridView.qml b/src/gui/Base/HGridView.qml new file mode 100644 index 00000000..2bb2f5ad --- /dev/null +++ b/src/gui/Base/HGridView.qml @@ -0,0 +1,140 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +import QtQuick 2.12 +import QtQuick.Controls 2.12 + +GridView { + id: gridView + interactive: allowDragging + currentIndex: -1 + keyNavigationWraps: true + highlightMoveDuration: theme.animationDuration + + // Keep highlighted delegate at the center + highlightRangeMode: GridView.ApplyRange + preferredHighlightBegin: height / 2 - currentItemHeight / 2 + preferredHighlightEnd: height / 2 + currentItemHeight / 2 + + maximumFlickVelocity: 4000 + + + highlight: Rectangle { + color: theme.controls.gridView.highlight + } + + ScrollBar.vertical: ScrollBar { + visible: gridView.interactive || ! gridView.allowDragging + } + + // property bool debug: false + + // https://doc.qt.io/qt-5/qml-qtquick-viewtransition.html + // #handling-interrupted-animations + add: Transition { + // ScriptAction { script: if (gridView.debug) print("add") } + HNumberAnimation { property: "opacity"; from: 0; to: 1 } + HNumberAnimation { property: "scale"; from: 0; to: 1 } + } + + move: Transition { + // ScriptAction { script: if (gridView.debug) print("move") } + HNumberAnimation { property: "opacity"; to: 1 } + HNumberAnimation { property: "scale"; to: 1 } + HNumberAnimation { properties: "x,y" } + } + + remove: Transition { + // ScriptAction { script: if (gridView.debug) print("remove") } + HNumberAnimation { property: "opacity"; to: 0 } + HNumberAnimation { property: "scale"; to: 0 } + } + + displaced: Transition { + // ScriptAction { script: if (gridView.debug) print("displaced") } + HNumberAnimation { property: "opacity"; to: 1 } + HNumberAnimation { property: "scale"; to: 1 } + HNumberAnimation { properties: "x,y" } + } + + onSelectedCountChanged: if (! selectedCount) lastCheckedDelegateIndex = 0 + + + property bool allowDragging: true + property alias cursorShape: mouseArea.cursorShape + property int currentItemHeight: currentItem ? currentItem.height : 0 + + property var checked: ({}) + property int lastCheckedDelegateIndex: 0 + property int selectedCount: Object.keys(checked).length + + + function check(...indices) { + for (const i of indices) { + const model = gridView.model.get(i) + checked[model.id] = model + } + + lastCheckedDelegateIndex = indices.slice(-1)[0] + checkedChanged() + } + + function checkFromLastToHere(here) { + const indices = utils.range(lastCheckedDelegateIndex, here) + eventList.check(...indices) + } + + function uncheck(...indices) { + for (const i of indices) { + const model = gridView.model.get(i) + delete checked[model.id] + } + + checkedChanged() + } + + function toggleCheck(...indices) { + const checkedIndices = [] + + for (const i of indices) { + const model = gridView.model.get(i) + + if (model.id in checked) { + delete checked[model.id] + } else { + checked[model.id] = model + checkedIndices.push(i) + } + } + + if (checkedIndices.length > 0) + lastCheckedDelegateIndex = checkedIndices.slice(-1)[0] + + checkedChanged() + } + + function getSortedChecked() { + return Object.values(checked).sort( + (a, b) => a.date > b.date ? 1 : -1 + ) + } + + + Connections { + target: gridView + enabled: ! gridView.allowDragging + // interactive gets temporarily set to true below to allow wheel scroll + onDraggingChanged: gridView.interactive = false + } + + MouseArea { + id: mouseArea + anchors.fill: parent + enabled: ! parent.allowDragging || cursorShape !== Qt.ArrowCursor + acceptedButtons: Qt.NoButton + onWheel: { + // Allow wheel usage, will be back to false on any drag attempt + parent.interactive = true + wheel.accepted = false + } + } +} diff --git a/src/gui/Base/HListView.qml b/src/gui/Base/HListView.qml index c9e18a65..4e938c6e 100644 --- a/src/gui/Base/HListView.qml +++ b/src/gui/Base/HListView.qml @@ -31,8 +31,6 @@ ListView { // https://doc.qt.io/qt-5/qml-qtquick-viewtransition.html // #handling-interrupted-animations - // XXX: add transitions are buggy when using DelegateModel, `add` should be - // set to `null` and delegates should have `ListView.onAdd: ...` instead. add: Transition { // ScriptAction { script: if (listView.debug) print("add") } HNumberAnimation { property: "opacity"; from: 0; to: 1 } diff --git a/src/gui/MainPane/Account.qml b/src/gui/MainPane/Account.qml index 70f8306f..01ba8869 100644 --- a/src/gui/MainPane/Account.qml +++ b/src/gui/MainPane/Account.qml @@ -5,11 +5,11 @@ import QtQuick.Layouts 1.12 import "../Base" import "../Base/HTile" -HTile { +HTileDelegate { id: account - implicitHeight: theme.baseElementsHeight backgroundColor: theme.accountView.account.background - padded: false + leftPadding: theme.spacing + rightPadding: 0 // the "add chat" button has padding contentItem: ContentRow { tile: account diff --git a/src/gui/MainPane/AccountsBar.qml b/src/gui/MainPane/AccountsBar.qml index 8e1b9068..f7b69b8e 100644 --- a/src/gui/MainPane/AccountsBar.qml +++ b/src/gui/MainPane/AccountsBar.qml @@ -2,33 +2,36 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 -import QtQuick.Layouts 1.12 import ".." import "../Base" import "../Base/HTile" -HColumnLayout { + +Rectangle { + implicitHeight: accountList.count >= 2 ? accountList.contentHeight : 0 + color: theme.accountsBar.accountList.background + + property RoomList roomList + readonly property alias accountList: accountList - HButton { - id: addAccountButton - icon.name: "add-account" - toolTip.text: qsTr("Add another account") - backgroundColor: theme.accountsBar.addAccountButtonBackground - onClicked: pageLoader.showPage("AddAccount/AddAccount") + Behavior on implicitHeight { HNumberAnimation {} } - Layout.preferredHeight: theme.baseElementsHeight - - HShortcut { - sequences: window.settings.keys.addNewAccount - onActivated: addAccountButton.clicked() - } - } - - HListView { + HGridView { id: accountList + anchors.centerIn: parent + width: Math.min(cellWidth * count, parent.width) + height: parent.height + // anchors.topMargin: theme.spacing / 2 + // anchors.bottomMargin: anchors.topMargin + // anchors.leftMargin: -theme.spacing / 2 + // anchors.rightMargin: anchors.leftMargin + + clip: true + cellWidth: theme.controls.avatar.size + theme.spacing + cellHeight: cellWidth currentIndex: roomList.count === 0 || roomList.currentIndex === -1 ? -1 : @@ -42,29 +45,23 @@ HColumnLayout { delegate: HTileDelegate { id: tile - width: accountList.width - backgroundColor: - theme.accountsBar.accountList.account.background - - topPadding: (accountList.width - avatar.width) / 4 - bottomPadding: topPadding - leftPadding: 0 - rightPadding: leftPadding + width: accountList.cellWidth + height: accountList.cellHeight + padded: false + backgroundColor: theme.accountsBar.accountList.account.background contentItem: Item { id: tileContent - implicitHeight: avatar.height HUserAvatar { id: avatar - anchors.horizontalCenter: parent.horizontalCenter + anchors.centerIn: parent userId: model.id displayName: model.display_name mxc: model.avatar_url // compact: tile.compact - radius: - theme.accountsBar.accountList.account.avatarRadius + radius: theme.accountsBar.accountList.account.avatarRadius } MessageIndicator { @@ -78,16 +75,15 @@ HColumnLayout { } HLoader { - anchors.fill: parent - anchors.leftMargin: - accountList.highlightItem ? - accountList.highlightItem.border.width : - 0 - + visible: false // XXX + anchors.centerIn: parent + width: avatar.width + height: avatar.height opacity: model.first_sync_done ? 0 : 1 active: opacity > 0 sourceComponent: Rectangle { + radius: avatar.radius color: utils.hsluv(0, 0, 0, 0.5) HBusyIndicator { @@ -118,14 +114,14 @@ HColumnLayout { Rectangle { id: border - width: theme.accountsBar.accountList.account.selectedBorderSize - height: parent.height + anchors.bottom: parent.bottom + width: parent.width + height: + theme.accountsBar.accountList.account.selectedBorderSize color: theme.accountsBar.accountList.account.selectedBorder } } - Layout.fillWidth: true - Layout.fillHeight: true HShortcut { sequences: window.settings.keys.goToPreviousAccount @@ -142,22 +138,30 @@ HColumnLayout { accountList.currentItem.leftClicked() } } - - Rectangle { - anchors.fill: parent - z: -100 - color: theme.accountsBar.accountList.background - } - } - - HButton { - id: settingsButton - backgroundColor: theme.accountsBar.settingsButtonBackground - icon.name: "settings" - toolTip.text: qsTr("Open config folder") - - onClicked: py.callCoro("get_config_dir", [], Qt.openUrlExternally) - - Layout.preferredHeight: theme.baseElementsHeight } } + + // HButton { + // id: settingsButton + // backgroundColor: theme.accountsBar.settingsButtonBackground + // icon.name: "settings" + // toolTip.text: qsTr("Open config folder") + + // onClicked: py.callCoro("get_config_dir", [], Qt.openUrlExternally) + + // Layout.preferredHeight: theme.baseElementsHeight + // } + // HButton { + // id: addAccountButton + // icon.name: "add-account" + // toolTip.text: qsTr("Add another account") + // backgroundColor: theme.accountsBar.addAccountButtonBackground + // onClicked: pageLoader.showPage("AddAccount/AddAccount") + + // Layout.preferredHeight: theme.baseElementsHeight + + // HShortcut { + // sequences: window.settings.keys.addNewAccount + // onActivated: addAccountButton.clicked() + // } + // } diff --git a/src/gui/MainPane/FilterRoomsField.qml b/src/gui/MainPane/FilterRoomsField.qml index 1fca87d4..8793e8da 100644 --- a/src/gui/MainPane/FilterRoomsField.qml +++ b/src/gui/MainPane/FilterRoomsField.qml @@ -20,7 +20,7 @@ HTextField { Keys.onEnterPressed: Keys.onReturnPressed(event) Keys.onReturnPressed: { - roomList.showRoomAtIndex() + roomList.showItemAtIndex() if (window.settings.clearRoomFilterOnEnter) text = "" } diff --git a/src/gui/MainPane/MainPane.qml b/src/gui/MainPane/MainPane.qml index 9cee8ba7..cc27a0fc 100644 --- a/src/gui/MainPane/MainPane.qml +++ b/src/gui/MainPane/MainPane.qml @@ -8,10 +8,9 @@ HDrawer { id: mainPane saveName: "mainPane" background: null - minimumSize: - accountBar.width + theme.controls.avatar.size + theme.spacing * 2 + minimumSize: theme.controls.avatar.size + theme.spacing * 2 - readonly property alias accountBar: accountBar + readonly property alias accountsBar: accountsBar readonly property alias roomList: roomList readonly property alias filterRoomsField: filterRoomsField @@ -23,32 +22,36 @@ HDrawer { when: ! mainUI.accountsPresent } - HRowLayout { + HColumnLayout { anchors.fill: parent - AccountsBar { - id: accountBar - roomList: roomList - - Layout.fillWidth: false + TopBar { + Layout.fillWidth: true + Layout.preferredHeight: theme.baseElementsHeight } - HColumnLayout { - RoomList { - id: roomList - clip: true - filter: filterRoomsField.text + AccountsBar { + id: accountsBar + roomList: roomList - Layout.fillWidth: true - Layout.fillHeight: true - } + Layout.fillWidth: true + Layout.maximumHeight: parent.height / 3 + } - FilterRoomsField { - id: filterRoomsField - roomList: roomList + RoomList { + id: roomList + clip: true + filter: filterRoomsField.text - Layout.fillWidth: true - } + Layout.fillWidth: true + Layout.fillHeight: true + } + + FilterRoomsField { + id: filterRoomsField + roomList: roomList + + Layout.fillWidth: true } } } diff --git a/src/gui/MainPane/Room.qml b/src/gui/MainPane/Room.qml index 7a35c499..0d2a14ee 100644 --- a/src/gui/MainPane/Room.qml +++ b/src/gui/MainPane/Room.qml @@ -10,6 +10,8 @@ import "../Base/HTile" HTileDelegate { id: room backgroundColor: theme.accountView.roomList.room.background + leftPadding: theme.spacing * 2 + rightPadding: theme.spacing opacity: model.left ? theme.accountView.roomList.room.leftRoomOpacity : 1 diff --git a/src/gui/MainPane/TopBar.qml b/src/gui/MainPane/TopBar.qml new file mode 100644 index 00000000..dc8b201e --- /dev/null +++ b/src/gui/MainPane/TopBar.qml @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later + +import QtQuick 2.12 +import QtQuick.Layouts 1.12 +import "../Base" + +Rectangle { + clip: true + color: theme.mainPaneTopBar.background + + HRowLayout { + anchors.fill: parent + + HButton { + backgroundColor: "transparent" + icon.name: "settings" + toolTip.text: qsTr("Open config folder") + + onClicked: py.callCoro("get_config_dir", [], Qt.openUrlExternally) + + Layout.fillHeight: true + } + + HButton { + backgroundColor: "transparent" + + text: qsTr("%1 %2") + .arg(Qt.application.displayName).arg(Qt.application.version) + label.color: theme.mainPaneTopBar.nameVersionLabel + toolTip.text: qsTr("Open project repository") + + onClicked: + Qt.openUrlExternally("https://github.com/mirukana/mirage") + + Layout.fillWidth: true + Layout.fillHeight: true + } + + HButton { + backgroundColor: "transparent" + icon.name: "reload-config-files" + toolTip.text: qsTr("Reload config files") + + onClicked: mainUI.reloadSettings() + + Layout.fillHeight: true + } + + HButton { + visible: Layout.preferredWidth > 0 + backgroundColor: "transparent" + icon.name: "go-back-to-chat-from-main-pane" + toolTip.text: qsTr("Go back to room") + + onClicked: mainPane.toggleFocus() + + Layout.preferredWidth: mainPane.collapse ? implicitWidth : 0 + Layout.fillHeight: true + + Behavior on Layout.preferredWidth { HNumberAnimation {} } + } + } +} diff --git a/src/themes/Midnight.qpl b/src/themes/Midnight.qpl index e72ea77a..1aa1b74d 100644 --- a/src/themes/Midnight.qpl +++ b/src/themes/Midnight.qpl @@ -273,6 +273,9 @@ ui: // color gradientStartColor: hsluv(0, 0, 0, 0.5) // color gradientEndColor: hsluv(0, 0, 0, 0.5) +mainPaneTopBar: + color background: colors.strongBackground + color nameVersionLabel: colors.text accountsBar: color everyRoomButtonBackground: colors.strongerBackground @@ -280,7 +283,7 @@ accountsBar: color settingsButtonBackground: colors.strongerBackground accountList: - color background: colors.strongerBackground + color background: colors.mediumBackground account: color background: "transparent" @@ -294,7 +297,7 @@ accountsBar: accountView: account: - color background: colors.strongBackground + color background: "transparent" color name: colors.text unreadIndicator: