Reorganize sidePane, accounts and rooms
- Accordion design for accounts and rooms (not finished) - Toolbar and account/room lists reduce correctly, buttons become hamburger menu if not enough width - Can set status using the "Set status message" account fields - Uniformized avatar sizes for sidePane, roomHeader and SendBox
This commit is contained in:
parent
16aa6142bb
commit
cccc43a9ae
|
@ -2,53 +2,83 @@ import QtQuick 2.7
|
|||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
Row {
|
||||
readonly property string displayName:
|
||||
Backend.getUser(section).display_name
|
||||
ColumnLayout {
|
||||
id: "accountDelegate"
|
||||
spacing: 0
|
||||
width: parent.width
|
||||
|
||||
id: row
|
||||
width: roomListView.width
|
||||
height: Math.max(accountLabel.height + statusEdit.height, avatar.height)
|
||||
RowLayout {
|
||||
id: "row"
|
||||
spacing: 0
|
||||
|
||||
Avatar { id: avatar; username: displayName; dimmension: 32 }
|
||||
|
||||
Rectangle {
|
||||
color: "#111"
|
||||
width: parent.width - avatar.width
|
||||
height: parent.height
|
||||
Avatar { id: "avatar"; username: display_name; dimmension: 36 }
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 1
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
spacing: 0
|
||||
|
||||
PlainLabel {
|
||||
id: accountLabel
|
||||
text: displayName
|
||||
color: "#CCC"
|
||||
id: "accountLabel"
|
||||
text: display_name
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
Layout.fillWidth: true
|
||||
|
||||
topPadding: -2
|
||||
bottomPadding: -2
|
||||
leftPadding: 5
|
||||
rightPadding: 5
|
||||
leftPadding: 6
|
||||
rightPadding: leftPadding
|
||||
}
|
||||
|
||||
TextField {
|
||||
id: statusEdit
|
||||
id: "statusEdit"
|
||||
text: status_message || ""
|
||||
placeholderText: qsTr("Set status message")
|
||||
background: Rectangle { color: "#333" }
|
||||
color: "#CCC"
|
||||
background: null
|
||||
color: "black"
|
||||
selectByMouse: true
|
||||
font.family: "Roboto"
|
||||
font.pixelSize: 12
|
||||
Layout.fillWidth: true
|
||||
padding: 0
|
||||
leftPadding: accountLabel.leftPadding
|
||||
rightPadding: leftPadding
|
||||
|
||||
topPadding: 0
|
||||
bottomPadding: 0
|
||||
leftPadding: 5
|
||||
rightPadding: 5
|
||||
onEditingFinished: {
|
||||
Backend.setStatusMessage(user_id, text)
|
||||
pageStack.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HButton {
|
||||
id: "toggleExpand"
|
||||
iconName: roomList.visible ? "up" : "down"
|
||||
Layout.maximumWidth: 28
|
||||
Layout.maximumHeight: Layout.maximumWidth
|
||||
|
||||
onClicked: {
|
||||
toggleExpand.ToolTip.hide()
|
||||
roomList.visible = ! roomList.visible
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RoomList {
|
||||
id: "roomList"
|
||||
visible: true
|
||||
user: Backend.getUser(user_id)
|
||||
|
||||
Layout.minimumHeight:
|
||||
roomList.visible ?
|
||||
roomList.contentHeight + roomList.anchors.margins * 2 :
|
||||
0
|
||||
Layout.maximumHeight: Layout.minimumHeight
|
||||
|
||||
Layout.minimumWidth: parent.width - Layout.leftMargin * 2
|
||||
Layout.maximumWidth: Layout.minimumWidth
|
||||
|
||||
Layout.margins: accountList.spacing
|
||||
Layout.leftMargin:
|
||||
sidePane.width < 36 + Layout.margins ? 0 : Layout.margins
|
||||
Layout.rightMargin: Layout.leftMargin
|
||||
}
|
||||
}
|
||||
|
|
11
harmonyqml/AccountList.qml
Normal file
11
harmonyqml/AccountList.qml
Normal file
|
@ -0,0 +1,11 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
ListView {
|
||||
id: "accountList"
|
||||
spacing: 8
|
||||
model: Backend.accountsModel
|
||||
delegate: AccountDelegate {}
|
||||
clip: true
|
||||
}
|
|
@ -2,41 +2,15 @@ import QtQuick 2.7
|
|||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
ToolButton {
|
||||
property string tooltip: ""
|
||||
property string iconName: ""
|
||||
property string targetPage: ""
|
||||
|
||||
HButton {
|
||||
function toolBarIsBig() {
|
||||
return roomPane.width >
|
||||
return sidePane.width >
|
||||
Layout.minimumWidth * (toolBar.children.length - 2)
|
||||
}
|
||||
|
||||
id: "button"
|
||||
display: ToolButton.IconOnly
|
||||
icon.source: "icons/" + iconName + ".svg"
|
||||
background: Rectangle { color: "transparent" }
|
||||
|
||||
visible: toolBarIsBig()
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumWidth: height
|
||||
|
||||
onClicked: { toolTip.hide(); pageStack.show_page(targetPage) }
|
||||
|
||||
ToolTip {
|
||||
id: "toolTip"
|
||||
text: tooltip
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
visible: text ? toolTipZone.containsMouse : false
|
||||
}
|
||||
MouseArea {
|
||||
id: toolTipZone
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton // Make button receive clicks normally
|
||||
|
||||
onEntered: button.background.color = "#656565"
|
||||
onExited: button.background.color = "transparent"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,11 @@ RowLayout {
|
|||
ActionButton {
|
||||
iconName: "settings"
|
||||
tooltip: "Settings"
|
||||
targetPage: "SettingsPage"
|
||||
}
|
||||
|
||||
ActionButton {
|
||||
iconName: "add_account"
|
||||
tooltip: "Add new account"
|
||||
targetPage: "AddAccountPage"
|
||||
}
|
||||
|
||||
ActionButton {
|
||||
|
@ -33,7 +31,7 @@ RowLayout {
|
|||
|
||||
ActionButton {
|
||||
iconName: "search"
|
||||
tooltip: "Filter rooms and people"
|
||||
tooltip: "Filter rooms"
|
||||
}
|
||||
|
||||
|
|
@ -3,6 +3,7 @@ import QtQuick.Controls 2.2
|
|||
import QtQuick.Layouts 1.4
|
||||
|
||||
ColumnLayout {
|
||||
property var user: null
|
||||
property var room: null
|
||||
|
||||
id: chatPage
|
||||
|
|
31
harmonyqml/HButton.qml
Normal file
31
harmonyqml/HButton.qml
Normal file
|
@ -0,0 +1,31 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
ToolButton {
|
||||
property string tooltip: ""
|
||||
property string iconName: ""
|
||||
|
||||
id: "button"
|
||||
display: ToolButton.IconOnly
|
||||
icon.source: "icons/" + iconName + ".svg"
|
||||
background: Rectangle { color: "transparent" }
|
||||
|
||||
onClicked: toolTip.hide()
|
||||
|
||||
ToolTip {
|
||||
id: "toolTip"
|
||||
text: tooltip
|
||||
delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
visible: text ? toolTipZone.containsMouse : false
|
||||
}
|
||||
MouseArea {
|
||||
id: "toolTipZone"
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton // Make button receive clicks normally
|
||||
|
||||
onEntered: button.background.color = "#656565"
|
||||
onExited: button.background.color = "transparent"
|
||||
}
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
import QtQuick 2.7
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
}
|
|
@ -13,7 +13,7 @@ Column {
|
|||
Backend.getUser(sender_id).display_name
|
||||
|
||||
readonly property bool isOwn:
|
||||
chatPage.room.account_id === sender_id
|
||||
chatPage.user.user_id === sender_id
|
||||
|
||||
readonly property var previousData:
|
||||
index > 0 ? messageListView.model.get(index - 1) : null
|
||||
|
|
|
@ -2,17 +2,22 @@ import QtQuick 2.7
|
|||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
Item {
|
||||
MouseArea {
|
||||
id: "root"
|
||||
width: roomListView.width
|
||||
width: roomList.width
|
||||
height: Math.max(roomLabel.height + subtitleLabel.height, avatar.height)
|
||||
|
||||
onClicked: pageStack.show_room(
|
||||
roomList.user,
|
||||
roomList.model.get(index)
|
||||
)
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
id: row
|
||||
spacing: 1
|
||||
|
||||
Avatar { id: avatar; username: display_name; dimmension: 32 }
|
||||
Avatar { id: avatar; username: display_name; dimmension: 36 }
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
@ -48,9 +53,4 @@ Item {
|
|||
|
||||
Item { Layout.fillWidth: true }
|
||||
}
|
||||
|
||||
HMouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: pageStack.show_room(roomListView.model.get(index))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import QtQuick.Layouts 1.4
|
|||
Rectangle {
|
||||
id: root
|
||||
Layout.fillWidth: true
|
||||
Layout.minimumHeight: 32
|
||||
Layout.minimumHeight: 36
|
||||
Layout.maximumHeight: Layout.minimumHeight
|
||||
color: "#BBB"
|
||||
|
||||
|
|
25
harmonyqml/RoomList.qml
Normal file
25
harmonyqml/RoomList.qml
Normal file
|
@ -0,0 +1,25 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
ListView {
|
||||
property var user: null
|
||||
|
||||
property int contentHeight: 0
|
||||
|
||||
onCountChanged: {
|
||||
var children = roomList.children
|
||||
var childrenHeight = 0
|
||||
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
childrenHeight += children[i].height
|
||||
}
|
||||
|
||||
contentHeight = childrenHeight + spacing * (children.length - 1)
|
||||
}
|
||||
|
||||
id: "roomList"
|
||||
spacing: 8
|
||||
model: Backend.roomsModel[user.user_id]
|
||||
delegate: RoomDelegate {}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
Rectangle {
|
||||
id: roomPane
|
||||
color: "gray"
|
||||
clip: true // Avoid artifacts when resizing pane width to minimum
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
TopBar {}
|
||||
|
||||
ListView {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
id: roomListView
|
||||
spacing: 0
|
||||
model: Backend.roomsModel
|
||||
delegate: RoomDelegate {}
|
||||
//highlight: Rectangle {color: "lightsteelblue"; radius: 5}
|
||||
|
||||
section.property: "account_id"
|
||||
section.delegate: AccountDelegate {}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -19,9 +19,10 @@ Rectangle {
|
|||
|
||||
Avatar {
|
||||
id: "avatar"
|
||||
username: Backend.getUser(chatPage.room.account_id).display_name
|
||||
username: chatPage.user.display_name
|
||||
dimmension: root.Layout.minimumHeight
|
||||
visible: textArea.text === ""
|
||||
//visible: textArea.text === ""
|
||||
visible: textArea.height <= root.Layout.minimumHeight
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
|
@ -49,7 +50,7 @@ Rectangle {
|
|||
return
|
||||
}
|
||||
|
||||
Backend.sendMessage(chatPage.room.account_id,
|
||||
Backend.sendMessage(chatPage.user.user_id,
|
||||
chatPage.room.room_id,
|
||||
textArea.text)
|
||||
textArea.clear()
|
||||
|
|
21
harmonyqml/SidePane.qml
Normal file
21
harmonyqml/SidePane.qml
Normal file
|
@ -0,0 +1,21 @@
|
|||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
Rectangle {
|
||||
id: sidePane
|
||||
color: "gray"
|
||||
clip: true // Avoid artifacts when resizing pane width to minimum
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
AccountList {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
ButtonsBar {}
|
||||
}
|
||||
}
|
|
@ -6,21 +6,26 @@ import QtQuick.Layouts 1.4
|
|||
Controls1.SplitView {
|
||||
anchors.fill: parent
|
||||
|
||||
RoomPane {
|
||||
Layout.minimumWidth: 32
|
||||
width: 180
|
||||
SidePane {
|
||||
Layout.minimumWidth: 36
|
||||
width: 200
|
||||
}
|
||||
|
||||
StackView {
|
||||
function show_page(componentName) {
|
||||
pageStack.replace(componentName + ".qml")
|
||||
}
|
||||
function show_room(room_obj) {
|
||||
pageStack.replace("ChatPage.qml", { room: room_obj })
|
||||
function show_room(user_obj, room_obj) {
|
||||
pageStack.replace(
|
||||
"ChatPage.qml", { user: user_obj, room: room_obj }
|
||||
)
|
||||
}
|
||||
|
||||
id: "pageStack"
|
||||
initialItem: ChatPage { room: Backend.roomsModel.get(0) }
|
||||
initialItem: ChatPage {
|
||||
user: Backend.accountsModel.get(0)
|
||||
room: Backend.roomsModel[Backend.accountsModel.get(0).user_id].get(0)
|
||||
}
|
||||
|
||||
onCurrentItemChanged: currentItem.forceActiveFocus()
|
||||
|
||||
|
|
|
@ -14,10 +14,10 @@ class User(NamedTuple):
|
|||
user_id: str
|
||||
display_name: str
|
||||
avatar_url: Optional[str] = None
|
||||
status_message: Optional[str] = None
|
||||
|
||||
|
||||
class Room(NamedTuple):
|
||||
account_id: str
|
||||
room_id: str
|
||||
display_name: str
|
||||
subtitle: str = ""
|
||||
|
@ -41,13 +41,19 @@ class Backend(QObject):
|
|||
super().__init__()
|
||||
self._known_users: Dict[str, User] = {}
|
||||
|
||||
self.rooms: ListModel = ListModel()
|
||||
self.accounts: ListModel = ListModel()
|
||||
self.rooms: DefaultDict[str, ListModel] = DefaultDict(ListModel)
|
||||
self.messages: DefaultDict[str, ListModel] = DefaultDict(ListModel)
|
||||
|
||||
|
||||
@pyqtProperty(_QtListModel, constant=True)
|
||||
def roomsModel(self) -> _QtListModel:
|
||||
return self.rooms.qt_model
|
||||
def accountsModel(self) -> _QtListModel:
|
||||
return self.accounts.qt_model
|
||||
|
||||
|
||||
@pyqtProperty("QVariantMap", constant=True)
|
||||
def roomsModel(self) -> Dict[str, _QtListModel]:
|
||||
return {account_id: l.qt_model for account_id, l in self.rooms.items()}
|
||||
|
||||
|
||||
@pyqtProperty("QVariantMap", constant=True)
|
||||
|
@ -73,6 +79,10 @@ class Backend(QObject):
|
|||
|
||||
@pyqtSlot(str, result="QVariantMap")
|
||||
def getUser(self, user_id: str) -> Dict[str, Any]:
|
||||
for user in self.accounts:
|
||||
if user.user_id == user_id:
|
||||
return user._asdict()
|
||||
|
||||
try:
|
||||
return self._known_users[user_id]._asdict()
|
||||
except KeyError:
|
||||
|
@ -87,3 +97,13 @@ class Backend(QObject):
|
|||
# pylint: disable=no-self-use
|
||||
md5 = hashlib.md5(bytes(string, "utf-8")).hexdigest()
|
||||
return float("0.%s" % int(md5[-10:], 16))
|
||||
|
||||
|
||||
@pyqtSlot(str, str)
|
||||
def setStatusMessage(self, user_id: str, to: str) -> None:
|
||||
for user in self.accounts:
|
||||
if user.user_id == user_id:
|
||||
user.status_message = to
|
||||
break
|
||||
else:
|
||||
raise ValueError(f"{user_id} not found in Backend.accounts")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
from PyQt5.QtCore import QDateTime, Qt
|
||||
|
||||
from .base import Backend, Message, Room
|
||||
from .base import Backend, Message, Room, User
|
||||
|
||||
|
||||
class DummyBackend(Backend):
|
||||
|
@ -15,16 +15,22 @@ class DummyBackend(Backend):
|
|||
db = lambda t: QDateTime.fromString(f"2019-03-20T{t}.456",
|
||||
Qt.ISODateWithMs)
|
||||
|
||||
self.rooms.extend([
|
||||
Room("@renko:matrix.org", "!test:matrix.org", "Test", "Test room"),
|
||||
Room("@renko:matrix.org", "!mary:matrix.org", "Mary",
|
||||
self.accounts.extend([
|
||||
User("@renko:matrix.org", "Renko", None, "Sleeping, zzz..."),
|
||||
User("@mary:matrix.org", "Mary"),
|
||||
])
|
||||
|
||||
self.rooms["@renko:matrix.org"].extend([
|
||||
Room("!test:matrix.org", "Test", "Test room"),
|
||||
Room("!mary:matrix.org", "Mary",
|
||||
"Lorem ipsum sit dolor amet this is a long text to test "
|
||||
"wrapping of room subtitle etc 1234 example foo bar abc", 2),
|
||||
Room("@renko:matrix.org", "!foo:matrix.org", "Another room"),
|
||||
Room("!foo:matrix.org", "Another room"),
|
||||
])
|
||||
|
||||
Room("@mary:matrix.org", "!test:matrix.org", "Test", "Test room"),
|
||||
Room("@mary:matrix.org", "!mary:matrix.org", "Renko",
|
||||
"Lorem ipsum sit dolor amet"),
|
||||
self.rooms["@mary:matrix.org"].extend([
|
||||
Room("!test:matrix.org", "Test", "Test room"),
|
||||
Room("!mary:matrix.org", "Renko", "Lorem ipsum sit dolor amet"),
|
||||
])
|
||||
|
||||
self.messages["!test:matrix.org"].extend([
|
||||
|
|
1
harmonyqml/icons/down.svg
Normal file
1
harmonyqml/icons/down.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="M0 7.33l2.829-2.83 9.175 9.339 9.167-9.339 2.829 2.83-11.996 12.17z"/></svg>
|
After Width: | Height: | Size: 168 B |
1
harmonyqml/icons/up.svg
Normal file
1
harmonyqml/icons/up.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="M0 16.67l2.829 2.83 9.175-9.339 9.167 9.339 2.829-2.83-11.996-12.17z"/></svg>
|
After Width: | Height: | Size: 169 B |
Loading…
Reference in New Issue
Block a user