New backend work

Models, account connection, fetching user profiles,
show connected accounts in sidebar
This commit is contained in:
miruka
2019-06-28 18:12:45 -04:00
parent e5bdf6a497
commit a1b4d8900f
27 changed files with 458 additions and 42 deletions

View File

@@ -37,16 +37,27 @@ ListModel {
return results
}
function upsert(where_role, is, new_item) {
function forEachWhere(where_role, is, max, func) {
var items = getWhere(where_role, is, max)
for (var i = 0; i < items.length; i++) {
func(item)
}
}
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)
if (indices.length == 0) {
listModel.append(new_item)
} else {
return listModel.get(listModel.count)
}
if (update_if_exist != false) {
listModel.set(indices[0], new_item)
}
return listModel.get(indices[0])
}
function pop(index) {
@@ -54,4 +65,38 @@ ListModel {
listModel.remove(index)
return item
}
function popWhere(where_role, is, max) {
var indices = getIndices(where_role, is, max)
var results = []
for (var i = 0; i < indices.length; i++) {
results.push(listModel.get(indices[i]))
listModel.remove(indices[i])
}
return results
}
function toObject(item_list) {
item_list = item_list || listModel
var obj_list = []
for (var i = 0; i < item_list.count; i++) {
var item = item_list.get(i)
var obj = JSON.parse(JSON.stringify(item))
for (var role in obj) {
if (obj[role]["objectName"] != undefined) {
obj[role] = toObject(item[role])
}
}
obj_list.push(obj)
}
return obj_list
}
function toJson() {
return JSON.stringify(toObject(), null, 4)
}
}

View File

@@ -1,2 +1,5 @@
// FIXME: Obsolete method, but need Qt 5.12+ for standard JS modules import
Qt.include("app.js")
Qt.include("users.js")
Qt.include("rooms.js")
Qt.include("rooms_timeline.js")

View File

@@ -0,0 +1,60 @@
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
if (category == "Invites") {
rooms.popWhere("clientId", clientId(user_id, "Rooms", room_id))
rooms.popWhere("clientId", clientId(user_id, "Left", room_id))
}
else if (category == "Rooms") {
rooms.popWhere("clientId", clientId(user_id, "Invites", room_id))
rooms.popWhere("clientId", clientId(user_id, "Left", room_id))
}
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))
if (old_room) {
display_name = old_room.displayName
avatar_url = old_room.avatarUrl
topic = old_room.topic
inviter = old_room.topic
}
}
rooms.upsert("clientId", client_id , {
"clientId": client_id,
"userId": user_id,
"category": category,
"roomId": room_id,
"displayName": display_name,
"avatarUrl": avatar_url,
"topic": topic,
"lastEventDate": last_event_date,
"inviter": inviter,
"leftEvent": left_event
})
//print("room up", rooms.toJson())
}
function onRoomDeleted(user_id, category, room_id) {
var client_id = clientId(user_id, category, room_id)
return models.rooms.popWhere("clientId", client_id, 1)
}
function onRoomMemberUpdated(room_id, user_id, typing) {
}
function onRoomMemberDeleted(room_id, user_id) {
}

View File

View File

@@ -0,0 +1,24 @@
function onAccountUpdated(user_id) {
models.accounts.append({"userId": user_id})
}
function AccountDeleted(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, {
"userId": user_id,
"displayName": display_name,
"avatarUrl": avatar_url,
"statusMessage": status_message
})
}
function onDeviceUpdated(user_id, device_id, ed25519_key, trust, display_name,
last_seen_ip, last_seen_date) {
}
function onDeviceDeleted(user_id, device_id) {
}

34
src/qml/Models.qml Normal file
View File

@@ -0,0 +1,34 @@
import QtQuick 2.7
import "Base"
QtObject {
property HListModel accounts: HListModel {}
property HListModel users: HListModel {
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)
if (found.length > 0) { return found[0] }
users.append({
"userId": wanted_user_id,
"displayName": "",
"avatarUrl": "",
"statusMessage": ""
})
py.callClientCoro(
as_account_id, "request_user_update_event", [wanted_user_id]
)
return users.getWhere("userId", wanted_user_id, 1)[0]
}
}
property HListModel devices: HListModel {}
property HListModel rooms: HListModel {}
property HListModel timelines: HListModel {}
}

