Working public room directory.

Fix "no known servers".
Rename all QMatrixClient to Quotient.
This commit is contained in:
Black Hat
2019-12-25 19:53:50 +08:00
parent 9d2dc3e96a
commit d25a9fb3a4
14 changed files with 297 additions and 161 deletions

View File

@@ -97,14 +97,14 @@ Dialog {
Layout.preferredHeight: 48 Layout.preferredHeight: 48
color: MPalette.foreground color: MPalette.foreground
icon: "\ue7ff" icon: "\ue5d2"
} }
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
color: MPalette.foreground color: MPalette.foreground
text: "Start a Chat" text: "Explore Rooms"
} }
} }
@@ -113,7 +113,7 @@ Dialog {
onPrimaryClicked: { onPrimaryClicked: {
joinRoomDialog.createObject(ApplicationWindow.overlay, {"controller": spectralController, "connection": spectralController.connection}).open() joinRoomDialog.createObject(ApplicationWindow.overlay, {"controller": spectralController, "connection": spectralController.connection}).open()
root.destroy() root.close()
} }
} }
} }

View File

@@ -21,7 +21,7 @@ Dialog {
id: root id: root
title: "Start a Chat" title: "Explore Rooms"
contentItem: ColumnLayout { contentItem: ColumnLayout {
spacing: 0 spacing: 0
@@ -30,17 +30,39 @@ Dialog {
Layout.fillWidth: true Layout.fillWidth: true
AutoTextField { AutoTextField {
property bool isRoomAlias: text.match(/#(.+):(.+)/g)
property var room: isRoomAlias ? connection.roomByAlias(text) : null
property bool isJoined: room != null
Layout.fillWidth: true Layout.fillWidth: true
id: identifierField id: identifierField
placeholderText: "Room Alias/User ID" placeholderText: "Find a room..."
Keys.onReturnPressed: { onEditingFinished: {
keyword = text keyword = text
} }
} }
Button {
id: joinButton
visible: identifierField.isRoomAlias
text: identifierField.isJoined ? "View" : "Join"
highlighted: true
flat: identifierField.isJoined
onClicked: {
if (identifierField.isJoined) {
roomListForm.joinRoom(identifierField.room)
} else {
spectralController.joinRoom(connection, identifierField.text)
}
}
}
ComboBox { ComboBox {
Layout.maximumWidth: 120 Layout.maximumWidth: 120
@@ -88,14 +110,13 @@ Dialog {
keyword: root.keyword keyword: root.keyword
} }
delegate: Item { delegate: Control {
width: publicRoomsListView.width width: publicRoomsListView.width
height: 40 height: 48
RowLayout { padding: 8
anchors.fill: parent
anchors.margins: 4
contentItem: RowLayout {
spacing: 8 spacing: 8
Avatar { Avatar {
@@ -109,20 +130,52 @@ Dialog {
ColumnLayout { ColumnLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.alignment: Qt.AlignHCenter
spacing: 0 spacing: 0
Label { RowLayout {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
text: name spacing: 4
color: MPalette.foreground
font.pixelSize: 13 Label {
textFormat: Text.PlainText Layout.fillWidth: true
elide: Text.ElideRight Layout.fillHeight: true
wrapMode: Text.NoWrap
text: name
color: MPalette.foreground
font.pixelSize: 13
textFormat: Text.PlainText
elide: Text.ElideRight
wrapMode: Text.NoWrap
}
Label {
visible: allowGuests
text: "GUESTS CAN JOIN"
color: MPalette.lighter
font.pixelSize: 10
padding: 4
background: Rectangle {
color: MPalette.banner
}
}
Label {
visible: worldReadable
text: "WORLD READABLE"
color: MPalette.lighter
font.pixelSize: 10
padding: 4
background: Rectangle {
color: MPalette.banner
}
}
} }
Label { Label {
@@ -139,10 +192,67 @@ Dialog {
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
} }
} }
}
RippleEffect { MaterialIcon {
anchors.fill: parent Layout.preferredWidth: 16
Layout.preferredHeight: 16
icon: "\ue7fc"
color: MPalette.lighter
font.pixelSize: 16
}
Label {
Layout.preferredWidth: 36
text: memberCount
color: MPalette.lighter
font.pixelSize: 12
}
Control {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
visible: isJoined
contentItem: MaterialIcon {
icon: "\ue89e"
color: MPalette.lighter
font.pixelSize: 20
}
background: RippleEffect {
circular: true
onClicked: {
roomListForm.joinRoom(connection.room(roomID))
root.close()
}
}
}
Control {
Layout.preferredWidth: 32
Layout.preferredHeight: 32
visible: !isJoined
contentItem: MaterialIcon {
icon: "\ue7f0"
color: MPalette.lighter
font.pixelSize: 20
}
background: RippleEffect {
circular: true
onClicked: {
spectralController.joinRoom(connection, roomID)
root.close()
}
}
}
} }
} }
@@ -155,17 +265,5 @@ Dialog {
} }
} }
// standardButtons: Dialog.Ok | Dialog.Cancel
// onAccepted: {
// var identifier = identifierField.text
// var firstChar = identifier.charAt(0)
// if (firstChar == "@") {
// spectralController.createDirectChat(spectralController.connection, identifier)
// } else if (firstChar == "!" || firstChar == "#") {
// spectralController.joinRoom(spectralController.connection, identifier)
// }
// }
onClosed: destroy() onClosed: destroy()
} }

View File

@@ -296,13 +296,7 @@ Item {
if (category === RoomType.Invited) { if (category === RoomType.Invited) {
acceptInvitationDialog.createObject(ApplicationWindow.overlay, {"room": currentRoom}).open() acceptInvitationDialog.createObject(ApplicationWindow.overlay, {"room": currentRoom}).open()
} else { } else {
if (enteredRoom) { joinRoom(currentRoom)
leaveRoom(enteredRoom)
enteredRoom.displayed = false
}
enterRoom(currentRoom)
enteredRoom = currentRoom
currentRoom.displayed = true
} }
} }
onSecondaryClicked: roomListContextMenu.createObject(parent, {"room": currentRoom}).popup() onSecondaryClicked: roomListContextMenu.createObject(parent, {"room": currentRoom}).popup()
@@ -427,4 +421,14 @@ Item {
AcceptInvitationDialog {} AcceptInvitationDialog {}
} }
function joinRoom(room) {
if (enteredRoom) {
leaveRoom(enteredRoom)
enteredRoom.displayed = false
}
enterRoom(room)
enteredRoom = room
room.displayed = true
}
} }

