Make sidebar collapsible
This commit is contained in:
@@ -18,6 +18,24 @@ Kirigami.ScrollablePage {
|
|||||||
id: page
|
id: page
|
||||||
|
|
||||||
property var enteredRoom
|
property var enteredRoom
|
||||||
|
property bool collapsedMode: Config.roomListPageWidth === applicationWindow().collapsedPageWidth && applicationWindow().shouldUseSidebars
|
||||||
|
|
||||||
|
onCollapsedModeChanged: if (collapsedMode) {
|
||||||
|
sortFilterRoomListModel.filterText = "";
|
||||||
|
if (page.contentItem && page.contentItem.flickableItem && page.contentItem.flickableItem.QQC2.ScrollBar.vertical) {
|
||||||
|
page.contentItem.flickableItem.QQC2.ScrollBar.vertical.visible = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
page.contentItem.flickableItem.QQC2.ScrollBar.vertical.visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK: the scrollbar is created with a 0 timer, so we need to set the visible flag
|
||||||
|
// after it has been created
|
||||||
|
Timer {
|
||||||
|
running: true
|
||||||
|
interval: 200
|
||||||
|
onTriggered: page.contentItem.flickableItem.QQC2.ScrollBar.vertical.visible = !collapsedMode;
|
||||||
|
}
|
||||||
|
|
||||||
function goToNextRoom() {
|
function goToNextRoom() {
|
||||||
do {
|
do {
|
||||||
@@ -33,17 +51,51 @@ Kirigami.ScrollablePage {
|
|||||||
listView.currentItem.action.trigger();
|
listView.currentItem.action.trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
title: i18n("Rooms")
|
titleDelegate: collapsedMode ? empty : searchField
|
||||||
|
|
||||||
titleDelegate: Kirigami.SearchField {
|
Component {
|
||||||
Layout.topMargin: Kirigami.Units.smallSpacing
|
id: empty
|
||||||
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
Item {}
|
||||||
Layout.fillHeight: true
|
|
||||||
Layout.fillWidth: true
|
|
||||||
onTextChanged: sortFilterRoomListModel.filterText = text
|
|
||||||
KeyNavigation.tab: listView
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: searchField
|
||||||
|
Kirigami.SearchField {
|
||||||
|
Layout.topMargin: Kirigami.Units.smallSpacing
|
||||||
|
Layout.bottomMargin: Kirigami.Units.smallSpacing
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
onTextChanged: sortFilterRoomListModel.filterText = text
|
||||||
|
KeyNavigation.tab: listView
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
header: QQC2.ItemDelegate {
|
||||||
|
visible: page.collapsedMode
|
||||||
|
action: Kirigami.Action {
|
||||||
|
id: enterRoomAction
|
||||||
|
onTriggered: quickView.item.open();
|
||||||
|
}
|
||||||
|
topPadding: Kirigami.Units.largeSpacing
|
||||||
|
leftPadding: Kirigami.Units.largeSpacing
|
||||||
|
rightPadding: Kirigami.Units.largeSpacing
|
||||||
|
bottomPadding: Kirigami.Units.largeSpacing
|
||||||
|
width: visible ? page.width : 0
|
||||||
|
height: visible ? Kirigami.Units.gridUnit * 2 : 0
|
||||||
|
|
||||||
|
Kirigami.Icon {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 22 * Kirigami.Units.devicePixelRatio
|
||||||
|
height: 22 * Kirigami.Units.devicePixelRatio
|
||||||
|
source: "search"
|
||||||
|
}
|
||||||
|
Kirigami.Separator {
|
||||||
|
width: parent.width
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: listView
|
id: listView
|
||||||
|
|
||||||
@@ -64,6 +116,7 @@ Kirigami.ScrollablePage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ItemSelectionModel {
|
ItemSelectionModel {
|
||||||
id: itemSelection
|
id: itemSelection
|
||||||
model: roomListModel
|
model: roomListModel
|
||||||
@@ -97,11 +150,14 @@ Kirigami.ScrollablePage {
|
|||||||
level: 3
|
level: 3
|
||||||
text: roomListModel.categoryName(section)
|
text: roomListModel.categoryName(section)
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
elide: Text.ElideRight
|
||||||
|
visible: !page.collapsedMode
|
||||||
}
|
}
|
||||||
Kirigami.Icon {
|
Kirigami.Icon {
|
||||||
source: roomListModel.categoryVisible(section) ? "go-up" : "go-down"
|
source: page.collapsedMode ? roomListModel.categoryIconName(section) : (roomListModel.categoryVisible(section) ? "go-up" : "go-down")
|
||||||
implicitHeight: Kirigami.Units.iconSizes.small
|
implicitHeight: Kirigami.Units.iconSizes.small
|
||||||
implicitWidth: Kirigami.Units.iconSizes.small
|
implicitWidth: Kirigami.Units.iconSizes.small
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,87 +165,128 @@ Kirigami.ScrollablePage {
|
|||||||
reuseItems: true
|
reuseItems: true
|
||||||
currentIndex: -1 // we don't want any room highlighted by default
|
currentIndex: -1 // we don't want any room highlighted by default
|
||||||
|
|
||||||
delegate: Kirigami.BasicListItem {
|
delegate: page.collapsedMode ? collapsedModeListComponent : normalModeListComponent
|
||||||
id: roomListItem
|
|
||||||
visible: model.categoryVisible || sortFilterRoomListModel.filterText.length > 0 || Config.mergeRoomList
|
|
||||||
topPadding: Kirigami.Units.largeSpacing
|
|
||||||
bottomPadding: Kirigami.Units.largeSpacing
|
|
||||||
highlighted: listView.currentIndex === index
|
|
||||||
focus: true
|
|
||||||
icon: undefined
|
|
||||||
action: Kirigami.Action {
|
|
||||||
id: enterRoomAction
|
|
||||||
onTriggered: {
|
|
||||||
RoomManager.enterRoom(currentRoom);
|
|
||||||
itemSelection.setCurrentIndex(sortFilterRoomListModel.mapToSource(
|
|
||||||
sortFilterRoomListModel.index(index, 0)), ItemSelectionModel.SelectCurrent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Keys.onEnterPressed: enterRoomAction.trigger()
|
|
||||||
Keys.onReturnPressed: enterRoomAction.trigger()
|
|
||||||
bold: unreadCount > 0
|
|
||||||
label: name ?? ""
|
|
||||||
subtitle: {
|
|
||||||
let txt = (lastEvent.length === 0 ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm, " ")
|
|
||||||
if (txt.length) {
|
|
||||||
return txt
|
|
||||||
}
|
|
||||||
return " "
|
|
||||||
}
|
|
||||||
|
|
||||||
leading: Kirigami.Avatar {
|
Component {
|
||||||
source: avatar ? "image://mxc/" + avatar : ""
|
id: collapsedModeListComponent
|
||||||
name: model.name || i18n("No Name")
|
|
||||||
implicitWidth: visible ? height : 0
|
|
||||||
visible: Config.showAvatarInTimeline
|
|
||||||
sourceSize.width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
|
||||||
sourceSize.height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
|
||||||
}
|
|
||||||
|
|
||||||
trailing: RowLayout {
|
QQC2.ItemDelegate {
|
||||||
QQC2.Label {
|
action: Kirigami.Action {
|
||||||
text: notificationCount
|
id: enterRoomAction
|
||||||
visible: notificationCount > 0
|
onTriggered: {
|
||||||
padding: Kirigami.Units.smallSpacing
|
RoomManager.enterRoom(currentRoom);
|
||||||
color: highlightCount > 0 ? "white" : Kirigami.Theme.textColor
|
itemSelection.setCurrentIndex(sortFilterRoomListModel.mapToSource(
|
||||||
Layout.minimumWidth: height
|
sortFilterRoomListModel.index(index, 0)), ItemSelectionModel.SelectCurrent)
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
background: Rectangle {
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
|
||||||
color: highlightCount > 0 ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.backgroundColor
|
|
||||||
radius: height / 2
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
QQC2.Button {
|
Keys.onEnterPressed: enterRoomAction.trigger()
|
||||||
id: configButton
|
Keys.onReturnPressed: enterRoomAction.trigger()
|
||||||
visible: roomListItem.hovered || Kirigami.Settings.isMobile
|
topPadding: Kirigami.Units.largeSpacing
|
||||||
Accessible.name: i18n("Configure room")
|
leftPadding: Kirigami.Units.largeSpacing
|
||||||
|
rightPadding: Kirigami.Units.largeSpacing
|
||||||
|
bottomPadding: Kirigami.Units.largeSpacing
|
||||||
|
width: ListView.view.width
|
||||||
|
height: ListView.view.width
|
||||||
|
|
||||||
action: Kirigami.Action {
|
contentItem: Kirigami.Avatar {
|
||||||
id: optionAction
|
source: avatar ? "image://mxc/" + avatar : ""
|
||||||
icon.name: "configure"
|
name: model.name || i18n("No Name")
|
||||||
onTriggered: {
|
sourceSize.width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||||
const menu = roomListContextMenu.createObject(page, {"room": currentRoom})
|
sourceSize.height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||||
configButton.visible = true
|
}
|
||||||
configButton.down = true
|
|
||||||
menu.closed.connect(function() {
|
QQC2.ToolTip {
|
||||||
configButton.down = undefined
|
enabled: text.length !== 0
|
||||||
configButton.visible = Qt.binding(function() { return roomListItem.hovered || Kirigami.Settings.isMobile })
|
text: name ?? ""
|
||||||
})
|
}
|
||||||
menu.popup()
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: roomListContextMenu
|
||||||
|
RoomListContextMenu {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: normalModeListComponent
|
||||||
|
Kirigami.BasicListItem {
|
||||||
|
id: roomListItem
|
||||||
|
visible: model.categoryVisible || sortFilterRoomListModel.filterText.length > 0 || Config.mergeRoomList
|
||||||
|
topPadding: Kirigami.Units.largeSpacing
|
||||||
|
bottomPadding: Kirigami.Units.largeSpacing
|
||||||
|
highlighted: listView.currentIndex === index
|
||||||
|
focus: true
|
||||||
|
icon: undefined
|
||||||
|
action: Kirigami.Action {
|
||||||
|
id: enterRoomAction
|
||||||
|
onTriggered: {
|
||||||
|
RoomManager.enterRoom(currentRoom);
|
||||||
|
itemSelection.setCurrentIndex(sortFilterRoomListModel.mapToSource(
|
||||||
|
sortFilterRoomListModel.index(index, 0)), ItemSelectionModel.SelectCurrent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keys.onEnterPressed: enterRoomAction.trigger()
|
||||||
|
Keys.onReturnPressed: enterRoomAction.trigger()
|
||||||
|
bold: unreadCount > 0
|
||||||
|
label: name ?? ""
|
||||||
|
subtitle: {
|
||||||
|
let txt = (lastEvent.length === 0 ? topic : lastEvent).replace(/(\r\n\t|\n|\r\t)/gm, " ")
|
||||||
|
if (txt.length) {
|
||||||
|
return txt
|
||||||
|
}
|
||||||
|
return " "
|
||||||
|
}
|
||||||
|
|
||||||
|
leading: Kirigami.Avatar {
|
||||||
|
source: avatar ? "image://mxc/" + avatar : ""
|
||||||
|
name: model.name || i18n("No Name")
|
||||||
|
implicitWidth: visible ? height : 0
|
||||||
|
visible: Config.showAvatarInTimeline
|
||||||
|
sourceSize.width: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||||
|
sourceSize.height: Kirigami.Units.gridUnit + Kirigami.Units.largeSpacing * 2
|
||||||
|
}
|
||||||
|
|
||||||
|
trailing: RowLayout {
|
||||||
|
QQC2.Label {
|
||||||
|
text: notificationCount
|
||||||
|
visible: notificationCount > 0
|
||||||
|
padding: Kirigami.Units.smallSpacing
|
||||||
|
color: highlightCount > 0 ? "white" : Kirigami.Theme.textColor
|
||||||
|
Layout.minimumWidth: height
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
background: Rectangle {
|
||||||
|
Kirigami.Theme.colorSet: Kirigami.Theme.Button
|
||||||
|
color: highlightCount > 0 ? Kirigami.Theme.positiveTextColor : Kirigami.Theme.backgroundColor
|
||||||
|
radius: height / 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QQC2.Button {
|
||||||
|
id: configButton
|
||||||
|
visible: roomListItem.hovered || Kirigami.Settings.isMobile
|
||||||
|
Accessible.name: i18n("Configure room")
|
||||||
|
|
||||||
|
action: Kirigami.Action {
|
||||||
|
id: optionAction
|
||||||
|
icon.name: "configure"
|
||||||
|
onTriggered: {
|
||||||
|
const menu = roomListContextMenu.createObject(page, {"room": currentRoom})
|
||||||
|
configButton.visible = true
|
||||||
|
configButton.down = true
|
||||||
|
menu.closed.connect(function() {
|
||||||
|
configButton.down = undefined
|
||||||
|
configButton.visible = Qt.binding(function() { return roomListItem.hovered || Kirigami.Settings.isMobile })
|
||||||
|
})
|
||||||
|
menu.popup()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Component {
|
|
||||||
id: roomListContextMenu
|
|
||||||
RoomListContextMenu {}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
footer: QQC2.ToolBar {
|
footer: QQC2.ToolBar {
|
||||||
visible: accountList.count > 1
|
visible: accountList.count > 1 && !collapsedMode
|
||||||
height: visible ? implicitHeight : 0
|
height: visible ? implicitHeight : 0
|
||||||
leftPadding: 0
|
leftPadding: 0
|
||||||
rightPadding: 0
|
rightPadding: 0
|
||||||
|
|||||||
65
qml/main.qml
65
qml/main.qml
@@ -166,7 +166,70 @@ Kirigami.ApplicationWindow {
|
|||||||
handleVisible: enabled && pageStack.layers.depth < 2 && pageStack.depth < 3
|
handleVisible: enabled && pageStack.layers.depth < 2 && pageStack.depth < 3
|
||||||
}
|
}
|
||||||
|
|
||||||
pageStack.columnView.columnWidth: Kirigami.Units.gridUnit * 17
|
readonly property int defaultPageWidth: Kirigami.Units.gridUnit * 17
|
||||||
|
readonly property int minPageWidth: Kirigami.Units.gridUnit * 10
|
||||||
|
readonly property int collapsedPageWidth: Kirigami.Units.gridUnit * 3 - Kirigami.Units.smallSpacing * 3
|
||||||
|
readonly property bool shouldUseSidebars: (Config.roomListPageWidth > minPageWidth ? root.width >= Kirigami.Units.gridUnit * 35 : root.width > Kirigami.Units.gridUnit * 27) && roomListLoaded
|
||||||
|
readonly property int pageWidth: {
|
||||||
|
if (Config.roomListPageWidth === -1) {
|
||||||
|
return defaultPageWidth;
|
||||||
|
} else if (Config.roomListPageWidth < minPageWidth) {
|
||||||
|
return collapsedPageWidth;
|
||||||
|
} else {
|
||||||
|
return Config.roomListPageWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pageStack.defaultColumnWidth: pageWidth
|
||||||
|
pageStack.columnView.columnResizeMode: shouldUseSidebars ? Kirigami.ColumnView.FixedColumns : Kirigami.ColumnView.SingleColumn
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
visible: root.pageStack.wideMode
|
||||||
|
z: 500
|
||||||
|
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
|
x: root.pageStack.defaultColumnWidth - (width / 2)
|
||||||
|
width: Kirigami.Units.devicePixelRatio * 2
|
||||||
|
|
||||||
|
property int _lastX: -1
|
||||||
|
enabled: !Kirigami.Settings.isMobile
|
||||||
|
|
||||||
|
cursorShape: !Kirigami.Settings.isMobile ? Qt.SplitHCursor : undefined
|
||||||
|
|
||||||
|
onPressed: _lastX = mouseX
|
||||||
|
onReleased: Config.save();
|
||||||
|
|
||||||
|
onPositionChanged: {
|
||||||
|
if (_lastX == -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mouse.x > _lastX) {
|
||||||
|
// we moved to the right
|
||||||
|
if (Config.roomListPageWidth === root.collapsedPageWidth && root.pageWidth + (mouse.x - _lastX) >= root.minPageWidth) {
|
||||||
|
// Here we get back directly to a more wide mode.
|
||||||
|
Config.roomListPageWidth = root.minPageWidth;
|
||||||
|
if (root.width < Kirigami.Units.gridUnit * 35) {
|
||||||
|
root.width = Kirigami.Units.gridUnit * 35;
|
||||||
|
}
|
||||||
|
} else if (Config.roomListPageWidth !== root.collapsedPageWidth) {
|
||||||
|
// Increase page width
|
||||||
|
Config.roomListPageWidth = Math.min(root.defaultPageWidth, root.pageWidth + (mouse.x - _lastX));
|
||||||
|
}
|
||||||
|
} else if (mouse.x < _lastX) {
|
||||||
|
const tmpWidth = root.pageWidth - (_lastX - mouse.x);
|
||||||
|
|
||||||
|
if (tmpWidth < root.minPageWidth) {
|
||||||
|
Config.roomListPageWidth = root.collapsedPageWidth;
|
||||||
|
} else {
|
||||||
|
Config.roomListPageWidth = tmpWidth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
globalDrawer: Kirigami.GlobalDrawer {
|
globalDrawer: Kirigami.GlobalDrawer {
|
||||||
property bool hasLayer
|
property bool hasLayer
|
||||||
|
|||||||
@@ -41,6 +41,9 @@
|
|||||||
<label>"Show your messages on the right</label>
|
<label>"Show your messages on the right</label>
|
||||||
<default>true</default>
|
<default>true</default>
|
||||||
</entry>
|
</entry>
|
||||||
|
<entry name="RoomListPageWidth" type="int">
|
||||||
|
<default>-1</default>
|
||||||
|
</entry>
|
||||||
</group>
|
</group>
|
||||||
<group name="Timeline">
|
<group name="Timeline">
|
||||||
<entry name="ShowAvatarInTimeline" type="bool">
|
<entry name="ShowAvatarInTimeline" type="bool">
|
||||||
|
|||||||
@@ -432,6 +432,24 @@ QString RoomListModel::categoryName(int section)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString RoomListModel::categoryIconName(int section)
|
||||||
|
{
|
||||||
|
switch (section) {
|
||||||
|
case 1:
|
||||||
|
return QStringLiteral("user-invisible");
|
||||||
|
case 2:
|
||||||
|
return QStringLiteral("favorite");
|
||||||
|
case 3:
|
||||||
|
return QStringLiteral("dialog-messages");
|
||||||
|
case 4:
|
||||||
|
return QStringLiteral("group");
|
||||||
|
case 5:
|
||||||
|
return QStringLiteral("object-order-lower");
|
||||||
|
default:
|
||||||
|
return QStringLiteral("tools-report-bug");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RoomListModel::setCategoryVisible(int category, bool visible)
|
void RoomListModel::setCategoryVisible(int category, bool visible)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ public:
|
|||||||
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
Q_INVOKABLE [[nodiscard]] static QString categoryName(int section);
|
Q_INVOKABLE [[nodiscard]] static QString categoryName(int section);
|
||||||
|
Q_INVOKABLE [[nodiscard]] static QString categoryIconName(int section);
|
||||||
Q_INVOKABLE void setCategoryVisible(int category, bool visible);
|
Q_INVOKABLE void setCategoryVisible(int category, bool visible);
|
||||||
Q_INVOKABLE [[nodiscard]] bool categoryVisible(int category) const;
|
Q_INVOKABLE [[nodiscard]] bool categoryVisible(int category) const;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user