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

@@ -195,7 +195,7 @@ void Controller::addConnection(Connection* c) {
c->sync(30000);
});
using namespace QMatrixClient;
using namespace Quotient;
setBusy(true);
@@ -213,7 +213,7 @@ void Controller::dropConnection(Connection* c) {
}
void Controller::invokeLogin() {
using namespace QMatrixClient;
using namespace Quotient;
const auto accounts = SettingsGroup("Accounts").childGroups();
for (const auto& accountId : accounts) {
AccountSettings account{accountId};
@@ -342,7 +342,11 @@ bool Controller::saveAccessTokenToKeyChain(const AccountSettings& account,
}
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, [=] {
emit errorOccured("Join Room Failed", joinRoomJob->errorString());
});

View File

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

View File

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

View File

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

View File

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

View File

@@ -167,6 +167,24 @@ QVariant PublicRoomListModel::data(const QModelIndex& index, int role) const {
if (role == TopicRole) {
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 {};
}
@@ -177,6 +195,11 @@ QHash<int, QByteArray> PublicRoomListModel::roleNames() const {
roles[NameRole] = "name";
roles[AvatarRole] = "avatar";
roles[TopicRole] = "topic";
roles[RoomIDRole] = "roomID";
roles[MemberCountRole] = "memberCount";
roles[AllowGuestsRole] = "allowGuests";
roles[WorldReadableRole] = "worldReadable";
roles[IsJoinedRole] = "isJoined";
return roles;
}

View File

@@ -20,7 +20,16 @@ class PublicRoomListModel : public QAbstractListModel {
Q_PROPERTY(bool hasMore READ hasMore NOTIFY hasMoreChanged)
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);

View File

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

View File

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

View File

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

View File

@@ -13,7 +13,7 @@
UserListModel::UserListModel(QObject* parent)
: QAbstractListModel(parent), m_currentRoom(nullptr) {}
void UserListModel::setRoom(QMatrixClient::Room* room) {
void UserListModel::setRoom(Quotient::Room* room) {
if (m_currentRoom == room)
return;
@@ -50,7 +50,7 @@ void UserListModel::setRoom(QMatrixClient::Room* room) {
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())
return nullptr;
return m_users.at(index.row());
@@ -89,16 +89,16 @@ int UserListModel::rowCount(const QModelIndex& parent) const {
return m_users.count();
}
void UserListModel::userAdded(QMatrixClient::User* user) {
void UserListModel::userAdded(Quotient::User* user) {
auto pos = findUserPos(user);
beginInsertRows(QModelIndex(), pos, pos);
m_users.insert(pos, user);
endInsertRows();
connect(user, &QMatrixClient::User::avatarChanged, this,
connect(user, &Quotient::User::avatarChanged, this,
&UserListModel::avatarChanged);
}
void UserListModel::userRemoved(QMatrixClient::User* user) {
void UserListModel::userRemoved(Quotient::User* user) {
auto pos = findUserPos(user);
if (pos != m_users.size()) {
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";
}
void UserListModel::refresh(QMatrixClient::User* user, QVector<int> roles) {
void UserListModel::refresh(Quotient::User* user, QVector<int> roles) {
auto pos = findUserPos(user);
if (pos != m_users.size())
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";
}
void UserListModel::avatarChanged(QMatrixClient::User* user,
const QMatrixClient::Room* context) {
void UserListModel::avatarChanged(Quotient::User* user,
const Quotient::Room* context) {
if (context == m_currentRoom)
refresh(user, {AvatarRole});
}