Build system, messages support and more

This commit is contained in:
miruka
2019-07-02 13:59:52 -04:00
parent 933341b7e6
commit 06c823aa67
53 changed files with 2264 additions and 446 deletions

View File

@@ -7,7 +7,14 @@ Rectangle {
property int dimension: HStyle.avatar.size
property bool hidden: false
function hue_from_name(name) {
function stripUserId(user_id) {
return user_id.substring(1) // Remove leading @
}
function stripRoomName(name) {
return name[0] == "#" ? name.substring(1) : name
}
function hueFromName(name) {
var hue = 0
for (var i = 0; i < name.length; i++) {
hue += name.charCodeAt(i) * 99
@@ -24,7 +31,7 @@ Rectangle {
color: name ?
Qt.hsla(
hue_from_name(name),
hueFromName(name),
HStyle.avatar.background.saturation,
HStyle.avatar.background.lightness,
HStyle.avatar.background.alpha

View File

@@ -32,11 +32,6 @@ Button {
signal pressed
signal released
function loadingUntilFutureDone(future) {
loading = true
future.onGotResult.connect(function() { loading = false })
}
id: button
background: Rectangle {

View File

@@ -1,85 +1,112 @@
import QtQuick 2.7
import SortFilterProxyModel 0.2
ListModel {
SortFilterProxyModel {
// To initialize a HListModel with items,
// use `Component.onCompleted: extend([{"foo": 1, "bar": 2}, ...])`
id: listModel
id: sortFilteredModel
property var model: ListModel {}
sourceModel: model // Can't assign a "ListModel {}" directly here
function append(dict) { return model.append(dict) }
function clear() { return model.clear() }
function insert(index, dict) { return model.inset(index, dict) }
function move(from, to, n) { return model.move(from, to, n) }
function remove(index, count) { return model.remove(index, count) }
function set(index, dict) { return model.set(index, dict) }
function sync() { return model.sync() }
function setProperty(index, prop, value) {
return model.setProperty(index, prop, value)
}
function extend(new_items) {
for (var i = 0; i < new_items.length; i++) {
listModel.append(new_items[i])
model.append(new_items[i])
}
}
function getIndices(where_role, is, max) { // max: undefined or int
function getIndices(where_roles_are, max_results, max_tries) {
// max arguments: unefined or int
var results = []
for (var i = 0; i < listModel.count; i++) {
if (listModel.get(i)[where_role] == is) {
results.push(i)
for (var i = 0; i < model.count; i++) {
var item = model.get(i)
var include = true
if (max && results.length >= max) {
for (var role in where_roles_are) {
if (item[role] != where_roles_are[role]) {
include = false
break
}
}
if (include) {
results.push(i)
if (max_results && results.length >= max_results) {
break
}
}
if (max_tries && i >= max_tries) {
break
}
}
return results
}
function getWhere(where_role, is, max) {
var indices = getIndices(where_role, is, max)
var results = []
function getWhere(roles_are, max_results, max_tries) {
var indices = getIndices(roles_are, max_results, max_tries)
var items = []
for (var i = 0; i < indices.length; i++) {
results.push(listModel.get(indices[i]))
items.push(model.get(indices[i]))
}
return results
return items
}
function forEachWhere(where_role, is, max, func) {
var items = getWhere(where_role, is, max)
function forEachWhere(roles_are, func, max_results, max_tries) {
var items = getWhere(roles_are, max_results, max_tries)
for (var i = 0; i < items.length; i++) {
func(item)
func(items[i])
}
}
function upsert(where_role, is, new_item, update_if_exist) {
// new_item can contain only the keys we're interested in updating
var indices = getIndices(where_role, is, 1)
function upsert(where_roles_are, new_item, update_if_exist, max_tries) {
var indices = getIndices(where_roles_are, 1, max_tries)
if (indices.length == 0) {
listModel.append(new_item)
return listModel.get(listModel.count)
model.append(new_item)
return model.get(model.count)
}
if (update_if_exist != false) {
listModel.set(indices[0], new_item)
model.set(indices[0], new_item)
}
return listModel.get(indices[0])
return model.get(indices[0])
}
function pop(index) {
var item = listModel.get(index)
listModel.remove(index)
var item = model.get(index)
model.remove(index)
return item
}
function popWhere(where_role, is, max) {
var indices = getIndices(where_role, is, max)
var results = []
function popWhere(roles_are, max_results, max_tries) {
var indices = getIndices(roles_are, max_results, max_tries)
var items = []
for (var i = 0; i < indices.length; i++) {
results.push(listModel.get(indices[i]))
listModel.remove(indices[i])
items.push(model.get(indices[i]))
model.remove(indices[i])
}
return results
return items
}
function toObject(item_list) {
item_list = item_list || listModel
item_list = item_list || sortFilteredModel
var obj_list = []
for (var i = 0; i < item_list.count; i++) {

View File

@@ -6,6 +6,7 @@ Banner {
color: HStyle.chat.inviteBanner.background
// TODO: get disp name from models.users, inviter = userid now
avatar.name: inviter ? inviter.displayname : ""
//avatar.imageUrl: inviter ? inviter.avatar_url : ""

View File

@@ -10,27 +10,27 @@ HColumnLayout {
property string category: ""
property string roomId: ""
readonly property var roomInfo:
Backend.accounts.get(userId)
.roomCategories.get(category)
.rooms.get(roomId)
readonly property var roomInfo: models.rooms.getWhere(
{"userId": userId, "roomId": roomId, "category": category}, 1
)[0]
readonly property var sender: Backend.users.get(userId)
readonly property var sender:
models.users.getWhere({"userId": userId}, 1)[0]
readonly property bool hasUnknownDevices:
category == "Rooms" ?
Backend.clients.get(userId).roomHasUnknownDevices(roomId) : false
readonly property bool hasUnknownDevices: false
//category == "Rooms" ?
//Backend.clients.get(userId).roomHasUnknownDevices(roomId) : false
id: chatPage
onFocusChanged: sendBox.setFocus()
Component.onCompleted: Backend.signals.roomCategoryChanged.connect(
function(forUserId, forRoomId, previous, now) {
if (chatPage && forUserId == userId && forRoomId == roomId) {
chatPage.category = now
}
}
)
//Component.onCompleted: Backend.signals.roomCategoryChanged.connect(
//function(forUserId, forRoomId, previous, now) {
//if (chatPage && forUserId == userId && forRoomId == roomId) {
//chatPage.category = now
//}
//}
//)
RoomHeader {
id: roomHeader
@@ -77,72 +77,72 @@ HColumnLayout {
}
}
RoomSidePane {
id: roomSidePane
// RoomSidePane {
//id: roomSidePane
activeView: roomHeader.activeButton
property int oldWidth: width
onActiveViewChanged:
activeView ? restoreAnimation.start() : hideAnimation.start()
//activeView: roomHeader.activeButton
//property int oldWidth: width
//onActiveViewChanged:
//activeView ? restoreAnimation.start() : hideAnimation.start()
NumberAnimation {
id: hideAnimation
target: roomSidePane
properties: "width"
duration: HStyle.animationDuration
from: target.width
to: 0
//NumberAnimation {
//id: hideAnimation
//target: roomSidePane
//properties: "width"
//duration: HStyle.animationDuration
//from: target.width
//to: 0
onStarted: {
target.oldWidth = target.width
target.Layout.minimumWidth = 0
}
}
//onStarted: {
//target.oldWidth = target.width
//target.Layout.minimumWidth = 0
//}
//}
NumberAnimation {
id: restoreAnimation
target: roomSidePane
properties: "width"
duration: HStyle.animationDuration
from: 0
to: target.oldWidth
//NumberAnimation {
//id: restoreAnimation
//target: roomSidePane
//properties: "width"
//duration: HStyle.animationDuration
//from: 0
//to: target.oldWidth
onStopped: target.Layout.minimumWidth = Qt.binding(
function() { return HStyle.avatar.size }
)
}
//onStopped: target.Layout.minimumWidth = Qt.binding(
//function() { return HStyle.avatar.size }
//)
//}
collapsed: width < HStyle.avatar.size + 8
//collapsed: width < HStyle.avatar.size + 8
property bool wasSnapped: false
property int referenceWidth: roomHeader.buttonsWidth
onReferenceWidthChanged: {
if (chatSplitView.canAutoSize || wasSnapped) {
if (wasSnapped) { chatSplitView.canAutoSize = true }
width = referenceWidth
}
}
//property bool wasSnapped: false
//property int referenceWidth: roomHeader.buttonsWidth
//onReferenceWidthChanged: {
//if (chatSplitView.canAutoSize || wasSnapped) {
//if (wasSnapped) { chatSplitView.canAutoSize = true }
//width = referenceWidth
//}
//}
property int currentWidth: width
onCurrentWidthChanged: {
if (referenceWidth != width &&
referenceWidth - 15 < width &&
width < referenceWidth + 15)
{
currentWidth = referenceWidth
width = referenceWidth
wasSnapped = true
currentWidth = Qt.binding(
function() { return roomSidePane.width }
)
} else {
wasSnapped = false
}
}
//property int currentWidth: width
//onCurrentWidthChanged: {
//if (referenceWidth != width &&
//referenceWidth - 15 < width &&
//width < referenceWidth + 15)
//{
//currentWidth = referenceWidth
//width = referenceWidth
//wasSnapped = true
//currentWidth = Qt.binding(
//function() { return roomSidePane.width }
//)
//} else {
//wasSnapped = false
//}
//}
width: referenceWidth // Initial width
Layout.minimumWidth: HStyle.avatar.size
Layout.maximumWidth: parent.width
}
//width: referenceWidth // Initial width
//Layout.minimumWidth: HStyle.avatar.size
//Layout.maximumWidth: parent.width
//}
}
}

View File

@@ -2,7 +2,7 @@ import QtQuick 2.7
import "../../Base"
HNoticePage {
text: dateTime.toLocaleDateString()
text: model.date.toLocaleDateString()
color: HStyle.chat.daybreak.foreground
backgroundColor: HStyle.chat.daybreak.background
radius: HStyle.chat.daybreak.radius

View File

@@ -16,7 +16,7 @@ Row {
HAvatar {
id: avatar
name: sender.displayName.value
name: sender.displayName || stripUserId(sender.userId)
hidden: combine
dimension: 28
}

View File

@@ -10,7 +10,7 @@ Row {
HAvatar {
id: avatar
hidden: combine
name: sender.displayName.value
name: senderInfo.displayName || stripUserId(model.senderId)
dimension: 48
}
@@ -38,8 +38,8 @@ Row {
visible: height > 0
id: nameLabel
text: sender.displayName.value
color: Qt.hsla(Backend.hueFromString(text),
text: senderInfo.displayName || model.senderId
color: Qt.hsla(avatar.hueFromName(avatar.name),
HStyle.displayName.saturation,
HStyle.displayName.lightness,
1)
@@ -56,17 +56,16 @@ Row {
width: parent.width
id: contentLabel
text: (dict.formatted_body ?
Backend.htmlFilter.filter(dict.formatted_body) :
dict.body) +
text: model.content +
"&nbsp;&nbsp;<font size=" + HStyle.fontSize.small +
"px color=" + HStyle.chat.message.date + ">" +
Qt.formatDateTime(dateTime, "hh:mm:ss") +
Qt.formatDateTime(model.date, "hh:mm:ss") +
"</font>" +
(isLocalEcho ?
(model.isLocalEcho ?
"&nbsp;<font size=" + HStyle.fontSize.small +
"px>⏳</font>" : "")
textFormat: Text.RichText
textFormat: model.type == "text" ?
Text.PlainText : Text.RichText
color: HStyle.chat.message.body
wrapMode: Text.Wrap

View File

@@ -1,7 +1,6 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import "../../Base"
import "../utils.js" as ChatJS
Column {
id: roomEventDelegate
@@ -10,46 +9,47 @@ Column {
return Math.round((((date2 - date1) % 86400000) % 3600000) / 60000)
}
function getIsMessage(type_) { return type_.startsWith("RoomMessage") }
function getPreviousItem() {
return index < roomEventListView.model.count - 1 ?
roomEventListView.model.get(index + 1) : null
}
function getIsMessage(type) {
return true
}
property var previousItem: getPreviousItem()
signal reloadPreviousItem()
onReloadPreviousItem: previousItem = getPreviousItem()
readonly property bool isMessage: getIsMessage(type)
property var senderInfo: null
Component.onCompleted:
senderInfo = models.users.getUser(chatPage.userId, senderId)
readonly property bool isUndecryptableEvent:
type === "OlmEvent" || type === "MegolmEvent"
//readonly property bool isMessage: ! model.type.match(/^event.*/)
readonly property bool isMessage: getIsMessage(model.type)
readonly property var sender: Backend.users.get(dict.sender)
readonly property bool isOwn: chatPage.userId === senderId
readonly property bool isOwn:
chatPage.userId === dict.sender
readonly property bool isFirstEvent: type == "RoomCreateEvent"
readonly property bool isFirstEvent: model.type == "eventCreate"
readonly property bool combine:
previousItem &&
! talkBreak &&
! dayBreak &&
getIsMessage(previousItem.type) === isMessage &&
previousItem.dict.sender === dict.sender &&
minsBetween(previousItem.dateTime, dateTime) <= 5
previousItem.senderId === senderId &&
minsBetween(previousItem.date, model.date) <= 5
readonly property bool dayBreak:
isFirstEvent ||
previousItem &&
dateTime.getDate() != previousItem.dateTime.getDate()
model.date.getDate() != previousItem.date.getDate()
readonly property bool talkBreak:
previousItem &&
! dayBreak &&
minsBetween(previousItem.dateTime, dateTime) >= 20
minsBetween(previousItem.date, model.date) >= 20
property int standardSpacing: 16

View File

@@ -1,4 +1,5 @@
import QtQuick 2.7
import SortFilterProxyModel 0.2
import "../../Base"
HRectangle {
@@ -8,10 +9,19 @@ HRectangle {
HListView {
id: roomEventListView
delegate: RoomEventDelegate {}
model: Backend.roomEvents.get(chatPage.roomId)
clip: true
model: HListModel {
sourceModel: models.timelines
filters: ValueFilter {
roleName: "roomId"
value: chatPage.roomId
}
}
delegate: RoomEventDelegate {}
anchors.fill: parent
anchors.leftMargin: space
anchors.rightMargin: space
@@ -29,7 +39,7 @@ HRectangle {
onYPosChanged: {
if (chatPage.category != "Invites" && yPos <= 0.1) {
Backend.loadPastEvents(chatPage.roomId)
//Backend.loadPastEvents(chatPage.roomId)
}
}
}

View File

@@ -3,7 +3,7 @@ import QtQuick.Layouts 1.3
import "../Base"
HRectangle {
property string displayName: ""
property var displayName: ""
property string topic: ""
property alias buttonsImplicitWidth: viewButtons.implicitWidth
@@ -22,7 +22,7 @@ HRectangle {
HAvatar {
id: avatar
name: displayName
name: stripRoomName(displayName) || qsTr("Empty room")
dimension: roomHeader.height
Layout.alignment: Qt.AlignTop
}

View File

@@ -15,7 +15,7 @@ MouseArea {
HAvatar {
id: memberAvatar
name: member.displayName.value
name: member.displayName || stripUserId(member.userId)
}
HColumnLayout {

View File

@@ -18,7 +18,7 @@ HRectangle {
HAvatar {
id: avatar
name: chatPage.sender.displayName.value
name: chatPage.sender.displayName || stripUserId(chatPage.userId)
dimension: root.Layout.minimumHeight
}

View File

@@ -1,26 +1,28 @@
function clientId(user_id, category, room_id) {
return user_id + " " + room_id + " " + category
}
function onRoomUpdated(user_id, category, room_id, display_name, avatar_url,
topic, last_event_date, inviter, left_event) {
var client_id = clientId(user_id, category, room_id)
var rooms = models.rooms
models.roomCategories.upsert({"userId": user_id, "name": category}, {
"userId": user_id,
"name": category
})
var rooms = models.rooms
function roles(for_category) {
return {"userId": user_id, "roomId": room_id, "category": for_category}
}
if (category == "Invites") {
rooms.popWhere("clientId", clientId(user_id, "Rooms", room_id))
rooms.popWhere("clientId", clientId(user_id, "Left", room_id))
rooms.popWhere(roles("Rooms"), 1)
rooms.popWhere(roles("Left"), 1)
}
else if (category == "Rooms") {
rooms.popWhere("clientId", clientId(user_id, "Invites", room_id))
rooms.popWhere("clientId", clientId(user_id, "Left", room_id))
rooms.popWhere(roles("Invites"), 1)
rooms.popWhere(roles("Left"), 1)
}
else if (category == "Left") {
var old_room =
rooms.popWhere("clientId", clientId(user_id, "Rooms", room_id)) ||
rooms.popWhere("clientId", clientId(user_id, "Invites", room_id))
var old_room = rooms.popWhere(roles("Invites"), 1)[0] ||
rooms.popWhere(roles("Rooms"), 1)[0]
if (old_room) {
display_name = old_room.displayName
@@ -30,8 +32,7 @@ function onRoomUpdated(user_id, category, room_id, display_name, avatar_url,
}
}
rooms.upsert("clientId", client_id , {
"clientId": client_id,
rooms.upsert(roles(category), {
"userId": user_id,
"category": category,
"roomId": room_id,
@@ -47,8 +48,8 @@ function onRoomUpdated(user_id, category, room_id, display_name, avatar_url,
function onRoomDeleted(user_id, category, room_id) {
var client_id = clientId(user_id, category, room_id)
return models.rooms.popWhere("clientId", client_id, 1)
var roles = {"userId": user_id, "roomId": room_id, "category": category}
models.rooms.popWhere(roles, 1)
}

View File

@@ -0,0 +1,12 @@
function onHtmlMessageReceived(type, room_id, event_id, sender_id, date,
is_local_echo, content) {
models.timelines.upsert({"eventId": event_id}, {
"type": type,
"roomId": room_id,
"eventId": event_id,
"senderId": sender_id,
"date": date,
"isLocalEcho": is_local_echo,
"content": content,
}, true, 1000)
}

View File

@@ -2,18 +2,17 @@ function onAccountUpdated(user_id) {
models.accounts.append({"userId": user_id})
}
function AccountDeleted(user_id) {
models.accounts.popWhere("userId", user_id, 1)
function onAccountDeleted(user_id) {
models.accounts.popWhere({"userId": user_id}, 1)
}
function onUserUpdated(user_id, display_name, avatar_url, status_message) {
models.users.upsert("userId", user_id, {
models.users.upsert({"userId": user_id}, {
"userId": user_id,
"displayName": display_name,
"avatarUrl": avatar_url,
"statusMessage": status_message
})
}
function onDeviceUpdated(user_id, device_id, ed25519_key, trust, display_name,

View File

@@ -1,4 +1,5 @@
import QtQuick 2.7
import SortFilterProxyModel 0.2
import "Base"
QtObject {
@@ -8,7 +9,7 @@ QtObject {
function getUser(as_account_id, wanted_user_id) {
wanted_user_id = wanted_user_id || as_account_id
var found = users.getWhere("userId", wanted_user_id, 1)
var found = users.getWhere({"userId": wanted_user_id}, 1)
if (found.length > 0) { return found[0] }
users.append({
@@ -22,13 +23,20 @@ QtObject {
as_account_id, "request_user_update_event", [wanted_user_id]
)
return users.getWhere("userId", wanted_user_id, 1)[0]
return users.getWhere({"userId": wanted_user_id}, 1)[0]
}
}
property HListModel devices: HListModel {}
property HListModel roomCategories: HListModel {}
property HListModel rooms: HListModel {}
property HListModel timelines: HListModel {}
property HListModel timelines: HListModel {
sorters: RoleSorter {
roleName: "date"
sortOrder: Qt.DescendingOrder
}
}
}

View File

@@ -4,7 +4,7 @@ import "../Base"
Item {
property string loginWith: "username"
property var client: null
property string userId: ""
HInterfaceBox {
id: rememberBox
@@ -20,10 +20,13 @@ Item {
buttonCallbacks: {
"yes": function(button) {
Backend.clients.remember(client)
py.callCoro("save_account", [userId])
pageStack.showPage("Default")
},
"no": function(button) {
py.callCoro("forget_account", [userId])
pageStack.showPage("Default")
},
"no": function(button) { pageStack.showPage("Default") },
}
HLabel {

View File

@@ -4,7 +4,7 @@ import "../Base"
Item {
property string loginWith: "username"
onFocusChanged: identifierField.forceActiveFocus()
onFocusChanged: idField.forceActiveFocus()
HInterfaceBox {
id: signInBox
@@ -23,15 +23,15 @@ Item {
"register": function(button) {},
"login": function(button) {
var future = Backend.clients.new(
"matrix.org", identifierField.text, passwordField.text
)
button.loadingUntilFutureDone(future)
future.onGotResult.connect(function(client) {
button.loading = true
var args = [idField.text, passwordField.text]
py.callCoro("login_client", args, {}, function(user_id) {
pageStack.showPage(
"RememberAccount",
{"loginWith": loginWith, "client": client}
{"loginWith": loginWith, "userId": user_id}
)
button.loading = false
})
},
@@ -58,7 +58,7 @@ Item {
}
HTextField {
id: identifierField
id: idField
placeholderText: qsTr(
loginWith === "email" ? "Email" :
loginWith === "phone" ? "Phone" :

View File

@@ -9,6 +9,7 @@ Python {
property bool ready: false
property var pendingCoroutines: ({})
signal willLoadAccounts(bool will)
property bool loadingAccounts: false
function callCoro(name, args, kwargs, callback) {
@@ -32,18 +33,20 @@ Python {
}
}
addImportPath("../..")
importNames("src", ["APP"], function() {
call("APP.start", [Qt.application.arguments], function(debug_on) {
window.debug = debug_on
addImportPath("src")
addImportPath("qrc:/")
importNames("python", ["APP"], function() {
call("APP.is_debug_on", [Qt.application.arguments], function(on) {
window.debug = on
callCoro("has_saved_accounts", [], {}, function(has) {
loadingAccounts = has
py.ready = true
willLoadAccounts(has)
if (has) {
py.loadingAccounts = true
py.callCoro("load_saved_accounts", [], {}, function() {
loadingAccounts = false
py.loadingAccounts = false
})
}
})

View File

@@ -20,7 +20,7 @@ Column {
HAvatar {
id: avatar
name: user.displayName
name: user.displayName || stripUserId(user.userId)
}
HColumnLayout {

View File

@@ -4,6 +4,8 @@ import "../Base"
HRowLayout {
id: toolBar
property alias roomFilter: filterField.text
Layout.fillWidth: true
Layout.preferredHeight: HStyle.bottomElementsHeight
@@ -17,8 +19,6 @@ HRowLayout {
placeholderText: qsTr("Filter rooms")
backgroundColor: HStyle.sidePane.filterRooms.background
onTextChanged: Backend.setRoomFilter(text)
Layout.fillWidth: true
Layout.preferredHeight: parent.height
}

View File

@@ -1,11 +1,20 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import SortFilterProxyModel 0.2
import "../Base"
HListView {
property string userId: ""
id: roomCategoriesList
model: Backend.accounts.get(userId).roomCategories
model: SortFilterProxyModel {
sourceModel: models.roomCategories
filters: ValueFilter {
roleName: "userId"
value: userId
}
}
delegate: RoomCategoryDelegate {}
}

View File

@@ -12,11 +12,11 @@ MouseArea {
HRowLayout {
width: parent.width
spacing: roomList.spacing
spacing: sidePane.normalSpacing
HAvatar {
id: roomAvatar
name: displayName
name: stripRoomName(displayName) || qsTr("Empty room")
}
HColumnLayout {
@@ -35,27 +35,27 @@ MouseArea {
Layout.maximumWidth: parent.width
}
HLabel {
function getText() {
return SidePaneJS.getLastRoomEventText(
roomId, roomList.userId
)
}
//HLabel {
//function getText() {
//return SidePaneJS.getLastRoomEventText(
//roomId, roomList.userId
//)
//}
property var lastEvTime: lastEventDateTime
onLastEvTimeChanged: subtitleLabel.text = getText()
//property var lastEvTime: lastEventDateTime
//onLastEvTimeChanged: subtitleLabel.text = getText()
id: subtitleLabel
visible: text !== ""
text: getText()
textFormat: Text.StyledText
//id: subtitleLabel
//visible: text !== ""
//text: getText()
//textFormat: Text.StyledText
font.pixelSize: HStyle.fontSize.small
elide: Text.ElideRight
maximumLineCount: 1
//font.pixelSize: HStyle.fontSize.small
//elide: Text.ElideRight
//maximumLineCount: 1
Layout.maximumWidth: parent.width
}
//Layout.maximumWidth: parent.width
//}
}
}
}

View File

@@ -1,5 +1,6 @@
import QtQuick 2.7
import QtQuick.Layouts 1.3
import SortFilterProxyModel 0.2
import "../Base"
HListView {
@@ -7,8 +8,37 @@ HListView {
property string category: ""
id: roomList
spacing: accountList.spacing
model:
Backend.accounts.get(userId).roomCategories.get(category).sortedRooms
spacing: sidePane.normalSpacing
model: SortFilterProxyModel {
sourceModel: models.rooms
filters: AllOf {
ValueFilter {
roleName: "category"
value: category
}
ValueFilter {
roleName: "userId"
value: userId
}
ExpressionFilter {
expression: {
var filter = paneToolBar.roomFilter.toLowerCase()
var words = filter.split(" ")
var room_name = displayName.toLowerCase()
for (var i = 0; i < words.length; i++) {
if (words[i] && room_name.indexOf(words[i]) == -1) {
return false
}
}
return true
}
}
}
}
delegate: RoomDelegate {}
}

View File

@@ -15,16 +15,18 @@ HRectangle {
Layout.fillWidth: true
Layout.fillHeight: true
spacing: collapsed ? 0 : normalSpacing
topMargin: spacing
bottomMargin: spacing
Layout.leftMargin: spacing
spacing: collapsed ? 0 : normalSpacing * 3
topMargin: normalSpacing
bottomMargin: normalSpacing
Layout.leftMargin: normalSpacing
Behavior on spacing {
NumberAnimation { duration: HStyle.animationDuration }
}
}
PaneToolBar {}
PaneToolBar {
id: paneToolBar
}
}
}

View File

@@ -8,10 +8,15 @@ import "SidePane"
Item {
id: mainUI
Connections {
target: py
onWillLoadAccounts: function(will) {
pageStack.showPage(will ? "Default" : "SignIn")
}
}
property bool accountsPresent:
models.accounts.count > 0 || py.loadingAccounts
onAccountsPresentChanged:
pageStack.showPage(accountsPresent ? "Default" : "SignIn")
HImage {
id: mainUIBackground