Code reformatting && tooltip.
This commit is contained in:
parent
d6b5cba61f
commit
6bd059ce63
52
main.cpp
52
main.cpp
|
@ -1,50 +1,50 @@
|
|||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QNetworkProxy>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QQmlContext>
|
||||
|
||||
#include "room.h"
|
||||
#include "matrix/controller.h"
|
||||
#include "matrix/roomlistmodel.h"
|
||||
#include "matrix/imageprovider.h"
|
||||
#include "matrix/messageeventmodel.h"
|
||||
#include "matrix/roomlistmodel.h"
|
||||
#include "room.h"
|
||||
|
||||
using namespace QMatrixClient;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
#if defined(Q_OS_WIN)
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
|
||||
QGuiApplication app(argc, argv);
|
||||
QGuiApplication app(argc, argv);
|
||||
|
||||
// Enable this if you need proxy.
|
||||
// QNetworkProxy proxy;
|
||||
// proxy.setType(QNetworkProxy::HttpProxy);
|
||||
// proxy.setHostName("localhost");
|
||||
// proxy.setPort(1082);
|
||||
// QNetworkProxy::setApplicationProxy(proxy);
|
||||
// Enable this if you need proxy.
|
||||
// QNetworkProxy proxy;
|
||||
// proxy.setType(QNetworkProxy::HttpProxy);
|
||||
// proxy.setHostName("localhost");
|
||||
// proxy.setPort(1082);
|
||||
// QNetworkProxy::setApplicationProxy(proxy);
|
||||
|
||||
qmlRegisterType<Room>(); qRegisterMetaType<Room*> ("Room*");
|
||||
qmlRegisterType<Room>();
|
||||
qRegisterMetaType<Room *>("Room*");
|
||||
|
||||
qmlRegisterType<Controller>("Matrique", 0, 1, "Controller");
|
||||
qmlRegisterType<RoomListModel>("Matrique", 0, 1, "RoomListModel");
|
||||
qmlRegisterType<MessageEventModel>("Matrique", 0, 1, "MessageEventModel");
|
||||
qRegisterMetaType<User*>("User*");
|
||||
qmlRegisterType<Controller>("Matrique", 0, 1, "Controller");
|
||||
qmlRegisterType<RoomListModel>("Matrique", 0, 1, "RoomListModel");
|
||||
qmlRegisterType<MessageEventModel>("Matrique", 0, 1, "MessageEventModel");
|
||||
qRegisterMetaType<User *>("User*");
|
||||
|
||||
QQmlApplicationEngine engine;
|
||||
QQmlApplicationEngine engine;
|
||||
|
||||
ImageProvider* m_provider = new ImageProvider();
|
||||
ImageProvider *m_provider = new ImageProvider();
|
||||
|
||||
engine.rootContext()->setContextProperty("imageProvider", m_provider->getConnection());
|
||||
engine.rootContext()->setContextProperty("imageProvider",
|
||||
m_provider->getConnection());
|
||||
|
||||
engine.addImageProvider(QLatin1String("mxc"), m_provider);
|
||||
engine.addImageProvider(QLatin1String("mxc"), m_provider);
|
||||
|
||||
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
|
||||
engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
|
||||
|
||||
if (engine.rootObjects().isEmpty())
|
||||
return -1;
|
||||
if (engine.rootObjects().isEmpty()) return -1;
|
||||
|
||||
return app.exec();
|
||||
return app.exec();
|
||||
}
|
||||
|
|
|
@ -3,67 +3,71 @@
|
|||
#include "connection.h"
|
||||
|
||||
Controller::Controller(QObject *parent) : QObject(parent) {
|
||||
connect(m_connection, &QMatrixClient::Connection::connected, this, &Controller::connected);
|
||||
connect(m_connection, &QMatrixClient::Connection::resolveError, this, &Controller::reconnect);
|
||||
connect(m_connection, &QMatrixClient::Connection::syncError, this, &Controller::reconnect);
|
||||
connect(m_connection, &QMatrixClient::Connection::syncDone, this, &Controller::resync);
|
||||
connect(m_connection, &QMatrixClient::Connection::connected, this, &Controller::connectionChanged);
|
||||
connect(m_connection, &QMatrixClient::Connection::connected, this,
|
||||
&Controller::connected);
|
||||
connect(m_connection, &QMatrixClient::Connection::resolveError, this,
|
||||
&Controller::reconnect);
|
||||
connect(m_connection, &QMatrixClient::Connection::syncError, this,
|
||||
&Controller::reconnect);
|
||||
connect(m_connection, &QMatrixClient::Connection::syncDone, this,
|
||||
&Controller::resync);
|
||||
connect(m_connection, &QMatrixClient::Connection::connected, this,
|
||||
&Controller::connectionChanged);
|
||||
}
|
||||
|
||||
Controller::~Controller() {
|
||||
m_connection->stopSync();
|
||||
}
|
||||
Controller::~Controller() { m_connection->stopSync(); }
|
||||
|
||||
void Controller::login() {
|
||||
if (!isLogin) {
|
||||
qDebug() << "UserID:" << userID;
|
||||
qDebug() << "Token:" << token;
|
||||
if (!isLogin) {
|
||||
qDebug() << "UserID:" << userID;
|
||||
qDebug() << "Token:" << token;
|
||||
|
||||
m_connection->setHomeserver(QUrl(homeserver));
|
||||
m_connection->connectWithToken(userID, token, "");
|
||||
}
|
||||
m_connection->setHomeserver(QUrl(homeserver));
|
||||
m_connection->connectWithToken(userID, token, "");
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::loginWithCredentials(QString serverAddr, QString user, QString pass) {
|
||||
if(!isLogin) {
|
||||
qDebug() << "Server:" << serverAddr;
|
||||
qDebug() << "User:" << user;
|
||||
qDebug() << "Pass:" << pass;
|
||||
void Controller::loginWithCredentials(QString serverAddr, QString user,
|
||||
QString pass) {
|
||||
if (!isLogin) {
|
||||
qDebug() << "Server:" << serverAddr;
|
||||
qDebug() << "User:" << user;
|
||||
qDebug() << "Pass:" << pass;
|
||||
|
||||
if(!user.isEmpty() && !pass.isEmpty()) {
|
||||
qDebug() << "Using given credential.";
|
||||
m_connection->setHomeserver(QUrl(serverAddr));
|
||||
m_connection->connectToServer(user, pass, "");
|
||||
}
|
||||
} else {
|
||||
qDebug() << "You are already logged in.";
|
||||
if (!user.isEmpty() && !pass.isEmpty()) {
|
||||
qDebug() << "Using given credential.";
|
||||
m_connection->setHomeserver(QUrl(serverAddr));
|
||||
m_connection->connectToServer(user, pass, "");
|
||||
}
|
||||
} else {
|
||||
qDebug() << "You are already logged in.";
|
||||
}
|
||||
}
|
||||
|
||||
void Controller::logout() {
|
||||
qDebug() << "Logging out.";
|
||||
setUserID("");
|
||||
setToken("");
|
||||
setIsLogin(false);
|
||||
qDebug() << "Logging out.";
|
||||
setUserID("");
|
||||
setToken("");
|
||||
setIsLogin(false);
|
||||
}
|
||||
|
||||
void Controller::connected() {
|
||||
qDebug() << "Logged in.";
|
||||
setHomeserver(m_connection->homeserver().toString());
|
||||
setUserID(m_connection->userId());
|
||||
setToken(m_connection->accessToken());
|
||||
m_connection->loadState();
|
||||
resync();
|
||||
setIsLogin(true);
|
||||
qDebug() << "Logged in.";
|
||||
setHomeserver(m_connection->homeserver().toString());
|
||||
setUserID(m_connection->userId());
|
||||
setToken(m_connection->accessToken());
|
||||
m_connection->loadState();
|
||||
resync();
|
||||
setIsLogin(true);
|
||||
}
|
||||
|
||||
void Controller::resync() {
|
||||
qDebug() << "Syncing Matrix.";
|
||||
m_connection->sync(30000);
|
||||
m_connection->saveState();
|
||||
qDebug() << "Syncing Matrix.";
|
||||
m_connection->sync(30000);
|
||||
m_connection->saveState();
|
||||
}
|
||||
|
||||
void Controller::reconnect() {
|
||||
qDebug() << "Connection lost. Reconnecting...";
|
||||
m_connection->connectWithToken(userID, token, "");
|
||||
qDebug() << "Connection lost. Reconnecting...";
|
||||
m_connection->connectWithToken(userID, token, "");
|
||||
}
|
||||
|
|
|
@ -3,99 +3,101 @@
|
|||
|
||||
#include <QObject>
|
||||
#include "connection.h"
|
||||
#include "user.h"
|
||||
#include "roomlistmodel.h"
|
||||
#include "user.h"
|
||||
|
||||
namespace QMatrixClient {
|
||||
class Connection;
|
||||
class Connection;
|
||||
}
|
||||
|
||||
class Controller : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class Controller : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection NOTIFY connectionChanged)
|
||||
Q_PROPERTY(bool isLogin READ getIsLogin WRITE setIsLogin NOTIFY isLoginChanged)
|
||||
Q_PROPERTY(QString homeserver READ getHomeserver WRITE setHomeserver NOTIFY homeserverChanged)
|
||||
Q_PROPERTY(QString userID READ getUserID WRITE setUserID NOTIFY userIDChanged)
|
||||
Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged)
|
||||
Q_PROPERTY(bool busy READ getBusy WRITE setBusy NOTIFY busyChanged)
|
||||
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection NOTIFY
|
||||
connectionChanged)
|
||||
Q_PROPERTY(
|
||||
bool isLogin READ getIsLogin WRITE setIsLogin NOTIFY isLoginChanged)
|
||||
Q_PROPERTY(QString homeserver READ getHomeserver WRITE setHomeserver NOTIFY
|
||||
homeserverChanged)
|
||||
Q_PROPERTY(QString userID READ getUserID WRITE setUserID NOTIFY userIDChanged)
|
||||
Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged)
|
||||
Q_PROPERTY(bool busy READ getBusy WRITE setBusy NOTIFY busyChanged)
|
||||
|
||||
public:
|
||||
explicit Controller(QObject *parent = nullptr);
|
||||
~Controller();
|
||||
public:
|
||||
explicit Controller(QObject* parent = nullptr);
|
||||
~Controller();
|
||||
|
||||
// All the Q_INVOKABLEs.
|
||||
Q_INVOKABLE void login();
|
||||
Q_INVOKABLE void loginWithCredentials(QString, QString, QString);
|
||||
Q_INVOKABLE void logout();
|
||||
// All the Q_INVOKABLEs.
|
||||
Q_INVOKABLE void login();
|
||||
Q_INVOKABLE void loginWithCredentials(QString, QString, QString);
|
||||
Q_INVOKABLE void logout();
|
||||
|
||||
// All the non-Q_INVOKABLE functions.
|
||||
// All the non-Q_INVOKABLE functions.
|
||||
|
||||
// All the Q_PROPERTYs.
|
||||
QMatrixClient::Connection* m_connection = new QMatrixClient::Connection();
|
||||
QMatrixClient::Connection* getConnection() { return m_connection; }
|
||||
// All the Q_PROPERTYs.
|
||||
QMatrixClient::Connection* m_connection = new QMatrixClient::Connection();
|
||||
QMatrixClient::Connection* getConnection() { return m_connection; }
|
||||
|
||||
bool isLogin = false;
|
||||
bool getIsLogin() { return isLogin; }
|
||||
void setIsLogin(bool n) {
|
||||
if(n != isLogin) {
|
||||
isLogin = n;
|
||||
emit isLoginChanged();
|
||||
}
|
||||
}
|
||||
bool isLogin = false;
|
||||
bool getIsLogin() { return isLogin; }
|
||||
void setIsLogin(bool n) {
|
||||
if (n != isLogin) {
|
||||
isLogin = n;
|
||||
emit isLoginChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString userID;
|
||||
QString getUserID() { return userID; }
|
||||
void setUserID(QString n) {
|
||||
if(n != userID) {
|
||||
userID = n;
|
||||
emit userIDChanged();
|
||||
}
|
||||
}
|
||||
QString userID;
|
||||
QString getUserID() { return userID; }
|
||||
void setUserID(QString n) {
|
||||
if (n != userID) {
|
||||
userID = n;
|
||||
emit userIDChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray token;
|
||||
QByteArray getToken() { return token; }
|
||||
void setToken(QByteArray n) {
|
||||
if(n != token) {
|
||||
token = n;
|
||||
emit tokenChanged();
|
||||
}
|
||||
}
|
||||
QByteArray token;
|
||||
QByteArray getToken() { return token; }
|
||||
void setToken(QByteArray n) {
|
||||
if (n != token) {
|
||||
token = n;
|
||||
emit tokenChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString homeserver;
|
||||
QString getHomeserver() { return homeserver; }
|
||||
void setHomeserver(QString n) {
|
||||
if (n != homeserver) {
|
||||
homeserver = n;
|
||||
emit homeserverChanged();
|
||||
}
|
||||
}
|
||||
QString homeserver;
|
||||
QString getHomeserver() { return homeserver; }
|
||||
void setHomeserver(QString n) {
|
||||
if (n != homeserver) {
|
||||
homeserver = n;
|
||||
emit homeserverChanged();
|
||||
}
|
||||
}
|
||||
|
||||
bool busy = false;
|
||||
bool getBusy() { return busy; }
|
||||
void setBusy(bool b) {
|
||||
if (b != busy) {
|
||||
busy = b;
|
||||
emit busyChanged();
|
||||
}
|
||||
}
|
||||
bool busy = false;
|
||||
bool getBusy() { return busy; }
|
||||
void setBusy(bool b) {
|
||||
if (b != busy) {
|
||||
busy = b;
|
||||
emit busyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void connected();
|
||||
void resync();
|
||||
void reconnect();
|
||||
private:
|
||||
void connected();
|
||||
void resync();
|
||||
void reconnect();
|
||||
|
||||
signals:
|
||||
void connectionChanged();
|
||||
void isLoginChanged();
|
||||
void userIDChanged();
|
||||
void tokenChanged();
|
||||
void homeserverChanged();
|
||||
void busyChanged();
|
||||
void errorOccured();
|
||||
signals:
|
||||
void connectionChanged();
|
||||
void isLoginChanged();
|
||||
void userIDChanged();
|
||||
void tokenChanged();
|
||||
void homeserverChanged();
|
||||
void busyChanged();
|
||||
void errorOccured();
|
||||
|
||||
public slots:
|
||||
public slots:
|
||||
};
|
||||
|
||||
#endif // CONTROLLER_H
|
||||
#endif // CONTROLLER_H
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "imageprovider.h"
|
||||
|
||||
#include <QtCore/QWaitCondition>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QMetaObject>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QWaitCondition>
|
||||
|
||||
#include "jobs/mediathumbnailjob.h"
|
||||
|
||||
|
@ -11,58 +11,57 @@
|
|||
using QMatrixClient::MediaThumbnailJob;
|
||||
|
||||
ImageProvider::ImageProvider(QObject* parent)
|
||||
: QQuickImageProvider(QQmlImageProviderBase::Image,
|
||||
QQmlImageProviderBase::ForceAsynchronousImageLoading)
|
||||
{
|
||||
: QQuickImageProvider(
|
||||
QQmlImageProviderBase::Image,
|
||||
QQmlImageProviderBase::ForceAsynchronousImageLoading) {
|
||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
|
||||
qRegisterMetaType<MediaThumbnailJob*>();
|
||||
qRegisterMetaType<MediaThumbnailJob*>();
|
||||
#endif
|
||||
m_connection = new ImageProviderConnection();
|
||||
m_connection = new ImageProviderConnection();
|
||||
}
|
||||
|
||||
QImage ImageProvider::requestImage(const QString& id,
|
||||
QSize* pSize, const QSize& requestedSize)
|
||||
{
|
||||
if (!id.startsWith("mxc://"))
|
||||
{
|
||||
qWarning() << "ImageProvider: won't fetch an invalid id:" << id
|
||||
<< "doesn't follow server/mediaId pattern";
|
||||
return {};
|
||||
}
|
||||
QImage ImageProvider::requestImage(const QString& id, QSize* pSize,
|
||||
const QSize& requestedSize) {
|
||||
if (!id.startsWith("mxc://")) {
|
||||
qWarning() << "ImageProvider: won't fetch an invalid id:" << id
|
||||
<< "doesn't follow server/mediaId pattern";
|
||||
return {};
|
||||
}
|
||||
|
||||
QUrl mxcUri { id };
|
||||
qDebug() << "ImageProvider::requestImage:" << mxcUri.toString();
|
||||
QUrl mxcUri{id};
|
||||
|
||||
MediaThumbnailJob* job = nullptr;
|
||||
QReadLocker locker(&m_lock);
|
||||
MediaThumbnailJob* job = nullptr;
|
||||
QReadLocker locker(&m_lock);
|
||||
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
|
||||
QMetaObject::invokeMethod(m_connection,
|
||||
[=] { return m_connection->getConnection()->getThumbnail(mxcUri, requestedSize); },
|
||||
Qt::BlockingQueuedConnection, &job);
|
||||
QMetaObject::invokeMethod(
|
||||
m_connection,
|
||||
[=] {
|
||||
return m_connection->getConnection()->getThumbnail(mxcUri,
|
||||
requestedSize);
|
||||
},
|
||||
Qt::BlockingQueuedConnection, &job);
|
||||
#else
|
||||
QMetaObject::invokeMethod(m_connection, "getThumbnail",
|
||||
Qt::BlockingQueuedConnection, Q_RETURN_ARG(MediaThumbnailJob*, job),
|
||||
Q_ARG(QUrl, mxcUri), Q_ARG(QSize, requestedSize));
|
||||
QMetaObject::invokeMethod(m_connection, "getThumbnail",
|
||||
Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(MediaThumbnailJob*, job),
|
||||
Q_ARG(QUrl, mxcUri), Q_ARG(QSize, requestedSize));
|
||||
#endif
|
||||
if (!job)
|
||||
{
|
||||
qDebug() << "ImageProvider: failed to send a request";
|
||||
return {};
|
||||
}
|
||||
QImage result;
|
||||
{
|
||||
QWaitCondition condition; // The most compact way to block on a signal
|
||||
job->connect(job, &MediaThumbnailJob::finished, job, [&] {
|
||||
result = job->thumbnail();
|
||||
condition.wakeAll();
|
||||
});
|
||||
condition.wait(&m_lock);
|
||||
}
|
||||
if (!job) {
|
||||
qDebug() << "ImageProvider: failed to send a request";
|
||||
return {};
|
||||
}
|
||||
QImage result;
|
||||
{
|
||||
QWaitCondition condition; // The most compact way to block on a signal
|
||||
job->connect(job, &MediaThumbnailJob::finished, job, [&] {
|
||||
result = job->thumbnail();
|
||||
condition.wakeAll();
|
||||
});
|
||||
condition.wait(&m_lock);
|
||||
}
|
||||
|
||||
if(pSize != nullptr)
|
||||
*pSize = result.size();
|
||||
if (pSize != nullptr) *pSize = result.size();
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,28 +1,27 @@
|
|||
#ifndef IMAGEPROVIDER_H
|
||||
#define IMAGEPROVIDER_H
|
||||
|
||||
#include <QtQuick/QQuickImageProvider>
|
||||
#include <QtCore/QReadWriteLock>
|
||||
#include <QObject>
|
||||
#include <QtCore/QReadWriteLock>
|
||||
#include <QtQuick/QQuickImageProvider>
|
||||
|
||||
#include "connection.h"
|
||||
#include "imageproviderconnection.h"
|
||||
|
||||
class ImageProvider: public QQuickImageProvider
|
||||
{
|
||||
public:
|
||||
explicit ImageProvider(QObject* parent = nullptr);
|
||||
class ImageProvider : public QQuickImageProvider {
|
||||
public:
|
||||
explicit ImageProvider(QObject* parent = nullptr);
|
||||
|
||||
QImage requestImage(const QString& id, QSize* pSize,
|
||||
const QSize& requestedSize) override;
|
||||
QImage requestImage(const QString& id, QSize* pSize,
|
||||
const QSize& requestedSize) override;
|
||||
|
||||
void initializeEngine(QQmlEngine *engine, const char *uri);
|
||||
void initializeEngine(QQmlEngine* engine, const char* uri);
|
||||
|
||||
ImageProviderConnection* getConnection() { return m_connection; }
|
||||
ImageProviderConnection* getConnection() { return m_connection; }
|
||||
|
||||
private:
|
||||
QReadWriteLock m_lock;
|
||||
ImageProviderConnection* m_connection;
|
||||
private:
|
||||
QReadWriteLock m_lock;
|
||||
ImageProviderConnection* m_connection;
|
||||
};
|
||||
|
||||
#endif // IMAGEPROVIDER_H
|
||||
#endif // IMAGEPROVIDER_H
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
#include "imageproviderconnection.h"
|
||||
|
||||
ImageProviderConnection::ImageProviderConnection(QObject* parent) : QObject(parent) {
|
||||
ImageProviderConnection::ImageProviderConnection(QObject* parent)
|
||||
: QObject(parent) {}
|
||||
|
||||
}
|
||||
|
||||
ImageProviderConnection::~ImageProviderConnection() {
|
||||
|
||||
}
|
||||
ImageProviderConnection::~ImageProviderConnection() {}
|
||||
|
|
|
@ -5,25 +5,26 @@
|
|||
|
||||
#include "connection.h"
|
||||
|
||||
class ImageProviderConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
class ImageProviderConnection : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection WRITE setConnection NOTIFY connectionChanged)
|
||||
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection WRITE
|
||||
setConnection NOTIFY connectionChanged)
|
||||
|
||||
public:
|
||||
explicit ImageProviderConnection(QObject* parent = nullptr);
|
||||
~ImageProviderConnection();
|
||||
public:
|
||||
explicit ImageProviderConnection(QObject* parent = nullptr);
|
||||
~ImageProviderConnection();
|
||||
|
||||
QMatrixClient::Connection* getConnection() { return m_connection; }
|
||||
void setConnection(QMatrixClient::Connection* connection) {
|
||||
emit connectionChanged();
|
||||
m_connection = connection;
|
||||
}
|
||||
private:
|
||||
QMatrixClient::Connection* m_connection;
|
||||
signals:
|
||||
void connectionChanged();
|
||||
QMatrixClient::Connection* getConnection() { return m_connection; }
|
||||
void setConnection(QMatrixClient::Connection* connection) {
|
||||
emit connectionChanged();
|
||||
m_connection = connection;
|
||||
}
|
||||
|
||||
private:
|
||||
QMatrixClient::Connection* m_connection;
|
||||
signals:
|
||||
void connectionChanged();
|
||||
};
|
||||
|
||||
#endif // IMAGEPROVIDERCONNECTION_H
|
||||
#endif // IMAGEPROVIDERCONNECTION_H
|
||||
|
|
|
@ -1,452 +1,379 @@
|
|||
#include "messageeventmodel.h"
|
||||
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtQml> // for qmlRegisterType()
|
||||
#include <QtCore/QSettings>
|
||||
#include <QtQml> // for qmlRegisterType()
|
||||
|
||||
#include "events/roommemberevent.h"
|
||||
#include "events/simplestateevents.h"
|
||||
#include "events/redactionevent.h"
|
||||
#include "events/roomavatarevent.h"
|
||||
#include "events/roommemberevent.h"
|
||||
#include "events/simplestateevents.h"
|
||||
|
||||
#include "connection.h"
|
||||
#include "user.h"
|
||||
#include "settings.h"
|
||||
#include "user.h"
|
||||
|
||||
MessageEventModel::MessageEventModel(QObject* parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
qmlRegisterType<QMatrixClient::FileTransferInfo>();
|
||||
qRegisterMetaType<QMatrixClient::FileTransferInfo>();
|
||||
: QAbstractListModel(parent) {
|
||||
qmlRegisterType<QMatrixClient::FileTransferInfo>();
|
||||
qRegisterMetaType<QMatrixClient::FileTransferInfo>();
|
||||
}
|
||||
|
||||
MessageEventModel::~MessageEventModel()
|
||||
{
|
||||
MessageEventModel::~MessageEventModel() {}
|
||||
|
||||
void MessageEventModel::setRoom(QMatrixClient::Room* room) {
|
||||
if (room == m_currentRoom) return;
|
||||
|
||||
beginResetModel();
|
||||
if (m_currentRoom) {
|
||||
m_currentRoom->disconnect(this);
|
||||
qDebug() << "Disconnected from" << m_currentRoom->id();
|
||||
}
|
||||
|
||||
m_currentRoom = room;
|
||||
if (room) {
|
||||
lastReadEventId = room->readMarkerEventId();
|
||||
using namespace QMatrixClient;
|
||||
connect(m_currentRoom, &Room::aboutToAddNewMessages, this,
|
||||
[=](RoomEventsRange events) {
|
||||
beginInsertRows(QModelIndex(), 0, int(events.size()) - 1);
|
||||
});
|
||||
connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this,
|
||||
[=](RoomEventsRange events) {
|
||||
if (rowCount() > 0) nextNewerRow = rowCount() - 1;
|
||||
beginInsertRows(QModelIndex(), rowCount(),
|
||||
rowCount() + int(events.size()) - 1);
|
||||
});
|
||||
connect(m_currentRoom, &Room::addedMessages, this, [=] {
|
||||
if (nextNewerRow > -1) {
|
||||
const auto idx = index(nextNewerRow);
|
||||
emit dataChanged(idx, idx);
|
||||
nextNewerRow = -1;
|
||||
}
|
||||
endInsertRows();
|
||||
});
|
||||
connect(m_currentRoom, &Room::readMarkerMoved, this, [this] {
|
||||
refreshEventRoles(
|
||||
std::exchange(lastReadEventId, m_currentRoom->readMarkerEventId()),
|
||||
{ReadMarkerRole});
|
||||
refreshEventRoles(lastReadEventId, {ReadMarkerRole});
|
||||
});
|
||||
connect(
|
||||
m_currentRoom, &Room::replacedEvent, this,
|
||||
[this](const RoomEvent* newEvent) { refreshEvent(newEvent->id()); });
|
||||
connect(m_currentRoom, &Room::fileTransferProgress, this,
|
||||
&MessageEventModel::refreshEvent);
|
||||
connect(m_currentRoom, &Room::fileTransferCompleted, this,
|
||||
&MessageEventModel::refreshEvent);
|
||||
connect(m_currentRoom, &Room::fileTransferFailed, this,
|
||||
&MessageEventModel::refreshEvent);
|
||||
connect(m_currentRoom, &Room::fileTransferCancelled, this,
|
||||
&MessageEventModel::refreshEvent);
|
||||
qDebug() << "Connected to room" << room->id() << "as"
|
||||
<< room->localUser()->id();
|
||||
} else
|
||||
lastReadEventId.clear();
|
||||
endResetModel();
|
||||
emit roomChanged();
|
||||
}
|
||||
|
||||
void MessageEventModel::setRoom(QMatrixClient::Room* room)
|
||||
{
|
||||
if (room == m_currentRoom)
|
||||
return;
|
||||
|
||||
beginResetModel();
|
||||
if( m_currentRoom )
|
||||
{
|
||||
m_currentRoom->disconnect( this );
|
||||
qDebug() << "Disconnected from" << m_currentRoom->id();
|
||||
}
|
||||
|
||||
m_currentRoom = room;
|
||||
if( room )
|
||||
{
|
||||
lastReadEventId = room->readMarkerEventId();
|
||||
using namespace QMatrixClient;
|
||||
connect(m_currentRoom, &Room::aboutToAddNewMessages, this,
|
||||
[=](RoomEventsRange events)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), 0, int(events.size()) - 1);
|
||||
});
|
||||
connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this,
|
||||
[=](RoomEventsRange events)
|
||||
{
|
||||
if (rowCount() > 0)
|
||||
nextNewerRow = rowCount() - 1;
|
||||
beginInsertRows(QModelIndex(), rowCount(),
|
||||
rowCount() + int(events.size()) - 1);
|
||||
});
|
||||
connect(m_currentRoom, &Room::addedMessages, this,
|
||||
[=] {
|
||||
if (nextNewerRow > -1)
|
||||
{
|
||||
const auto idx = index(nextNewerRow);
|
||||
emit dataChanged(idx, idx);
|
||||
nextNewerRow = -1;
|
||||
}
|
||||
endInsertRows();
|
||||
});
|
||||
connect(m_currentRoom, &Room::readMarkerMoved, this, [this] {
|
||||
refreshEventRoles(
|
||||
std::exchange(lastReadEventId,
|
||||
m_currentRoom->readMarkerEventId()),
|
||||
{ReadMarkerRole});
|
||||
refreshEventRoles(lastReadEventId, {ReadMarkerRole});
|
||||
});
|
||||
connect(m_currentRoom, &Room::replacedEvent, this,
|
||||
[this] (const RoomEvent* newEvent) {
|
||||
refreshEvent(newEvent->id());
|
||||
});
|
||||
connect(m_currentRoom, &Room::fileTransferProgress,
|
||||
this, &MessageEventModel::refreshEvent);
|
||||
connect(m_currentRoom, &Room::fileTransferCompleted,
|
||||
this, &MessageEventModel::refreshEvent);
|
||||
connect(m_currentRoom, &Room::fileTransferFailed,
|
||||
this, &MessageEventModel::refreshEvent);
|
||||
connect(m_currentRoom, &Room::fileTransferCancelled,
|
||||
this, &MessageEventModel::refreshEvent);
|
||||
qDebug() << "Connected to room" << room->id()
|
||||
<< "as" << room->localUser()->id();
|
||||
} else
|
||||
lastReadEventId.clear();
|
||||
endResetModel();
|
||||
emit roomChanged();
|
||||
}
|
||||
|
||||
void MessageEventModel::refreshEvent(const QString& eventId)
|
||||
{
|
||||
refreshEventRoles(eventId, {});
|
||||
void MessageEventModel::refreshEvent(const QString& eventId) {
|
||||
refreshEventRoles(eventId, {});
|
||||
}
|
||||
|
||||
void MessageEventModel::refreshEventRoles(const QString& eventId,
|
||||
const QVector<int> roles)
|
||||
{
|
||||
const auto it = m_currentRoom->findInTimeline(eventId);
|
||||
if (it != m_currentRoom->timelineEdge())
|
||||
{
|
||||
const auto row = it - m_currentRoom->messageEvents().rbegin();
|
||||
emit dataChanged(index(row), index(row), roles);
|
||||
}
|
||||
const QVector<int> roles) {
|
||||
const auto it = m_currentRoom->findInTimeline(eventId);
|
||||
if (it != m_currentRoom->timelineEdge()) {
|
||||
const auto row = it - m_currentRoom->messageEvents().rbegin();
|
||||
emit dataChanged(index(row), index(row), roles);
|
||||
}
|
||||
}
|
||||
|
||||
inline bool hasValidTimestamp(const QMatrixClient::TimelineItem& ti)
|
||||
{
|
||||
return ti->timestamp().isValid();
|
||||
inline bool hasValidTimestamp(const QMatrixClient::TimelineItem& ti) {
|
||||
return ti->timestamp().isValid();
|
||||
}
|
||||
|
||||
QDateTime MessageEventModel::makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const
|
||||
{
|
||||
const auto& timeline = m_currentRoom->messageEvents();
|
||||
auto ts = baseIt->event()->timestamp();
|
||||
if (ts.isValid())
|
||||
return ts;
|
||||
QDateTime MessageEventModel::makeMessageTimestamp(
|
||||
QMatrixClient::Room::rev_iter_t baseIt) const {
|
||||
const auto& timeline = m_currentRoom->messageEvents();
|
||||
auto ts = baseIt->event()->timestamp();
|
||||
if (ts.isValid()) return ts;
|
||||
|
||||
// The event is most likely redacted or just invalid.
|
||||
// Look for the nearest date around and slap zero time to it.
|
||||
using QMatrixClient::TimelineItem;
|
||||
auto rit = std::find_if(baseIt, timeline.rend(),
|
||||
hasValidTimestamp);
|
||||
if (rit != timeline.rend())
|
||||
return { rit->event()->timestamp().date(), {0,0}, Qt::LocalTime };
|
||||
auto it = std::find_if(baseIt.base(), timeline.end(), hasValidTimestamp);
|
||||
if (it != timeline.end())
|
||||
return { it->event()->timestamp().date(), {0,0}, Qt::LocalTime };
|
||||
// The event is most likely redacted or just invalid.
|
||||
// Look for the nearest date around and slap zero time to it.
|
||||
using QMatrixClient::TimelineItem;
|
||||
auto rit = std::find_if(baseIt, timeline.rend(), hasValidTimestamp);
|
||||
if (rit != timeline.rend())
|
||||
return {rit->event()->timestamp().date(), {0, 0}, Qt::LocalTime};
|
||||
auto it = std::find_if(baseIt.base(), timeline.end(), hasValidTimestamp);
|
||||
if (it != timeline.end())
|
||||
return {it->event()->timestamp().date(), {0, 0}, Qt::LocalTime};
|
||||
|
||||
// What kind of room is that?..
|
||||
qCritical() << "No valid timestamps in the room timeline!";
|
||||
return {};
|
||||
// What kind of room is that?..
|
||||
qCritical() << "No valid timestamps in the room timeline!";
|
||||
return {};
|
||||
}
|
||||
|
||||
QString MessageEventModel::makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const
|
||||
{
|
||||
auto date = makeMessageTimestamp(baseIt).toLocalTime().date();
|
||||
if (QMatrixClient::SettingsGroup("UI")
|
||||
.value("banner_human_friendly_date", true).toBool())
|
||||
{
|
||||
if (date == QDate::currentDate())
|
||||
return tr("Today");
|
||||
if (date == QDate::currentDate().addDays(-1))
|
||||
return tr("Yesterday");
|
||||
if (date == QDate::currentDate().addDays(-2))
|
||||
return tr("The day before yesterday");
|
||||
if (date > QDate::currentDate().addDays(-7))
|
||||
return date.toString("dddd");
|
||||
}
|
||||
return date.toString(Qt::DefaultLocaleShortDate);
|
||||
QString MessageEventModel::makeDateString(
|
||||
QMatrixClient::Room::rev_iter_t baseIt) const {
|
||||
auto date = makeMessageTimestamp(baseIt).toLocalTime().date();
|
||||
if (QMatrixClient::SettingsGroup("UI")
|
||||
.value("banner_human_friendly_date", true)
|
||||
.toBool()) {
|
||||
if (date == QDate::currentDate()) return tr("Today");
|
||||
if (date == QDate::currentDate().addDays(-1)) return tr("Yesterday");
|
||||
if (date == QDate::currentDate().addDays(-2))
|
||||
return tr("The day before yesterday");
|
||||
if (date > QDate::currentDate().addDays(-7)) return date.toString("dddd");
|
||||
}
|
||||
return date.toString(Qt::DefaultLocaleShortDate);
|
||||
}
|
||||
|
||||
int MessageEventModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
if(!m_currentRoom || parent.isValid())
|
||||
return 0;
|
||||
return m_currentRoom->timelineSize();
|
||||
int MessageEventModel::rowCount(const QModelIndex& parent) const {
|
||||
if (!m_currentRoom || parent.isValid()) return 0;
|
||||
return m_currentRoom->timelineSize();
|
||||
}
|
||||
|
||||
QVariant MessageEventModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if( !m_currentRoom ||
|
||||
index.row() < 0 || index.row() >= m_currentRoom->timelineSize())
|
||||
return QVariant();
|
||||
|
||||
const auto timelineIt = m_currentRoom->messageEvents().rbegin() + index.row();
|
||||
const auto& ti = *timelineIt;
|
||||
|
||||
using namespace QMatrixClient;
|
||||
if( role == Qt::DisplayRole )
|
||||
{
|
||||
if (ti->isRedacted())
|
||||
{
|
||||
auto reason = ti->redactedBecause()->reason();
|
||||
if (reason.isEmpty())
|
||||
return tr("Redacted");
|
||||
else
|
||||
return tr("Redacted: %1")
|
||||
.arg(ti->redactedBecause()->reason());
|
||||
}
|
||||
|
||||
if( ti->type() == EventType::RoomMessage )
|
||||
{
|
||||
using namespace MessageEventContent;
|
||||
|
||||
auto* e = ti.viewAs<RoomMessageEvent>();
|
||||
if (e->hasTextContent() && e->mimeType().name() != "text/plain")
|
||||
return static_cast<const TextContent*>(e->content())->body;
|
||||
if (e->hasFileContent())
|
||||
{
|
||||
auto fileCaption = e->content()->fileInfo()->originalName;
|
||||
if (fileCaption.isEmpty())
|
||||
fileCaption = m_currentRoom->prettyPrint(e->plainBody());
|
||||
if (fileCaption.isEmpty())
|
||||
return tr("a file");
|
||||
}
|
||||
return m_currentRoom->prettyPrint(e->plainBody());
|
||||
}
|
||||
if( ti->type() == EventType::RoomMember )
|
||||
{
|
||||
auto* e = ti.viewAs<RoomMemberEvent>();
|
||||
// FIXME: Rewind to the name that was at the time of this event
|
||||
QString subjectName = m_currentRoom->roomMembername(e->userId());
|
||||
// The below code assumes senderName output in AuthorRole
|
||||
switch( e->membership() )
|
||||
{
|
||||
case MembershipType::Invite:
|
||||
if (e->repeatsState())
|
||||
return tr("reinvited %1 to the room").arg(subjectName);
|
||||
// [[fallthrough]]
|
||||
case MembershipType::Join:
|
||||
{
|
||||
if (e->repeatsState())
|
||||
return tr("joined the room (repeated)");
|
||||
if (!e->prev_content() ||
|
||||
e->membership() != e->prev_content()->membership)
|
||||
{
|
||||
return e->membership() == MembershipType::Invite
|
||||
? tr("invited %1 to the room").arg(subjectName)
|
||||
: tr("joined the room");
|
||||
}
|
||||
QString text {};
|
||||
if (e->displayName() != e->prev_content()->displayName)
|
||||
{
|
||||
if (e->displayName().isEmpty())
|
||||
text = tr("cleared the display name");
|
||||
else
|
||||
text = tr("changed the display name to %1")
|
||||
.arg(e->displayName());
|
||||
}
|
||||
if (e->avatarUrl() != e->prev_content()->avatarUrl)
|
||||
{
|
||||
if (!text.isEmpty())
|
||||
text += " and ";
|
||||
if (e->avatarUrl().isEmpty())
|
||||
text += tr("cleared the avatar");
|
||||
else
|
||||
text += tr("updated the avatar");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
case MembershipType::Leave:
|
||||
if (e->prev_content() &&
|
||||
e->prev_content()->membership == MembershipType::Ban)
|
||||
{
|
||||
if (e->senderId() != e->userId())
|
||||
return tr("unbanned %1").arg(subjectName);
|
||||
else
|
||||
return tr("self-unbanned");
|
||||
}
|
||||
if (e->senderId() != e->userId())
|
||||
return tr("has put %1 out of the room").arg(subjectName);
|
||||
else
|
||||
return tr("left the room");
|
||||
case MembershipType::Ban:
|
||||
if (e->senderId() != e->userId())
|
||||
return tr("banned %1 from the room").arg(subjectName);
|
||||
else
|
||||
return tr("self-banned from the room");
|
||||
case MembershipType::Knock:
|
||||
return tr("knocked");
|
||||
case MembershipType::Undefined:
|
||||
return tr("made something unknown");
|
||||
}
|
||||
}
|
||||
if( ti->type() == EventType::RoomAliases )
|
||||
{
|
||||
auto* e = ti.viewAs<RoomAliasesEvent>();
|
||||
return tr("set aliases to: %1").arg(e->aliases().join(", "));
|
||||
}
|
||||
if( ti->type() == EventType::RoomCanonicalAlias )
|
||||
{
|
||||
auto* e = ti.viewAs<RoomCanonicalAliasEvent>();
|
||||
if (e->alias().isEmpty())
|
||||
return tr("cleared the room main alias");
|
||||
else
|
||||
return tr("set the room main alias to: %1").arg(e->alias());
|
||||
}
|
||||
if( ti->type() == EventType::RoomName )
|
||||
{
|
||||
auto* e = ti.viewAs<RoomNameEvent>();
|
||||
if (e->name().isEmpty())
|
||||
return tr("cleared the room name");
|
||||
else
|
||||
return tr("set the room name to: %1").arg(e->name());
|
||||
}
|
||||
if( ti->type() == EventType::RoomTopic )
|
||||
{
|
||||
auto* e = ti.viewAs<RoomTopicEvent>();
|
||||
if (e->topic().isEmpty())
|
||||
return tr("cleared the topic");
|
||||
else
|
||||
return tr("set the topic to: %1").arg(e->topic());
|
||||
}
|
||||
if( ti->type() == EventType::RoomAvatar )
|
||||
{
|
||||
return tr("changed the room avatar");
|
||||
}
|
||||
if( ti->type() == EventType::RoomEncryption )
|
||||
{
|
||||
return tr("activated End-to-End Encryption");
|
||||
}
|
||||
return tr("Unknown Event");
|
||||
}
|
||||
|
||||
if( role == Qt::ToolTipRole )
|
||||
{
|
||||
return ti->originalJson();
|
||||
}
|
||||
|
||||
if( role == EventTypeRole )
|
||||
{
|
||||
if (ti->isStateEvent())
|
||||
return "state";
|
||||
|
||||
if (ti->type() == EventType::RoomMessage)
|
||||
{
|
||||
switch (ti.viewAs<RoomMessageEvent>()->msgtype())
|
||||
{
|
||||
case MessageEventType::Emote:
|
||||
return "emote";
|
||||
case MessageEventType::Notice:
|
||||
return "notice";
|
||||
case MessageEventType::Image:
|
||||
return "image";
|
||||
case MessageEventType::File:
|
||||
case MessageEventType::Audio:
|
||||
case MessageEventType::Video:
|
||||
return "file";
|
||||
default:
|
||||
return "message";
|
||||
}
|
||||
}
|
||||
|
||||
return "other";
|
||||
}
|
||||
|
||||
if( role == TimeRole )
|
||||
return makeMessageTimestamp(timelineIt);
|
||||
|
||||
if( role == SectionRole )
|
||||
return makeDateString(timelineIt); // FIXME: move date rendering to QML
|
||||
|
||||
if( role == AuthorRole )
|
||||
{
|
||||
auto userId = ti->senderId();
|
||||
// FIXME: It shouldn't be User, it should be its state "as of event"
|
||||
return QVariant::fromValue(m_currentRoom->user(userId));
|
||||
}
|
||||
|
||||
if (role == ContentTypeRole)
|
||||
{
|
||||
if (ti->type() == EventType::RoomMessage)
|
||||
{
|
||||
const auto& contentType =
|
||||
ti.viewAs<RoomMessageEvent>()->mimeType().name();
|
||||
return contentType == "text/plain" ? "text/html" : contentType;
|
||||
}
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
if (role == ContentRole)
|
||||
{
|
||||
if (ti->isRedacted())
|
||||
{
|
||||
auto reason = ti->redactedBecause()->reason();
|
||||
if (reason.isEmpty())
|
||||
return tr("Redacted");
|
||||
else
|
||||
return tr("Redacted: %1")
|
||||
.arg(ti->redactedBecause()->reason());
|
||||
}
|
||||
|
||||
if( ti->type() == EventType::RoomMessage )
|
||||
{
|
||||
using namespace MessageEventContent;
|
||||
|
||||
auto* e = ti.viewAs<RoomMessageEvent>();
|
||||
switch (e->msgtype())
|
||||
{
|
||||
case MessageEventType::Image:
|
||||
case MessageEventType::File:
|
||||
case MessageEventType::Audio:
|
||||
case MessageEventType::Video:
|
||||
return QVariant::fromValue(e->content()->originalJson);
|
||||
default:
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if( role == ReadMarkerRole )
|
||||
return ti->id() == lastReadEventId;
|
||||
|
||||
if( role == SpecialMarksRole )
|
||||
{
|
||||
if (ti->isStateEvent() && ti.viewAs<StateEventBase>()->repeatsState())
|
||||
return "hidden";
|
||||
return ti->isRedacted() ? "redacted" : "";
|
||||
}
|
||||
|
||||
if( role == EventIdRole )
|
||||
return ti->id();
|
||||
|
||||
if( role == LongOperationRole )
|
||||
{
|
||||
if (ti->type() == EventType::RoomMessage &&
|
||||
ti.viewAs<RoomMessageEvent>()->hasFileContent())
|
||||
{
|
||||
auto info = m_currentRoom->fileTransferInfo(ti->id());
|
||||
return QVariant::fromValue(info);
|
||||
}
|
||||
}
|
||||
|
||||
auto aboveEventIt = timelineIt + 1; // FIXME: shouldn't be here, because #312
|
||||
if (aboveEventIt != m_currentRoom->timelineEdge())
|
||||
{
|
||||
if( role == AboveSectionRole )
|
||||
return makeDateString(aboveEventIt);
|
||||
|
||||
if( role == AboveAuthorRole )
|
||||
return QVariant::fromValue(
|
||||
m_currentRoom->user((*aboveEventIt)->senderId()));
|
||||
}
|
||||
|
||||
QVariant MessageEventModel::data(const QModelIndex& index, int role) const {
|
||||
if (!m_currentRoom || index.row() < 0 ||
|
||||
index.row() >= m_currentRoom->timelineSize())
|
||||
return QVariant();
|
||||
|
||||
const auto timelineIt = m_currentRoom->messageEvents().rbegin() + index.row();
|
||||
const auto& ti = *timelineIt;
|
||||
|
||||
using namespace QMatrixClient;
|
||||
if (role == Qt::DisplayRole) {
|
||||
if (ti->isRedacted()) {
|
||||
auto reason = ti->redactedBecause()->reason();
|
||||
if (reason.isEmpty())
|
||||
return tr("Redacted");
|
||||
else
|
||||
return tr("Redacted: %1").arg(ti->redactedBecause()->reason());
|
||||
}
|
||||
|
||||
if (ti->type() == EventType::RoomMessage) {
|
||||
using namespace MessageEventContent;
|
||||
|
||||
auto* e = ti.viewAs<RoomMessageEvent>();
|
||||
if (e->hasTextContent() && e->mimeType().name() != "text/plain")
|
||||
return static_cast<const TextContent*>(e->content())->body;
|
||||
if (e->hasFileContent()) {
|
||||
auto fileCaption = e->content()->fileInfo()->originalName;
|
||||
if (fileCaption.isEmpty())
|
||||
fileCaption = m_currentRoom->prettyPrint(e->plainBody());
|
||||
if (fileCaption.isEmpty()) return tr("a file");
|
||||
}
|
||||
return m_currentRoom->prettyPrint(e->plainBody());
|
||||
}
|
||||
if (ti->type() == EventType::RoomMember) {
|
||||
auto* e = ti.viewAs<RoomMemberEvent>();
|
||||
// FIXME: Rewind to the name that was at the time of this event
|
||||
QString subjectName = m_currentRoom->roomMembername(e->userId());
|
||||
// The below code assumes senderName output in AuthorRole
|
||||
switch (e->membership()) {
|
||||
case MembershipType::Invite:
|
||||
if (e->repeatsState())
|
||||
return tr("reinvited %1 to the room").arg(subjectName);
|
||||
// [[fallthrough]]
|
||||
case MembershipType::Join: {
|
||||
if (e->repeatsState()) return tr("joined the room (repeated)");
|
||||
if (!e->prev_content() ||
|
||||
e->membership() != e->prev_content()->membership) {
|
||||
return e->membership() == MembershipType::Invite
|
||||
? tr("invited %1 to the room").arg(subjectName)
|
||||
: tr("joined the room");
|
||||
}
|
||||
QString text{};
|
||||
if (e->displayName() != e->prev_content()->displayName) {
|
||||
if (e->displayName().isEmpty())
|
||||
text = tr("cleared the display name");
|
||||
else
|
||||
text = tr("changed the display name to %1").arg(e->displayName());
|
||||
}
|
||||
if (e->avatarUrl() != e->prev_content()->avatarUrl) {
|
||||
if (!text.isEmpty()) text += " and ";
|
||||
if (e->avatarUrl().isEmpty())
|
||||
text += tr("cleared the avatar");
|
||||
else
|
||||
text += tr("updated the avatar");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
case MembershipType::Leave:
|
||||
if (e->prev_content() &&
|
||||
e->prev_content()->membership == MembershipType::Ban) {
|
||||
if (e->senderId() != e->userId())
|
||||
return tr("unbanned %1").arg(subjectName);
|
||||
else
|
||||
return tr("self-unbanned");
|
||||
}
|
||||
if (e->senderId() != e->userId())
|
||||
return tr("has put %1 out of the room").arg(subjectName);
|
||||
else
|
||||
return tr("left the room");
|
||||
case MembershipType::Ban:
|
||||
if (e->senderId() != e->userId())
|
||||
return tr("banned %1 from the room").arg(subjectName);
|
||||
else
|
||||
return tr("self-banned from the room");
|
||||
case MembershipType::Knock:
|
||||
return tr("knocked");
|
||||
case MembershipType::Undefined:
|
||||
return tr("made something unknown");
|
||||
}
|
||||
}
|
||||
if (ti->type() == EventType::RoomAliases) {
|
||||
auto* e = ti.viewAs<RoomAliasesEvent>();
|
||||
return tr("set aliases to: %1").arg(e->aliases().join(", "));
|
||||
}
|
||||
if (ti->type() == EventType::RoomCanonicalAlias) {
|
||||
auto* e = ti.viewAs<RoomCanonicalAliasEvent>();
|
||||
if (e->alias().isEmpty())
|
||||
return tr("cleared the room main alias");
|
||||
else
|
||||
return tr("set the room main alias to: %1").arg(e->alias());
|
||||
}
|
||||
if (ti->type() == EventType::RoomName) {
|
||||
auto* e = ti.viewAs<RoomNameEvent>();
|
||||
if (e->name().isEmpty())
|
||||
return tr("cleared the room name");
|
||||
else
|
||||
return tr("set the room name to: %1").arg(e->name());
|
||||
}
|
||||
if (ti->type() == EventType::RoomTopic) {
|
||||
auto* e = ti.viewAs<RoomTopicEvent>();
|
||||
if (e->topic().isEmpty())
|
||||
return tr("cleared the topic");
|
||||
else
|
||||
return tr("set the topic to: %1").arg(e->topic());
|
||||
}
|
||||
if (ti->type() == EventType::RoomAvatar) {
|
||||
return tr("changed the room avatar");
|
||||
}
|
||||
if (ti->type() == EventType::RoomEncryption) {
|
||||
return tr("activated End-to-End Encryption");
|
||||
}
|
||||
return tr("Unknown Event");
|
||||
}
|
||||
|
||||
if (role == Qt::ToolTipRole) {
|
||||
return ti->originalJson();
|
||||
}
|
||||
|
||||
if (role == EventTypeRole) {
|
||||
if (ti->isStateEvent()) return "state";
|
||||
|
||||
if (ti->type() == EventType::RoomMessage) {
|
||||
switch (ti.viewAs<RoomMessageEvent>()->msgtype()) {
|
||||
case MessageEventType::Emote:
|
||||
return "emote";
|
||||
case MessageEventType::Notice:
|
||||
return "notice";
|
||||
case MessageEventType::Image:
|
||||
return "image";
|
||||
case MessageEventType::File:
|
||||
case MessageEventType::Audio:
|
||||
case MessageEventType::Video:
|
||||
return "file";
|
||||
default:
|
||||
return "message";
|
||||
}
|
||||
}
|
||||
|
||||
return "other";
|
||||
}
|
||||
|
||||
if (role == TimeRole) return makeMessageTimestamp(timelineIt);
|
||||
|
||||
if (role == SectionRole)
|
||||
return makeDateString(timelineIt); // FIXME: move date rendering to QML
|
||||
|
||||
if (role == AuthorRole) {
|
||||
auto userId = ti->senderId();
|
||||
// FIXME: It shouldn't be User, it should be its state "as of event"
|
||||
return QVariant::fromValue(m_currentRoom->user(userId));
|
||||
}
|
||||
|
||||
if (role == ContentTypeRole) {
|
||||
if (ti->type() == EventType::RoomMessage) {
|
||||
const auto& contentType =
|
||||
ti.viewAs<RoomMessageEvent>()->mimeType().name();
|
||||
return contentType == "text/plain" ? "text/html" : contentType;
|
||||
}
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
if (role == ContentRole) {
|
||||
if (ti->isRedacted()) {
|
||||
auto reason = ti->redactedBecause()->reason();
|
||||
if (reason.isEmpty())
|
||||
return tr("Redacted");
|
||||
else
|
||||
return tr("Redacted: %1").arg(ti->redactedBecause()->reason());
|
||||
}
|
||||
|
||||
if (ti->type() == EventType::RoomMessage) {
|
||||
using namespace MessageEventContent;
|
||||
|
||||
auto* e = ti.viewAs<RoomMessageEvent>();
|
||||
switch (e->msgtype()) {
|
||||
case MessageEventType::Image:
|
||||
case MessageEventType::File:
|
||||
case MessageEventType::Audio:
|
||||
case MessageEventType::Video:
|
||||
return QVariant::fromValue(e->content()->originalJson);
|
||||
default:;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (role == ReadMarkerRole) return ti->id() == lastReadEventId;
|
||||
|
||||
if (role == SpecialMarksRole) {
|
||||
if (ti->isStateEvent() && ti.viewAs<StateEventBase>()->repeatsState())
|
||||
return "hidden";
|
||||
return ti->isRedacted() ? "redacted" : "";
|
||||
}
|
||||
|
||||
if (role == EventIdRole) return ti->id();
|
||||
|
||||
if (role == LongOperationRole) {
|
||||
if (ti->type() == EventType::RoomMessage &&
|
||||
ti.viewAs<RoomMessageEvent>()->hasFileContent()) {
|
||||
auto info = m_currentRoom->fileTransferInfo(ti->id());
|
||||
return QVariant::fromValue(info);
|
||||
}
|
||||
}
|
||||
|
||||
auto aboveEventIt = timelineIt + 1; // FIXME: shouldn't be here, because #312
|
||||
if (aboveEventIt != m_currentRoom->timelineEdge()) {
|
||||
if (role == AboveSectionRole) return makeDateString(aboveEventIt);
|
||||
|
||||
if (role == AboveAuthorRole)
|
||||
return QVariant::fromValue(
|
||||
m_currentRoom->user((*aboveEventIt)->senderId()));
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
|
||||
QHash<int, QByteArray> MessageEventModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||
roles[EventTypeRole] = "eventType";
|
||||
roles[EventIdRole] = "eventId";
|
||||
roles[TimeRole] = "time";
|
||||
roles[SectionRole] = "section";
|
||||
roles[AboveSectionRole] = "aboveSection";
|
||||
roles[AuthorRole] = "author";
|
||||
roles[AboveAuthorRole] = "aboveAuthor";
|
||||
roles[ContentRole] = "content";
|
||||
roles[ContentTypeRole] = "contentType";
|
||||
roles[HighlightRole] = "highlight";
|
||||
roles[ReadMarkerRole] = "readMarker";
|
||||
roles[SpecialMarksRole] = "marks";
|
||||
roles[LongOperationRole] = "progressInfo";
|
||||
roles[EventResolvedTypeRole] = "eventResolvedType";
|
||||
return roles;
|
||||
QHash<int, QByteArray> MessageEventModel::roleNames() const {
|
||||
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||
roles[EventTypeRole] = "eventType";
|
||||
roles[EventIdRole] = "eventId";
|
||||
roles[TimeRole] = "time";
|
||||
roles[SectionRole] = "section";
|
||||
roles[AboveSectionRole] = "aboveSection";
|
||||
roles[AuthorRole] = "author";
|
||||
roles[AboveAuthorRole] = "aboveAuthor";
|
||||
roles[ContentRole] = "content";
|
||||
roles[ContentTypeRole] = "contentType";
|
||||
roles[HighlightRole] = "highlight";
|
||||
roles[ReadMarkerRole] = "readMarker";
|
||||
roles[SpecialMarksRole] = "marks";
|
||||
roles[LongOperationRole] = "progressInfo";
|
||||
roles[EventResolvedTypeRole] = "eventResolvedType";
|
||||
return roles;
|
||||
}
|
||||
|
|
|
@ -4,54 +4,55 @@
|
|||
#include <QtCore/QAbstractListModel>
|
||||
#include "room.h"
|
||||
|
||||
class MessageEventModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QMatrixClient::Room* room READ getRoom WRITE setRoom NOTIFY roomChanged)
|
||||
class MessageEventModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(
|
||||
QMatrixClient::Room* room READ getRoom WRITE setRoom NOTIFY roomChanged)
|
||||
|
||||
public:
|
||||
enum EventRoles {
|
||||
EventTypeRole = Qt::UserRole + 1,
|
||||
EventIdRole,
|
||||
TimeRole,
|
||||
SectionRole,
|
||||
AboveSectionRole,
|
||||
AuthorRole,
|
||||
AboveAuthorRole,
|
||||
ContentRole,
|
||||
ContentTypeRole,
|
||||
HighlightRole,
|
||||
ReadMarkerRole,
|
||||
SpecialMarksRole,
|
||||
LongOperationRole,
|
||||
// For debugging
|
||||
EventResolvedTypeRole,
|
||||
};
|
||||
public:
|
||||
enum EventRoles {
|
||||
EventTypeRole = Qt::UserRole + 1,
|
||||
EventIdRole,
|
||||
TimeRole,
|
||||
SectionRole,
|
||||
AboveSectionRole,
|
||||
AuthorRole,
|
||||
AboveAuthorRole,
|
||||
ContentRole,
|
||||
ContentTypeRole,
|
||||
HighlightRole,
|
||||
ReadMarkerRole,
|
||||
SpecialMarksRole,
|
||||
LongOperationRole,
|
||||
// For debugging
|
||||
EventResolvedTypeRole,
|
||||
};
|
||||
|
||||
explicit MessageEventModel(QObject* parent = nullptr);
|
||||
~MessageEventModel();
|
||||
explicit MessageEventModel(QObject* parent = nullptr);
|
||||
~MessageEventModel();
|
||||
|
||||
QMatrixClient::Room* getRoom() { return m_currentRoom; }
|
||||
void setRoom(QMatrixClient::Room* room);
|
||||
QMatrixClient::Room* getRoom() { return m_currentRoom; }
|
||||
void setRoom(QMatrixClient::Room* room);
|
||||
|
||||
Q_INVOKABLE int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
Q_INVOKABLE int rowCount(
|
||||
const QModelIndex& parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
|
||||
private slots:
|
||||
void refreshEvent(const QString& eventId);
|
||||
private slots:
|
||||
void refreshEvent(const QString& eventId);
|
||||
|
||||
private:
|
||||
QMatrixClient::Room* m_currentRoom = nullptr;
|
||||
QString lastReadEventId;
|
||||
int nextNewerRow = -1;
|
||||
private:
|
||||
QMatrixClient::Room* m_currentRoom = nullptr;
|
||||
QString lastReadEventId;
|
||||
int nextNewerRow = -1;
|
||||
|
||||
QDateTime makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const;
|
||||
QString makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const;
|
||||
void refreshEventRoles(const QString& eventId, const QVector<int> roles);
|
||||
QDateTime makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const;
|
||||
QString makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const;
|
||||
void refreshEventRoles(const QString& eventId, const QVector<int> roles);
|
||||
|
||||
signals:
|
||||
void roomChanged();
|
||||
signals:
|
||||
void roomChanged();
|
||||
};
|
||||
|
||||
#endif // MESSAGEEVENTMODEL_H
|
||||
#endif // MESSAGEEVENTMODEL_H
|
||||
|
|
|
@ -1,103 +1,83 @@
|
|||
#include "roomlistmodel.h"
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtGui/QBrush>
|
||||
#include <QtGui/QColor>
|
||||
#include <QtCore/QDebug>
|
||||
|
||||
RoomListModel::RoomListModel(QObject* parent)
|
||||
: QAbstractListModel(parent)
|
||||
{
|
||||
RoomListModel::RoomListModel(QObject* parent) : QAbstractListModel(parent) {}
|
||||
|
||||
}
|
||||
RoomListModel::~RoomListModel() {}
|
||||
|
||||
RoomListModel::~RoomListModel()
|
||||
{
|
||||
}
|
||||
|
||||
void RoomListModel::setConnection(QMatrixClient::Connection* connection)
|
||||
{
|
||||
beginResetModel();
|
||||
m_connection = connection;
|
||||
m_rooms.clear();
|
||||
connect( connection, &QMatrixClient::Connection::newRoom, this, &RoomListModel::addRoom );
|
||||
for( QMatrixClient::Room* room: connection->roomMap().values() ) {
|
||||
connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged );
|
||||
m_rooms.append(room);
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
QMatrixClient::Room* RoomListModel::roomAt(int row)
|
||||
{
|
||||
return m_rooms.at(row);
|
||||
}
|
||||
|
||||
void RoomListModel::addRoom(QMatrixClient::Room* room)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count());
|
||||
connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged );
|
||||
void RoomListModel::setConnection(QMatrixClient::Connection* connection) {
|
||||
beginResetModel();
|
||||
m_connection = connection;
|
||||
m_rooms.clear();
|
||||
connect(connection, &QMatrixClient::Connection::newRoom, this,
|
||||
&RoomListModel::addRoom);
|
||||
for (QMatrixClient::Room* room : connection->roomMap().values()) {
|
||||
connect(room, &QMatrixClient::Room::namesChanged, this,
|
||||
&RoomListModel::namesChanged);
|
||||
m_rooms.append(room);
|
||||
endInsertRows();
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
int RoomListModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
if( parent.isValid() )
|
||||
return 0;
|
||||
return m_rooms.count();
|
||||
QMatrixClient::Room* RoomListModel::roomAt(int row) { return m_rooms.at(row); }
|
||||
|
||||
void RoomListModel::addRoom(QMatrixClient::Room* room) {
|
||||
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count());
|
||||
connect(room, &QMatrixClient::Room::namesChanged, this,
|
||||
&RoomListModel::namesChanged);
|
||||
m_rooms.append(room);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
QVariant RoomListModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
if( !index.isValid() )
|
||||
return QVariant();
|
||||
int RoomListModel::rowCount(const QModelIndex& parent) const {
|
||||
if (parent.isValid()) return 0;
|
||||
return m_rooms.count();
|
||||
}
|
||||
|
||||
if( index.row() >= m_rooms.count() )
|
||||
{
|
||||
qDebug() << "UserListModel: something wrong here...";
|
||||
return QVariant();
|
||||
}
|
||||
QMatrixClient::Room* room = m_rooms.at(index.row());
|
||||
if( role == Qt::DisplayRole )
|
||||
{
|
||||
return room->displayName();
|
||||
}
|
||||
if( role == Qt::ForegroundRole )
|
||||
{
|
||||
if( room->highlightCount() > 0 )
|
||||
return QBrush(QColor("orange"));
|
||||
return QVariant();
|
||||
}
|
||||
if( role == Qt::DecorationRole )
|
||||
{
|
||||
if ( room->avatarUrl().toString() != "" ) {
|
||||
return room->avatarUrl();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
if ( role == Qt::StatusTipRole )
|
||||
{
|
||||
return room->topic();
|
||||
QVariant RoomListModel::data(const QModelIndex& index, int role) const {
|
||||
if (!index.isValid()) return QVariant();
|
||||
|
||||
if (index.row() >= m_rooms.count()) {
|
||||
qDebug() << "UserListModel: something wrong here...";
|
||||
return QVariant();
|
||||
}
|
||||
QMatrixClient::Room* room = m_rooms.at(index.row());
|
||||
if (role == Qt::DisplayRole) {
|
||||
return room->displayName();
|
||||
}
|
||||
if (role == Qt::ForegroundRole) {
|
||||
if (room->highlightCount() > 0) return QBrush(QColor("orange"));
|
||||
return QVariant();
|
||||
}
|
||||
if (role == Qt::DecorationRole) {
|
||||
if (room->avatarUrl().toString() != "") {
|
||||
return room->avatarUrl();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
if (role == Qt::StatusTipRole) {
|
||||
return room->topic();
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void RoomListModel::namesChanged(QMatrixClient::Room* room)
|
||||
{
|
||||
int row = m_rooms.indexOf(room);
|
||||
emit dataChanged(index(row), index(row));
|
||||
void RoomListModel::namesChanged(QMatrixClient::Room* room) {
|
||||
int row = m_rooms.indexOf(room);
|
||||
emit dataChanged(index(row), index(row));
|
||||
}
|
||||
|
||||
void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room)
|
||||
{
|
||||
int row = m_rooms.indexOf(room);
|
||||
emit dataChanged(index(row), index(row));
|
||||
void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room) {
|
||||
int row = m_rooms.indexOf(room);
|
||||
emit dataChanged(index(row), index(row));
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> RoomListModel::roleNames() const {
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[Qt::DisplayRole] = "name";
|
||||
roles[Qt::DecorationRole] = "avatar";
|
||||
roles[Qt::StatusTipRole] = "topic";
|
||||
return roles;
|
||||
QHash<int, QByteArray> roles;
|
||||
roles[Qt::DisplayRole] = "name";
|
||||
roles[Qt::DecorationRole] = "avatar";
|
||||
roles[Qt::StatusTipRole] = "topic";
|
||||
return roles;
|
||||
}
|
||||
|
|
|
@ -2,39 +2,41 @@
|
|||
#define ROOMLISTMODEL_H
|
||||
|
||||
#include <QtCore/QAbstractListModel>
|
||||
#include "room.h"
|
||||
#include "connection.h"
|
||||
#include "room.h"
|
||||
|
||||
class RoomListModel: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection)
|
||||
class RoomListModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection WRITE
|
||||
setConnection)
|
||||
|
||||
public:
|
||||
RoomListModel(QObject* parent=0);
|
||||
virtual ~RoomListModel();
|
||||
public:
|
||||
RoomListModel(QObject* parent = 0);
|
||||
virtual ~RoomListModel();
|
||||
|
||||
QMatrixClient::Connection* getConnection() {return m_connection;}
|
||||
void setConnection(QMatrixClient::Connection* connection);
|
||||
QMatrixClient::Connection* getConnection() { return m_connection; }
|
||||
void setConnection(QMatrixClient::Connection* connection);
|
||||
|
||||
Q_INVOKABLE QMatrixClient::Room* roomAt(int row);
|
||||
Q_INVOKABLE QMatrixClient::Room* roomAt(int row);
|
||||
|
||||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||
Q_INVOKABLE int rowCount(const QModelIndex& parent=QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex& index,
|
||||
int role = Qt::DisplayRole) const override;
|
||||
Q_INVOKABLE int rowCount(
|
||||
const QModelIndex& parent = QModelIndex()) const override;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
QHash<int, QByteArray> roleNames() const;
|
||||
|
||||
private slots:
|
||||
void namesChanged(QMatrixClient::Room* room);
|
||||
void unreadMessagesChanged(QMatrixClient::Room* room);
|
||||
void addRoom(QMatrixClient::Room* room);
|
||||
private slots:
|
||||
void namesChanged(QMatrixClient::Room* room);
|
||||
void unreadMessagesChanged(QMatrixClient::Room* room);
|
||||
void addRoom(QMatrixClient::Room* room);
|
||||
|
||||
private:
|
||||
QMatrixClient::Connection* m_connection = nullptr;
|
||||
QList<QMatrixClient::Room*> m_rooms;
|
||||
private:
|
||||
QMatrixClient::Connection* m_connection = nullptr;
|
||||
QList<QMatrixClient::Room*> m_rooms;
|
||||
|
||||
signals:
|
||||
void connectionChanged();
|
||||
signals:
|
||||
void connectionChanged();
|
||||
};
|
||||
|
||||
#endif // ROOMLISTMODEL_H
|
||||
#endif // ROOMLISTMODEL_H
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import QtQuick 2.10
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick 2.11
|
||||
import QtQuick.Layouts 1.11
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Controls.Material 2.3
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Controls.Material 2.4
|
||||
import Qt.labs.settings 1.0
|
||||
import "qrc:/qml/component"
|
||||
|
||||
|
@ -60,13 +60,13 @@ Page {
|
|||
id: mainCol
|
||||
width: parent.width
|
||||
|
||||
ImageStatus {
|
||||
Layout.preferredWidth: 96
|
||||
Layout.preferredHeight: 96
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
// ImageStatus {
|
||||
// Layout.preferredWidth: 96
|
||||
// Layout.preferredHeight: 96
|
||||
// Layout.alignment: Qt.AlignHCenter
|
||||
|
||||
source: "qrc:/asset/img/avatar.png"
|
||||
}
|
||||
// source: "qrc:/asset/img/avatar.png"
|
||||
// }
|
||||
|
||||
TextField {
|
||||
id: serverField
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.11
|
||||
import Matrique 0.1
|
||||
|
||||
import "qrc:/qml/form"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.4
|
||||
|
||||
ItemDelegate {
|
||||
id: itemDelegate
|
||||
|
|
|
@ -1,17 +1,22 @@
|
|||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.4
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls.Material 2.4
|
||||
|
||||
Item {
|
||||
property bool opaqueBackground: false
|
||||
property alias source: avatar.source
|
||||
property bool round: true
|
||||
property string source: ""
|
||||
property string displayText: ""
|
||||
readonly property bool showImage: source
|
||||
readonly property bool showInitial: !showImage && displayText
|
||||
|
||||
id: item
|
||||
|
||||
Rectangle {
|
||||
width: item.width
|
||||
height: item.width
|
||||
radius: item.width / 2
|
||||
radius: round ? item.width / 2 : 0
|
||||
color: "white"
|
||||
visible: opaqueBackground
|
||||
}
|
||||
|
@ -20,6 +25,8 @@ Item {
|
|||
id: avatar
|
||||
width: item.width
|
||||
height: item.width
|
||||
visible: showImage
|
||||
source: item.source
|
||||
|
||||
mipmap: true
|
||||
layer.enabled: true
|
||||
|
@ -35,9 +42,42 @@ Item {
|
|||
anchors.centerIn: parent
|
||||
width: avatar.width
|
||||
height: avatar.width
|
||||
radius: avatar.width / 2
|
||||
radius: round? avatar.width / 2 : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
anchors.fill: parent
|
||||
color: "white"
|
||||
visible: showInitial
|
||||
text: showInitial ? getInitials(displayText)[0] : ""
|
||||
font.pixelSize: 22
|
||||
font.bold: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
background: Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: round? width / 2 : 0
|
||||
color: showInitial ? stringToColor(displayText) : Material.accent
|
||||
}
|
||||
}
|
||||
|
||||
function getInitials(text) {
|
||||
return text.toUpperCase().replace(/[^a-zA-Z- ]/g, "").match(/\b\w/g);
|
||||
}
|
||||
|
||||
function stringToColor(str) {
|
||||
var hash = 0;
|
||||
for (var i = 0; i < str.length; i++) {
|
||||
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||
}
|
||||
var colour = '#';
|
||||
for (var i = 0; i < 3; i++) {
|
||||
var value = (hash >> (i * 8)) & 0xFF;
|
||||
colour += ('00' + value.toString(16)).substr(-2);
|
||||
}
|
||||
return colour;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls.Material 2.3
|
||||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.11
|
||||
import QtQuick.Controls.Material 2.4
|
||||
|
||||
Item {
|
||||
property alias icon: iconText.text
|
||||
|
@ -17,5 +17,5 @@ Item {
|
|||
color: item.color
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls.Material 2.3
|
||||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.11
|
||||
import QtQuick.Controls.Material 2.4
|
||||
|
||||
Item {
|
||||
Rectangle {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls.Material 2.3
|
||||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.11
|
||||
import QtQuick.Controls.Material 2.4
|
||||
|
||||
Item {
|
||||
property var page
|
||||
|
@ -29,7 +29,7 @@ Item {
|
|||
anchors.fill: parent
|
||||
|
||||
onClicked: {
|
||||
if(page != null && stackView.currentItem !== page) {
|
||||
if(!page && stackView.currentItem !== page) {
|
||||
if(stackView.depth === 1) {
|
||||
stackView.replace(page)
|
||||
} else {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls.Material 2.3
|
||||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.4
|
||||
import QtQuick.Controls.Material 2.4
|
||||
import "qrc:/qml/component"
|
||||
|
||||
Item {
|
||||
|
|
|
@ -2,8 +2,8 @@ import QtQuick 2.11
|
|||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.11
|
||||
import QtGraphicalEffects 1.0
|
||||
import QtQuick.Controls.Material 2.3
|
||||
import QtQml.Models 2.3
|
||||
import QtQuick.Controls.Material 2.4
|
||||
import QtQml.Models 2.4
|
||||
import Matrique 0.1
|
||||
|
||||
import "qrc:/qml/component"
|
||||
|
@ -27,6 +27,10 @@ Item {
|
|||
height: 80
|
||||
onClicked: listView.currentIndex = index
|
||||
|
||||
ToolTip.visible: pressed
|
||||
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
ToolTip.text: name
|
||||
|
||||
contentItem: RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
|
@ -36,7 +40,8 @@ Item {
|
|||
Layout.preferredWidth: height
|
||||
Layout.fillHeight: true
|
||||
|
||||
source: avatar == null || avatar == "" ? "qrc:/asset/img/avatar.png" : "image://mxc/" + avatar
|
||||
source: avatar ? "image://mxc/" + avatar : ""
|
||||
displayText: name
|
||||
opaqueBackground: true
|
||||
}
|
||||
|
||||
|
@ -52,10 +57,10 @@ Item {
|
|||
Layout.fillHeight: true
|
||||
|
||||
text: {
|
||||
if (name != "") {
|
||||
if (name) {
|
||||
return name;
|
||||
}
|
||||
if (alias != "") {
|
||||
if (alias) {
|
||||
return alias;
|
||||
}
|
||||
return id
|
||||
|
@ -69,7 +74,7 @@ Item {
|
|||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
text: topic === "" ? "No topic yet." : topic
|
||||
text: topic ? topic : "No topic yet."
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
@ -133,7 +138,7 @@ Item {
|
|||
}
|
||||
|
||||
Rectangle {
|
||||
width: searchField.activeFocus || searchField.text != "" ? parent.width : 0
|
||||
width: searchField.activeFocus || searchField.text ? parent.width : 0
|
||||
height: parent.height
|
||||
color: "white"
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import QtQuick 2.10
|
||||
import QtQuick.Controls 2.3
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls.Material 2.3
|
||||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.11
|
||||
import QtQuick.Controls.Material 2.4
|
||||
import QtGraphicalEffects 1.0
|
||||
import Matrique 0.1
|
||||
import "qrc:/qml/component"
|
||||
|
@ -16,7 +16,7 @@ Item {
|
|||
|
||||
background: Item {
|
||||
anchors.fill: parent
|
||||
visible: currentRoom == null
|
||||
visible: !currentRoom
|
||||
Pane {
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ Item {
|
|||
anchors.fill: parent
|
||||
spacing: 0
|
||||
|
||||
visible: currentRoom != null
|
||||
visible: currentRoom
|
||||
|
||||
Pane {
|
||||
z: 10
|
||||
|
@ -52,7 +52,8 @@ Item {
|
|||
ImageStatus {
|
||||
Layout.preferredWidth: parent.height
|
||||
Layout.fillHeight: true
|
||||
source: currentRoom != null && currentRoom.avatarUrl != "" ? "image://mxc/" + currentRoom.avatarUrl : "qrc:/asset/img/avatar.png"
|
||||
source: currentRoom && currentRoom.avatarUrl != "" ? "image://mxc/" + currentRoom.avatarUrl : null
|
||||
displayText: currentRoom ? currentRoom.displayName : ""
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
@ -61,7 +62,7 @@ Item {
|
|||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: currentRoom != null ? currentRoom.displayName : ""
|
||||
text: currentRoom ? currentRoom.displayName : ""
|
||||
font.pointSize: 16
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.NoWrap
|
||||
|
@ -69,7 +70,7 @@ Item {
|
|||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: currentRoom != null ? currentRoom.topic : ""
|
||||
text: currentRoom ? currentRoom.topic : ""
|
||||
elide: Text.ElideRight
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
@ -88,12 +89,14 @@ Item {
|
|||
displayMarginEnd: 40
|
||||
verticalLayoutDirection: ListView.BottomToTop
|
||||
spacing: 12
|
||||
|
||||
model: MessageEventModel{
|
||||
id: messageEventModel
|
||||
room: currentRoom
|
||||
|
||||
onModelReset: currentRoom.getPreviousContent(50)
|
||||
}
|
||||
|
||||
delegate: Row {
|
||||
readonly property bool sentByMe: author === currentRoom.localUser
|
||||
|
||||
|
@ -102,18 +105,28 @@ Item {
|
|||
anchors.right: sentByMe ? parent.right : undefined
|
||||
spacing: 6
|
||||
|
||||
Image {
|
||||
ImageStatus {
|
||||
id: avatar
|
||||
width: height
|
||||
height: 40
|
||||
mipmap: true
|
||||
round: false
|
||||
visible: !sentByMe
|
||||
source: author.avatarUrl != "" ? "image://mxc/" + author.avatarUrl : "qrc:/asset/img/avatar.png"
|
||||
source: author.avatarUrl != "" ? "image://mxc/" + author.avatarUrl : null
|
||||
displayText: author.displayName
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
|
||||
ToolTip.visible: pressed
|
||||
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
|
||||
ToolTip.text: author.displayName
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: Math.min(messageText.implicitWidth + 24,
|
||||
messageListView.width - (!sentByMe ? avatar.width + messageRow.spacing : 0))
|
||||
messageListView.width - (!sentByMe ? avatar.width + messageRow.spacing : 0))
|
||||
height: messageText.implicitHeight + 24
|
||||
color: sentByMe ? "lightgrey" : Material.accent
|
||||
|
||||
|
@ -121,6 +134,7 @@ Item {
|
|||
id: messageText
|
||||
text: display
|
||||
color: sentByMe ? "black" : "white"
|
||||
linkColor: sentByMe ? Material.accent : "white"
|
||||
anchors.fill: parent
|
||||
anchors.margins: 12
|
||||
wrapMode: Label.Wrap
|
||||
|
|
25
qml/main.qml
25
qml/main.qml
|
@ -1,6 +1,6 @@
|
|||
import QtQuick 2.11
|
||||
import QtQuick.Controls 2.4
|
||||
import QtQuick.Layouts 1.4
|
||||
import QtQuick.Layouts 1.11
|
||||
import QtQuick.Controls.Material 2.4
|
||||
import QtGraphicalEffects 1.0
|
||||
import Qt.labs.settings 1.0
|
||||
|
@ -28,16 +28,16 @@ ApplicationWindow {
|
|||
property alias token: matriqueController.token
|
||||
}
|
||||
|
||||
// Platform.SystemTrayIcon {
|
||||
// visible: true
|
||||
// iconSource: "qrc:/asset/img/icon.png"
|
||||
// Platform.SystemTrayIcon {
|
||||
// visible: true
|
||||
// iconSource: "qrc:/asset/img/icon.png"
|
||||
|
||||
// onActivated: {
|
||||
// window.show()
|
||||
// window.raise()
|
||||
// window.requestActivate()
|
||||
// }
|
||||
// }
|
||||
// onActivated: {
|
||||
// window.show()
|
||||
// window.raise()
|
||||
// window.requestActivate()
|
||||
// }
|
||||
// }
|
||||
|
||||
Controller {
|
||||
id: matriqueController
|
||||
|
@ -118,7 +118,8 @@ ApplicationWindow {
|
|||
anchors.fill: parent
|
||||
anchors.margins: 15
|
||||
|
||||
source: matriqueController.connection.localUser != null ? "image://mxc/" + matriqueController.connection.localUser.avatarUrl : "qrc:/asset/img/avatar.png"
|
||||
source: matriqueController.connection.localUser && matriqueController.connection.localUser.avatarUrl ? "image://mxc/" + matriqueController.connection.localUser.avatarUrl : ""
|
||||
displayText: matriqueController.connection.localUser && matriqueController.connection.localUser.displayText ? matriqueController.connection.localUser.displayText : "N"
|
||||
opaqueBackground: false
|
||||
}
|
||||
|
||||
|
@ -158,7 +159,7 @@ ApplicationWindow {
|
|||
imageProvider.connection = matriqueController.connection
|
||||
|
||||
console.log(matriqueController.homeserver, matriqueController.userID, matriqueController.token)
|
||||
if (matriqueController.userID != "" && matriqueController.token != "") {
|
||||
if (matriqueController.userID && matriqueController.token) {
|
||||
console.log("Perform auto-login.");
|
||||
matriqueController.login();
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue