Code reformatting && tooltip.

This commit is contained in:
Black Hat 2018-07-09 10:45:26 +08:00
parent d6b5cba61f
commit 6bd059ce63
22 changed files with 826 additions and 854 deletions

View File

@ -1,50 +1,50 @@
#include <QGuiApplication> #include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QNetworkProxy> #include <QNetworkProxy>
#include <QQmlApplicationEngine>
#include <QQmlContext> #include <QQmlContext>
#include "room.h"
#include "matrix/controller.h" #include "matrix/controller.h"
#include "matrix/roomlistmodel.h"
#include "matrix/imageprovider.h" #include "matrix/imageprovider.h"
#include "matrix/messageeventmodel.h" #include "matrix/messageeventmodel.h"
#include "matrix/roomlistmodel.h"
#include "room.h"
using namespace QMatrixClient; using namespace QMatrixClient;
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif #endif
QGuiApplication app(argc, argv); QGuiApplication app(argc, argv);
// Enable this if you need proxy. // Enable this if you need proxy.
// QNetworkProxy proxy; // QNetworkProxy proxy;
// proxy.setType(QNetworkProxy::HttpProxy); // proxy.setType(QNetworkProxy::HttpProxy);
// proxy.setHostName("localhost"); // proxy.setHostName("localhost");
// proxy.setPort(1082); // proxy.setPort(1082);
// QNetworkProxy::setApplicationProxy(proxy); // QNetworkProxy::setApplicationProxy(proxy);
qmlRegisterType<Room>(); qRegisterMetaType<Room*> ("Room*"); qmlRegisterType<Room>();
qRegisterMetaType<Room *>("Room*");
qmlRegisterType<Controller>("Matrique", 0, 1, "Controller"); qmlRegisterType<Controller>("Matrique", 0, 1, "Controller");
qmlRegisterType<RoomListModel>("Matrique", 0, 1, "RoomListModel"); qmlRegisterType<RoomListModel>("Matrique", 0, 1, "RoomListModel");
qmlRegisterType<MessageEventModel>("Matrique", 0, 1, "MessageEventModel"); qmlRegisterType<MessageEventModel>("Matrique", 0, 1, "MessageEventModel");
qRegisterMetaType<User*>("User*"); 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()) if (engine.rootObjects().isEmpty()) return -1;
return -1;
return app.exec(); return app.exec();
} }

View File

