Display room messages and other events
This commit is contained in:
parent
5c8fd4500d
commit
9c66166c4f
21
TODO.md
21
TODO.md
@ -1 +1,20 @@
|
||||
-
|
||||
- Separate categories for invited, group and direct rooms
|
||||
- Invited → Accept/Deny dialog
|
||||
- Keep the room header name and topic updated
|
||||
- Merge login page
|
||||
- Show actual display name for AccountDelegate
|
||||
|
||||
- When inviting someone to direct chat, room is "Empty room" until accepted,
|
||||
it should be the peer's display name instead.
|
||||
- Support "Empty room (was ...)" after peer left
|
||||
|
||||
- Catch network errors in socket operations
|
||||
|
||||
- Proper logoff when closing client
|
||||
|
||||
- Handle cases where an avatar char is # or @ (#alias room, @user\_id)
|
||||
|
||||
- Use Loader? for MessageDelegate to show sub-components based on condition
|
||||
- Better names and organization for the Message components
|
||||
|
||||
- Load previous events on scroll up
|
||||
|
@ -2,10 +2,12 @@
|
||||
# This file is part of harmonyqml, licensed under GPLv3.
|
||||
|
||||
import hashlib
|
||||
from typing import Dict
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSlot
|
||||
|
||||
from .client_manager import ClientManager
|
||||
from .model.items import User
|
||||
from .model.qml_models import QMLModels
|
||||
|
||||
|
||||
@ -35,6 +37,18 @@ class Backend(QObject):
|
||||
return self._models
|
||||
|
||||
|
||||
@pyqtSlot(str, result="QVariantMap")
|
||||
def getUser(self, user_id: str) -> Dict[str, str]:
|
||||
for client in self.clientManager.clients.values():
|
||||
for room in client.nio.rooms.values():
|
||||
|
||||
name = room.user_name(user_id)
|
||||
if name:
|
||||
return User(user_id=user_id, display_name=name)._asdict()
|
||||
|
||||
return User(user_id=user_id, display_name=user_id)._asdict()
|
||||
|
||||
|
||||
@pyqtSlot(str, result=float)
|
||||
def hueFromString(self, string: str) -> float:
|
||||
# pylint:disable=no-self-use
|
||||
|
@ -7,15 +7,13 @@ import sys
|
||||
import traceback
|
||||
from concurrent.futures import Future, ThreadPoolExecutor
|
||||
from threading import Event, currentThread
|
||||
from typing import Callable, DefaultDict, Dict
|
||||
from typing import Callable, DefaultDict
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtProperty, pyqtSignal, pyqtSlot
|
||||
|
||||
import nio
|
||||
import nio.responses as nr
|
||||
|
||||
from .model.items import User
|
||||
|
||||
# One pool per hostname/remote server;
|
||||
# multiple Client for different accounts on the same server can exist.
|
||||
_POOLS: DefaultDict[str, ThreadPoolExecutor] = \
|
||||
@ -39,9 +37,10 @@ def futurize(func: Callable) -> Callable:
|
||||
|
||||
|
||||
class Client(QObject):
|
||||
roomInvited = pyqtSignal(str)
|
||||
roomJoined = pyqtSignal(str)
|
||||
roomLeft = pyqtSignal(str)
|
||||
roomInvited = pyqtSignal(str)
|
||||
roomJoined = pyqtSignal(str)
|
||||
roomLeft = pyqtSignal(str)
|
||||
roomEventReceived = pyqtSignal(str, str, dict)
|
||||
|
||||
|
||||
def __init__(self, hostname: str, username: str, device_id: str = ""
|
||||
@ -114,21 +113,13 @@ class Client(QObject):
|
||||
for room_id in response.rooms.invite:
|
||||
self.roomInvited.emit(room_id)
|
||||
|
||||
for room_id in response.rooms.join:
|
||||
for room_id, room_info in response.rooms.join.items():
|
||||
self.roomJoined.emit(room_id)
|
||||
|
||||
for ev in room_info.timeline.events:
|
||||
self.roomEventReceived.emit(
|
||||
room_id, type(ev).__name__, ev.__dict__
|
||||
)
|
||||
|
||||
for room_id in response.rooms.leave:
|
||||
self.roomLeft.emit(room_id)
|
||||
|
||||
|
||||
@pyqtSlot(str, str, result="QVariantMap")
|
||||
def getUser(self, room_id: str, user_id: str) -> Dict[str, str]:
|
||||
try:
|
||||
name = self.nio.rooms[room_id].user_name(user_id)
|
||||
except KeyError:
|
||||
name = None
|
||||
|
||||
return User(
|
||||
user_id = user_id,
|
||||
display_name = name or user_id,
|
||||
)._asdict()
|
||||
|
@ -1,11 +1,11 @@
|
||||
# Copyright 2019 miruka
|
||||
# This file is part of harmonyqml, licensed under GPLv3.
|
||||
|
||||
from typing import NamedTuple, Optional
|
||||
from typing import Dict, NamedTuple, Optional
|
||||
|
||||
from PyQt5.QtCore import QDateTime
|
||||
|
||||
from .enums import Activity, MessageKind, Presence
|
||||
from .enums import Activity, Presence
|
||||
|
||||
|
||||
class User(NamedTuple):
|
||||
@ -26,9 +26,7 @@ class Room(NamedTuple):
|
||||
avatar_url: Optional[str] = None
|
||||
|
||||
|
||||
class Message(NamedTuple):
|
||||
sender_id: str
|
||||
date_time: QDateTime
|
||||
content: str
|
||||
kind: MessageKind = MessageKind.text
|
||||
sender_avatar: Optional[str] = None
|
||||
class RoomEvent(NamedTuple):
|
||||
type: str
|
||||
date_time: QDateTime
|
||||
dict: Dict[str, str]
|
||||
|
@ -13,9 +13,9 @@ class QMLModels(QObject):
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._accounts: ListModel = ListModel()
|
||||
self._rooms: ListModelMap = ListModelMap()
|
||||
self._messages: ListModelMap = ListModelMap()
|
||||
self._accounts: ListModel = ListModel()
|
||||
self._rooms: ListModelMap = ListModelMap()
|
||||
self._room_events: ListModelMap = ListModelMap()
|
||||
|
||||
|
||||
@pyqtProperty(ListModel, constant=True)
|
||||
@ -29,5 +29,5 @@ class QMLModels(QObject):
|
||||
|
||||
|
||||
@pyqtProperty("QVariant", constant=True)
|
||||
def messages(self):
|
||||
return self._messages
|
||||
def roomEvents(self):
|
||||
return self._room_events
|
||||
|
@ -1,18 +1,18 @@
|
||||
# Copyright 2019 miruka
|
||||
# This file is part of harmonyqml, licensed under GPLv3.
|
||||
|
||||
from typing import Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from PyQt5.QtCore import QObject
|
||||
from PyQt5.QtCore import QDateTime, QObject, pyqtBoundSignal
|
||||
|
||||
from .backend import Backend
|
||||
from .client import Client
|
||||
from .model.items import Room, User
|
||||
from .model.items import Room, RoomEvent, User
|
||||
|
||||
|
||||
class SignalManager(QObject):
|
||||
def __init__(self, backend: Backend) -> None:
|
||||
super().__init__()
|
||||
super().__init__(parent=backend)
|
||||
self.backend = backend
|
||||
|
||||
cm = self.backend.clientManager
|
||||
@ -34,10 +34,15 @@ class SignalManager(QObject):
|
||||
|
||||
|
||||
def connectClient(self, client: Client) -> None:
|
||||
for sig_name in ("roomInvited", "roomJoined", "roomLeft"):
|
||||
sig = getattr(client, sig_name)
|
||||
on_sig = getattr(self, f"on{sig_name[0].upper()}{sig_name[1:]}")
|
||||
sig.connect(lambda room_id, o=on_sig, c=client: o(c, room_id))
|
||||
for name in dir(client):
|
||||
attr = getattr(client, name)
|
||||
|
||||
if isinstance(attr, pyqtBoundSignal):
|
||||
def onSignal(*args, name=name) -> None:
|
||||
func = getattr(self, f"on{name[0].upper()}{name[1:]}")
|
||||
func(client, *args)
|
||||
|
||||
attr.connect(onSignal)
|
||||
|
||||
|
||||
def onRoomInvited(self, client: Client, room_id: str) -> None:
|
||||
@ -69,3 +74,25 @@ class SignalManager(QObject):
|
||||
def onRoomLeft(self, client: Client, room_id: str) -> None:
|
||||
rooms = self.backend.models.rooms[client.userID]
|
||||
del rooms[rooms.indexWhere("room_id", room_id)]
|
||||
|
||||
|
||||
def onRoomEventReceived(
|
||||
self, _: Client, room_id: str, etype: str, edict: Dict[str, Any]
|
||||
) -> None:
|
||||
model = self.backend.models.roomEvents[room_id]
|
||||
date_time = QDateTime.fromMSecsSinceEpoch(edict["server_timestamp"])
|
||||
new_event = RoomEvent(type=etype, date_time=date_time, dict=edict)
|
||||
|
||||
# Insert event in model at the right position, based on timestamps
|
||||
# to keep them sorted by date of arrival.
|
||||
# Iterate in reverse, since a new event is more likely to be appended,
|
||||
# but events can arrive out of order.
|
||||
if not model or model[-1].date_time < new_event.date_time:
|
||||
model.append(new_event)
|
||||
else:
|
||||
for i, event in enumerate(reversed(model)):
|
||||
if event.date_time < new_event.date_time:
|
||||
model.insert(-i, new_event)
|
||||
break
|
||||
else:
|
||||
model.insert(0, new_event)
|
||||
|
@ -17,9 +17,9 @@ Controls1.SplitView {
|
||||
function show_page(componentName) {
|
||||
pageStack.replace(componentName + ".qml")
|
||||
}
|
||||
function show_room(user_obj, room_obj) {
|
||||
function show_room(user_id, room_obj) {
|
||||
pageStack.replace(
|
||||
"chat/Root.qml", { user: user_obj, room: room_obj }
|
||||
"chat/Root.qml", { user_id: user_id, room: room_obj }
|
||||
)
|
||||
}
|
||||
|
||||
|
45
harmonyqml/components/chat/EventContent.qml
Normal file
45
harmonyqml/components/chat/EventContent.qml
Normal file
@ -0,0 +1,45 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.4
|
||||
import "../base" as Base
|
||||
import "get_event_text.js" as GetEventTextJS
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: standardSpacing
|
||||
layoutDirection: isOwn ? Qt.RightToLeft : Qt.LeftToRight
|
||||
anchors.right: isOwn ? parent.right : undefined
|
||||
|
||||
readonly property string contentText:
|
||||
(isMessage || isUndecryptableEvent) ?
|
||||
"" :
|
||||
GetEventTextJS.get_event_text(type, dict)
|
||||
|
||||
Base.Avatar {
|
||||
id: avatar
|
||||
name: displayName
|
||||
invisible: combine
|
||||
dimmension: 28
|
||||
}
|
||||
|
||||
Base.HLabel {
|
||||
id: contentLabel
|
||||
text: "<font color=gray>" +
|
||||
displayName + " " + contentText +
|
||||
" <font size=" + smallSize + "px>" +
|
||||
Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
"</font></font>"
|
||||
textFormat: Text.RichText
|
||||
background: Rectangle {color: "#DDD"}
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
leftPadding: horizontalPadding
|
||||
rightPadding: horizontalPadding
|
||||
topPadding: verticalPadding
|
||||
bottomPadding: verticalPadding
|
||||
|
||||
Layout.maximumWidth: Math.min(
|
||||
600, messageListView.width - avatar.width - row.spacing
|
||||
)
|
||||
}
|
||||
}
|
61
harmonyqml/components/chat/MessageContent.qml
Normal file
61
harmonyqml/components/chat/MessageContent.qml
Normal file
@ -0,0 +1,61 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Controls 2.0
|
||||
import QtQuick.Layouts 1.4
|
||||
import "../base" as Base
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: standardSpacing
|
||||
layoutDirection: isOwn ? Qt.RightToLeft : Qt.LeftToRight
|
||||
anchors.right: isOwn ? parent.right : undefined
|
||||
|
||||
Base.Avatar { id: avatar; invisible: combine; name: displayName }
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
Base.HLabel {
|
||||
visible: ! combine
|
||||
id: nameLabel
|
||||
text: displayName
|
||||
background: Rectangle {color: "#DDD"}
|
||||
color: isOwn ? "teal" : "purple"
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
Layout.preferredWidth: contentLabel.width
|
||||
horizontalAlignment: isOwn ? Text.AlignRight : Text.AlignLeft
|
||||
|
||||
leftPadding: horizontalPadding
|
||||
rightPadding: horizontalPadding
|
||||
topPadding: verticalPadding
|
||||
}
|
||||
|
||||
Base.HLabel {
|
||||
id: contentLabel
|
||||
//text: (isOwn ? "" : content + " ") +
|
||||
//"<font size=" + smallSize + "px color=gray>" +
|
||||
//Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
//"</font>" +
|
||||
// (isOwn ? " " + content : "")
|
||||
|
||||
text: (isUndecryptableEvent ?
|
||||
"<font color=darkred>Missing decryption keys for this message.</font>" :
|
||||
dict.formatted_body || dict.body) +
|
||||
" <font size=" + smallSize + "px color=gray>" +
|
||||
Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
"</font>"
|
||||
textFormat: Text.RichText
|
||||
background: Rectangle {color: "#DDD"}
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
leftPadding: horizontalPadding
|
||||
rightPadding: horizontalPadding
|
||||
bottomPadding: verticalPadding
|
||||
|
||||
Layout.minimumWidth: nameLabel.implicitWidth
|
||||
Layout.maximumWidth: Math.min(
|
||||
600, messageListView.width - avatar.width - row.spacing
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -10,11 +10,16 @@ Column {
|
||||
return Math.round((((date2 - date1) % 86400000) % 3600000) / 60000)
|
||||
}
|
||||
|
||||
readonly property bool isMessage: type.startsWith("RoomMessage")
|
||||
|
||||
readonly property bool isUndecryptableEvent:
|
||||
type === "OlmEvent" || type === "MegolmEvent"
|
||||
|
||||
readonly property string displayName:
|
||||
Backend.getUser(chatPage.room.room_id, sender_id).display_name
|
||||
Backend.getUser(dict.sender).display_name
|
||||
|
||||
readonly property bool isOwn:
|
||||
chatPage.user.user_id === sender_id
|
||||
chatPage.user_id === dict.sender
|
||||
|
||||
readonly property var previousData:
|
||||
index > 0 ? messageListView.model.get(index - 1) : null
|
||||
@ -23,7 +28,8 @@ Column {
|
||||
|
||||
readonly property bool combine:
|
||||
! isFirstMessage &&
|
||||
previousData.sender_id == sender_id &&
|
||||
previousData.isMessage === isMessage &&
|
||||
previousData.dict.sender === dict.sender &&
|
||||
mins_between(previousData.date_time, date_time) <= 5
|
||||
|
||||
readonly property bool dayBreak:
|
||||
@ -49,59 +55,7 @@ Column {
|
||||
|
||||
Daybreak { visible: dayBreak }
|
||||
|
||||
MessageContent { visible: isMessage || isUndecryptableEvent }
|
||||
|
||||
Row {
|
||||
id: row
|
||||
spacing: standardSpacing
|
||||
layoutDirection: isOwn ? Qt.RightToLeft : Qt.LeftToRight
|
||||
anchors.right: isOwn ? parent.right : undefined
|
||||
|
||||
Base.Avatar { id: avatar; invisible: combine; name: displayName }
|
||||
|
||||
ColumnLayout {
|
||||
spacing: 0
|
||||
|
||||
Base.HLabel {
|
||||
visible: ! combine
|
||||
id: nameLabel
|
||||
text: displayName
|
||||
background: Rectangle {color: "#DDD"}
|
||||
color: isOwn ? "teal" : "purple"
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
Layout.preferredWidth: contentLabel.width
|
||||
horizontalAlignment: isOwn ? Text.AlignRight : Text.AlignLeft
|
||||
|
||||
leftPadding: horizontalPadding
|
||||
rightPadding: horizontalPadding
|
||||
topPadding: verticalPadding
|
||||
}
|
||||
|
||||
Base.HLabel {
|
||||
id: contentLabel
|
||||
//text: (isOwn ? "" : content + " ") +
|
||||
//"<font size=" + smallSize + "px color=gray>" +
|
||||
//Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
//"</font>" +
|
||||
// (isOwn ? " " + content : "")
|
||||
|
||||
text: content +
|
||||
" <font size=" + smallSize + "px color=gray>" +
|
||||
Qt.formatDateTime(date_time, "hh:mm:ss") +
|
||||
"</font>"
|
||||
textFormat: Text.RichText
|
||||
background: Rectangle {color: "#DDD"}
|
||||
wrapMode: Text.Wrap
|
||||
|
||||
leftPadding: horizontalPadding
|
||||
rightPadding: horizontalPadding
|
||||
bottomPadding: verticalPadding
|
||||
|
||||
Layout.minimumWidth: nameLabel.implicitWidth
|
||||
Layout.maximumWidth: Math.min(
|
||||
600, messageListView.width - avatar.width - row.spacing
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
EventContent { visible: ! (isMessage || isUndecryptableEvent) }
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ Rectangle {
|
||||
ListView {
|
||||
id: messageListView
|
||||
anchors.fill: parent
|
||||
model: Backend.models.messages.get(chatPage.room.room_id)
|
||||
model: Backend.models.roomEvents.get(chatPage.room.room_id)
|
||||
delegate: MessageDelegate {}
|
||||
//highlight: Rectangle {color: "lightsteelblue"; radius: 5}
|
||||
|
||||
|
@ -33,7 +33,7 @@ Rectangle {
|
||||
|
||||
Base.HLabel {
|
||||
id: "roomDescription"
|
||||
text: chatPage.room.description
|
||||
text: chatPage.room.description || ""
|
||||
font.pixelSize: smallSize
|
||||
elide: Text.ElideRight
|
||||
maximumLineCount: 1
|
||||
|
@ -3,7 +3,7 @@ import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.4
|
||||
|
||||
ColumnLayout {
|
||||
property var user: null
|
||||
property var user_id: null
|
||||
property var room: null
|
||||
|
||||
id: chatPage
|
||||
|
@ -20,7 +20,7 @@ Rectangle {
|
||||
|
||||
Base.Avatar {
|
||||
id: "avatar"
|
||||
name: chatPage.user.display_name
|
||||
name: Backend.getUser(chatPage.user_id).display_name
|
||||
dimmension: root.Layout.minimumHeight
|
||||
//visible: textArea.text === ""
|
||||
visible: textArea.height <= root.Layout.minimumHeight
|
||||
|
122
harmonyqml/components/chat/get_event_text.js
Normal file
122
harmonyqml/components/chat/get_event_text.js
Normal file
@ -0,0 +1,122 @@
|
||||
function get_event_text(type, dict) {
|
||||
switch (type) {
|
||||
case "RoomCreateEvent":
|
||||
return (dict.federate ? "allowed" : "blocked") +
|
||||
" users on other matrix servers " +
|
||||
(dict.federate ? "to join" : "from joining") +
|
||||
" this room."
|
||||
break
|
||||
|
||||
case "RoomGuestAccessEvent":
|
||||
return (dict.guest_access === "can_join" ? "allowed " : "forbad") +
|
||||
"guests to join the room."
|
||||
break
|
||||
|
||||
case "RoomJoinRulesEvent":
|
||||
return "made the room " +
|
||||
(dict.join_rule === "public." ? "public" : "invite only.")
|
||||
break
|
||||
|
||||
case "RoomHistoryVisibilityEvent":
|
||||
return get_history_visibility_event_text(dict)
|
||||
break
|
||||
|
||||
case "PowerLevelsEvent":
|
||||
return "changed the room's permissions."
|
||||
|
||||
case "RoomMemberEvent":
|
||||
return get_member_event_text(dict)
|
||||
break
|
||||
|
||||
case "RoomAliasEvent":
|
||||
return "set the room's main address to " +
|
||||
dict.canonical_alias + "."
|
||||
break
|
||||
|
||||
case "RoomNameEvent":
|
||||
return "changed the room's name to \"" + dict.name + "\"."
|
||||
break
|
||||
|
||||
case "RoomTopicEvent":
|
||||
return "changed the room's topic to \"" + dict.topic + "\"."
|
||||
break
|
||||
|
||||
case "RoomEncryptionEvent":
|
||||
return "turned on encryption for this room."
|
||||
break
|
||||
|
||||
default:
|
||||
console.log(type + "\n" + JSON.stringify(dict, null, 4) + "\n")
|
||||
return "did something this client does not understand."
|
||||
|
||||
//case "CallEvent": TODO
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function get_history_visibility_event_text(dict) {
|
||||
switch (dict.history_visibility) {
|
||||
case "shared":
|
||||
var end = "all room members."
|
||||
break
|
||||
|
||||
case "world_readable":
|
||||
var end = "any member or outsider."
|
||||
break
|
||||
|
||||
case "joined":
|
||||
var end = "all room members since they joined."
|
||||
break
|
||||
|
||||
case "invited":
|
||||
var end = "all room members since they were invited."
|
||||
break
|
||||
}
|
||||
|
||||
return "made future history visible to " + end
|
||||
}
|
||||
|
||||
|
||||
function get_member_event_text(dict) {
|
||||
var info = dict.content, prev = dict.prev_content
|
||||
|
||||
if (! prev || (info.membership != prev.membership)) {
|
||||
switch (info.membership) {
|
||||
case "join":
|
||||
return "joined the room."
|
||||
break
|
||||
|
||||
case "invite":
|
||||
var name = Backend.getUser(dict.state_key).display_name
|
||||
var name = name === dict.state_key ? info.displayname : name
|
||||
return "invited " + name + " to the room."
|
||||
break
|
||||
|
||||
case "leave":
|
||||
return "left the room."
|
||||
break
|
||||
|
||||
case "ban":
|
||||
return "was banned from the room."
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var changed = []
|
||||
|
||||
if (prev && (info.avatar_url != prev.avatar_url)) {
|
||||
changed.push("profile picture")
|
||||
}
|
||||
|
||||
if (prev && (info.displayname != prev.displayname)) {
|
||||
changed.push("display name from \"" +
|
||||
(prev.displayname || dict.state_key) + '" to "' +
|
||||
(info.displayname || dict.state_key) + '"')
|
||||
}
|
||||
|
||||
if (changed.length > 0) {
|
||||
return "changed their " + changed.join(" and ") + "."
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
@ -9,7 +9,7 @@ MouseArea {
|
||||
height: roomList.childrenHeight
|
||||
|
||||
onClicked: pageStack.show_room(
|
||||
roomList.user_id,
|
||||
roomList.for_user_id,
|
||||
roomList.model.get(index)
|
||||
)
|
||||
|
||||
@ -38,7 +38,7 @@ MouseArea {
|
||||
rightPadding: leftPadding
|
||||
}
|
||||
Base.HLabel {
|
||||
property var msgModel: Backend.models.messages.get(room_id)
|
||||
property var msgModel: Backend.models.roomEvents.get(room_id)
|
||||
|
||||
function get_text() {
|
||||
if (msgModel.count < 1) { return "" }
|
||||
@ -46,17 +46,16 @@ MouseArea {
|
||||
var msg = msgModel.get(-1)
|
||||
var color_ = (msg.sender_id === roomList.user_id ?
|
||||
"darkblue" : "purple")
|
||||
var client = Backend.clientManager.clients[RoomList.for_user_id]
|
||||
|
||||
return "<font color=\"" + color_ + "\">" +
|
||||
client.getUser(room_id, msg.sender_id).display_name +
|
||||
Backend.getUser(msg.sender_id).display_name +
|
||||
":</font> " +
|
||||
msg.content
|
||||
}
|
||||
|
||||
id: subtitleLabel
|
||||
visible: text !== ""
|
||||
text: msgModel.reloadThis, get_text()
|
||||
//text: msgModel.reloadThis, get_text()
|
||||
textFormat: Text.StyledText
|
||||
|
||||
font.pixelSize: smallSize
|
||||
|
Loading…
Reference in New Issue
Block a user