Make Chat show spinner until ready
Like EditAccount, instead of crashing if the room isn't loaded yet.
This commit is contained in:
parent
5b421f02d8
commit
246058e647
|
@ -91,6 +91,17 @@ class Backend:
|
|||
))
|
||||
|
||||
|
||||
async def wait_until_client_exists(self, user_id: str = "") -> None:
|
||||
while True:
|
||||
if user_id and user_id in self.clients:
|
||||
return
|
||||
|
||||
if not user_id and self.clients:
|
||||
return
|
||||
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
||||
# General functions
|
||||
|
||||
async def load_settings(self) -> Tuple[Dict[str, Any], ...]:
|
||||
|
@ -99,7 +110,7 @@ class Backend:
|
|||
|
||||
async def request_user_update_event(self, user_id: str) -> None:
|
||||
if not self.clients:
|
||||
return
|
||||
await self.wait_until_client_exists()
|
||||
|
||||
client = self.clients.get(
|
||||
user_id,
|
||||
|
|
|
@ -4,13 +4,11 @@
|
|||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../Base"
|
||||
import "Banners"
|
||||
import "Timeline"
|
||||
import "RoomSidePane"
|
||||
|
||||
HPage {
|
||||
id: chatPage
|
||||
onFocusChanged: sendBox.setFocus()
|
||||
|
||||
property bool ready: roomInfo && ! roomInfo.loading
|
||||
|
||||
property var roomInfo: null
|
||||
onRoomInfoChanged: if (! roomInfo) { pageStack.showPage("Default") }
|
||||
|
@ -27,120 +25,34 @@ HPage {
|
|||
|
||||
header: RoomHeader {
|
||||
id: roomHeader
|
||||
width: parent.width
|
||||
displayName: roomInfo.displayName
|
||||
topic: roomInfo.topic
|
||||
|
||||
clip: height < implicitHeight
|
||||
width: parent.width
|
||||
height: ready ? implicitHeight : 0
|
||||
Behavior on height { HNumberAnimation {} }
|
||||
}
|
||||
|
||||
page.leftPadding: 0
|
||||
page.rightPadding: 0
|
||||
|
||||
HSplitView {
|
||||
id: chatSplitView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
HColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
EventList {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
TypingMembersBar {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
InviteBanner {
|
||||
visible: category == "Invites"
|
||||
inviterId: roomInfo.inviterId
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
//UnknownDevicesBanner {
|
||||
//visible: category == "Rooms" && hasUnknownDevices
|
||||
//
|
||||
//Layout.fillWidth: true
|
||||
//}
|
||||
|
||||
SendBox {
|
||||
id: sendBox
|
||||
visible: category == "Rooms" && ! hasUnknownDevices
|
||||
}
|
||||
|
||||
LeftBanner {
|
||||
visible: category == "Left"
|
||||
userId: chatPage.userId
|
||||
|
||||
Layout.fillWidth: true
|
||||
Loader {
|
||||
Timer {
|
||||
interval: 200
|
||||
repeat: true
|
||||
running: ! ready
|
||||
onTriggered: {
|
||||
let info = rooms.find(userId, category, roomId)
|
||||
if (! info.loading) { roomInfo = Qt.binding(() => info) }
|
||||
}
|
||||
}
|
||||
|
||||
RoomSidePane {
|
||||
id: roomSidePane
|
||||
source: ready ? "ChatSplitView.qml" : "../Base/HBusyIndicator.qml"
|
||||
|
||||
activeView: roomHeader.activeButton
|
||||
property int oldWidth: width
|
||||
onActiveViewChanged:
|
||||
activeView ? restoreAnimation.start() : hideAnimation.start()
|
||||
|
||||
HNumberAnimation {
|
||||
id: hideAnimation
|
||||
target: roomSidePane
|
||||
properties: "width"
|
||||
from: target.width
|
||||
to: 0
|
||||
|
||||
onStarted: {
|
||||
target.oldWidth = target.width
|
||||
target.Layout.minimumWidth = 0
|
||||
}
|
||||
}
|
||||
|
||||
HNumberAnimation {
|
||||
id: restoreAnimation
|
||||
target: roomSidePane
|
||||
properties: "width"
|
||||
from: 0
|
||||
to: target.oldWidth
|
||||
|
||||
onStopped: target.Layout.minimumWidth = Qt.binding(
|
||||
() => theme.avatar.size
|
||||
)
|
||||
}
|
||||
|
||||
collapsed: width < theme.avatar.size + theme.spacing
|
||||
|
||||
property bool wasSnapped: false
|
||||
property int referenceWidth: roomHeader.buttonsWidth
|
||||
onReferenceWidthChanged: {
|
||||
if (! chatSplitView.manuallyResized || wasSnapped) {
|
||||
if (wasSnapped) { chatSplitView.manuallyResized = false }
|
||||
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(() => roomSidePane.width)
|
||||
} else {
|
||||
wasSnapped = false
|
||||
}
|
||||
}
|
||||
|
||||
width: referenceWidth // Initial width
|
||||
Layout.minimumWidth: theme.avatar.size
|
||||
Layout.maximumWidth:
|
||||
parent.width - theme.minimumSupportedWidthPlusSpacing
|
||||
}
|
||||
Layout.fillWidth: ready
|
||||
Layout.fillHeight: ready
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
}
|
||||
}
|
||||
|
|
117
src/qml/Chat/ChatSplitView.qml
Normal file
117
src/qml/Chat/ChatSplitView.qml
Normal file
|
@ -0,0 +1,117 @@
|
|||
// Copyright 2019 miruka
|
||||
// This file is part of harmonyqml, licensed under LGPLv3.
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import "../Base"
|
||||
import "Banners"
|
||||
import "Timeline"
|
||||
import "RoomSidePane"
|
||||
|
||||
HSplitView {
|
||||
id: chatSplitView
|
||||
Component.onCompleted: sendBox.setFocus()
|
||||
|
||||
HColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
EventList {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
TypingMembersBar {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
InviteBanner {
|
||||
visible: category == "Invites"
|
||||
inviterId: roomInfo.inviterId
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
//UnknownDevicesBanner {
|
||||
//visible: category == "Rooms" && hasUnknownDevices
|
||||
//
|
||||
//Layout.fillWidth: true
|
||||
//}
|
||||
|
||||
SendBox {
|
||||
id: sendBox
|
||||
visible: category == "Rooms" && ! hasUnknownDevices
|
||||
}
|
||||
|
||||
LeftBanner {
|
||||
visible: category == "Left"
|
||||
userId: chatPage.userId
|
||||
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
RoomSidePane {
|
||||
id: roomSidePane
|
||||
|
||||
activeView: roomHeader.activeButton
|
||||
property int oldWidth: width
|
||||
onActiveViewChanged:
|
||||
activeView ? restoreAnimation.start() : hideAnimation.start()
|
||||
|
||||
HNumberAnimation {
|
||||
id: hideAnimation
|
||||
target: roomSidePane
|
||||
properties: "width"
|
||||
from: target.width
|
||||
to: 0
|
||||
|
||||
onStarted: {
|
||||
target.oldWidth = target.width
|
||||
target.Layout.minimumWidth = 0
|
||||
}
|
||||
}
|
||||
|
||||
HNumberAnimation {
|
||||
id: restoreAnimation
|
||||
target: roomSidePane
|
||||
properties: "width"
|
||||
from: 0
|
||||
to: target.oldWidth
|
||||
|
||||
onStopped: target.Layout.minimumWidth = Qt.binding(
|
||||
() => theme.avatar.size
|
||||
)
|
||||
}
|
||||
|
||||
collapsed: width < theme.avatar.size + theme.spacing
|
||||
|
||||
property bool wasSnapped: false
|
||||
property int referenceWidth: roomHeader.buttonsWidth
|
||||
onReferenceWidthChanged: {
|
||||
if (! chatSplitView.manuallyResized || wasSnapped) {
|
||||
if (wasSnapped) { chatSplitView.manuallyResized = false }
|
||||
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(() => roomSidePane.width)
|
||||
} else {
|
||||
wasSnapped = false
|
||||
}
|
||||
}
|
||||
|
||||
width: referenceWidth // Initial width
|
||||
Layout.minimumWidth: theme.avatar.size
|
||||
Layout.maximumWidth:
|
||||
parent.width - theme.minimumSupportedWidthPlusSpacing
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@ function onRoomUpdated(
|
|||
else if (category == "Left") { replace = find("Invites") || find("Rooms")}
|
||||
|
||||
let item = {
|
||||
loading: false,
|
||||
typingText: typingTextFor(typingMembers, userId),
|
||||
|
||||
userId, category, roomId, displayName, avatarUrl, topic, members,
|
||||
|
|
|
@ -9,4 +9,24 @@ HListModel {
|
|||
sorters: StringSorter {
|
||||
roleName: "displayName"
|
||||
}
|
||||
|
||||
readonly property ListModel _emptyModel: ListModel {}
|
||||
|
||||
function find(userId, category, roomId) {
|
||||
if (! userId) { return }
|
||||
|
||||
let found = rooms.getWhere({userId, roomId, category}, 1)[0]
|
||||
if (found) { return found }
|
||||
|
||||
return {
|
||||
userId, category, roomId,
|
||||
displayName: "",
|
||||
avatarUrl: "",
|
||||
topic: "",
|
||||
members: _emptyModel,
|
||||
typingText: "",
|
||||
inviterId: "",
|
||||
loading: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ HListModel {
|
|||
// the expression with invalid data to establish property bindings
|
||||
if (! userId) { return }
|
||||
|
||||
let found = getWhere({userId}, 1)
|
||||
if (found.length > 0) { return found[0] }
|
||||
let found = getWhere({userId}, 1)[0]
|
||||
if (found) { return found }
|
||||
|
||||
py.callCoro("request_user_update_event", [userId])
|
||||
|
||||
|
|
|
@ -27,10 +27,12 @@ Python {
|
|||
}
|
||||
|
||||
function callClientCoro(accountId, name, args=[], callback=null) {
|
||||
callCoro("wait_until_client_exists", [accountId], () => {
|
||||
let uuid = Math.random() + "." + name
|
||||
|
||||
pendingCoroutines[uuid] = callback || function() {}
|
||||
call("APP.call_client_coro", [accountId, name, uuid, args])
|
||||
})
|
||||
}
|
||||
|
||||
function saveConfig(backend_attribute, data, callback=null) {
|
||||
|
|
|
@ -69,8 +69,8 @@ Item {
|
|||
}
|
||||
|
||||
function showRoom(userId, category, roomId) {
|
||||
let info = rooms.getWhere({userId, roomId, category}, 1)[0]
|
||||
show("Chat/Chat.qml", {"roomInfo": info})
|
||||
let roomInfo = rooms.find(userId, category, roomId)
|
||||
show("Chat/Chat.qml", {roomInfo})
|
||||
}
|
||||
|
||||
onCurrentItemChanged: if (currentItem) {
|
||||
|
|
Loading…
Reference in New Issue
Block a user