Add a basic member list pane to rooms
1
TODO.md
|
@ -1,7 +1,6 @@
|
||||||
- Refactoring
|
- Refactoring
|
||||||
- Migrate more JS functions to their own files / Implement in Python instead
|
- Migrate more JS functions to their own files / Implement in Python instead
|
||||||
- Don't bake in size properties for components
|
- Don't bake in size properties for components
|
||||||
- Cleanup unused icons
|
|
||||||
|
|
||||||
- Bug fixes
|
- Bug fixes
|
||||||
- dataclass-like `default_factory` for ListItem
|
- dataclass-like `default_factory` for ListItem
|
||||||
|
|
|
@ -3,9 +3,9 @@ import QtQuick.Layouts 1.3
|
||||||
import "../Base"
|
import "../Base"
|
||||||
import "Banners"
|
import "Banners"
|
||||||
import "RoomEventList"
|
import "RoomEventList"
|
||||||
import "DetailsPane"
|
import "RoomSidePane"
|
||||||
|
|
||||||
HSplitView {
|
HColumnLayout {
|
||||||
property string userId: ""
|
property string userId: ""
|
||||||
property string category: ""
|
property string category: ""
|
||||||
property string roomId: ""
|
property string roomId: ""
|
||||||
|
@ -32,46 +32,58 @@ HSplitView {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
HColumnLayout {
|
RoomHeader {
|
||||||
|
id: roomHeader
|
||||||
|
displayName: roomInfo.displayName
|
||||||
|
topic: roomInfo.topic || ""
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: 32
|
||||||
RoomHeader {
|
|
||||||
displayName: roomInfo.displayName
|
|
||||||
topic: roomInfo.topic || ""
|
|
||||||
}
|
|
||||||
|
|
||||||
RoomEventList {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.fillHeight: true
|
|
||||||
}
|
|
||||||
|
|
||||||
TypingMembersBar {}
|
|
||||||
|
|
||||||
InviteBanner {
|
|
||||||
visible: category === "Invites"
|
|
||||||
inviter: roomInfo.inviter
|
|
||||||
}
|
|
||||||
|
|
||||||
UnknownDevicesBanner {
|
|
||||||
visible: category == "Rooms" && hasUnknownDevices
|
|
||||||
}
|
|
||||||
|
|
||||||
SendBox {
|
|
||||||
id: sendBox
|
|
||||||
visible: category == "Rooms" && ! hasUnknownDevices
|
|
||||||
}
|
|
||||||
|
|
||||||
LeftBanner {
|
|
||||||
visible: category === "Left"
|
|
||||||
leftEvent: roomInfo.leftEvent
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DetailsPane {
|
|
||||||
property int parentWidth: parent.width
|
|
||||||
onParentWidthChanged: width = Math.min(parent.width * 0.3, 300)
|
|
||||||
|
|
||||||
Layout.minimumWidth: 36
|
HSplitView {
|
||||||
Layout.maximumWidth: parent.width
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
|
||||||
|
HColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
RoomEventList {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
|
||||||
|
TypingMembersBar {}
|
||||||
|
|
||||||
|
InviteBanner {
|
||||||
|
visible: category === "Invites"
|
||||||
|
inviter: roomInfo.inviter
|
||||||
|
}
|
||||||
|
|
||||||
|
UnknownDevicesBanner {
|
||||||
|
visible: category == "Rooms" && hasUnknownDevices
|
||||||
|
}
|
||||||
|
|
||||||
|
SendBox {
|
||||||
|
id: sendBox
|
||||||
|
visible: category == "Rooms" && ! hasUnknownDevices
|
||||||
|
}
|
||||||
|
|
||||||
|
LeftBanner {
|
||||||
|
visible: category === "Left"
|
||||||
|
leftEvent: roomInfo.leftEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomSidePane {
|
||||||
|
id: roomSidePane
|
||||||
|
|
||||||
|
property int referenceWidth: roomHeader.buttonsWidth
|
||||||
|
onReferenceWidthChanged: width = referenceWidth
|
||||||
|
|
||||||
|
Layout.minimumWidth: 36
|
||||||
|
Layout.maximumWidth: parent.width
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,14 @@ HRectangle {
|
||||||
property string displayName: ""
|
property string displayName: ""
|
||||||
property string topic: ""
|
property string topic: ""
|
||||||
|
|
||||||
|
property bool collapseButtons: width < 480
|
||||||
|
property alias buttonsWidth: viewButtons.width
|
||||||
|
|
||||||
id: roomHeader
|
id: roomHeader
|
||||||
color: HStyle.chat.roomHeader.background
|
color: HStyle.chat.roomHeader.background
|
||||||
|
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.preferredHeight: 32
|
|
||||||
|
|
||||||
HRowLayout {
|
HRowLayout {
|
||||||
id: row
|
id: row
|
||||||
spacing: 8
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
HAvatar {
|
HAvatar {
|
||||||
|
@ -30,7 +29,12 @@ HRectangle {
|
||||||
font.pixelSize: HStyle.fontSize.big
|
font.pixelSize: HStyle.fontSize.big
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
Layout.maximumWidth: row.width - row.totalSpacing - avatar.width
|
|
||||||
|
Layout.maximumWidth:
|
||||||
|
row.width - Layout.leftMargin * 2 - avatar.width -
|
||||||
|
viewButtons.width -
|
||||||
|
(expandButton.visible ? expandButton.width : 0)
|
||||||
|
Layout.leftMargin: 8
|
||||||
}
|
}
|
||||||
|
|
||||||
HLabel {
|
HLabel {
|
||||||
|
@ -39,10 +43,56 @@ HRectangle {
|
||||||
font.pixelSize: HStyle.fontSize.small
|
font.pixelSize: HStyle.fontSize.small
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
maximumLineCount: 1
|
maximumLineCount: 1
|
||||||
|
|
||||||
Layout.maximumWidth:
|
Layout.maximumWidth:
|
||||||
row.width - row.totalSpacing - avatar.width - roomName.width
|
row.width - Layout.leftMargin * 2 - avatar.width -
|
||||||
|
roomName.width - viewButtons.width -
|
||||||
|
(expandButton.visible ? expandButton.width : 0)
|
||||||
|
Layout.leftMargin: 8
|
||||||
}
|
}
|
||||||
|
|
||||||
HSpacer {}
|
HSpacer {}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: viewButtons
|
||||||
|
Layout.maximumWidth: collapseButtons ? 0 : implicitWidth
|
||||||
|
|
||||||
|
HButton {
|
||||||
|
iconName: "room_view_members"
|
||||||
|
}
|
||||||
|
|
||||||
|
HButton {
|
||||||
|
iconName: "room_view_files"
|
||||||
|
}
|
||||||
|
|
||||||
|
HButton {
|
||||||
|
iconName: "room_view_notifications"
|
||||||
|
}
|
||||||
|
|
||||||
|
HButton {
|
||||||
|
iconName: "room_view_history"
|
||||||
|
}
|
||||||
|
|
||||||
|
HButton {
|
||||||
|
iconName: "room_view_settings"
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on Layout.maximumWidth {
|
||||||
|
NumberAnimation { id: buttonsAnimation; duration: 150 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HButton {
|
||||||
|
id: expandButton
|
||||||
|
z: 1
|
||||||
|
anchors.right: parent.right
|
||||||
|
opacity: collapseButtons ? 1 : 0
|
||||||
|
visible: opacity > 0
|
||||||
|
iconName: "reduced_room_buttons"
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation { duration: buttonsAnimation.duration * 2 }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
37
harmonyqml/components/Chat/RoomSidePane/MemberDelegate.qml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import "../../Base"
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: memberDelegate
|
||||||
|
width: memberList.width
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
property var member: Backend.users.get(modelData)
|
||||||
|
|
||||||
|
HRowLayout {
|
||||||
|
width: parent.width
|
||||||
|
spacing: memberList.spacing
|
||||||
|
|
||||||
|
HAvatar {
|
||||||
|
id: memberAvatar
|
||||||
|
name: member.displayName.value
|
||||||
|
}
|
||||||
|
|
||||||
|
HColumnLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.maximumWidth:
|
||||||
|
parent.width - parent.totalSpacing - memberAvatar.width
|
||||||
|
|
||||||
|
HLabel {
|
||||||
|
id: memberName
|
||||||
|
text: member.displayName.value
|
||||||
|
elide: Text.ElideRight
|
||||||
|
maximumLineCount: 1
|
||||||
|
verticalAlignment: Qt.AlignVCenter
|
||||||
|
|
||||||
|
Layout.maximumWidth: parent.width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
harmonyqml/components/Chat/RoomSidePane/MembersView.qml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import "../../Base"
|
||||||
|
|
||||||
|
Column {
|
||||||
|
property int normalSpacing: 8
|
||||||
|
property bool collapsed:
|
||||||
|
width < roomSidePane.Layout.minimumWidth + normalSpacing
|
||||||
|
|
||||||
|
leftPadding: collapsed ? 0 : normalSpacing
|
||||||
|
rightPadding: leftPadding
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
|
||||||
|
id: memberList
|
||||||
|
|
||||||
|
spacing: collapsed ? 0 : normalSpacing
|
||||||
|
topMargin: spacing
|
||||||
|
bottomMargin: topMargin
|
||||||
|
|
||||||
|
Behavior on spacing {
|
||||||
|
NumberAnimation { duration: 150 }
|
||||||
|
}
|
||||||
|
|
||||||
|
model: chatPage.roomInfo.members
|
||||||
|
delegate: MemberDelegate {}
|
||||||
|
}
|
||||||
|
}
|
16
harmonyqml/components/Chat/RoomSidePane/RoomSidePane.qml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
import QtQuick 2.7
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import "../../Base"
|
||||||
|
|
||||||
|
HRectangle {
|
||||||
|
id: roomSidePane
|
||||||
|
|
||||||
|
HColumnLayout {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
MembersView {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,8 +50,21 @@ Item {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (pageStack.initialPageSet) { return }
|
if (pageStack.initialPageSet) { return }
|
||||||
pageStack.initialPageSet = true
|
pageStack.initialPageSet = true
|
||||||
showRoom("@test_mary:matrix.org", "Rooms", "!TSXGsbBbdwsdylIOJZ:matrix.org")
|
showPage(accountsLoggedIn ? "Default" : "SignIn")
|
||||||
//showPage(accountsLoggedIn ? "Default" : "SignIn")
|
if (accountsLoggedIn) { initialRoomTimer.start() }
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
// TODO: remove this, debug
|
||||||
|
id: initialRoomTimer
|
||||||
|
interval: appWindow.reloadedTimes > 0 ? 0 : 5000
|
||||||
|
repeat: false
|
||||||
|
onTriggered: pageStack.showRoom(
|
||||||
|
"@test_mary:matrix.org",
|
||||||
|
"Rooms",
|
||||||
|
//"!TSXGsbBbdwsdylIOJZ:matrix.org"
|
||||||
|
"!HfNYlUkGqcWcpDQJpb:matrix.org"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onCurrentItemChanged: if (currentItem) {
|
onCurrentItemChanged: if (currentItem) {
|
||||||
|
|
|
@ -10,6 +10,8 @@ ApplicationWindow {
|
||||||
|
|
||||||
onClosing: Backend.clients.removeAll()
|
onClosing: Backend.clients.removeAll()
|
||||||
|
|
||||||
|
property int reloadedTimes: 0
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: "UI.qml"
|
source: "UI.qml"
|
||||||
|
|
|
@ -70,9 +70,12 @@ class Engine(QQmlApplicationEngine):
|
||||||
|
|
||||||
def reloadQml(self) -> None:
|
def reloadQml(self) -> None:
|
||||||
loader = self.rootObjects()[0].findChild(QObject, "UILoader")
|
loader = self.rootObjects()[0].findChild(QObject, "UILoader")
|
||||||
|
|
||||||
source = loader.property("source")
|
source = loader.property("source")
|
||||||
loader.setProperty("source", None)
|
loader.setProperty("source", None)
|
||||||
self.clearComponentCache()
|
self.clearComponentCache()
|
||||||
|
|
||||||
|
window = self.rootObjects()[0]
|
||||||
|
reloaded_times = window.property("reloadedTimes")
|
||||||
|
window.setProperty("reloadedTimes", reloaded_times + 1)
|
||||||
|
|
||||||
loader.setProperty("source", source)
|
loader.setProperty("source", source)
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 1h-24v16.981h4v5.019l7-5.019h13z"/></svg>
|
|
Before Width: | Height: | Size: 137 B |
|
@ -1 +0,0 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M21 13v10h-6v-6h-6v6h-6v-10h-3l12-12 12 12h-3zm-1-5.907v-5.093h-3v2.093l3 3z"/></svg>
|
|
Before Width: | Height: | Size: 177 B |
1
harmonyqml/icons/reduced_room_buttons.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M6 12c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3zm9 0c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3zm9 0c0 1.657-1.343 3-3 3s-3-1.343-3-3 1.343-3 3-3 3 1.343 3 3z"/></svg>
|
After Width: | Height: | Size: 288 B |
1
harmonyqml/icons/room_view_files.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M22 13v-13h-20v24h8.409c4.857 0 3.335-8 3.335-8 3.009.745 8.256.419 8.256-3zm-4-7h-12v-1h12v1zm0 3h-12v-1h12v1zm0 3h-12v-1h12v1zm-2.091 6.223c2.047.478 4.805-.279 6.091-1.179-1.494 1.998-5.23 5.708-7.432 6.881 1.156-1.168 1.563-4.234 1.341-5.702z"/></svg>
|
After Width: | Height: | Size: 347 B |
1
harmonyqml/icons/room_view_history.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M24 12c0 6.627-5.373 12-12 12s-12-5.373-12-12h2c0 5.514 4.486 10 10 10s10-4.486 10-10-4.486-10-10-10c-2.777 0-5.287 1.141-7.099 2.977l2.061 2.061-6.962 1.354 1.305-7.013 2.179 2.18c2.172-2.196 5.182-3.559 8.516-3.559 6.627 0 12 5.373 12 12zm-13-6v8h7v-2h-5v-6h-2z"/></svg>
|
After Width: | Height: | Size: 364 B |
Before Width: | Height: | Size: 344 B After Width: | Height: | Size: 344 B |
1
harmonyqml/icons/room_view_notifications.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15.137 3.945c-.644-.374-1.042-1.07-1.041-1.82v-.003c.001-1.172-.938-2.122-2.096-2.122s-2.097.95-2.097 2.122v.003c.001.751-.396 1.446-1.041 1.82-4.667 2.712-1.985 11.715-6.862 13.306v1.749h20v-1.749c-4.877-1.591-2.195-10.594-6.863-13.306zm-3.137-2.945c.552 0 1 .449 1 1 0 .552-.448 1-1 1s-1-.448-1-1c0-.551.448-1 1-1zm3 20c0 1.598-1.392 3-2.971 3s-3.029-1.402-3.029-3h6z"/></svg>
|
After Width: | Height: | Size: 471 B |
1
harmonyqml/icons/room_view_settings.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M6 18h-2v5h-2v-5h-2v-3h6v3zm-2-17h-2v12h2v-12zm11 7h-6v3h2v12h2v-12h2v-3zm-2-7h-2v5h2v-5zm11 14h-6v3h2v5h2v-5h2v-3zm-2-14h-2v12h2v-12z"/></svg>
|
After Width: | Height: | Size: 235 B |