Capitalization, list model and room header work

- Standardized capitalization for variables and file names everywhere in
  QML and JS, get rid of mixed camelCase/snakeCase,
  use camelCase like everywhere in Qt

- ListModel items are now stored and returned as real QObjects with
  PyQt properties and signals.
  This makes dynamic property binding a lot easier and eliminates the need
  for many hacks.

- New update(), updateOrAppendWhere() methods and roles property
  for ListModel

- RoomHeader now properly updates when the room title or topic changes

- Add Backend.pdb(), to make it easier to start the debugger from QML
This commit is contained in:
miruka
2019-04-20 17:36:21 -04:00
parent b33f5f1d34
commit 8f35e60801
34 changed files with 304 additions and 250 deletions

View File

@@ -0,0 +1,87 @@
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.4
import "../base" as Base
ColumnLayout {
id: "accountDelegate"
spacing: 0
width: parent.width
RowLayout {
id: "row"
spacing: 0
Base.Avatar { id: "avatar"; name: displayName; dimmension: 36 }
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 0
Base.HLabel {
id: "accountLabel"
text: displayName.value || userId
elide: Text.ElideRight
maximumLineCount: 1
Layout.fillWidth: true
leftPadding: 6
rightPadding: leftPadding
}
TextField {
id: "statusEdit"
text: statusMessage || ""
placeholderText: qsTr("Set status message")
background: null
color: "black"
selectByMouse: true
font.family: "Roboto"
font.pixelSize: 12
Layout.fillWidth: true
padding: 0
leftPadding: accountLabel.leftPadding
rightPadding: leftPadding
onEditingFinished: {
Backend.setStatusMessage(userId, text)
pageStack.forceActiveFocus()
}
}
}
Base.HToolButton {
id: "toggleExpand"
iconName: roomList.visible ? "up" : "down"
Layout.maximumWidth: 28
Layout.minimumHeight: row.height
onClicked: {
toggleExpand.ToolTip.hide()
roomList.visible = ! roomList.visible
}
}
}
RoomList {
id: "roomList"
visible: true
interactive: false // no scrolling
forUserId: userId
Layout.minimumHeight:
roomList.visible ?
roomList.contentHeight :
0
Layout.maximumHeight: Layout.minimumHeight
Layout.minimumWidth:
parent.width - Layout.leftMargin - Layout.rightMargin
Layout.maximumWidth: Layout.minimumWidth
Layout.margins: accountList.spacing
Layout.leftMargin:
sidePane.width < 36 + Layout.margins ? 0 : Layout.margins
Layout.rightMargin: 0
}
}

View 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.models.accounts
delegate: AccountDelegate {}
clip: true
}

View File

@@ -0,0 +1,49 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4
import "../base" as Base
RowLayout {
id: "toolBar"
Layout.fillWidth: true
Layout.maximumHeight: 32
spacing: 0
HToolButton {
visible: ! toolBarIsBig()
iconName: "reduced_menu"
tooltip: "Menu"
}
HToolButton {
iconName: "settings"
tooltip: "Settings"
}
HToolButton {
iconName: "add_account"
tooltip: "Add new account"
}
HToolButton {
iconName: "set_status"
tooltip: "Set status for all accounts"
}
HToolButton {
iconName: "search"
tooltip: "Filter rooms"
}
TextField {
id: filterField
visible: false
placeholderText: qsTr("Filter rooms")
selectByMouse: true
font.family: "Roboto"
Layout.fillWidth: true
Layout.fillHeight: true
background: Rectangle { color: "lightgray" }
}
}

View File

@@ -0,0 +1,17 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4
import "../base" as Base
Base.HToolButton {
function toolBarIsBig() {
return sidePane.width >
Layout.minimumWidth * (toolBar.children.length - 2)
}
id: "button"
visible: toolBarIsBig()
Layout.fillHeight: true
Layout.fillWidth: true
Layout.minimumWidth: height
}

View File

@@ -0,0 +1,67 @@
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.4
import "../base" as Base
import "utils.js" as SidePaneJS
MouseArea {
id: "root"
width: roomList.width
height: roomList.childrenHeight
onClicked: pageStack.showRoom(roomList.forUserId, roomId)
RowLayout {
anchors.fill: parent
id: row
spacing: 1
Base.Avatar { id: avatar; name: displayName; dimmension: root.height }
ColumnLayout {
spacing: 0
Base.HLabel {
id: roomLabel
text: displayName ? displayName : "<i>Empty room</i>"
textFormat: Text.StyledText
elide: Text.ElideRight
maximumLineCount: 1
Layout.maximumWidth: row.width - row.spacing - avatar.width
verticalAlignment: Qt.AlignVCenter
topPadding: -2
bottomPadding: subtitleLabel.visible ? 0 : topPadding
leftPadding: 5
rightPadding: leftPadding
}
Base.HLabel {
function getText() {
return SidePaneJS.getLastRoomEventText(roomId)
}
Connections {
target: Backend.models.roomEvents.get(roomId)
onChanged: subtitleLabel.text = subtitleLabel.getText()
}
id: subtitleLabel
visible: text !== ""
text: getText()
textFormat: Text.StyledText
font.pixelSize: smallSize
elide: Text.ElideRight
maximumLineCount: 1
Layout.maximumWidth: roomLabel.Layout.maximumWidth
topPadding: -2
bottomPadding: topPadding
leftPadding: 5
rightPadding: leftPadding
}
}
Item { Layout.fillWidth: true }
}
}

View File

@@ -0,0 +1,21 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4
import "../base" as Base
ListView {
property var forUserId: null
property int childrenHeight: 36
property int contentHeight: 0
onCountChanged: {
contentHeight = childrenHeight * model.count +
spacing * (model.count - 1)
}
id: "roomList"
spacing: 8
model: Backend.models.rooms.get(forUserId)
delegate: RoomDelegate {}
}

View File

@@ -0,0 +1,22 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4
import "../base" as Base
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
}
HToolBar {}
}
}

View File

@@ -0,0 +1,42 @@
.import "../chat/utils.js" as ChatJS
function getLastRoomEventText(roomId) {
var eventsModel = Backend.models.roomEvents.get(roomId)
for (var i = 0; i < eventsModel.count; i++) {
var ev = eventsModel.get(i)
if (ev.type !== "RoomMemberEvent") {
var found = true
break
}
}
if (! found) { return "" }
var name = Backend.getUserDisplayName(ev.dict.sender, false).result()
var undecryptable = ev.type === "OlmEvent" || ev.type === "MegolmEvent"
if (undecryptable || ev.type.startsWith("RoomMessage")) {
var color = ev.dict.sender === roomList.forUserId ?
"darkblue" : "purple"
return "<font color='" +
color +
"'>" +
name +
":</font> " +
(undecryptable ?
"<font color='darkred'>Undecryptable<font>" :
ev.dict.body)
} else {
return "<font color='" +
(undecryptable ? "darkred" : "#444") +
"'>" +
name +
" " +
ChatJS.getEventText(ev.type, ev.dict) +
"</font>"
}
}