@ -3,16 +3,19 @@
#include "connection.h" #include "connection.h"
Controller::Controller(QObject *parent) : QObject(parent) { Controller::Controller(QObject *parent) : QObject(parent) {
connect(m_connection, &QMatrixClient::Connection::connected, this, &Controller::connected); connect(m_connection, &QMatrixClient::Connection::connected, this,
connect(m_connection, &QMatrixClient::Connection::resolveError, this, &Controller::reconnect); &Controller::connected);
connect(m_connection, &QMatrixClient::Connection::syncError, this, &Controller::reconnect); connect(m_connection, &QMatrixClient::Connection::resolveError, this,
connect(m_connection, &QMatrixClient::Connection::syncDone, this, &Controller::resync); &Controller::reconnect);
connect(m_connection, &QMatrixClient::Connection::connected, this, &Controller::connectionChanged); 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() { Controller::~Controller() { m_connection->stopSync(); }
m_connection->stopSync();
}
void Controller::login() { void Controller::login() {
if (!isLogin) { if (!isLogin) {
@ -24,13 +27,14 @@ void Controller::login() {
} }
} }
void Controller::loginWithCredentials(QString serverAddr, QString user, QString pass) { void Controller::loginWithCredentials(QString serverAddr, QString user,
if(!isLogin) { QString pass) {
if (!isLogin) {
qDebug() << "Server:" << serverAddr; qDebug() << "Server:" << serverAddr;
qDebug() << "User:" << user; qDebug() << "User:" << user;
qDebug() << "Pass:" << pass; qDebug() << "Pass:" << pass;
if(!user.isEmpty() && !pass.isEmpty()) { if (!user.isEmpty() && !pass.isEmpty()) {
qDebug() << "Using given credential."; qDebug() << "Using given credential.";
m_connection->setHomeserver(QUrl(serverAddr)); m_connection->setHomeserver(QUrl(serverAddr));
m_connection->connectToServer(user, pass, ""); m_connection->connectToServer(user, pass, "");

View File

@ -3,26 +3,28 @@
#include <QObject> #include <QObject>
#include "connection.h" #include "connection.h"
#include "user.h"
#include "roomlistmodel.h" #include "roomlistmodel.h"
#include "user.h"
namespace QMatrixClient { namespace QMatrixClient {
class Connection; class Connection;
} }
class Controller : public QObject class Controller : public QObject {
{
Q_OBJECT Q_OBJECT
Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection NOTIFY connectionChanged) Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection NOTIFY
Q_PROPERTY(bool isLogin READ getIsLogin WRITE setIsLogin NOTIFY isLoginChanged) connectionChanged)
Q_PROPERTY(QString homeserver READ getHomeserver WRITE setHomeserver NOTIFY homeserverChanged) 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(QString userID READ getUserID WRITE setUserID NOTIFY userIDChanged)
Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged) Q_PROPERTY(QByteArray token READ getToken WRITE setToken NOTIFY tokenChanged)
Q_PROPERTY(bool busy READ getBusy WRITE setBusy NOTIFY busyChanged) Q_PROPERTY(bool busy READ getBusy WRITE setBusy NOTIFY busyChanged)
public: public:
explicit Controller(QObject *parent = nullptr); explicit Controller(QObject* parent = nullptr);
~Controller(); ~Controller();
// All the Q_INVOKABLEs. // All the Q_INVOKABLEs.
@ -39,7 +41,7 @@ class Controller : public QObject
bool isLogin = false; bool isLogin = false;
bool getIsLogin() { return isLogin; } bool getIsLogin() { return isLogin; }
void setIsLogin(bool n) { void setIsLogin(bool n) {
if(n != isLogin) { if (n != isLogin) {
isLogin = n; isLogin = n;
emit isLoginChanged(); emit isLoginChanged();
} }
@ -48,7 +50,7 @@ class Controller : public QObject
QString userID; QString userID;
QString getUserID() { return userID; } QString getUserID() { return userID; }
void setUserID(QString n) { void setUserID(QString n) {
if(n != userID) { if (n != userID) {
userID = n; userID = n;
emit userIDChanged(); emit userIDChanged();
} }
@ -57,7 +59,7 @@ class Controller : public QObject
QByteArray token; QByteArray token;
QByteArray getToken() { return token; } QByteArray getToken() { return token; }
void setToken(QByteArray n) { void setToken(QByteArray n) {
if(n != token) { if (n != token) {
token = n; token = n;
emit tokenChanged(); emit tokenChanged();
} }

View File

@ -1,8 +1,8 @@
#include "imageprovider.h" #include "imageprovider.h"
#include <QtCore/QWaitCondition>
#include <QtCore/QDebug>
#include <QMetaObject> #include <QMetaObject>
#include <QtCore/QDebug>
#include <QtCore/QWaitCondition>
#include "jobs/mediathumbnailjob.h" #include "jobs/mediathumbnailjob.h"
@ -11,42 +11,43 @@
using QMatrixClient::MediaThumbnailJob; using QMatrixClient::MediaThumbnailJob;
ImageProvider::ImageProvider(QObject* parent) ImageProvider::ImageProvider(QObject* parent)
: QQuickImageProvider(QQmlImageProviderBase::Image, : QQuickImageProvider(
QQmlImageProviderBase::ForceAsynchronousImageLoading) QQmlImageProviderBase::Image,
{ QQmlImageProviderBase::ForceAsynchronousImageLoading) {
#if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0)) #if (QT_VERSION < QT_VERSION_CHECK(5, 10, 0))
qRegisterMetaType<MediaThumbnailJob*>(); qRegisterMetaType<MediaThumbnailJob*>();
#endif #endif
m_connection = new ImageProviderConnection(); m_connection = new ImageProviderConnection();
} }
QImage ImageProvider::requestImage(const QString& id, QImage ImageProvider::requestImage(const QString& id, QSize* pSize,
QSize* pSize, const QSize& requestedSize) const QSize& requestedSize) {
{ if (!id.startsWith("mxc://")) {
if (!id.startsWith("mxc://"))
{
qWarning() << "ImageProvider: won't fetch an invalid id:" << id qWarning() << "ImageProvider: won't fetch an invalid id:" << id
<< "doesn't follow server/mediaId pattern"; << "doesn't follow server/mediaId pattern";
return {}; return {};
} }
QUrl mxcUri { id }; QUrl mxcUri{id};
qDebug() << "ImageProvider::requestImage:" << mxcUri.toString();
MediaThumbnailJob* job = nullptr; MediaThumbnailJob* job = nullptr;
QReadLocker locker(&m_lock); QReadLocker locker(&m_lock);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(5, 10, 0))
QMetaObject::invokeMethod(m_connection, QMetaObject::invokeMethod(
[=] { return m_connection->getConnection()->getThumbnail(mxcUri, requestedSize); }, m_connection,
[=] {
return m_connection->getConnection()->getThumbnail(mxcUri,
requestedSize);
},
Qt::BlockingQueuedConnection, &job); Qt::BlockingQueuedConnection, &job);
#else #else
QMetaObject::invokeMethod(m_connection, "getThumbnail", QMetaObject::invokeMethod(m_connection, "getThumbnail",
Qt::BlockingQueuedConnection, Q_RETURN_ARG(MediaThumbnailJob*, job), Qt::BlockingQueuedConnection,
Q_RETURN_ARG(MediaThumbnailJob*, job),
Q_ARG(QUrl, mxcUri), Q_ARG(QSize, requestedSize)); Q_ARG(QUrl, mxcUri), Q_ARG(QSize, requestedSize));
#endif #endif
if (!job) if (!job) {
{
qDebug() << "ImageProvider: failed to send a request"; qDebug() << "ImageProvider: failed to send a request";
return {}; return {};
} }
@ -60,9 +61,7 @@ QImage ImageProvider::requestImage(const QString& id,
condition.wait(&m_lock); condition.wait(&m_lock);
} }
if(pSize != nullptr) if (pSize != nullptr) *pSize = result.size();
*pSize = result.size();
return result; return result;
} }

View File

@ -1,22 +1,21 @@
#ifndef IMAGEPROVIDER_H #ifndef IMAGEPROVIDER_H
#define IMAGEPROVIDER_H #define IMAGEPROVIDER_H
#include <QtQuick/QQuickImageProvider>
#include <QtCore/QReadWriteLock>
#include <QObject> #include <QObject>
#include <QtCore/QReadWriteLock>
#include <QtQuick/QQuickImageProvider>
#include "connection.h" #include "connection.h"
#include "imageproviderconnection.h" #include "imageproviderconnection.h"
class ImageProvider: public QQuickImageProvider class ImageProvider : public QQuickImageProvider {
{
public: public:
explicit ImageProvider(QObject* parent = nullptr); explicit ImageProvider(QObject* parent = nullptr);
QImage requestImage(const QString& id, QSize* pSize, QImage requestImage(const QString& id, QSize* pSize,
const QSize& requestedSize) override; 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; }

View File

@ -1,9 +1,6 @@
#include "imageproviderconnection.h" #include "imageproviderconnection.h"
ImageProviderConnection::ImageProviderConnection(QObject* parent) : QObject(parent) { ImageProviderConnection::ImageProviderConnection(QObject* parent)
: QObject(parent) {}
} ImageProviderConnection::~ImageProviderConnection() {}
ImageProviderConnection::~ImageProviderConnection() {
}

View File

@ -5,11 +5,11 @@
#include "connection.h" #include "connection.h"
class ImageProviderConnection : public QObject class ImageProviderConnection : public QObject {
{
Q_OBJECT 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: public:
explicit ImageProviderConnection(QObject* parent = nullptr); explicit ImageProviderConnection(QObject* parent = nullptr);
@ -20,6 +20,7 @@ class ImageProviderConnection : public QObject
emit connectionChanged(); emit connectionChanged();
m_connection = connection; m_connection = connection;
} }
private: private:
QMatrixClient::Connection* m_connection; QMatrixClient::Connection* m_connection;
signals: signals:

View File

@ -1,64 +1,51 @@
#include "messageeventmodel.h" #include "messageeventmodel.h"
#include <QtCore/QSettings>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <QtCore/QSettings>
#include <QtQml> // for qmlRegisterType() #include <QtQml> // for qmlRegisterType()
#include "events/roommemberevent.h"
#include "events/simplestateevents.h"
#include "events/redactionevent.h" #include "events/redactionevent.h"
#include "events/roomavatarevent.h" #include "events/roomavatarevent.h"
#include "events/roommemberevent.h"
#include "events/simplestateevents.h"
#include "connection.h" #include "connection.h"
#include "user.h"
#include "settings.h" #include "settings.h"
#include "user.h"
MessageEventModel::MessageEventModel(QObject* parent) MessageEventModel::MessageEventModel(QObject* parent)
: QAbstractListModel(parent) : QAbstractListModel(parent) {
{
qmlRegisterType<QMatrixClient::FileTransferInfo>(); qmlRegisterType<QMatrixClient::FileTransferInfo>();
qRegisterMetaType<QMatrixClient::FileTransferInfo>(); qRegisterMetaType<QMatrixClient::FileTransferInfo>();
} }
MessageEventModel::~MessageEventModel() MessageEventModel::~MessageEventModel() {}
{
} void MessageEventModel::setRoom(QMatrixClient::Room* room) {
if (room == m_currentRoom) return;
void MessageEventModel::setRoom(QMatrixClient::Room* room)
{
if (room == m_currentRoom)
return;
beginResetModel(); beginResetModel();
if( m_currentRoom ) if (m_currentRoom) {
{ m_currentRoom->disconnect(this);
m_currentRoom->disconnect( this );
qDebug() << "Disconnected from" << m_currentRoom->id(); qDebug() << "Disconnected from" << m_currentRoom->id();
} }
m_currentRoom = room; m_currentRoom = room;
if( room ) if (room) {
{
lastReadEventId = room->readMarkerEventId(); lastReadEventId = room->readMarkerEventId();
using namespace QMatrixClient; using namespace QMatrixClient;
connect(m_currentRoom, &Room::aboutToAddNewMessages, this, connect(m_currentRoom, &Room::aboutToAddNewMessages, this,
[=](RoomEventsRange events) [=](RoomEventsRange events) {
{
beginInsertRows(QModelIndex(), 0, int(events.size()) - 1); beginInsertRows(QModelIndex(), 0, int(events.size()) - 1);
}); });
connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this, connect(m_currentRoom, &Room::aboutToAddHistoricalMessages, this,
[=](RoomEventsRange events) [=](RoomEventsRange events) {
{ if (rowCount() > 0) nextNewerRow = rowCount() - 1;
if (rowCount() > 0)
nextNewerRow = rowCount() - 1;
beginInsertRows(QModelIndex(), rowCount(), beginInsertRows(QModelIndex(), rowCount(),
rowCount() + int(events.size()) - 1); rowCount() + int(events.size()) - 1);
}); });
connect(m_currentRoom, &Room::addedMessages, this, connect(m_currentRoom, &Room::addedMessages, this, [=] {
[=] { if (nextNewerRow > -1) {
if (nextNewerRow > -1)
{
const auto idx = index(nextNewerRow); const auto idx = index(nextNewerRow);
emit dataChanged(idx, idx); emit dataChanged(idx, idx);
nextNewerRow = -1; nextNewerRow = -1;
@ -67,175 +54,146 @@ void MessageEventModel::setRoom(QMatrixClient::Room* room)
}); });
connect(m_currentRoom, &Room::readMarkerMoved, this, [this] { connect(m_currentRoom, &Room::readMarkerMoved, this, [this] {
refreshEventRoles( refreshEventRoles(
std::exchange(lastReadEventId, std::exchange(lastReadEventId, m_currentRoom->readMarkerEventId()),
m_currentRoom->readMarkerEventId()),
{ReadMarkerRole}); {ReadMarkerRole});
refreshEventRoles(lastReadEventId, {ReadMarkerRole}); refreshEventRoles(lastReadEventId, {ReadMarkerRole});
}); });
connect(m_currentRoom, &Room::replacedEvent, this, connect(
[this] (const RoomEvent* newEvent) { m_currentRoom, &Room::replacedEvent, this,
refreshEvent(newEvent->id()); [this](const RoomEvent* newEvent) { refreshEvent(newEvent->id()); });
}); connect(m_currentRoom, &Room::fileTransferProgress, this,
connect(m_currentRoom, &Room::fileTransferProgress, &MessageEventModel::refreshEvent);
this, &MessageEventModel::refreshEvent); connect(m_currentRoom, &Room::fileTransferCompleted, this,
connect(m_currentRoom, &Room::fileTransferCompleted, &MessageEventModel::refreshEvent);
this, &MessageEventModel::refreshEvent); connect(m_currentRoom, &Room::fileTransferFailed, this,
connect(m_currentRoom, &Room::fileTransferFailed, &MessageEventModel::refreshEvent);
this, &MessageEventModel::refreshEvent); connect(m_currentRoom, &Room::fileTransferCancelled, this,
connect(m_currentRoom, &Room::fileTransferCancelled, &MessageEventModel::refreshEvent);
this, &MessageEventModel::refreshEvent); qDebug() << "Connected to room" << room->id() << "as"
qDebug() << "Connected to room" << room->id() << room->localUser()->id();
<< "as" << room->localUser()->id();
} else } else
lastReadEventId.clear(); lastReadEventId.clear();
endResetModel(); endResetModel();
emit roomChanged(); emit roomChanged();
} }
void MessageEventModel::refreshEvent(const QString& eventId) void MessageEventModel::refreshEvent(const QString& eventId) {
{
refreshEventRoles(eventId, {}); refreshEventRoles(eventId, {});
} }
void MessageEventModel::refreshEventRoles(const QString& eventId, void MessageEventModel::refreshEventRoles(const QString& eventId,
const QVector<int> roles) const QVector<int> roles) {
{
const auto it = m_currentRoom->findInTimeline(eventId); const auto it = m_currentRoom->findInTimeline(eventId);
if (it != m_currentRoom->timelineEdge()) if (it != m_currentRoom->timelineEdge()) {
{
const auto row = it - m_currentRoom->messageEvents().rbegin(); const auto row = it - m_currentRoom->messageEvents().rbegin();
emit dataChanged(index(row), index(row), roles); emit dataChanged(index(row), index(row), roles);
} }
} }
inline bool hasValidTimestamp(const QMatrixClient::TimelineItem& ti) inline bool hasValidTimestamp(const QMatrixClient::TimelineItem& ti) {
{
return ti->timestamp().isValid(); return ti->timestamp().isValid();
} }
QDateTime MessageEventModel::makeMessageTimestamp(QMatrixClient::Room::rev_iter_t baseIt) const QDateTime MessageEventModel::makeMessageTimestamp(
{ QMatrixClient::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()) return ts;
return ts;
// 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 QMatrixClient::TimelineItem;
auto rit = std::find_if(baseIt, timeline.rend(), auto rit = std::find_if(baseIt, timeline.rend(), hasValidTimestamp);
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};
auto it = std::find_if(baseIt.base(), timeline.end(), hasValidTimestamp); auto it = std::find_if(baseIt.base(), timeline.end(), hasValidTimestamp);
if (it != timeline.end()) if (it != timeline.end())
return { it->event()->timestamp().date(), {0,0}, Qt::LocalTime }; return {it->event()->timestamp().date(), {0, 0}, Qt::LocalTime};
// What kind of room is that?.. // What kind of room is that?..
qCritical() << "No valid timestamps in the room timeline!"; qCritical() << "No valid timestamps in the room timeline!";
return {}; return {};
} }
QString MessageEventModel::makeDateString(QMatrixClient::Room::rev_iter_t baseIt) const QString MessageEventModel::makeDateString(
{ QMatrixClient::Room::rev_iter_t baseIt) const {
auto date = makeMessageTimestamp(baseIt).toLocalTime().date(); auto date = makeMessageTimestamp(baseIt).toLocalTime().date();
if (QMatrixClient::SettingsGroup("UI") if (QMatrixClient::SettingsGroup("UI")
.value("banner_human_friendly_date", true).toBool()) .value("banner_human_friendly_date", true)
{ .toBool()) {
if (date == QDate::currentDate()) if (date == QDate::currentDate()) return tr("Today");
return tr("Today"); if (date == QDate::currentDate().addDays(-1)) return tr("Yesterday");
if (date == QDate::currentDate().addDays(-1))
return tr("Yesterday");
if (date == QDate::currentDate().addDays(-2)) if (date == QDate::currentDate().addDays(-2))
return tr("The day before yesterday"); return tr("The day before yesterday");
if (date > QDate::currentDate().addDays(-7)) if (date > QDate::currentDate().addDays(-7)) return date.toString("dddd");
return date.toString("dddd");
} }
return date.toString(Qt::DefaultLocaleShortDate); return date.toString(Qt::DefaultLocaleShortDate);
} }
int MessageEventModel::rowCount(const QModelIndex& parent) const int MessageEventModel::rowCount(const QModelIndex& parent) const {
{ if (!m_currentRoom || parent.isValid()) return 0;
if(!m_currentRoom || parent.isValid())
return 0;
return m_currentRoom->timelineSize(); return m_currentRoom->timelineSize();
} }
QVariant MessageEventModel::data(const QModelIndex& index, int role) const QVariant MessageEventModel::data(const QModelIndex& index, int role) const {
{ if (!m_currentRoom || index.row() < 0 ||
if( !m_currentRoom || index.row() >= m_currentRoom->timelineSize())
index.row() < 0 || index.row() >= m_currentRoom->timelineSize())
return QVariant(); return QVariant();
const auto timelineIt = m_currentRoom->messageEvents().rbegin() + index.row(); const auto timelineIt = m_currentRoom->messageEvents().rbegin() + index.row();
const auto& ti = *timelineIt; const auto& ti = *timelineIt;
using namespace QMatrixClient; using namespace QMatrixClient;
if( role == Qt::DisplayRole ) if (role == Qt::DisplayRole) {
{ if (ti->isRedacted()) {
if (ti->isRedacted())
{
auto reason = ti->redactedBecause()->reason(); auto reason = ti->redactedBecause()->reason();
if (reason.isEmpty()) if (reason.isEmpty())
return tr("Redacted"); return tr("Redacted");
else else
return tr("Redacted: %1") return tr("Redacted: %1").arg(ti->redactedBecause()->reason());
.arg(ti->redactedBecause()->reason());
} }
if( ti->type() == EventType::RoomMessage ) if (ti->type() == EventType::RoomMessage) {
{
using namespace MessageEventContent; using namespace MessageEventContent;
auto* e = ti.viewAs<RoomMessageEvent>(); auto* e = ti.viewAs<RoomMessageEvent>();
if (e->hasTextContent() && e->mimeType().name() != "text/plain") if (e->hasTextContent() && e->mimeType().name() != "text/plain")
return static_cast<const TextContent*>(e->content())->body; return static_cast<const TextContent*>(e->content())->body;
if (e->hasFileContent()) if (e->hasFileContent()) {
{
auto fileCaption = e->content()->fileInfo()->originalName; auto fileCaption = e->content()->fileInfo()->originalName;
if (fileCaption.isEmpty()) if (fileCaption.isEmpty())
fileCaption = m_currentRoom->prettyPrint(e->plainBody()); fileCaption = m_currentRoom->prettyPrint(e->plainBody());
if (fileCaption.isEmpty()) if (fileCaption.isEmpty()) return tr("a file");
return tr("a file");
} }
return m_currentRoom->prettyPrint(e->plainBody()); return m_currentRoom->prettyPrint(e->plainBody());
} }
if( ti->type() == EventType::RoomMember ) if (ti->type() == EventType::RoomMember) {
{
auto* e = ti.viewAs<RoomMemberEvent>(); auto* e = ti.viewAs<RoomMemberEvent>();
// FIXME: Rewind to the name that was at the time of this event // FIXME: Rewind to the name that was at the time of this event
QString subjectName = m_currentRoom->roomMembername(e->userId()); QString subjectName = m_currentRoom->roomMembername(e->userId());
// The below code assumes senderName output in AuthorRole // The below code assumes senderName output in AuthorRole
switch( e->membership() ) switch (e->membership()) {
{
case MembershipType::Invite: case MembershipType::Invite:
if (e->repeatsState()) if (e->repeatsState())
return tr("reinvited %1 to the room").arg(subjectName); return tr("reinvited %1 to the room").arg(subjectName);
// [[fallthrough]] // [[fallthrough]]
case MembershipType::Join: case MembershipType::Join: {
{ if (e->repeatsState()) return tr("joined the room (repeated)");
if (e->repeatsState())
return tr("joined the room (repeated)");
if (!e->prev_content() || if (!e->prev_content() ||
e->membership() != e->prev_content()->membership) e->membership() != e->prev_content()->membership) {
{
return e->membership() == MembershipType::Invite return e->membership() == MembershipType::Invite
? tr("invited %1 to the room").arg(subjectName) ? tr("invited %1 to the room").arg(subjectName)
: tr("joined the room"); : tr("joined the room");
} }
QString text {}; QString text{};
if (e->displayName() != e->prev_content()->displayName) if (e->displayName() != e->prev_content()->displayName) {
{
if (e->displayName().isEmpty()) if (e->displayName().isEmpty())
text = tr("cleared the display name"); text = tr("cleared the display name");
else else
text = tr("changed the display name to %1") text = tr("changed the display name to %1").arg(e->displayName());
.arg(e->displayName());
} }
if (e->avatarUrl() != e->prev_content()->avatarUrl) if (e->avatarUrl() != e->prev_content()->avatarUrl) {
{ if (!text.isEmpty()) text += " and ";
if (!text.isEmpty())
text += " and ";
if (e->avatarUrl().isEmpty()) if (e->avatarUrl().isEmpty())
text += tr("cleared the avatar"); text += tr("cleared the avatar");
else else
@ -245,8 +203,7 @@ QVariant MessageEventModel::data(const QModelIndex& index, int role) const
} }
case MembershipType::Leave: case MembershipType::Leave:
if (e->prev_content() && if (e->prev_content() &&
e->prev_content()->membership == MembershipType::Ban) e->prev_content()->membership == MembershipType::Ban) {
{
if (e->senderId() != e->userId()) if (e->senderId() != e->userId())
return tr("unbanned %1").arg(subjectName); return tr("unbanned %1").arg(subjectName);
else else
@ -267,60 +224,49 @@ QVariant MessageEventModel::data(const QModelIndex& index, int role) const
return tr("made something unknown"); return tr("made something unknown");
} }
} }
if( ti->type() == EventType::RoomAliases ) if (ti->type() == EventType::RoomAliases) {
{
auto* e = ti.viewAs<RoomAliasesEvent>(); auto* e = ti.viewAs<RoomAliasesEvent>();
return tr("set aliases to: %1").arg(e->aliases().join(", ")); return tr("set aliases to: %1").arg(e->aliases().join(", "));
} }
if( ti->type() == EventType::RoomCanonicalAlias ) if (ti->type() == EventType::RoomCanonicalAlias) {
{
auto* e = ti.viewAs<RoomCanonicalAliasEvent>(); auto* e = ti.viewAs<RoomCanonicalAliasEvent>();
if (e->alias().isEmpty()) if (e->alias().isEmpty())
return tr("cleared the room main alias"); return tr("cleared the room main alias");
else else
return tr("set the room main alias to: %1").arg(e->alias()); return tr("set the room main alias to: %1").arg(e->alias());
} }
if( ti->type() == EventType::RoomName ) if (ti->type() == EventType::RoomName) {
{
auto* e = ti.viewAs<RoomNameEvent>(); auto* e = ti.viewAs<RoomNameEvent>();
if (e->name().isEmpty()) if (e->name().isEmpty())
return tr("cleared the room name"); return tr("cleared the room name");
else else
return tr("set the room name to: %1").arg(e->name()); return tr("set the room name to: %1").arg(e->name());
} }
if( ti->type() == EventType::RoomTopic ) if (ti->type() == EventType::RoomTopic) {
{
auto* e = ti.viewAs<RoomTopicEvent>(); auto* e = ti.viewAs<RoomTopicEvent>();
if (e->topic().isEmpty()) if (e->topic().isEmpty())
return tr("cleared the topic"); return tr("cleared the topic");
else else
return tr("set the topic to: %1").arg(e->topic()); return tr("set the topic to: %1").arg(e->topic());
} }
if( ti->type() == EventType::RoomAvatar ) if (ti->type() == EventType::RoomAvatar) {
{
return tr("changed the room avatar"); return tr("changed the room avatar");
} }
if( ti->type() == EventType::RoomEncryption ) if (ti->type() == EventType::RoomEncryption) {
{
return tr("activated End-to-End Encryption"); return tr("activated End-to-End Encryption");
} }
return tr("Unknown Event"); return tr("Unknown Event");
} }
if( role == Qt::ToolTipRole ) if (role == Qt::ToolTipRole) {
{
return ti->originalJson(); return ti->originalJson();
} }
if( role == EventTypeRole ) if (role == EventTypeRole) {
{ if (ti->isStateEvent()) return "state";
if (ti->isStateEvent())
return "state";
if (ti->type() == EventType::RoomMessage) if (ti->type() == EventType::RoomMessage) {
{ switch (ti.viewAs<RoomMessageEvent>()->msgtype()) {
switch (ti.viewAs<RoomMessageEvent>()->msgtype())
{
case MessageEventType::Emote: case MessageEventType::Emote:
return "emote"; return "emote";
case MessageEventType::Notice: case MessageEventType::Notice:
@ -339,23 +285,19 @@ QVariant MessageEventModel::data(const QModelIndex& index, int role) const
return "other"; return "other";
} }
if( role == TimeRole ) if (role == TimeRole) return makeMessageTimestamp(timelineIt);
return makeMessageTimestamp(timelineIt);
if( role == SectionRole ) if (role == SectionRole)
return makeDateString(timelineIt); // FIXME: move date rendering to QML return makeDateString(timelineIt); // FIXME: move date rendering to QML
if( role == AuthorRole ) if (role == AuthorRole) {
{
auto userId = ti->senderId(); auto userId = ti->senderId();
// FIXME: It shouldn't be User, it should be its state "as of event" // FIXME: It shouldn't be User, it should be its state "as of event"
return QVariant::fromValue(m_currentRoom->user(userId)); return QVariant::fromValue(m_currentRoom->user(userId));
} }
if (role == ContentTypeRole) if (role == ContentTypeRole) {
{ if (ti->type() == EventType::RoomMessage) {
if (ti->type() == EventType::RoomMessage)
{
const auto& contentType = const auto& contentType =
ti.viewAs<RoomMessageEvent>()->mimeType().name(); ti.viewAs<RoomMessageEvent>()->mimeType().name();
return contentType == "text/plain" ? "text/html" : contentType; return contentType == "text/plain" ? "text/html" : contentType;
@ -363,66 +305,53 @@ QVariant MessageEventModel::data(const QModelIndex& index, int role) const
return "text/plain"; return "text/plain";
} }
if (role == ContentRole) if (role == ContentRole) {
{ if (ti->isRedacted()) {
if (ti->isRedacted())
{
auto reason = ti->redactedBecause()->reason(); auto reason = ti->redactedBecause()->reason();
if (reason.isEmpty()) if (reason.isEmpty())
return tr("Redacted"); return tr("Redacted");
else else
return tr("Redacted: %1") return tr("Redacted: %1").arg(ti->redactedBecause()->reason());
.arg(ti->redactedBecause()->reason());
} }
if( ti->type() == EventType::RoomMessage ) if (ti->type() == EventType::RoomMessage) {
{
using namespace MessageEventContent; using namespace MessageEventContent;
auto* e = ti.viewAs<RoomMessageEvent>(); auto* e = ti.viewAs<RoomMessageEvent>();
switch (e->msgtype()) switch (e->msgtype()) {
{
case MessageEventType::Image: case MessageEventType::Image:
case MessageEventType::File: case MessageEventType::File:
case MessageEventType::Audio: case MessageEventType::Audio:
case MessageEventType::Video: case MessageEventType::Video:
return QVariant::fromValue(e->content()->originalJson); return QVariant::fromValue(e->content()->originalJson);
default: default:;
;
} }
} }
} }
if( role == ReadMarkerRole ) if (role == ReadMarkerRole) return ti->id() == lastReadEventId;
return ti->id() == lastReadEventId;
if( role == SpecialMarksRole ) if (role == SpecialMarksRole) {
{
if (ti->isStateEvent() && ti.viewAs<StateEventBase>()->repeatsState()) if (ti->isStateEvent() && ti.viewAs<StateEventBase>()->repeatsState())
return "hidden"; return "hidden";
return ti->isRedacted() ? "redacted" : ""; return ti->isRedacted() ? "redacted" : "";
} }
if( role == EventIdRole ) if (role == EventIdRole) return ti->id();
return ti->id();
if( role == LongOperationRole ) if (role == LongOperationRole) {
{
if (ti->type() == EventType::RoomMessage && if (ti->type() == EventType::RoomMessage &&
ti.viewAs<RoomMessageEvent>()->hasFileContent()) ti.viewAs<RoomMessageEvent>()->hasFileContent()) {
{
auto info = m_currentRoom->fileTransferInfo(ti->id()); auto info = m_currentRoom->fileTransferInfo(ti->id());
return QVariant::fromValue(info); return QVariant::fromValue(info);
} }
} }
auto aboveEventIt = timelineIt + 1; // FIXME: shouldn't be here, because #312 auto aboveEventIt = timelineIt + 1; // FIXME: shouldn't be here, because #312
if (aboveEventIt != m_currentRoom->timelineEdge()) if (aboveEventIt != m_currentRoom->timelineEdge()) {
{ if (role == AboveSectionRole) return makeDateString(aboveEventIt);
if( role == AboveSectionRole )
return makeDateString(aboveEventIt);
if( role == AboveAuthorRole ) if (role == AboveAuthorRole)
return QVariant::fromValue( return QVariant::fromValue(
m_currentRoom->user((*aboveEventIt)->senderId())); m_currentRoom->user((*aboveEventIt)->senderId()));
} }
@ -430,9 +359,7 @@ QVariant MessageEventModel::data(const QModelIndex& index, int role) const
return QVariant(); return QVariant();
} }
QHash<int, QByteArray> MessageEventModel::roleNames() const {
QHash<int, QByteArray> MessageEventModel::roleNames() const
{
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
roles[EventTypeRole] = "eventType"; roles[EventTypeRole] = "eventType";
roles[EventIdRole] = "eventId"; roles[EventIdRole] = "eventId";

View File

@ -4,10 +4,10 @@
#include <QtCore/QAbstractListModel> #include <QtCore/QAbstractListModel>
#include "room.h" #include "room.h"
class MessageEventModel: public QAbstractListModel class MessageEventModel : public QAbstractListModel {
{
Q_OBJECT Q_OBJECT
Q_PROPERTY(QMatrixClient::Room* room READ getRoom WRITE setRoom NOTIFY roomChanged) Q_PROPERTY(
QMatrixClient::Room* room READ getRoom WRITE setRoom NOTIFY roomChanged)
public: public:
enum EventRoles { enum EventRoles {
@ -34,7 +34,8 @@ class MessageEventModel: public QAbstractListModel
QMatrixClient::Room* getRoom() { return m_currentRoom; } QMatrixClient::Room* getRoom() { return m_currentRoom; }
void setRoom(QMatrixClient::Room* room); void setRoom(QMatrixClient::Room* room);
Q_INVOKABLE int rowCount(const QModelIndex& parent = QModelIndex()) const override; Q_INVOKABLE int rowCount(
const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role) const override; QVariant data(const QModelIndex& index, int role) const override;
QHash<int, QByteArray> roleNames() const; QHash<int, QByteArray> roleNames() const;

View File

@ -1,95 +1,75 @@
#include "roomlistmodel.h" #include "roomlistmodel.h"
#include <QtCore/QDebug>
#include <QtGui/QBrush> #include <QtGui/QBrush>
#include <QtGui/QColor> #include <QtGui/QColor>
#include <QtCore/QDebug>
RoomListModel::RoomListModel(QObject* parent) RoomListModel::RoomListModel(QObject* parent) : QAbstractListModel(parent) {}
: QAbstractListModel(parent)
{
} RoomListModel::~RoomListModel() {}
RoomListModel::~RoomListModel() void RoomListModel::setConnection(QMatrixClient::Connection* connection) {
{
}
void RoomListModel::setConnection(QMatrixClient::Connection* connection)
{
beginResetModel(); beginResetModel();
m_connection = connection; m_connection = connection;
m_rooms.clear(); m_rooms.clear();
connect( connection, &QMatrixClient::Connection::newRoom, this, &RoomListModel::addRoom ); connect(connection, &QMatrixClient::Connection::newRoom, this,
for( QMatrixClient::Room* room: connection->roomMap().values() ) { &RoomListModel::addRoom);
connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged ); for (QMatrixClient::Room* room : connection->roomMap().values()) {
connect(room, &QMatrixClient::Room::namesChanged, this,
&RoomListModel::namesChanged);
m_rooms.append(room); m_rooms.append(room);
} }
endResetModel(); endResetModel();
} }
QMatrixClient::Room* RoomListModel::roomAt(int row) QMatrixClient::Room* RoomListModel::roomAt(int row) { return m_rooms.at(row); }
{
return m_rooms.at(row);
}
void RoomListModel::addRoom(QMatrixClient::Room* room) void RoomListModel::addRoom(QMatrixClient::Room* room) {
{
beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count()); beginInsertRows(QModelIndex(), m_rooms.count(), m_rooms.count());
connect( room, &QMatrixClient::Room::namesChanged, this, &RoomListModel::namesChanged ); connect(room, &QMatrixClient::Room::namesChanged, this,
&RoomListModel::namesChanged);
m_rooms.append(room); m_rooms.append(room);
endInsertRows(); endInsertRows();
} }
int RoomListModel::rowCount(const QModelIndex& parent) const int RoomListModel::rowCount(const QModelIndex& parent) const {
{ if (parent.isValid()) return 0;
if( parent.isValid() )
return 0;
return m_rooms.count(); return m_rooms.count();
} }
QVariant RoomListModel::data(const QModelIndex& index, int role) const QVariant RoomListModel::data(const QModelIndex& index, int role) const {
{ if (!index.isValid()) return QVariant();
if( !index.isValid() )
return QVariant();
if( index.row() >= m_rooms.count() ) if (index.row() >= m_rooms.count()) {
{
qDebug() << "UserListModel: something wrong here..."; qDebug() << "UserListModel: something wrong here...";
return QVariant(); return QVariant();
} }
QMatrixClient::Room* room = m_rooms.at(index.row()); QMatrixClient::Room* room = m_rooms.at(index.row());
if( role == Qt::DisplayRole ) if (role == Qt::DisplayRole) {
{
return room->displayName(); return room->displayName();
} }
if( role == Qt::ForegroundRole ) if (role == Qt::ForegroundRole) {
{ if (room->highlightCount() > 0) return QBrush(QColor("orange"));
if( room->highlightCount() > 0 )
return QBrush(QColor("orange"));
return QVariant(); return QVariant();
} }
if( role == Qt::DecorationRole ) if (role == Qt::DecorationRole) {
{ if (room->avatarUrl().toString() != "") {
if ( room->avatarUrl().toString() != "" ) {
return room->avatarUrl(); return room->avatarUrl();
} }
return QVariant(); return QVariant();
} }
if ( role == Qt::StatusTipRole ) if (role == Qt::StatusTipRole) {
{
return room->topic(); return room->topic();
} }
return QVariant(); return QVariant();
} }
void RoomListModel::namesChanged(QMatrixClient::Room* room) void RoomListModel::namesChanged(QMatrixClient::Room* room) {
{
int row = m_rooms.indexOf(room); int row = m_rooms.indexOf(room);
emit dataChanged(index(row), index(row)); emit dataChanged(index(row), index(row));
} }
void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room) void RoomListModel::unreadMessagesChanged(QMatrixClient::Room* room) {
{
int row = m_rooms.indexOf(room); int row = m_rooms.indexOf(room);
emit dataChanged(index(row), index(row)); emit dataChanged(index(row), index(row));
} }

View File

@ -2,25 +2,27 @@
#define ROOMLISTMODEL_H #define ROOMLISTMODEL_H
#include <QtCore/QAbstractListModel> #include <QtCore/QAbstractListModel>
#include "room.h"
#include "connection.h" #include "connection.h"
#include "room.h"
class RoomListModel: public QAbstractListModel class RoomListModel : public QAbstractListModel {
{
Q_OBJECT Q_OBJECT
Q_PROPERTY(QMatrixClient::Connection *connection READ getConnection WRITE setConnection) Q_PROPERTY(QMatrixClient::Connection* connection READ getConnection WRITE
setConnection)
public: public:
RoomListModel(QObject* parent=0); RoomListModel(QObject* parent = 0);
virtual ~RoomListModel(); virtual ~RoomListModel();
QMatrixClient::Connection* getConnection() {return m_connection;} QMatrixClient::Connection* getConnection() { return m_connection; }
void setConnection(QMatrixClient::Connection* 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; QVariant data(const QModelIndex& index,
Q_INVOKABLE int rowCount(const QModelIndex& parent=QModelIndex()) const override; 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;

View File

@ -1,8 +1,8 @@
import QtQuick 2.10 import QtQuick 2.11
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.11
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQuick.Controls 2.3 import QtQuick.Controls 2.4
import QtQuick.Controls.Material 2.3 import QtQuick.Controls.Material 2.4
import Qt.labs.settings 1.0 import Qt.labs.settings 1.0
import "qrc:/qml/component" import "qrc:/qml/component"
@ -60,13 +60,13 @@ Page {
id: mainCol id: mainCol
width: parent.width width: parent.width
ImageStatus { // ImageStatus {
Layout.preferredWidth: 96 // Layout.preferredWidth: 96
Layout.preferredHeight: 96 // Layout.preferredHeight: 96
Layout.alignment: Qt.AlignHCenter // Layout.alignment: Qt.AlignHCenter
source: "qrc:/asset/img/avatar.png" // source: "qrc:/asset/img/avatar.png"
} // }
TextField { TextField {
id: serverField id: serverField

View File

@ -1,6 +1,6 @@
import QtQuick 2.11 import QtQuick 2.11
import QtQuick.Controls 2.3 import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.11
import Matrique 0.1 import Matrique 0.1
import "qrc:/qml/form" import "qrc:/qml/form"

View File

@ -1,5 +1,5 @@
import QtQuick 2.3 import QtQuick 2.11
import QtQuick.Controls 2.3 import QtQuick.Controls 2.4
ItemDelegate { ItemDelegate {
id: itemDelegate id: itemDelegate

View File

@ -1,17 +1,22 @@
import QtQuick 2.11 import QtQuick 2.11
import QtQuick.Controls 2.4 import QtQuick.Controls 2.4
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQuick.Controls.Material 2.4
Item { Item {
property bool opaqueBackground: false 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 id: item
Rectangle { Rectangle {
width: item.width width: item.width
height: item.width height: item.width
radius: item.width / 2 radius: round ? item.width / 2 : 0
color: "white" color: "white"
visible: opaqueBackground visible: opaqueBackground
} }
@ -20,6 +25,8 @@ Item {
id: avatar id: avatar
width: item.width width: item.width
height: item.width height: item.width
visible: showImage
source: item.source
mipmap: true mipmap: true
layer.enabled: true layer.enabled: true
@ -35,9 +42,42 @@ Item {
anchors.centerIn: parent anchors.centerIn: parent
width: avatar.width width: avatar.width
height: 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;
}
} }

View File

@ -1,7 +1,7 @@
import QtQuick 2.10 import QtQuick 2.11
import QtQuick.Controls 2.3 import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.11
import QtQuick.Controls.Material 2.3 import QtQuick.Controls.Material 2.4
Item { Item {
property alias icon: iconText.text property alias icon: iconText.text

View File

@ -1,7 +1,7 @@
import QtQuick 2.10 import QtQuick 2.11
import QtQuick.Controls 2.3 import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.11
import QtQuick.Controls.Material 2.3 import QtQuick.Controls.Material 2.4
Item { Item {
Rectangle { Rectangle {

View File

@ -1,7 +1,7 @@
import QtQuick 2.10 import QtQuick 2.11
import QtQuick.Controls 2.3 import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.11
import QtQuick.Controls.Material 2.3 import QtQuick.Controls.Material 2.4
Item { Item {
property var page property var page
@ -29,7 +29,7 @@ Item {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
if(page != null && stackView.currentItem !== page) { if(!page && stackView.currentItem !== page) {
if(stackView.depth === 1) { if(stackView.depth === 1) {
stackView.replace(page) stackView.replace(page)
} else { } else {

View File

@ -1,7 +1,7 @@
import QtQuick 2.10 import QtQuick 2.11
import QtQuick.Controls 2.3 import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.4
import QtQuick.Controls.Material 2.3 import QtQuick.Controls.Material 2.4
import "qrc:/qml/component" import "qrc:/qml/component"
Item { Item {

View File

@ -2,8 +2,8 @@ import QtQuick 2.11
import QtQuick.Controls 2.4 import QtQuick.Controls 2.4
import QtQuick.Layouts 1.11 import QtQuick.Layouts 1.11
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import QtQuick.Controls.Material 2.3 import QtQuick.Controls.Material 2.4
import QtQml.Models 2.3 import QtQml.Models 2.4
import Matrique 0.1 import Matrique 0.1
import "qrc:/qml/component" import "qrc:/qml/component"
@ -27,6 +27,10 @@ Item {
height: 80 height: 80
onClicked: listView.currentIndex = index onClicked: listView.currentIndex = index
ToolTip.visible: pressed
ToolTip.delay: Qt.styleHints.mousePressAndHoldInterval
ToolTip.text: name
contentItem: RowLayout { contentItem: RowLayout {
anchors.fill: parent anchors.fill: parent
anchors.margins: 16 anchors.margins: 16
@ -36,7 +40,8 @@ Item {
Layout.preferredWidth: height Layout.preferredWidth: height
Layout.fillHeight: true Layout.fillHeight: true
source: avatar == null || avatar == "" ? "qrc:/asset/img/avatar.png" : "image://mxc/" + avatar source: avatar ? "image://mxc/" + avatar : ""
displayText: name
opaqueBackground: true opaqueBackground: true
} }
@ -52,10 +57,10 @@ Item {
Layout.fillHeight: true Layout.fillHeight: true
text: { text: {
if (name != "") { if (name) {
return name; return name;
} }
if (alias != "") { if (alias) {
return alias; return alias;
} }
return id return id
@ -69,7 +74,7 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
text: topic === "" ? "No topic yet." : topic text: topic ? topic : "No topic yet."
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
} }
@ -133,7 +138,7 @@ Item {
} }
Rectangle { Rectangle {
width: searchField.activeFocus || searchField.text != "" ? parent.width : 0 width: searchField.activeFocus || searchField.text ? parent.width : 0
height: parent.height height: parent.height
color: "white" color: "white"

View File

@ -1,7 +1,7 @@
import QtQuick 2.10 import QtQuick 2.11
import QtQuick.Controls 2.3 import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3 import QtQuick.Layouts 1.11
import QtQuick.Controls.Material 2.3 import QtQuick.Controls.Material 2.4
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import Matrique 0.1 import Matrique 0.1
import "qrc:/qml/component" import "qrc:/qml/component"
@ -16,7 +16,7 @@ Item {
background: Item { background: Item {
anchors.fill: parent anchors.fill: parent
visible: currentRoom == null visible: !currentRoom
Pane { Pane {
anchors.fill: parent anchors.fill: parent
} }
@ -32,7 +32,7 @@ Item {
anchors.fill: parent anchors.fill: parent
spacing: 0 spacing: 0
visible: currentRoom != null visible: currentRoom
Pane { Pane {
z: 10 z: 10
@ -52,7 +52,8 @@ Item {
ImageStatus { ImageStatus {
Layout.preferredWidth: parent.height Layout.preferredWidth: parent.height
Layout.fillHeight: true 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 { ColumnLayout {
@ -61,7 +62,7 @@ Item {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: currentRoom != null ? currentRoom.displayName : "" text: currentRoom ? currentRoom.displayName : ""
font.pointSize: 16 font.pointSize: 16
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
@ -69,7 +70,7 @@ Item {
Label { Label {
Layout.fillWidth: true Layout.fillWidth: true
text: currentRoom != null ? currentRoom.topic : "" text: currentRoom ? currentRoom.topic : ""
elide: Text.ElideRight elide: Text.ElideRight
wrapMode: Text.NoWrap wrapMode: Text.NoWrap
} }
@ -88,12 +89,14 @@ Item {
displayMarginEnd: 40 displayMarginEnd: 40
verticalLayoutDirection: ListView.BottomToTop verticalLayoutDirection: ListView.BottomToTop
spacing: 12 spacing: 12
model: MessageEventModel{ model: MessageEventModel{
id: messageEventModel id: messageEventModel
room: currentRoom room: currentRoom
onModelReset: currentRoom.getPreviousContent(50) onModelReset: currentRoom.getPreviousContent(50)
} }
delegate: Row { delegate: Row {
readonly property bool sentByMe: author === currentRoom.localUser readonly property bool sentByMe: author === currentRoom.localUser
@ -102,13 +105,23 @@ Item {
anchors.right: sentByMe ? parent.right : undefined anchors.right: sentByMe ? parent.right : undefined
spacing: 6 spacing: 6
Image { ImageStatus {
id: avatar id: avatar
width: height width: height
height: 40 height: 40
mipmap: true round: false
visible: !sentByMe 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 { Rectangle {
@ -121,6 +134,7 @@ Item {
id: messageText id: messageText
text: display text: display
color: sentByMe ? "black" : "white" color: sentByMe ? "black" : "white"
linkColor: sentByMe ? Material.accent : "white"
anchors.fill: parent anchors.fill: parent
anchors.margins: 12 anchors.margins: 12
wrapMode: Label.Wrap wrapMode: Label.Wrap

View File

@ -1,6 +1,6 @@
import QtQuick 2.11 import QtQuick 2.11
import QtQuick.Controls 2.4 import QtQuick.Controls 2.4
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.11
import QtQuick.Controls.Material 2.4 import QtQuick.Controls.Material 2.4
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
import Qt.labs.settings 1.0 import Qt.labs.settings 1.0
@ -28,16 +28,16 @@ ApplicationWindow {
property alias token: matriqueController.token property alias token: matriqueController.token
} }
// Platform.SystemTrayIcon { // Platform.SystemTrayIcon {
// visible: true // visible: true
// iconSource: "qrc:/asset/img/icon.png" // iconSource: "qrc:/asset/img/icon.png"
// onActivated: { // onActivated: {
// window.show() // window.show()
// window.raise() // window.raise()
// window.requestActivate() // window.requestActivate()
// } // }
// } // }
Controller { Controller {
id: matriqueController id: matriqueController
@ -118,7 +118,8 @@ ApplicationWindow {
anchors.fill: parent anchors.fill: parent
anchors.margins: 15 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 opaqueBackground: false
} }
@ -158,7 +159,7 @@ ApplicationWindow {
imageProvider.connection = matriqueController.connection imageProvider.connection = matriqueController.connection
console.log(matriqueController.homeserver, matriqueController.userID, matriqueController.token) console.log(matriqueController.homeserver, matriqueController.userID, matriqueController.token)
if (matriqueController.userID != "" && matriqueController.token != "") { if (matriqueController.userID && matriqueController.token) {
console.log("Perform auto-login."); console.log("Perform auto-login.");
matriqueController.login(); matriqueController.login();
} else { } else {