View File

@@ -195,7 +195,7 @@ void Controller::addConnection(Connection* c) {
c->sync(30000); c->sync(30000);
}); });
using namespace QMatrixClient; using namespace Quotient;
setBusy(true); setBusy(true);
@@ -213,7 +213,7 @@ void Controller::dropConnection(Connection* c) {
} }
void Controller::invokeLogin() { void Controller::invokeLogin() {
using namespace QMatrixClient; using namespace Quotient;
const auto accounts = SettingsGroup("Accounts").childGroups(); const auto accounts = SettingsGroup("Accounts").childGroups();
for (const auto& accountId : accounts) { for (const auto& accountId : accounts) {
AccountSettings account{accountId}; AccountSettings account{accountId};
@@ -342,7 +342,11 @@ bool Controller::saveAccessTokenToKeyChain(const AccountSettings& account,
} }
void Controller::joinRoom(Connection* c, const QString& alias) { void Controller::joinRoom(Connection* c, const QString& alias) {
auto joinRoomJob = c->joinRoom(alias); if (!alias.contains(":"))
return;
auto knownServer = alias.mid(alias.indexOf(":") + 1);
auto joinRoomJob = c->joinRoom(alias, QStringList{knownServer});
joinRoomJob->connect(joinRoomJob, &JoinRoomJob::failure, [=] { joinRoomJob->connect(joinRoomJob, &JoinRoomJob::failure, [=] {
emit errorOccured("Join Room Failed", joinRoomJob->errorString()); emit errorOccured("Join Room Failed", joinRoomJob->errorString());
}); });

View File

@@ -22,7 +22,7 @@
#include "trayicon.h" #include "trayicon.h"
#include "userlistmodel.h" #include "userlistmodel.h"
using namespace QMatrixClient; using namespace Quotient;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
@@ -53,6 +53,7 @@ int main(int argc, char* argv[]) {
qRegisterMetaType<User*>("User*"); qRegisterMetaType<User*>("User*");
qRegisterMetaType<User*>("const User*"); qRegisterMetaType<User*>("const User*");
qRegisterMetaType<User*>("const Quotient::User*");
qRegisterMetaType<Room*>("Room*"); qRegisterMetaType<Room*>("Room*");
qRegisterMetaType<Connection*>("Connection*"); qRegisterMetaType<Connection*>("Connection*");
qRegisterMetaType<MessageEventType>("MessageEventType"); qRegisterMetaType<MessageEventType>("MessageEventType");

View File

@@ -6,9 +6,9 @@
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QThread> #include <QtCore/QThread>
using QMatrixClient::BaseJob; using Quotient::BaseJob;
ThumbnailResponse::ThumbnailResponse(QMatrixClient::Connection* c, ThumbnailResponse::ThumbnailResponse(Quotient::Connection* c,
QString id, QString id,
const QSize& size) const QSize& size)
: c(c), : c(c),

View File

@@ -1,14 +1,13 @@
#include "messageeventmodel.h" #include "messageeventmodel.h"
#include <connection.h> #include <connection.h>
#include <settings.h>
#include <user.h>
#include <events/reactionevent.h> #include <events/reactionevent.h>
#include <events/redactionevent.h> #include <events/redactionevent.h>
#include <events/roomavatarevent.h> #include <events/roomavatarevent.h>
#include <events/roommemberevent.h> #include <events/roommemberevent.h>
#include <events/simplestateevents.h> #include <events/simplestateevents.h>
#include <settings.h>
#include <user.h>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtQml> // for qmlRegisterType() #include <QtQml> // for qmlRegisterType()
@@ -42,7 +41,7 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const {
MessageEventModel::MessageEventModel(QObject* parent) MessageEventModel::MessageEventModel(QObject* parent)
: QAbstractListModel(parent), m_currentRoom(nullptr) { : QAbstractListModel(parent), m_currentRoom(nullptr) {
using namespace QMatrixClient; using namespace Quotient;
qmlRegisterType<FileTransferInfo>(); qmlRegisterType<FileTransferInfo>();
qRegisterMetaType<FileTransferInfo>(); qRegisterMetaType<FileTransferInfo>();
qmlRegisterUncreatableType<EventStatus>( qmlRegisterUncreatableType<EventStatus>(
@@ -64,7 +63,7 @@ void MessageEventModel::setRoom(SpectralRoom* room) {
if (room) { if (room) {
lastReadEventId = room->readMarkerEventId(); lastReadEventId = room->readMarkerEventId();
using namespace QMatrixClient; using namespace Quotient;
connect(m_currentRoom, &Room::aboutToAddNewMessages, this, connect(m_currentRoom, &Room::aboutToAddNewMessages, this,
[=](RoomEventsRange events) { [=](RoomEventsRange events) {
beginInsertRows({}, timelineBaseIndex(), beginInsertRows({}, timelineBaseIndex(),
@@ -207,12 +206,12 @@ int MessageEventModel::refreshEventRoles(const QString& id,
return row; return row;
} }
inline bool hasValidTimestamp(const QMatrixClient::TimelineItem& ti) { inline bool hasValidTimestamp(const Quotient::TimelineItem& ti) {
return ti->timestamp().isValid(); return ti->timestamp().isValid();
} }
QDateTime MessageEventModel::makeMessageTimestamp( QDateTime MessageEventModel::makeMessageTimestamp(
const QMatrixClient::Room::rev_iter_t& baseIt) const { const Quotient::Room::rev_iter_t& baseIt) const {
const auto& timeline = m_currentRoom->messageEvents(); const auto& timeline = m_currentRoom->messageEvents();
auto ts = baseIt->event()->timestamp(); auto ts = baseIt->event()->timestamp();
if (ts.isValid()) if (ts.isValid())
@@ -220,7 +219,7 @@ QDateTime MessageEventModel::makeMessageTimestamp(
// The event is most likely redacted or just invalid. // The event is most likely redacted or just invalid.
// Look for the nearest date around and slap zero time to it. // Look for the nearest date around and slap zero time to it.
using QMatrixClient::TimelineItem; using Quotient::TimelineItem;
auto rit = std::find_if(baseIt, timeline.rend(), hasValidTimestamp); auto rit = std::find_if(baseIt, timeline.rend(), hasValidTimestamp);
if (rit != timeline.rend()) if (rit != timeline.rend())
return {rit->event()->timestamp().date(), {0, 0}, Qt::LocalTime}; return {rit->event()->timestamp().date(), {0, 0}, Qt::LocalTime};
@@ -269,16 +268,18 @@ int MessageEventModel::rowCount(const QModelIndex& parent) const {
return m_currentRoom->timelineSize(); return m_currentRoom->timelineSize();
} }
inline QVariantMap userAtEvent(SpectralUser* user, SpectralRoom* room, const RoomEvent& evt) { inline QVariantMap userAtEvent(SpectralUser* user,
return QVariantMap{ SpectralRoom* room,
{"isLocalUser", user->id() == room->localUser()->id()}, const RoomEvent& evt) {
{"id", user->id()}, return QVariantMap{
{"avatarMediaId", user->avatarMediaId(room)}, {"isLocalUser", user->id() == room->localUser()->id()},
{"avatarUrl", user->avatarUrl(room)}, {"id", user->id()},
{"displayName", user->displayname(room)}, {"avatarMediaId", user->avatarMediaId(room)},
{"color", user->color()}, {"avatarUrl", user->avatarUrl(room)},
{"object", QVariant::fromValue(user)}, {"displayName", user->displayname(room)},
}; {"color", user->color()},
{"object", QVariant::fromValue(user)},
};
} }
QVariant MessageEventModel::data(const QModelIndex& idx, int role) const { QVariant MessageEventModel::data(const QModelIndex& idx, int role) const {
@@ -340,9 +341,10 @@ QVariant MessageEventModel::data(const QModelIndex& idx, int role) const {
return EventTypeRegistry::getMatrixType(evt.type()); return EventTypeRegistry::getMatrixType(evt.type());
if (role == AuthorRole) { if (role == AuthorRole) {
auto author = static_cast<SpectralUser*>(isPending ? m_currentRoom->localUser() auto author = static_cast<SpectralUser*>(
: m_currentRoom->user(evt.senderId())); isPending ? m_currentRoom->localUser()
return userAtEvent(author, m_currentRoom, evt); : m_currentRoom->user(evt.senderId()));
return userAtEvent(author, m_currentRoom, evt);
} }
if (role == ContentTypeRole) { if (role == ContentTypeRole) {
@@ -455,8 +457,9 @@ QVariant MessageEventModel::data(const QModelIndex& idx, int role) const {
return QVariantMap{ return QVariantMap{
{"eventId", replyEventId}, {"eventId", replyEventId},
{"display", m_currentRoom->eventToString(replyEvt, Qt::RichText)}, {"display", m_currentRoom->eventToString(replyEvt, Qt::RichText)},
{"author", {"author", userAtEvent(static_cast<SpectralUser*>(
userAtEvent(static_cast<SpectralUser*>(m_currentRoom->user(replyEvt.senderId())), m_currentRoom, evt)}}; m_currentRoom->user(replyEvt.senderId())),
m_currentRoom, evt)}};
} }
if (role == ShowAuthorRole) { if (role == ShowAuthorRole) {

View File

@@ -1,11 +1,11 @@
#ifndef MESSAGEEVENTMODEL_H #ifndef MESSAGEEVENTMODEL_H
#define MESSAGEEVENTMODEL_H #define MESSAGEEVENTMODEL_H
#include <QtCore/QAbstractListModel>
#include "room.h" #include "room.h"
#include "spectralroom.h" #include "spectralroom.h"
#include <QtCore/QAbstractListModel>
class MessageEventModel : public QAbstractListModel { class MessageEventModel : public QAbstractListModel {
Q_OBJECT Q_OBJECT
Q_PROPERTY(SpectralRoom* room READ room WRITE setRoom NOTIFY roomChanged) Q_PROPERTY(SpectralRoom* room READ room WRITE setRoom NOTIFY roomChanged)
@@ -72,7 +72,7 @@ class MessageEventModel : public QAbstractListModel {
int timelineBaseIndex() const; int timelineBaseIndex() const;
QDateTime makeMessageTimestamp( QDateTime makeMessageTimestamp(
const QMatrixClient::Room::rev_iter_t& baseIt) const; const Quotient::Room::rev_iter_t& baseIt) const;
QString renderDate(QDateTime timestamp) const; QString renderDate(QDateTime timestamp) const;
void refreshLastUserEvents(int baseRow); void refreshLastUserEvents(int baseRow);

View File

@@ -167,6 +167,24 @@ QVariant PublicRoomListModel::data(const QModelIndex& index, int role) const {
if (role == TopicRole) { if (role == TopicRole) {
return room.topic; return room.topic;
} }
if (role == RoomIDRole) {
return room.roomId;
}
if (role == MemberCountRole) {
return room.numJoinedMembers;
}
if (role == AllowGuestsRole) {
return room.guestCanJoin;
}
if (role == WorldReadableRole) {
return room.worldReadable;
}
if (role == IsJoinedRole) {
if (!m_connection)
return {};
return m_connection->room(room.roomId, JoinState::Join) != nullptr;
}
return {}; return {};
} }
@@ -177,6 +195,11 @@ QHash<int, QByteArray> PublicRoomListModel::roleNames() const {
roles[NameRole] = "name"; roles[NameRole] = "name";
roles[AvatarRole] = "avatar"; roles[AvatarRole] = "avatar";
roles[TopicRole] = "topic"; roles[TopicRole] = "topic";
roles[RoomIDRole] = "roomID";
roles[MemberCountRole] = "memberCount";
roles[AllowGuestsRole] = "allowGuests";
roles[WorldReadableRole] = "worldReadable";
roles[IsJoinedRole] = "isJoined";
return roles; return roles;
} }

View File

@@ -20,7 +20,16 @@ class PublicRoomListModel : public QAbstractListModel {
Q_PROPERTY(bool hasMore READ hasMore NOTIFY hasMoreChanged) Q_PROPERTY(bool hasMore READ hasMore NOTIFY hasMoreChanged)
public: public:
enum EventRoles { NameRole = Qt::DisplayRole + 1, AvatarRole, TopicRole }; enum EventRoles {
NameRole = Qt::DisplayRole + 1,
AvatarRole,
TopicRole,
RoomIDRole,
MemberCountRole,
AllowGuestsRole,
WorldReadableRole,
IsJoinedRole,
};
PublicRoomListModel(QObject* parent = nullptr); PublicRoomListModel(QObject* parent = nullptr);

View File

@@ -1,8 +1,16 @@
#include "spectralroom.h" #include "spectralroom.h"
#include "connection.h" #include <cmark.h>
#include "user.h"
#include <QFileDialog>
#include <QFileInfo>
#include <QImageReader>
#include <QMetaObject>
#include <QMimeDatabase>
#include <QTextDocument>
#include <functional>
#include "connection.h"
#include "csapi/account-data.h" #include "csapi/account-data.h"
#include "csapi/content-repo.h" #include "csapi/content-repo.h"
#include "csapi/leaving.h" #include "csapi/leaving.h"
@@ -14,18 +22,7 @@
#include "events/roommessageevent.h" #include "events/roommessageevent.h"
#include "events/typingevent.h" #include "events/typingevent.h"
#include "jobs/downloadfilejob.h" #include "jobs/downloadfilejob.h"
#include "user.h"
#include <functional>
#include <QFileDialog>
#include <QFileInfo>
#include <QImageReader>
#include <QMetaObject>
#include <QMimeDatabase>
#include <QTextDocument>
#include <cmark.h>
#include "utils.h" #include "utils.h"
SpectralRoom::SpectralRoom(Connection* connection, SpectralRoom::SpectralRoom(Connection* connection,
@@ -117,8 +114,7 @@ QString SpectralRoom::lastEvent() const {
continue; continue;
return user(evt->senderId())->displayname() + return user(evt->senderId())->displayname() +
(evt->isStateEvent() ? " " : ": ") + (evt->isStateEvent() ? " " : ": ") + eventToString(*evt);
eventToString(*evt);
} }
return ""; return "";
} }
@@ -127,7 +123,7 @@ bool SpectralRoom::isEventHighlighted(const RoomEvent* e) const {
return highlights.contains(e); return highlights.contains(e);
} }
void SpectralRoom::checkForHighlights(const QMatrixClient::TimelineItem& ti) { void SpectralRoom::checkForHighlights(const Quotient::TimelineItem& ti) {
auto localUserId = localUser()->id(); auto localUserId = localUser()->id();
if (ti->senderId() == localUserId) if (ti->senderId() == localUserId)
return; return;
@@ -230,20 +226,21 @@ QString SpectralRoom::avatarMediaId() const {
} }
QString SpectralRoom::eventToString(const RoomEvent& evt, QString SpectralRoom::eventToString(const RoomEvent& evt,
Qt::TextFormat format, bool removeReply) const { Qt::TextFormat format,
bool removeReply) const {
const bool prettyPrint = (format == Qt::RichText); const bool prettyPrint = (format == Qt::RichText);
using namespace QMatrixClient; using namespace Quotient;
return visit( return visit(
evt, evt,
[prettyPrint, removeReply](const RoomMessageEvent& e) { [prettyPrint, removeReply](const RoomMessageEvent& e) {
using namespace MessageEventContent; using namespace MessageEventContent;
if (prettyPrint && e.hasTextContent() && if (prettyPrint && e.hasTextContent() &&
e.mimeType().name() != "text/plain") { e.mimeType().name() != "text/plain") {
auto htmlBody = static_cast<const TextContent*>(e.content())->body; auto htmlBody = static_cast<const TextContent*>(e.content())->body;
if (removeReply) { if (removeReply) {
htmlBody.remove(utils::removeRichReplyRegex); htmlBody.remove(utils::removeRichReplyRegex);
} }
htmlBody.replace(utils::userPillRegExp, "<b>\\1</b>"); htmlBody.replace(utils::userPillRegExp, "<b>\\1</b>");
htmlBody.replace(utils::strikethroughRegExp, "<s>\\1</s>"); htmlBody.replace(utils::strikethroughRegExp, "<s>\\1</s>");
@@ -255,24 +252,23 @@ QString SpectralRoom::eventToString(const RoomEvent& evt,
auto fileCaption = auto fileCaption =
e.content()->fileInfo()->originalName.toHtmlEscaped(); e.content()->fileInfo()->originalName.toHtmlEscaped();
if (fileCaption.isEmpty()) { if (fileCaption.isEmpty()) {
fileCaption = prettyPrint fileCaption = prettyPrint ? Quotient::prettyPrint(e.plainBody())
? QMatrixClient::prettyPrint(e.plainBody()) : e.plainBody();
: e.plainBody();
} else if (e.content()->fileInfo()->originalName != e.plainBody()) { } else if (e.content()->fileInfo()->originalName != e.plainBody()) {
fileCaption = e.plainBody() + " | " + fileCaption; fileCaption = e.plainBody() + " | " + fileCaption;
} }
return !fileCaption.isEmpty() ? fileCaption : tr("a file"); return !fileCaption.isEmpty() ? fileCaption : tr("a file");
} }
if (prettyPrint) { if (prettyPrint) {
auto plainBody = e.plainBody(); auto plainBody = e.plainBody();
if (removeReply) { if (removeReply) {
plainBody.remove(utils::removeReplyRegex); plainBody.remove(utils::removeReplyRegex);
} }
return QMatrixClient::prettyPrint(plainBody); return Quotient::prettyPrint(plainBody);
} }
if (removeReply) { if (removeReply) {
return e.plainBody().remove(utils::removeReplyRegex); return e.plainBody().remove(utils::removeReplyRegex);
} }
return e.plainBody(); return e.plainBody();
}, },
@@ -364,9 +360,8 @@ QString SpectralRoom::eventToString(const RoomEvent& evt,
return (e.topic().isEmpty()) return (e.topic().isEmpty())
? tr("cleared the topic") ? tr("cleared the topic")
: tr("set the topic to: %1") : tr("set the topic to: %1")
.arg(prettyPrint .arg(prettyPrint ? Quotient::prettyPrint(e.topic())
? QMatrixClient::prettyPrint(e.topic()) : e.topic());
: e.topic());
}, },
[](const RoomAvatarEvent&) { return tr("changed the room avatar"); }, [](const RoomAvatarEvent&) { return tr("changed the room avatar"); },
[](const EncryptionEvent&) { [](const EncryptionEvent&) {
@@ -486,21 +481,20 @@ void SpectralRoom::postPlainMessage(const QString& text,
if (isReply) { if (isReply) {
const auto& replyEvt = **replyIt; const auto& replyEvt = **replyIt;
QJsonObject json{ QJsonObject json{{"msgtype", msgTypeToString(type)},
{"msgtype", msgTypeToString(type)}, {"body", "> <" + replyEvt.senderId() + "> " +
{"body", "> <" + replyEvt.senderId() + "> " + eventToString(replyEvt) + eventToString(replyEvt) + "\n\n" + text},
"\n\n" + text}, {"format", "org.matrix.custom.html"},
{"format", "org.matrix.custom.html"}, {"m.relates_to",
{"m.relates_to", QJsonObject{{"m.in_reply_to",
QJsonObject{ QJsonObject{{"event_id", replyEventId}}}}},
{"m.in_reply_to", QJsonObject{{"event_id", replyEventId}}}}}, {"formatted_body",
{"formatted_body", "<mx-reply><blockquote><a href=\"https://matrix.to/#/" +
"<mx-reply><blockquote><a href=\"https://matrix.to/#/" + id() + "/" + id() + "/" + replyEventId +
replyEventId + "\">In reply to</a> <a href=\"https://matrix.to/#/" +
"\">In reply to</a> <a href=\"https://matrix.to/#/" + replyEvt.senderId() + "\">" + replyEvt.senderId() +
replyEvt.senderId() + "\">" + replyEvt.senderId() + "</a><br>" + "</a><br>" + eventToString(replyEvt, Qt::RichText) +
eventToString(replyEvt, Qt::RichText) + "</blockquote></mx-reply>" + text.toHtmlEscaped()}};
"</blockquote></mx-reply>" + text.toHtmlEscaped()}};
postJson("m.room.message", json); postJson("m.room.message", json);
return; return;
@@ -521,21 +515,20 @@ void SpectralRoom::postHtmlMessage(const QString& text,
if (isReply) { if (isReply) {
const auto& replyEvt = **replyIt; const auto& replyEvt = **replyIt;
QJsonObject json{ QJsonObject json{{"msgtype", msgTypeToString(type)},
{"msgtype", msgTypeToString(type)}, {"body", "> <" + replyEvt.senderId() + "> " +
{"body", "> <" + replyEvt.senderId() + "> " + eventToString(replyEvt) + eventToString(replyEvt) + "\n\n" + text},
"\n\n" + text}, {"format", "org.matrix.custom.html"},
{"format", "org.matrix.custom.html"}, {"m.relates_to",
{"m.relates_to", QJsonObject{{"m.in_reply_to",
QJsonObject{ QJsonObject{{"event_id", replyEventId}}}}},
{"m.in_reply_to", QJsonObject{{"event_id", replyEventId}}}}}, {"formatted_body",
{"formatted_body", "<mx-reply><blockquote><a href=\"https://matrix.to/#/" +
"<mx-reply><blockquote><a href=\"https://matrix.to/#/" + id() + "/" + id() + "/" + replyEventId +
replyEventId + "\">In reply to</a> <a href=\"https://matrix.to/#/" +
"\">In reply to</a> <a href=\"https://matrix.to/#/" + replyEvt.senderId() + "\">" + replyEvt.senderId() +
replyEvt.senderId() + "\">" + replyEvt.senderId() + "</a><br>" + "</a><br>" + eventToString(replyEvt, Qt::RichText) +
eventToString(replyEvt, Qt::RichText) + "</blockquote></mx-reply>" + html}};
"</blockquote></mx-reply>" + html}};
postJson("m.room.message", json); postJson("m.room.message", json);
return; return;

View File

@@ -1,13 +1,6 @@
#ifndef SpectralRoom_H #ifndef SpectralRoom_H
#define SpectralRoom_H #define SpectralRoom_H
#include "room.h"
#include "spectraluser.h"
#include <QObject>
#include <QPointer>
#include <QTimer>
#include <events/encryptionevent.h> #include <events/encryptionevent.h>
#include <events/redactionevent.h> #include <events/redactionevent.h>
#include <events/roomavatarevent.h> #include <events/roomavatarevent.h>
@@ -16,7 +9,14 @@
#include <events/roommessageevent.h> #include <events/roommessageevent.h>
#include <events/simplestateevents.h> #include <events/simplestateevents.h>
using namespace QMatrixClient; #include <QObject>
#include <QPointer>
#include <QTimer>
#include "room.h"
#include "spectraluser.h"
using namespace Quotient;
class SpectralRoom : public Room { class SpectralRoom : public Room {
Q_OBJECT Q_OBJECT
@@ -37,7 +37,7 @@ class SpectralRoom : public Room {
QVariantList getUsersTyping() const; QVariantList getUsersTyping() const;
QString lastEvent() const; QString lastEvent() const;
bool isEventHighlighted(const QMatrixClient::RoomEvent* e) const; bool isEventHighlighted(const Quotient::RoomEvent* e) const;
QDateTime lastActiveTime() const; QDateTime lastActiveTime() const;
@@ -70,16 +70,17 @@ class SpectralRoom : public Room {
QString avatarMediaId() const; QString avatarMediaId() const;
QString eventToString(const RoomEvent& evt, QString eventToString(const RoomEvent& evt,
Qt::TextFormat format = Qt::PlainText, bool removeReply = true) const; Qt::TextFormat format = Qt::PlainText,
bool removeReply = true) const;
private: private:
QString m_cachedInput; QString m_cachedInput;
QSet<const QMatrixClient::RoomEvent*> highlights; QSet<const Quotient::RoomEvent*> highlights;
bool m_hasFileUploading = false; bool m_hasFileUploading = false;
int m_fileUploadingProgress = 0; int m_fileUploadingProgress = 0;
void checkForHighlights(const QMatrixClient::TimelineItem& ti); void checkForHighlights(const Quotient::TimelineItem& ti);
void onAddNewTimelineEvents(timeline_iter_t from) override; void onAddNewTimelineEvents(timeline_iter_t from) override;
void onAddHistoricalTimelineEvents(rev_iter_t from) override; void onAddHistoricalTimelineEvents(rev_iter_t from) override;

View File

@@ -1,12 +1,12 @@
#ifndef SpectralUser_H #ifndef SpectralUser_H
#define SpectralUser_H #define SpectralUser_H
#include <QObject>
#include "room.h" #include "room.h"
#include "user.h" #include "user.h"
#include <QObject> using namespace Quotient;
using namespace QMatrixClient;
class SpectralUser : public User { class SpectralUser : public User {
Q_OBJECT Q_OBJECT

View File

@@ -13,7 +13,7 @@
UserListModel::UserListModel(QObject* parent) UserListModel::UserListModel(QObject* parent)
: QAbstractListModel(parent), m_currentRoom(nullptr) {} : QAbstractListModel(parent), m_currentRoom(nullptr) {}
void UserListModel::setRoom(QMatrixClient::Room* room) { void UserListModel::setRoom(Quotient::Room* room) {
if (m_currentRoom == room) if (m_currentRoom == room)
return; return;
@@ -50,7 +50,7 @@ void UserListModel::setRoom(QMatrixClient::Room* room) {
emit roomChanged(); emit roomChanged();
} }
QMatrixClient::User* UserListModel::userAt(QModelIndex index) const { Quotient::User* UserListModel::userAt(QModelIndex index) const {
if (index.row() < 0 || index.row() >= m_users.size()) if (index.row() < 0 || index.row() >= m_users.size())
return nullptr; return nullptr;
return m_users.at(index.row()); return m_users.at(index.row());
@@ -89,16 +89,16 @@ int UserListModel::rowCount(const QModelIndex& parent) const {
return m_users.count(); return m_users.count();
} }
void UserListModel::userAdded(QMatrixClient::User* user) { void UserListModel::userAdded(Quotient::User* user) {
auto pos = findUserPos(user); auto pos = findUserPos(user);
beginInsertRows(QModelIndex(), pos, pos); beginInsertRows(QModelIndex(), pos, pos);
m_users.insert(pos, user); m_users.insert(pos, user);
endInsertRows(); endInsertRows();
connect(user, &QMatrixClient::User::avatarChanged, this, connect(user, &Quotient::User::avatarChanged, this,
&UserListModel::avatarChanged); &UserListModel::avatarChanged);
} }
void UserListModel::userRemoved(QMatrixClient::User* user) { void UserListModel::userRemoved(Quotient::User* user) {
auto pos = findUserPos(user); auto pos = findUserPos(user);
if (pos != m_users.size()) { if (pos != m_users.size()) {
beginRemoveRows(QModelIndex(), pos, pos); beginRemoveRows(QModelIndex(), pos, pos);
@@ -109,7 +109,7 @@ void UserListModel::userRemoved(QMatrixClient::User* user) {
qWarning() << "Trying to remove a room member not in the user list"; qWarning() << "Trying to remove a room member not in the user list";
} }
void UserListModel::refresh(QMatrixClient::User* user, QVector<int> roles) { void UserListModel::refresh(Quotient::User* user, QVector<int> roles) {
auto pos = findUserPos(user); auto pos = findUserPos(user);
if (pos != m_users.size()) if (pos != m_users.size())
emit dataChanged(index(pos), index(pos), roles); emit dataChanged(index(pos), index(pos), roles);
@@ -117,8 +117,8 @@ void UserListModel::refresh(QMatrixClient::User* user, QVector<int> roles) {
qWarning() << "Trying to access a room member not in the user list"; qWarning() << "Trying to access a room member not in the user list";
} }
void UserListModel::avatarChanged(QMatrixClient::User* user, void UserListModel::avatarChanged(Quotient::User* user,
const QMatrixClient::Room* context) { const Quotient::Room* context) {
if (context == m_currentRoom) if (context == m_currentRoom)
refresh(user, {AvatarRole}); refresh(user, {AvatarRole});
} }