View File

@@ -6,16 +6,25 @@ import "EventHandlers/includes.js" as EventHandlers
Python {
id: py
signal ready(bool accountsToLoad)
property bool ready: false
property var pendingCoroutines: ({})
property bool loadingAccounts: false
function callCoro(name, args, kwargs, callback) {
call("APP.call_backend_coro", [name, args, kwargs], function(uuid){
pendingCoroutines[uuid] = callback || function() {}
})
}
function callClientCoro(account_id, name, args, kwargs, callback) {
var args = [account_id, name, args, kwargs]
call("APP.call_client_coro", args, function(uuid){
pendingCoroutines[uuid] = callback || function() {}
})
}
Component.onCompleted: {
for (var func in EventHandlers) {
if (EventHandlers.hasOwnProperty(func)) {
@@ -29,8 +38,14 @@ Python {
window.debug = debug_on
callCoro("has_saved_accounts", [], {}, function(has) {
print(has)
py.ready(has)
loadingAccounts = has
py.ready = true
if (has) {
py.callCoro("load_saved_accounts", [], {}, function() {
loadingAccounts = false
})
}
})
})
})

View File

@@ -6,7 +6,9 @@ Column {
id: accountDelegate
width: parent.width
property var user: Backend.users.get(userId)
// Avoid binding loop by using Component.onCompleted
property var user: null
Component.onCompleted: user = models.users.getUser(userId)
property string roomCategoriesListUserId: userId
property bool expanded: true
@@ -18,7 +20,7 @@ Column {
HAvatar {
id: avatar
name: user.displayName.value
name: user.displayName
}
HColumnLayout {
@@ -27,7 +29,7 @@ Column {
HLabel {
id: accountLabel
text: user.displayName.value
text: user.displayName || user.userId
elide: HLabel.ElideRight
maximumLineCount: 1
Layout.fillWidth: true

View File

@@ -6,6 +6,6 @@ HListView {
id: accountList
clip: true
model: Backend.accounts
model: models.accounts
delegate: AccountDelegate {}
}

View File

@@ -8,7 +8,10 @@ import "SidePane"
Item {
id: mainUI
property bool accountsLoggedIn: Backend.clients.count > 0
property bool accountsPresent:
models.accounts.count > 0 || py.loadingAccounts
onAccountsPresentChanged:
pageStack.showPage(accountsPresent ? "Default" : "SignIn")
HImage {
id: mainUIBackground
@@ -26,7 +29,7 @@ Item {
SidePane {
id: sidePane
visible: accountsLoggedIn
visible: accountsPresent
collapsed: width < Layout.minimumWidth + normalSpacing
property int parentWidth: parent.width
@@ -68,17 +71,6 @@ Item {
)
}
Connections {
target: py
onReady: function(accountsToLoad) {
pageStack.showPage(accountsToLoad ? "Default" : "SignIn")
if (accountsToLoad) {
py.callCoro("load_saved_accounts")
// initialRoomTimer.start()
}
}
}
Timer {
// TODO: remove this, debug
id: initialRoomTimer

View File

@@ -1,5 +1,6 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import "Base"
ApplicationWindow {
id: window
@@ -7,7 +8,7 @@ ApplicationWindow {
height: 480
visible: true
color: "black"
title: "Test"
title: "Harmony QML"
property bool debug: false
property bool ready: false
@@ -23,6 +24,10 @@ ApplicationWindow {
id: py
}
Models {
id: models
}
LoadingScreen {
id: loadingScreen
anchors.fill: parent
@@ -38,7 +43,7 @@ ApplicationWindow {
source: uiLoader.ready ? "UI.qml" : ""
Behavior on scale {
NumberAnimation { duration: 100 }
NumberAnimation { duration: HStyle.animationDuration }
}
}
}