Modern C++.
This commit is contained in:
@@ -31,7 +31,7 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|||||||
"MinSizeRel" "RelWithDebInfo")
|
"MinSizeRel" "RelWithDebInfo")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 14)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
|
||||||
# Setup command line parameters for the compiler and linker
|
# Setup command line parameters for the compiler and linker
|
||||||
foreach (FLAG "" all pedantic extra no-unused-parameter)
|
foreach (FLAG "" all pedantic extra no-unused-parameter)
|
||||||
|
|||||||
@@ -276,42 +276,6 @@ Dialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MenuSeparator {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
}
|
|
||||||
|
|
||||||
RowLayout {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
Button {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
flat: true
|
|
||||||
text: "Set background image"
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
var fileDialog = openFileDialog.createObject(ApplicationWindow.overlay)
|
|
||||||
|
|
||||||
fileDialog.chosen.connect(function(path) {
|
|
||||||
if (!path) return
|
|
||||||
|
|
||||||
room.setBackgroundFromLocalFile(path)
|
|
||||||
})
|
|
||||||
|
|
||||||
fileDialog.open()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
Layout.fillWidth: true
|
|
||||||
|
|
||||||
flat: true
|
|
||||||
text: "Clear background image"
|
|
||||||
|
|
||||||
onClicked: room.clearBackground()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
|
|||||||
@@ -172,25 +172,10 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Image {
|
|
||||||
readonly property int sourceDim: (Math.ceil(Math.max(width, height) / 360) + 1) * 360
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
|
|
||||||
visible: currentRoom && currentRoom.backgroundMediaId
|
|
||||||
|
|
||||||
sourceSize.width: sourceDim
|
|
||||||
sourceSize.height: sourceDim
|
|
||||||
|
|
||||||
fillMode: Image.PreserveAspectCrop
|
|
||||||
|
|
||||||
source: currentRoom && currentRoom.backgroundMediaId ? "image://mxc/" + currentRoom.backgroundMediaId : ""
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
visible: currentRoom && !currentRoom.backgroundMediaId
|
visible: currentRoom
|
||||||
color: MSettings.darkTheme ? "#242424" : "#EBEFF2"
|
color: MSettings.darkTheme ? "#242424" : "#EBEFF2"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,12 +243,12 @@ Item {
|
|||||||
if (currentRoom) {
|
if (currentRoom) {
|
||||||
movingTimer.restart()
|
movingTimer.restart()
|
||||||
|
|
||||||
// var lastScrollPosition = sortedMessageEventModel.mapFromSource(currentRoom.savedTopVisibleIndex())
|
// var lastScrollPosition = sortedMessageEventModel.mapFromSource(currentRoom.savedTopVisibleIndex())
|
||||||
// if (lastScrollPosition === 0) {
|
// if (lastScrollPosition === 0) {
|
||||||
// messageListView.positionViewAtBeginning()
|
// messageListView.positionViewAtBeginning()
|
||||||
// } else {
|
// } else {
|
||||||
// messageListView.currentIndex = lastScrollPosition
|
// messageListView.currentIndex = lastScrollPosition
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize < 20)
|
if (messageListView.contentY < messageListView.originY + 10 || currentRoom.timelineSize < 20)
|
||||||
currentRoom.getPreviousContent(50)
|
currentRoom.getPreviousContent(50)
|
||||||
@@ -544,7 +529,7 @@ Item {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
||||||
visible: currentRoom && currentRoom.hasUsersTyping
|
visible: currentRoom && currentRoom.usersTyping.length > 0
|
||||||
padding: 4
|
padding: 4
|
||||||
|
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
@@ -554,7 +539,7 @@ Item {
|
|||||||
spacing: -8
|
spacing: -8
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: currentRoom && currentRoom.hasUsersTyping ? currentRoom.usersTyping : null
|
model: currentRoom && currentRoom.usersTyping.length > 0 ? currentRoom.usersTyping : null
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
Layout.preferredWidth: 28
|
Layout.preferredWidth: 28
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class AccountListModel : public QAbstractListModel {
|
|||||||
|
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
Controller* controller() { return m_controller; }
|
Controller* controller() const { return m_controller; }
|
||||||
void setController(Controller* value);
|
void setController(Controller* value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ Controller::Controller(QObject* parent) : QObject(parent) {
|
|||||||
connect(&m_ncm, &QNetworkConfigurationManager::onlineStateChanged, this,
|
connect(&m_ncm, &QNetworkConfigurationManager::onlineStateChanged, this,
|
||||||
&Controller::isOnlineChanged);
|
&Controller::isOnlineChanged);
|
||||||
|
|
||||||
QTimer::singleShot(0, this, SLOT(invokeLogin()));
|
QTimer::singleShot(0, this, [=] { invokeLogin(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
Controller::~Controller() {
|
Controller::~Controller() {
|
||||||
for (Connection* c : m_connections) {
|
for (auto c : m_connections) {
|
||||||
c->stopSync();
|
c->stopSync();
|
||||||
c->saveState();
|
c->saveState();
|
||||||
}
|
}
|
||||||
@@ -66,74 +66,79 @@ void Controller::loginWithCredentials(QString serverAddr,
|
|||||||
QString user,
|
QString user,
|
||||||
QString pass,
|
QString pass,
|
||||||
QString deviceName) {
|
QString deviceName) {
|
||||||
if (!user.isEmpty() && !pass.isEmpty()) {
|
if (user.isEmpty() || pass.isEmpty()) {
|
||||||
if (deviceName.isEmpty()) {
|
return;
|
||||||
deviceName = "Spectral " + QSysInfo::machineHostName() + " " +
|
|
||||||
QSysInfo::productType() + " " + QSysInfo::productVersion() +
|
|
||||||
" " + QSysInfo::currentCpuArchitecture();
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl serverUrl(serverAddr);
|
|
||||||
|
|
||||||
Connection* conn = new Connection(this);
|
|
||||||
if (serverUrl.isValid()) {
|
|
||||||
conn->setHomeserver(serverUrl);
|
|
||||||
}
|
|
||||||
conn->connectToServer(user, pass, deviceName, "");
|
|
||||||
connect(conn, &Connection::connected, [=] {
|
|
||||||
AccountSettings account(conn->userId());
|
|
||||||
account.setKeepLoggedIn(true);
|
|
||||||
account.clearAccessToken(); // Drop the legacy - just in case
|
|
||||||
account.setHomeserver(conn->homeserver());
|
|
||||||
account.setDeviceId(conn->deviceId());
|
|
||||||
account.setDeviceName(deviceName);
|
|
||||||
if (!saveAccessTokenToKeyChain(account, conn->accessToken()))
|
|
||||||
qWarning() << "Couldn't save access token";
|
|
||||||
account.sync();
|
|
||||||
addConnection(conn);
|
|
||||||
setConnection(conn);
|
|
||||||
});
|
|
||||||
connect(conn, &Connection::networkError,
|
|
||||||
[=](QString error, QString, int, int) {
|
|
||||||
emit errorOccured("Network Error", error);
|
|
||||||
});
|
|
||||||
connect(conn, &Connection::loginError, [=](QString error, QString) {
|
|
||||||
emit errorOccured("Login Failed", error);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (deviceName.isEmpty()) {
|
||||||
|
deviceName = "Spectral " + QSysInfo::machineHostName() + " " +
|
||||||
|
QSysInfo::productType() + " " + QSysInfo::productVersion() +
|
||||||
|
" " + QSysInfo::currentCpuArchitecture();
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrl serverUrl(serverAddr);
|
||||||
|
|
||||||
|
auto conn = new Connection(this);
|
||||||
|
if (serverUrl.isValid()) {
|
||||||
|
conn->setHomeserver(serverUrl);
|
||||||
|
}
|
||||||
|
conn->connectToServer(user, pass, deviceName, "");
|
||||||
|
|
||||||
|
connect(conn, &Connection::connected, [=] {
|
||||||
|
AccountSettings account(conn->userId());
|
||||||
|
account.setKeepLoggedIn(true);
|
||||||
|
account.clearAccessToken(); // Drop the legacy - just in case
|
||||||
|
account.setHomeserver(conn->homeserver());
|
||||||
|
account.setDeviceId(conn->deviceId());
|
||||||
|
account.setDeviceName(deviceName);
|
||||||
|
if (!saveAccessTokenToKeyChain(account, conn->accessToken()))
|
||||||
|
qWarning() << "Couldn't save access token";
|
||||||
|
account.sync();
|
||||||
|
addConnection(conn);
|
||||||
|
setConnection(conn);
|
||||||
|
});
|
||||||
|
connect(conn, &Connection::networkError,
|
||||||
|
[=](QString error, QString, int, int) {
|
||||||
|
emit errorOccured("Network Error", error);
|
||||||
|
});
|
||||||
|
connect(conn, &Connection::loginError, [=](QString error, QString) {
|
||||||
|
emit errorOccured("Login Failed", error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::loginWithAccessToken(QString serverAddr,
|
void Controller::loginWithAccessToken(QString serverAddr,
|
||||||
QString user,
|
QString user,
|
||||||
QString token,
|
QString token,
|
||||||
QString deviceName) {
|
QString deviceName) {
|
||||||
if (!user.isEmpty() && !token.isEmpty()) {
|
if (user.isEmpty() || token.isEmpty()) {
|
||||||
QUrl serverUrl(serverAddr);
|
return;
|
||||||
|
|
||||||
Connection* conn = new Connection(this);
|
|
||||||
if (serverUrl.isValid()) {
|
|
||||||
conn->setHomeserver(serverUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(conn, &Connection::connected, [=] {
|
|
||||||
AccountSettings account(conn->userId());
|
|
||||||
account.setKeepLoggedIn(true);
|
|
||||||
account.clearAccessToken(); // Drop the legacy - just in case
|
|
||||||
account.setHomeserver(conn->homeserver());
|
|
||||||
account.setDeviceId(conn->deviceId());
|
|
||||||
account.setDeviceName(deviceName);
|
|
||||||
if (!saveAccessTokenToKeyChain(account, conn->accessToken()))
|
|
||||||
qWarning() << "Couldn't save access token";
|
|
||||||
account.sync();
|
|
||||||
addConnection(conn);
|
|
||||||
setConnection(conn);
|
|
||||||
});
|
|
||||||
connect(conn, &Connection::networkError,
|
|
||||||
[=](QString error, QString, int, int) {
|
|
||||||
emit errorOccured("Network Error", error);
|
|
||||||
});
|
|
||||||
conn->connectWithToken(user, token, deviceName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QUrl serverUrl(serverAddr);
|
||||||
|
|
||||||
|
auto conn = new Connection(this);
|
||||||
|
if (serverUrl.isValid()) {
|
||||||
|
conn->setHomeserver(serverUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(conn, &Connection::connected, [=] {
|
||||||
|
AccountSettings account(conn->userId());
|
||||||
|
account.setKeepLoggedIn(true);
|
||||||
|
account.clearAccessToken(); // Drop the legacy - just in case
|
||||||
|
account.setHomeserver(conn->homeserver());
|
||||||
|
account.setDeviceId(conn->deviceId());
|
||||||
|
account.setDeviceName(deviceName);
|
||||||
|
if (!saveAccessTokenToKeyChain(account, conn->accessToken()))
|
||||||
|
qWarning() << "Couldn't save access token";
|
||||||
|
account.sync();
|
||||||
|
addConnection(conn);
|
||||||
|
setConnection(conn);
|
||||||
|
});
|
||||||
|
connect(conn, &Connection::networkError,
|
||||||
|
[=](QString error, QString, int, int) {
|
||||||
|
emit errorOccured("Network Error", error);
|
||||||
|
});
|
||||||
|
conn->connectWithToken(user, token, deviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Controller::logout(Connection* conn) {
|
void Controller::logout(Connection* conn) {
|
||||||
@@ -149,7 +154,8 @@ void Controller::logout(Connection* conn) {
|
|||||||
job.setAutoDelete(true);
|
job.setAutoDelete(true);
|
||||||
job.setKey(conn->userId());
|
job.setKey(conn->userId());
|
||||||
QEventLoop loop;
|
QEventLoop loop;
|
||||||
QKeychain::DeletePasswordJob::connect(&job, &QKeychain::Job::finished, &loop, &QEventLoop::quit);
|
QKeychain::DeletePasswordJob::connect(&job, &QKeychain::Job::finished, &loop,
|
||||||
|
&QEventLoop::quit);
|
||||||
job.start();
|
job.start();
|
||||||
loop.exec();
|
loop.exec();
|
||||||
|
|
||||||
@@ -169,21 +175,24 @@ void Controller::logout(Connection* conn) {
|
|||||||
void Controller::addConnection(Connection* c) {
|
void Controller::addConnection(Connection* c) {
|
||||||
Q_ASSERT_X(c, __FUNCTION__, "Attempt to add a null connection");
|
Q_ASSERT_X(c, __FUNCTION__, "Attempt to add a null connection");
|
||||||
|
|
||||||
m_connections.push_back(c);
|
m_connections += c;
|
||||||
|
|
||||||
c->setLazyLoading(true);
|
c->setLazyLoading(true);
|
||||||
|
|
||||||
connect(c, &Connection::syncDone, this, [=] {
|
connect(c, &Connection::syncDone, this, [=] {
|
||||||
setBusy(false);
|
setBusy(false);
|
||||||
|
|
||||||
emit syncDone();
|
emit syncDone();
|
||||||
|
|
||||||
c->sync(30000);
|
c->sync(30000);
|
||||||
c->saveState();
|
c->saveState();
|
||||||
});
|
});
|
||||||
connect(c, &Connection::loggedOut, this, [=] { dropConnection(c); });
|
connect(c, &Connection::loggedOut, this, [=] { dropConnection(c); });
|
||||||
connect(&m_ncm, &QNetworkConfigurationManager::onlineStateChanged,
|
connect(&m_ncm, &QNetworkConfigurationManager::onlineStateChanged,
|
||||||
[=](bool status) {
|
[=](bool status) {
|
||||||
if (!status)
|
if (!status) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
c->stopSync();
|
c->stopSync();
|
||||||
c->sync(30000);
|
c->sync(30000);
|
||||||
@@ -231,8 +240,11 @@ void Controller::invokeLogin() {
|
|||||||
c->connectWithToken(account.userId(), accessToken, account.deviceId());
|
c->connectWithToken(account.userId(), accessToken, account.deviceId());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_connections.isEmpty())
|
|
||||||
|
if (!m_connections.isEmpty()) {
|
||||||
setConnection(m_connections[0]);
|
setConnection(m_connections[0]);
|
||||||
|
}
|
||||||
|
|
||||||
emit initiated();
|
emit initiated();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +345,7 @@ bool Controller::saveAccessTokenToKeyChain(const AccountSettings& account,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Controller::joinRoom(Connection* c, const QString& alias) {
|
void Controller::joinRoom(Connection* c, const QString& alias) {
|
||||||
JoinRoomJob* joinRoomJob = c->joinRoom(alias);
|
auto joinRoomJob = c->joinRoom(alias);
|
||||||
joinRoomJob->connect(joinRoomJob, &JoinRoomJob::failure, [=] {
|
joinRoomJob->connect(joinRoomJob, &JoinRoomJob::failure, [=] {
|
||||||
emit errorOccured("Join Room Failed", joinRoomJob->errorString());
|
emit errorOccured("Join Room Failed", joinRoomJob->errorString());
|
||||||
});
|
});
|
||||||
@@ -342,7 +354,7 @@ void Controller::joinRoom(Connection* c, const QString& alias) {
|
|||||||
void Controller::createRoom(Connection* c,
|
void Controller::createRoom(Connection* c,
|
||||||
const QString& name,
|
const QString& name,
|
||||||
const QString& topic) {
|
const QString& topic) {
|
||||||
CreateRoomJob* createRoomJob =
|
auto createRoomJob =
|
||||||
c->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
|
c->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
|
||||||
createRoomJob->connect(createRoomJob, &CreateRoomJob::failure, [=] {
|
createRoomJob->connect(createRoomJob, &CreateRoomJob::failure, [=] {
|
||||||
emit errorOccured("Create Room Failed", createRoomJob->errorString());
|
emit errorOccured("Create Room Failed", createRoomJob->errorString());
|
||||||
@@ -350,7 +362,7 @@ void Controller::createRoom(Connection* c,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Controller::createDirectChat(Connection* c, const QString& userID) {
|
void Controller::createDirectChat(Connection* c, const QString& userID) {
|
||||||
CreateRoomJob* createRoomJob = c->createDirectChat(userID);
|
auto createRoomJob = c->createDirectChat(userID);
|
||||||
createRoomJob->connect(createRoomJob, &CreateRoomJob::failure, [=] {
|
createRoomJob->connect(createRoomJob, &CreateRoomJob::failure, [=] {
|
||||||
emit errorOccured("Create Direct Chat Failed",
|
emit errorOccured("Create Direct Chat Failed",
|
||||||
createRoomJob->errorString());
|
createRoomJob->errorString());
|
||||||
@@ -358,24 +370,16 @@ void Controller::createDirectChat(Connection* c, const QString& userID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Controller::playAudio(QUrl localFile) {
|
void Controller::playAudio(QUrl localFile) {
|
||||||
QMediaPlayer* player = new QMediaPlayer;
|
auto player = new QMediaPlayer;
|
||||||
player->setMedia(localFile);
|
player->setMedia(localFile);
|
||||||
player->play();
|
player->play();
|
||||||
connect(player, &QMediaPlayer::stateChanged, [=] { player->deleteLater(); });
|
connect(player, &QMediaPlayer::stateChanged, [=] { player->deleteLater(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
int Controller::dpi() {
|
|
||||||
return SettingsGroup("Interface").value("dpi", 100).toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::setDpi(int dpi) {
|
|
||||||
SettingsGroup("Interface").setValue("dpi", dpi);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Controller::changeAvatar(Connection* conn, QUrl localFile) {
|
void Controller::changeAvatar(Connection* conn, QUrl localFile) {
|
||||||
auto job = conn->uploadFile(localFile.toLocalFile());
|
auto job = conn->uploadFile(localFile.toLocalFile());
|
||||||
if (isJobRunning(job)) {
|
if (isJobRunning(job)) {
|
||||||
connect(job, &BaseJob::success, this, [this, conn, job] {
|
connect(job, &BaseJob::success, this, [conn, job] {
|
||||||
conn->callApi<SetAvatarUrlJob>(conn->userId(), job->contentUri());
|
conn->callApi<SetAvatarUrlJob>(conn->userId(), job->contentUri());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,10 +34,7 @@ class Controller : public QObject {
|
|||||||
Q_INVOKABLE void loginWithCredentials(QString, QString, QString, QString);
|
Q_INVOKABLE void loginWithCredentials(QString, QString, QString, QString);
|
||||||
Q_INVOKABLE void loginWithAccessToken(QString, QString, QString, QString);
|
Q_INVOKABLE void loginWithAccessToken(QString, QString, QString, QString);
|
||||||
|
|
||||||
QVector<Connection*> connections() { return m_connections; }
|
QVector<Connection*> connections() const { return m_connections; }
|
||||||
|
|
||||||
Q_INVOKABLE int dpi();
|
|
||||||
Q_INVOKABLE void setDpi(int dpi);
|
|
||||||
|
|
||||||
// All the non-Q_INVOKABLE functions.
|
// All the non-Q_INVOKABLE functions.
|
||||||
void addConnection(Connection* c);
|
void addConnection(Connection* c);
|
||||||
@@ -46,19 +43,20 @@ class Controller : public QObject {
|
|||||||
// All the Q_PROPERTYs.
|
// All the Q_PROPERTYs.
|
||||||
int accountCount() { return m_connections.count(); }
|
int accountCount() { return m_connections.count(); }
|
||||||
|
|
||||||
bool quitOnLastWindowClosed() {
|
bool quitOnLastWindowClosed() const {
|
||||||
return QApplication::quitOnLastWindowClosed();
|
return QApplication::quitOnLastWindowClosed();
|
||||||
}
|
}
|
||||||
void setQuitOnLastWindowClosed(bool value) {
|
void setQuitOnLastWindowClosed(bool value) {
|
||||||
if (quitOnLastWindowClosed() != value) {
|
if (quitOnLastWindowClosed() != value) {
|
||||||
QApplication::setQuitOnLastWindowClosed(value);
|
QApplication::setQuitOnLastWindowClosed(value);
|
||||||
|
|
||||||
emit quitOnLastWindowClosedChanged();
|
emit quitOnLastWindowClosedChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isOnline() { return m_ncm.isOnline(); }
|
bool isOnline() const { return m_ncm.isOnline(); }
|
||||||
|
|
||||||
bool busy() { return m_busy; }
|
bool busy() const { return m_busy; }
|
||||||
void setBusy(bool busy) {
|
void setBusy(bool busy) {
|
||||||
if (m_busy == busy) {
|
if (m_busy == busy) {
|
||||||
return;
|
return;
|
||||||
@@ -67,9 +65,10 @@ class Controller : public QObject {
|
|||||||
emit busyChanged();
|
emit busyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Connection* connection() {
|
Connection* connection() const {
|
||||||
if (m_connection.isNull())
|
if (m_connection.isNull())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
return m_connection;
|
return m_connection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,49 +28,49 @@ QVariantList EmojiModel::filterModel(const QString& filter) {
|
|||||||
QVariantList result;
|
QVariantList result;
|
||||||
|
|
||||||
for (QVariant e : people) {
|
for (QVariant e : people) {
|
||||||
Emoji emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (emoji.shortname.startsWith(filter)) {
|
if (emoji.shortname.startsWith(filter)) {
|
||||||
result.append(e);
|
result.append(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (QVariant e : nature) {
|
for (QVariant e : nature) {
|
||||||
Emoji emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (emoji.shortname.startsWith(filter)) {
|
if (emoji.shortname.startsWith(filter)) {
|
||||||
result.append(e);
|
result.append(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (QVariant e : food) {
|
for (QVariant e : food) {
|
||||||
Emoji emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (emoji.shortname.startsWith(filter)) {
|
if (emoji.shortname.startsWith(filter)) {
|
||||||
result.append(e);
|
result.append(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (QVariant e : activity) {
|
for (QVariant e : activity) {
|
||||||
Emoji emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (emoji.shortname.startsWith(filter)) {
|
if (emoji.shortname.startsWith(filter)) {
|
||||||
result.append(e);
|
result.append(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (QVariant e : travel) {
|
for (QVariant e : travel) {
|
||||||
Emoji emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (emoji.shortname.startsWith(filter)) {
|
if (emoji.shortname.startsWith(filter)) {
|
||||||
result.append(e);
|
result.append(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (QVariant e : objects) {
|
for (QVariant e : objects) {
|
||||||
Emoji emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (emoji.shortname.startsWith(filter)) {
|
if (emoji.shortname.startsWith(filter)) {
|
||||||
result.append(e);
|
result.append(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (QVariant e : symbols) {
|
for (QVariant e : symbols) {
|
||||||
Emoji emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (emoji.shortname.startsWith(filter)) {
|
if (emoji.shortname.startsWith(filter)) {
|
||||||
result.append(e);
|
result.append(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (QVariant e : flags) {
|
for (QVariant e : flags) {
|
||||||
Emoji emoji = qvariant_cast<Emoji>(e);
|
auto emoji = qvariant_cast<Emoji>(e);
|
||||||
if (emoji.shortname.startsWith(filter)) {
|
if (emoji.shortname.startsWith(filter)) {
|
||||||
result.append(e);
|
result.append(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ ImageClipboard::ImageClipboard(QObject* parent)
|
|||||||
&ImageClipboard::imageChanged);
|
&ImageClipboard::imageChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ImageClipboard::hasImage() {
|
bool ImageClipboard::hasImage() const {
|
||||||
return !image().isNull();
|
return !image().isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage ImageClipboard::image() {
|
QImage ImageClipboard::image() const {
|
||||||
return m_clipboard->image();
|
return m_clipboard->image();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,8 +31,9 @@ bool ImageClipboard::saveImage(const QUrl& localPath) {
|
|||||||
|
|
||||||
QString path = QFileInfo(localPath.toLocalFile()).absolutePath();
|
QString path = QFileInfo(localPath.toLocalFile()).absolutePath();
|
||||||
QDir dir;
|
QDir dir;
|
||||||
if (!dir.exists(path))
|
if (!dir.exists(path)) {
|
||||||
dir.mkpath(path);
|
dir.mkpath(path);
|
||||||
|
}
|
||||||
|
|
||||||
i.save(localPath.toLocalFile());
|
i.save(localPath.toLocalFile());
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ class ImageClipboard : public QObject {
|
|||||||
public:
|
public:
|
||||||
explicit ImageClipboard(QObject* parent = nullptr);
|
explicit ImageClipboard(QObject* parent = nullptr);
|
||||||
|
|
||||||
bool hasImage();
|
bool hasImage() const;
|
||||||
QImage image();
|
QImage image() const;
|
||||||
|
|
||||||
Q_INVOKABLE bool saveImage(const QUrl& localPath);
|
Q_INVOKABLE bool saveImage(const QUrl& localPath);
|
||||||
|
|
||||||
|
|||||||
@@ -307,6 +307,8 @@ QVariant MessageEventModel::data(const QModelIndex& idx, int role) const {
|
|||||||
return "audio";
|
return "audio";
|
||||||
case MessageEventType::Video:
|
case MessageEventType::Video:
|
||||||
return "video";
|
return "video";
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (e->hasFileContent())
|
if (e->hasFileContent())
|
||||||
return "file";
|
return "file";
|
||||||
@@ -540,7 +542,7 @@ QVariant MessageEventModel::data(const QModelIndex& idx, int role) const {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
int MessageEventModel::eventIDToIndex(const QString& eventID) {
|
int MessageEventModel::eventIDToIndex(const QString& eventID) const {
|
||||||
const auto it = m_currentRoom->findInTimeline(eventID);
|
const auto it = m_currentRoom->findInTimeline(eventID);
|
||||||
if (it == m_currentRoom->timelineEdge()) {
|
if (it == m_currentRoom->timelineEdge()) {
|
||||||
qWarning() << "Trying to find inexistent event:" << eventID;
|
qWarning() << "Trying to find inexistent event:" << eventID;
|
||||||
|
|||||||
@@ -48,9 +48,9 @@ class MessageEventModel : public QAbstractListModel {
|
|||||||
};
|
};
|
||||||
|
|
||||||
explicit MessageEventModel(QObject* parent = nullptr);
|
explicit MessageEventModel(QObject* parent = nullptr);
|
||||||
~MessageEventModel();
|
~MessageEventModel() override;
|
||||||
|
|
||||||
SpectralRoom* room() { return m_currentRoom; }
|
SpectralRoom* room() const { return m_currentRoom; }
|
||||||
void setRoom(SpectralRoom* room);
|
void setRoom(SpectralRoom* room);
|
||||||
|
|
||||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
@@ -58,7 +58,7 @@ class MessageEventModel : public QAbstractListModel {
|
|||||||
int role = Qt::DisplayRole) const override;
|
int role = Qt::DisplayRole) const override;
|
||||||
QHash<int, QByteArray> roleNames() const override;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
Q_INVOKABLE int eventIDToIndex(const QString& eventID);
|
Q_INVOKABLE int eventIDToIndex(const QString& eventID) const;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
int refreshEvent(const QString& eventId);
|
int refreshEvent(const QString& eventId);
|
||||||
|
|||||||
@@ -59,18 +59,19 @@ void RoomListModel::setConnection(Connection* connection) {
|
|||||||
void RoomListModel::doResetModel() {
|
void RoomListModel::doResetModel() {
|
||||||
beginResetModel();
|
beginResetModel();
|
||||||
m_rooms.clear();
|
m_rooms.clear();
|
||||||
for (auto r : m_connection->roomMap())
|
for (auto r : m_connection->roomMap()) {
|
||||||
doAddRoom(r);
|
doAddRoom(r);
|
||||||
|
}
|
||||||
endResetModel();
|
endResetModel();
|
||||||
refreshNotificationCount();
|
refreshNotificationCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
SpectralRoom* RoomListModel::roomAt(int row) {
|
SpectralRoom* RoomListModel::roomAt(int row) const {
|
||||||
return m_rooms.at(row);
|
return m_rooms.at(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RoomListModel::doAddRoom(Room* r) {
|
void RoomListModel::doAddRoom(Room* r) {
|
||||||
if (auto* room = static_cast<SpectralRoom*>(r)) {
|
if (auto room = static_cast<SpectralRoom*>(r)) {
|
||||||
m_rooms.append(room);
|
m_rooms.append(room);
|
||||||
connectRoomSignals(room);
|
connectRoomSignals(room);
|
||||||
emit roomAdded(room);
|
emit roomAdded(room);
|
||||||
@@ -134,7 +135,7 @@ void RoomListModel::updateRoom(Room* room, Room* prev) {
|
|||||||
// That doesn't look right but technically we still can do it.
|
// That doesn't look right but technically we still can do it.
|
||||||
}
|
}
|
||||||
// Ok, we're through with pre-checks, now for the real thing.
|
// Ok, we're through with pre-checks, now for the real thing.
|
||||||
auto* newRoom = static_cast<SpectralRoom*>(room);
|
auto newRoom = static_cast<SpectralRoom*>(room);
|
||||||
const auto it = std::find_if(
|
const auto it = std::find_if(
|
||||||
m_rooms.begin(), m_rooms.end(),
|
m_rooms.begin(), m_rooms.end(),
|
||||||
[=](const SpectralRoom* r) { return r == prev || r == newRoom; });
|
[=](const SpectralRoom* r) { return r == prev || r == newRoom; });
|
||||||
|
|||||||
@@ -45,23 +45,23 @@ class RoomListModel : public QAbstractListModel {
|
|||||||
CurrentRoomRole,
|
CurrentRoomRole,
|
||||||
};
|
};
|
||||||
|
|
||||||
RoomListModel(QObject* parent = 0);
|
RoomListModel(QObject* parent = nullptr);
|
||||||
virtual ~RoomListModel();
|
virtual ~RoomListModel() override;
|
||||||
|
|
||||||
Connection* connection() { return m_connection; }
|
Connection* connection() const { return m_connection; }
|
||||||
void setConnection(Connection* connection);
|
void setConnection(Connection* connection);
|
||||||
void doResetModel();
|
void doResetModel();
|
||||||
|
|
||||||
Q_INVOKABLE SpectralRoom* roomAt(int row);
|
Q_INVOKABLE SpectralRoom* roomAt(int row) const;
|
||||||
|
|
||||||
QVariant data(const QModelIndex& index,
|
QVariant data(const QModelIndex& index,
|
||||||
int role = Qt::DisplayRole) const override;
|
int role = Qt::DisplayRole) const override;
|
||||||
Q_INVOKABLE int rowCount(
|
Q_INVOKABLE int rowCount(
|
||||||
const QModelIndex& parent = QModelIndex()) const override;
|
const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
|
||||||
QHash<int, QByteArray> roleNames() const;
|
QHash<int, QByteArray> roleNames() const override;
|
||||||
|
|
||||||
int notificationCount() { return m_notificationCount; }
|
int notificationCount() const { return m_notificationCount; }
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void doAddRoom(Room* room);
|
void doAddRoom(Room* room);
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include "events/typingevent.h"
|
#include "events/typingevent.h"
|
||||||
#include "jobs/downloadfilejob.h"
|
#include "jobs/downloadfilejob.h"
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QImageReader>
|
#include <QImageReader>
|
||||||
@@ -34,24 +36,10 @@ SpectralRoom::SpectralRoom(Connection* connection,
|
|||||||
&SpectralRoom::countChanged);
|
&SpectralRoom::countChanged);
|
||||||
connect(this, &SpectralRoom::highlightCountChanged, this,
|
connect(this, &SpectralRoom::highlightCountChanged, this,
|
||||||
&SpectralRoom::countChanged);
|
&SpectralRoom::countChanged);
|
||||||
connect(this, &Room::addedMessages, this, [=] { setBusy(false); });
|
|
||||||
connect(this, &Room::fileTransferCompleted, this, [=] {
|
connect(this, &Room::fileTransferCompleted, this, [=] {
|
||||||
setFileUploadingProgress(0);
|
setFileUploadingProgress(0);
|
||||||
setHasFileUploading(false);
|
setHasFileUploading(false);
|
||||||
});
|
});
|
||||||
connect(this, &Room::accountDataChanged, this, [=](QString type) {
|
|
||||||
if (type == backgroundEventType)
|
|
||||||
emit backgroundChanged();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QString getMIME(const QUrl& fileUrl) {
|
|
||||||
return QMimeDatabase().mimeTypeForFile(fileUrl.toLocalFile()).name();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline QSize getImageSize(const QUrl& imageUrl) {
|
|
||||||
QImageReader reader(imageUrl.toLocalFile());
|
|
||||||
return reader.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectralRoom::uploadFile(const QUrl& url, const QString& body) {
|
void SpectralRoom::uploadFile(const QUrl& url, const QString& body) {
|
||||||
@@ -61,13 +49,13 @@ void SpectralRoom::uploadFile(const QUrl& url, const QString& body) {
|
|||||||
QString txnId = postFile(body.isEmpty() ? url.fileName() : body, url, false);
|
QString txnId = postFile(body.isEmpty() ? url.fileName() : body, url, false);
|
||||||
setHasFileUploading(true);
|
setHasFileUploading(true);
|
||||||
connect(this, &Room::fileTransferCompleted,
|
connect(this, &Room::fileTransferCompleted,
|
||||||
[=](QString id, QUrl localFile, QUrl mxcUrl) {
|
[=](QString id, QUrl /*localFile*/, QUrl /*mxcUrl*/) {
|
||||||
if (id == txnId) {
|
if (id == txnId) {
|
||||||
setFileUploadingProgress(0);
|
setFileUploadingProgress(0);
|
||||||
setHasFileUploading(false);
|
setHasFileUploading(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(this, &Room::fileTransferFailed, [=](QString id, QString error) {
|
connect(this, &Room::fileTransferFailed, [=](QString id, QString /*error*/) {
|
||||||
if (id == txnId) {
|
if (id == txnId) {
|
||||||
setFileUploadingProgress(0);
|
setFileUploadingProgress(0);
|
||||||
setHasFileUploading(false);
|
setHasFileUploading(false);
|
||||||
@@ -91,24 +79,14 @@ void SpectralRoom::forget() {
|
|||||||
connection()->forgetRoom(id());
|
connection()->forgetRoom(id());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SpectralRoom::hasUsersTyping() {
|
QVariantList SpectralRoom::getUsersTyping() const {
|
||||||
QList<User*> users = usersTyping();
|
auto users = usersTyping();
|
||||||
if (users.isEmpty())
|
users.removeAll(localUser());
|
||||||
return false;
|
QVariantList userVariants;
|
||||||
int count = users.length();
|
|
||||||
if (users.contains(localUser()))
|
|
||||||
count--;
|
|
||||||
return count != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantList SpectralRoom::getUsersTyping() {
|
|
||||||
QList<User*> users = usersTyping();
|
|
||||||
users.removeOne(localUser());
|
|
||||||
QVariantList out;
|
|
||||||
for (User* user : users) {
|
for (User* user : users) {
|
||||||
out.append(QVariant::fromValue(user));
|
userVariants.append(QVariant::fromValue(user));
|
||||||
}
|
}
|
||||||
return out;
|
return userVariants;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectralRoom::sendTypingNotification(bool isTyping) {
|
void SpectralRoom::sendTypingNotification(bool isTyping) {
|
||||||
@@ -116,7 +94,7 @@ void SpectralRoom::sendTypingNotification(bool isTyping) {
|
|||||||
id(), isTyping, 10000);
|
id(), isTyping, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString SpectralRoom::lastEvent() {
|
QString SpectralRoom::lastEvent() const {
|
||||||
for (auto i = messageEvents().rbegin(); i < messageEvents().rend(); i++) {
|
for (auto i = messageEvents().rbegin(); i < messageEvents().rend(); i++) {
|
||||||
const RoomEvent* evt = i->get();
|
const RoomEvent* evt = i->get();
|
||||||
|
|
||||||
@@ -185,7 +163,7 @@ void SpectralRoom::countChanged() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QDateTime SpectralRoom::lastActiveTime() {
|
QDateTime SpectralRoom::lastActiveTime() const {
|
||||||
if (timelineSize() == 0)
|
if (timelineSize() == 0)
|
||||||
return QDateTime();
|
return QDateTime();
|
||||||
return messageEvents().rbegin()->get()->timestamp();
|
return messageEvents().rbegin()->get()->timestamp();
|
||||||
@@ -194,13 +172,13 @@ QDateTime SpectralRoom::lastActiveTime() {
|
|||||||
int SpectralRoom::savedTopVisibleIndex() const {
|
int SpectralRoom::savedTopVisibleIndex() const {
|
||||||
return firstDisplayedMarker() == timelineEdge()
|
return firstDisplayedMarker() == timelineEdge()
|
||||||
? 0
|
? 0
|
||||||
: firstDisplayedMarker() - messageEvents().rbegin();
|
: int(firstDisplayedMarker() - messageEvents().rbegin());
|
||||||
}
|
}
|
||||||
|
|
||||||
int SpectralRoom::savedBottomVisibleIndex() const {
|
int SpectralRoom::savedBottomVisibleIndex() const {
|
||||||
return lastDisplayedMarker() == timelineEdge()
|
return lastDisplayedMarker() == timelineEdge()
|
||||||
? 0
|
? 0
|
||||||
: lastDisplayedMarker() - messageEvents().rbegin();
|
: int(lastDisplayedMarker() - messageEvents().rbegin());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectralRoom::saveViewport(int topIndex, int bottomIndex) {
|
void SpectralRoom::saveViewport(int topIndex, int bottomIndex) {
|
||||||
@@ -217,17 +195,13 @@ void SpectralRoom::saveViewport(int topIndex, int bottomIndex) {
|
|||||||
setLastDisplayedEvent(maxTimelineIndex() - bottomIndex);
|
setLastDisplayedEvent(maxTimelineIndex() - bottomIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectralRoom::getPreviousContent(int limit) {
|
QVariantList SpectralRoom::getUsers(const QString& keyword) const {
|
||||||
setBusy(true);
|
const auto userList = users();
|
||||||
Room::getPreviousContent(limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariantList SpectralRoom::getUsers(const QString& prefix) {
|
|
||||||
auto userList = users();
|
|
||||||
QVariantList matchedList;
|
QVariantList matchedList;
|
||||||
for (auto u : userList)
|
for (const auto u : userList)
|
||||||
if (u->displayname(this).toLower().startsWith(prefix.toLower()))
|
if (u->displayname(this).contains(keyword, Qt::CaseInsensitive)) {
|
||||||
matchedList.append(QVariant::fromValue(u));
|
matchedList.append(QVariant::fromValue(u));
|
||||||
|
}
|
||||||
|
|
||||||
return matchedList;
|
return matchedList;
|
||||||
}
|
}
|
||||||
@@ -236,54 +210,167 @@ QUrl SpectralRoom::urlToMxcUrl(QUrl mxcUrl) {
|
|||||||
return DownloadFileJob::makeRequestUrl(connection()->homeserver(), mxcUrl);
|
return DownloadFileJob::makeRequestUrl(connection()->homeserver(), mxcUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
QUrl SpectralRoom::backgroundUrl() {
|
QString SpectralRoom::avatarMediaId() const {
|
||||||
return hasAccountData(backgroundEventType)
|
if (const auto avatar = Room::avatarMediaId(); !avatar.isEmpty()) {
|
||||||
? QUrl(accountData(backgroundEventType)
|
return avatar;
|
||||||
.get()
|
}
|
||||||
->contentJson()["url"]
|
|
||||||
.toString())
|
// Use the first (excluding self) user's avatar for direct chats
|
||||||
: QUrl();
|
const auto dcUsers = directChatUsers();
|
||||||
|
for (const auto u : dcUsers) {
|
||||||
|
if (u != localUser()) {
|
||||||
|
return u->avatarMediaId();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectralRoom::setBackgroundUrl(QUrl url) {
|
QString SpectralRoom::eventToString(const RoomEvent& evt,
|
||||||
if (url.isEmpty() || url == backgroundUrl())
|
Qt::TextFormat format) const {
|
||||||
return;
|
const bool prettyPrint = (format == Qt::RichText);
|
||||||
|
|
||||||
connection()->callApi<SetAccountDataPerRoomJob>(
|
using namespace QMatrixClient;
|
||||||
localUser()->id(), id(), backgroundEventType,
|
return visit(
|
||||||
QJsonObject{{"url", url.toString()}});
|
evt,
|
||||||
}
|
[prettyPrint](const RoomMessageEvent& e) {
|
||||||
|
using namespace MessageEventContent;
|
||||||
|
|
||||||
void SpectralRoom::setBackgroundFromLocalFile(QUrl url) {
|
if (prettyPrint && e.hasTextContent() &&
|
||||||
if (url.isEmpty())
|
e.mimeType().name() != "text/plain")
|
||||||
return;
|
return static_cast<const TextContent*>(e.content())->body;
|
||||||
|
if (e.hasFileContent()) {
|
||||||
auto txnId = connection()->generateTxnId();
|
auto fileCaption =
|
||||||
Room::uploadFile(txnId, url);
|
e.content()->fileInfo()->originalName.toHtmlEscaped();
|
||||||
|
if (fileCaption.isEmpty()) {
|
||||||
connect(this, &Room::fileTransferCompleted,
|
fileCaption = prettyPrint
|
||||||
[=](QString id, QUrl localFile, QUrl mxcUrl) {
|
? QMatrixClient::prettyPrint(e.plainBody())
|
||||||
if (id == txnId) {
|
: e.plainBody();
|
||||||
setBackgroundUrl(mxcUrl);
|
}
|
||||||
|
return !fileCaption.isEmpty() ? fileCaption : tr("a file");
|
||||||
|
}
|
||||||
|
return prettyPrint ? QMatrixClient::prettyPrint(e.plainBody())
|
||||||
|
: e.plainBody();
|
||||||
|
},
|
||||||
|
[this](const RoomMemberEvent& e) {
|
||||||
|
// FIXME: Rewind to the name that was at the time of this event
|
||||||
|
auto subjectName = this->user(e.userId())->displayname();
|
||||||
|
// 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.prevContent() ||
|
||||||
|
e.membership() != e.prevContent()->membership) {
|
||||||
|
return e.membership() == MembershipType::Invite
|
||||||
|
? tr("invited %1 to the room").arg(subjectName)
|
||||||
|
: tr("joined the room");
|
||||||
|
}
|
||||||
|
QString text{};
|
||||||
|
if (e.isRename()) {
|
||||||
|
if (e.displayName().isEmpty())
|
||||||
|
text = tr("cleared their display name");
|
||||||
|
else
|
||||||
|
text = tr("changed their display name to %1")
|
||||||
|
.arg(e.displayName().toHtmlEscaped());
|
||||||
|
}
|
||||||
|
if (e.isAvatarUpdate()) {
|
||||||
|
if (!text.isEmpty())
|
||||||
|
text += " and ";
|
||||||
|
if (e.avatarUrl().isEmpty())
|
||||||
|
text += tr("cleared their avatar");
|
||||||
|
else if (e.prevContent()->avatarUrl.isEmpty())
|
||||||
|
text += tr("set an avatar");
|
||||||
|
else
|
||||||
|
text += tr("updated their avatar");
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
case MembershipType::Leave:
|
||||||
|
if (e.prevContent() &&
|
||||||
|
e.prevContent()->membership == MembershipType::Invite) {
|
||||||
|
return (e.senderId() != e.userId())
|
||||||
|
? tr("withdrew %1's invitation").arg(subjectName)
|
||||||
|
: tr("rejected the invitation");
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpectralRoom::clearBackground() {
|
if (e.prevContent() &&
|
||||||
connection()->callApi<SetAccountDataPerRoomJob>(
|
e.prevContent()->membership == MembershipType::Ban) {
|
||||||
localUser()->id(), id(), backgroundEventType, QJsonObject{});
|
return (e.senderId() != e.userId())
|
||||||
}
|
? tr("unbanned %1").arg(subjectName)
|
||||||
|
: tr("self-unbanned");
|
||||||
QString SpectralRoom::backgroundMediaId() {
|
}
|
||||||
if (!hasAccountData(backgroundEventType))
|
return (e.senderId() != e.userId())
|
||||||
return {};
|
? tr("has put %1 out of the room: %2")
|
||||||
|
.arg(subjectName, e.contentJson()["reason"_ls]
|
||||||
auto url = backgroundUrl();
|
.toString()
|
||||||
return url.authority() + url.path();
|
.toHtmlEscaped())
|
||||||
|
: tr("left the room");
|
||||||
|
case MembershipType::Ban:
|
||||||
|
return (e.senderId() != e.userId())
|
||||||
|
? tr("banned %1 from the room: %2")
|
||||||
|
.arg(subjectName, e.contentJson()["reason"_ls]
|
||||||
|
.toString()
|
||||||
|
.toHtmlEscaped())
|
||||||
|
: tr("self-banned from the room");
|
||||||
|
case MembershipType::Knock:
|
||||||
|
return tr("knocked");
|
||||||
|
default:;
|
||||||
|
}
|
||||||
|
return tr("made something unknown");
|
||||||
|
},
|
||||||
|
[](const RoomAliasesEvent& e) {
|
||||||
|
return tr("has set room aliases on server %1 to: %2")
|
||||||
|
.arg(e.stateKey(), QLocale().createSeparatedList(e.aliases()));
|
||||||
|
},
|
||||||
|
[](const RoomCanonicalAliasEvent& e) {
|
||||||
|
return (e.alias().isEmpty())
|
||||||
|
? tr("cleared the room main alias")
|
||||||
|
: tr("set the room main alias to: %1").arg(e.alias());
|
||||||
|
},
|
||||||
|
[](const RoomNameEvent& e) {
|
||||||
|
return (e.name().isEmpty()) ? tr("cleared the room name")
|
||||||
|
: tr("set the room name to: %1")
|
||||||
|
.arg(e.name().toHtmlEscaped());
|
||||||
|
},
|
||||||
|
[prettyPrint](const RoomTopicEvent& e) {
|
||||||
|
return (e.topic().isEmpty())
|
||||||
|
? tr("cleared the topic")
|
||||||
|
: tr("set the topic to: %1")
|
||||||
|
.arg(prettyPrint
|
||||||
|
? QMatrixClient::prettyPrint(e.topic())
|
||||||
|
: e.topic());
|
||||||
|
},
|
||||||
|
[](const RoomAvatarEvent&) { return tr("changed the room avatar"); },
|
||||||
|
[](const EncryptionEvent&) {
|
||||||
|
return tr("activated End-to-End Encryption");
|
||||||
|
},
|
||||||
|
[](const RoomCreateEvent& e) {
|
||||||
|
return (e.isUpgrade() ? tr("upgraded the room to version %1")
|
||||||
|
: tr("created the room, version %1"))
|
||||||
|
.arg(e.version().isEmpty() ? "1" : e.version().toHtmlEscaped());
|
||||||
|
},
|
||||||
|
[](const StateEventBase& e) {
|
||||||
|
// A small hack for state events from TWIM bot
|
||||||
|
return e.stateKey() == "twim"
|
||||||
|
? tr("updated the database", "TWIM bot updated the database")
|
||||||
|
: e.stateKey().isEmpty()
|
||||||
|
? tr("updated %1 state", "%1 - Matrix event type")
|
||||||
|
.arg(e.matrixType())
|
||||||
|
: tr("updated %1 state for %2",
|
||||||
|
"%1 - Matrix event type, %2 - state key")
|
||||||
|
.arg(e.matrixType(),
|
||||||
|
e.stateKey().toHtmlEscaped());
|
||||||
|
},
|
||||||
|
tr("Unknown event"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpectralRoom::changeAvatar(QUrl localFile) {
|
void SpectralRoom::changeAvatar(QUrl localFile) {
|
||||||
auto job = connection()->uploadFile(localFile.toLocalFile());
|
const auto job = connection()->uploadFile(localFile.toLocalFile());
|
||||||
if (isJobRunning(job)) {
|
if (isJobRunning(job)) {
|
||||||
connect(job, &BaseJob::success, this, [this, job] {
|
connect(job, &BaseJob::success, this, [this, job] {
|
||||||
connection()->callApi<SetRoomStateJob>(
|
connection()->callApi<SetRoomStateJob>(
|
||||||
@@ -297,7 +384,7 @@ void SpectralRoom::addLocalAlias(const QString& alias) {
|
|||||||
if (aliases.contains(alias))
|
if (aliases.contains(alias))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
aliases.append(alias);
|
aliases += alias;
|
||||||
|
|
||||||
setLocalAliases(aliases);
|
setLocalAliases(aliases);
|
||||||
}
|
}
|
||||||
@@ -314,12 +401,12 @@ void SpectralRoom::removeLocalAlias(const QString& alias) {
|
|||||||
|
|
||||||
QString SpectralRoom::markdownToHTML(const QString& markdown) {
|
QString SpectralRoom::markdownToHTML(const QString& markdown) {
|
||||||
const auto str = markdown.toUtf8();
|
const auto str = markdown.toUtf8();
|
||||||
const char* tmp_buf =
|
char* tmp_buf =
|
||||||
cmark_markdown_to_html(str.constData(), str.size(), CMARK_OPT_DEFAULT);
|
cmark_markdown_to_html(str.constData(), str.size(), CMARK_OPT_DEFAULT);
|
||||||
|
|
||||||
std::string html(tmp_buf);
|
const std::string html(tmp_buf);
|
||||||
|
|
||||||
free((char*)tmp_buf);
|
free(tmp_buf);
|
||||||
|
|
||||||
auto result = QString::fromStdString(html).trimmed();
|
auto result = QString::fromStdString(html).trimmed();
|
||||||
|
|
||||||
@@ -332,8 +419,8 @@ QString SpectralRoom::markdownToHTML(const QString& markdown) {
|
|||||||
void SpectralRoom::postArbitaryMessage(const QString& text,
|
void SpectralRoom::postArbitaryMessage(const QString& text,
|
||||||
MessageEventType type,
|
MessageEventType type,
|
||||||
const QString& replyEventId) {
|
const QString& replyEventId) {
|
||||||
auto parsedHTML = markdownToHTML(text);
|
const auto parsedHTML = markdownToHTML(text);
|
||||||
bool isRichText = Qt::mightBeRichText(parsedHTML);
|
const bool isRichText = Qt::mightBeRichText(parsedHTML);
|
||||||
|
|
||||||
if (isRichText) { // Markdown
|
if (isRichText) { // Markdown
|
||||||
postHtmlMessage(text, parsedHTML, type, replyEventId);
|
postHtmlMessage(text, parsedHTML, type, replyEventId);
|
||||||
@@ -463,7 +550,7 @@ void SpectralRoom::toggleReaction(const QString& eventId,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!redactEventIds.isEmpty()) {
|
if (!redactEventIds.isEmpty()) {
|
||||||
for (auto redactEventId : redactEventIds) {
|
for (const auto& redactEventId : redactEventIds) {
|
||||||
redactEvent(redactEventId);
|
redactEvent(redactEventId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -20,20 +20,12 @@ using namespace QMatrixClient;
|
|||||||
|
|
||||||
class SpectralRoom : public Room {
|
class SpectralRoom : public Room {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
Q_PROPERTY(bool hasUsersTyping READ hasUsersTyping NOTIFY typingChanged)
|
|
||||||
Q_PROPERTY(QVariantList usersTyping READ getUsersTyping NOTIFY typingChanged)
|
Q_PROPERTY(QVariantList usersTyping READ getUsersTyping NOTIFY typingChanged)
|
||||||
Q_PROPERTY(QString cachedInput READ cachedInput WRITE setCachedInput NOTIFY
|
Q_PROPERTY(QString cachedInput MEMBER m_cachedInput NOTIFY cachedInputChanged)
|
||||||
cachedInputChanged)
|
Q_PROPERTY(bool hasFileUploading READ hasFileUploading WRITE
|
||||||
Q_PROPERTY(bool hasFileUploading READ hasFileUploading NOTIFY
|
setHasFileUploading NOTIFY hasFileUploadingChanged)
|
||||||
hasFileUploadingChanged)
|
|
||||||
Q_PROPERTY(int fileUploadingProgress READ fileUploadingProgress NOTIFY
|
Q_PROPERTY(int fileUploadingProgress READ fileUploadingProgress NOTIFY
|
||||||
fileUploadingProgressChanged)
|
fileUploadingProgressChanged)
|
||||||
Q_PROPERTY(bool busy READ busy NOTIFY busyChanged)
|
|
||||||
Q_PROPERTY(QUrl backgroundUrl READ backgroundUrl WRITE setBackgroundUrl NOTIFY
|
|
||||||
backgroundChanged)
|
|
||||||
Q_PROPERTY(
|
|
||||||
QString backgroundMediaId READ backgroundMediaId NOTIFY backgroundChanged)
|
|
||||||
// Q_PROPERTY(QUrl avatarUrl READ avatarUrl NOTIFY avatarChanged)
|
|
||||||
Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
|
Q_PROPERTY(QString avatarMediaId READ avatarMediaId NOTIFY avatarChanged
|
||||||
STORED false)
|
STORED false)
|
||||||
|
|
||||||
@@ -42,244 +34,51 @@ class SpectralRoom : public Room {
|
|||||||
QString roomId,
|
QString roomId,
|
||||||
JoinState joinState = {});
|
JoinState joinState = {});
|
||||||
|
|
||||||
const QString& cachedInput() const { return m_cachedInput; }
|
QVariantList getUsersTyping() const;
|
||||||
void setCachedInput(const QString& input) {
|
|
||||||
if (input != m_cachedInput) {
|
|
||||||
m_cachedInput = input;
|
|
||||||
emit cachedInputChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool busy() { return m_busy; }
|
QString lastEvent() const;
|
||||||
void setBusy(bool value) {
|
|
||||||
if (m_busy != value) {
|
|
||||||
m_busy = value;
|
|
||||||
emit busyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hasUsersTyping();
|
|
||||||
QVariantList getUsersTyping();
|
|
||||||
|
|
||||||
QString lastEvent();
|
|
||||||
bool isEventHighlighted(const QMatrixClient::RoomEvent* e) const;
|
bool isEventHighlighted(const QMatrixClient::RoomEvent* e) const;
|
||||||
|
|
||||||
QDateTime lastActiveTime();
|
QDateTime lastActiveTime() const;
|
||||||
|
|
||||||
bool hasFileUploading() { return m_hasFileUploading; }
|
bool hasFileUploading() const { return m_hasFileUploading; }
|
||||||
void setHasFileUploading(bool value) {
|
void setHasFileUploading(bool value) {
|
||||||
if (m_hasFileUploading != value) {
|
if (value == m_hasFileUploading) {
|
||||||
m_hasFileUploading = value;
|
return;
|
||||||
emit hasFileUploadingChanged();
|
|
||||||
}
|
}
|
||||||
|
m_hasFileUploading = value;
|
||||||
|
emit hasFileUploadingChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
int fileUploadingProgress() { return m_fileUploadingProgress; }
|
int fileUploadingProgress() const { return m_fileUploadingProgress; }
|
||||||
void setFileUploadingProgress(int value) {
|
void setFileUploadingProgress(int value) {
|
||||||
if (m_fileUploadingProgress != value) {
|
if (m_fileUploadingProgress == value) {
|
||||||
m_fileUploadingProgress = value;
|
return;
|
||||||
emit fileUploadingProgressChanged();
|
|
||||||
}
|
}
|
||||||
|
m_fileUploadingProgress = value;
|
||||||
|
emit fileUploadingProgressChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_INVOKABLE int savedTopVisibleIndex() const;
|
Q_INVOKABLE int savedTopVisibleIndex() const;
|
||||||
Q_INVOKABLE int savedBottomVisibleIndex() const;
|
Q_INVOKABLE int savedBottomVisibleIndex() const;
|
||||||
Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex);
|
Q_INVOKABLE void saveViewport(int topIndex, int bottomIndex);
|
||||||
|
|
||||||
Q_INVOKABLE void getPreviousContent(int limit = 10);
|
Q_INVOKABLE QVariantList getUsers(const QString& keyword) const;
|
||||||
|
|
||||||
Q_INVOKABLE QVariantList getUsers(const QString& prefix);
|
|
||||||
|
|
||||||
Q_INVOKABLE QUrl urlToMxcUrl(QUrl mxcUrl);
|
Q_INVOKABLE QUrl urlToMxcUrl(QUrl mxcUrl);
|
||||||
|
|
||||||
QUrl avatarUrl() const {
|
QString avatarMediaId() const;
|
||||||
if (!Room::avatarUrl().isEmpty())
|
|
||||||
return Room::avatarUrl();
|
|
||||||
|
|
||||||
// Use the first (excluding self) user's avatar for direct chats
|
QString eventToString(const RoomEvent& evt,
|
||||||
const auto dcUsers = directChatUsers();
|
Qt::TextFormat format = Qt::PlainText) const;
|
||||||
for (auto* u : dcUsers)
|
|
||||||
if (u != localUser())
|
|
||||||
return u->avatarUrl();
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QString avatarMediaId() const {
|
|
||||||
if (!Room::avatarMediaId().isEmpty())
|
|
||||||
return Room::avatarMediaId();
|
|
||||||
|
|
||||||
// Use the first (excluding self) user's avatar for direct chats
|
|
||||||
const auto dcUsers = directChatUsers();
|
|
||||||
for (auto* u : dcUsers)
|
|
||||||
if (u != localUser())
|
|
||||||
return u->avatarMediaId();
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
QUrl backgroundUrl();
|
|
||||||
Q_INVOKABLE void setBackgroundUrl(QUrl url);
|
|
||||||
Q_INVOKABLE void clearBackground();
|
|
||||||
Q_INVOKABLE void setBackgroundFromLocalFile(QUrl url);
|
|
||||||
|
|
||||||
QString backgroundMediaId();
|
|
||||||
|
|
||||||
template <typename BaseEventT>
|
|
||||||
QString eventToString(const BaseEventT& evt,
|
|
||||||
Qt::TextFormat format = Qt::PlainText) {
|
|
||||||
bool prettyPrint = (format == Qt::RichText);
|
|
||||||
|
|
||||||
using namespace QMatrixClient;
|
|
||||||
return visit(
|
|
||||||
evt,
|
|
||||||
[this, prettyPrint](const RoomMessageEvent& e) {
|
|
||||||
using namespace MessageEventContent;
|
|
||||||
|
|
||||||
if (prettyPrint && e.hasTextContent() &&
|
|
||||||
e.mimeType().name() != "text/plain")
|
|
||||||
return static_cast<const TextContent*>(e.content())->body;
|
|
||||||
if (e.hasFileContent()) {
|
|
||||||
auto fileCaption =
|
|
||||||
e.content()->fileInfo()->originalName.toHtmlEscaped();
|
|
||||||
if (fileCaption.isEmpty()) {
|
|
||||||
if (prettyPrint)
|
|
||||||
fileCaption = this->prettyPrint(e.plainBody());
|
|
||||||
else
|
|
||||||
fileCaption = e.plainBody();
|
|
||||||
}
|
|
||||||
return !fileCaption.isEmpty() ? fileCaption : tr("a file");
|
|
||||||
}
|
|
||||||
return prettyPrint ? this->prettyPrint(e.plainBody()) : e.plainBody();
|
|
||||||
},
|
|
||||||
[this](const RoomMemberEvent& e) {
|
|
||||||
// FIXME: Rewind to the name that was at the time of this event
|
|
||||||
auto subjectName = this->user(e.userId())->displayname();
|
|
||||||
// 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.prevContent() ||
|
|
||||||
e.membership() != e.prevContent()->membership) {
|
|
||||||
return e.membership() == MembershipType::Invite
|
|
||||||
? tr("invited %1 to the room").arg(subjectName)
|
|
||||||
: tr("joined the room");
|
|
||||||
}
|
|
||||||
QString text{};
|
|
||||||
if (e.isRename()) {
|
|
||||||
if (e.displayName().isEmpty())
|
|
||||||
text = tr("cleared their display name");
|
|
||||||
else
|
|
||||||
text = tr("changed their display name to %1")
|
|
||||||
.arg(e.displayName().toHtmlEscaped());
|
|
||||||
}
|
|
||||||
if (e.isAvatarUpdate()) {
|
|
||||||
if (!text.isEmpty())
|
|
||||||
text += " and ";
|
|
||||||
if (e.avatarUrl().isEmpty())
|
|
||||||
text += tr("cleared their avatar");
|
|
||||||
else if (e.prevContent()->avatarUrl.isEmpty())
|
|
||||||
text += tr("set an avatar");
|
|
||||||
else
|
|
||||||
text += tr("updated their avatar");
|
|
||||||
}
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
case MembershipType::Leave:
|
|
||||||
if (e.prevContent() &&
|
|
||||||
e.prevContent()->membership == MembershipType::Invite) {
|
|
||||||
return (e.senderId() != e.userId())
|
|
||||||
? tr("withdrew %1's invitation").arg(subjectName)
|
|
||||||
: tr("rejected the invitation");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e.prevContent() &&
|
|
||||||
e.prevContent()->membership == MembershipType::Ban) {
|
|
||||||
return (e.senderId() != e.userId())
|
|
||||||
? tr("unbanned %1").arg(subjectName)
|
|
||||||
: tr("self-unbanned");
|
|
||||||
}
|
|
||||||
return (e.senderId() != e.userId())
|
|
||||||
? tr("has put %1 out of the room: %2")
|
|
||||||
.arg(subjectName, e.contentJson()["reason"_ls]
|
|
||||||
.toString()
|
|
||||||
.toHtmlEscaped())
|
|
||||||
: tr("left the room");
|
|
||||||
case MembershipType::Ban:
|
|
||||||
return (e.senderId() != e.userId())
|
|
||||||
? tr("banned %1 from the room: %2")
|
|
||||||
.arg(subjectName, e.contentJson()["reason"_ls]
|
|
||||||
.toString()
|
|
||||||
.toHtmlEscaped())
|
|
||||||
: tr("self-banned from the room");
|
|
||||||
case MembershipType::Knock:
|
|
||||||
return tr("knocked");
|
|
||||||
default:;
|
|
||||||
}
|
|
||||||
return tr("made something unknown");
|
|
||||||
},
|
|
||||||
[](const RoomAliasesEvent& e) {
|
|
||||||
return tr("has set room aliases on server %1 to: %2")
|
|
||||||
.arg(e.stateKey(), QLocale().createSeparatedList(e.aliases()));
|
|
||||||
},
|
|
||||||
[](const RoomCanonicalAliasEvent& e) {
|
|
||||||
return (e.alias().isEmpty())
|
|
||||||
? tr("cleared the room main alias")
|
|
||||||
: tr("set the room main alias to: %1").arg(e.alias());
|
|
||||||
},
|
|
||||||
[](const RoomNameEvent& e) {
|
|
||||||
return (e.name().isEmpty()) ? tr("cleared the room name")
|
|
||||||
: tr("set the room name to: %1")
|
|
||||||
.arg(e.name().toHtmlEscaped());
|
|
||||||
},
|
|
||||||
[this, prettyPrint](const RoomTopicEvent& e) {
|
|
||||||
return (e.topic().isEmpty())
|
|
||||||
? tr("cleared the topic")
|
|
||||||
: tr("set the topic to: %1")
|
|
||||||
.arg(prettyPrint ? this->prettyPrint(e.topic())
|
|
||||||
: e.topic());
|
|
||||||
},
|
|
||||||
[](const RoomAvatarEvent&) { return tr("changed the room avatar"); },
|
|
||||||
[](const EncryptionEvent&) {
|
|
||||||
return tr("activated End-to-End Encryption");
|
|
||||||
},
|
|
||||||
[](const RoomCreateEvent& e) {
|
|
||||||
return (e.isUpgrade() ? tr("upgraded the room to version %1")
|
|
||||||
: tr("created the room, version %1"))
|
|
||||||
.arg(e.version().isEmpty() ? "1" : e.version().toHtmlEscaped());
|
|
||||||
},
|
|
||||||
[](const StateEventBase& e) {
|
|
||||||
// A small hack for state events from TWIM bot
|
|
||||||
return e.stateKey() == "twim"
|
|
||||||
? tr("updated the database",
|
|
||||||
"TWIM bot updated the database")
|
|
||||||
: e.stateKey().isEmpty()
|
|
||||||
? tr("updated %1 state", "%1 - Matrix event type")
|
|
||||||
.arg(e.matrixType())
|
|
||||||
: tr("updated %1 state for %2",
|
|
||||||
"%1 - Matrix event type, %2 - state key")
|
|
||||||
.arg(e.matrixType(),
|
|
||||||
e.stateKey().toHtmlEscaped());
|
|
||||||
},
|
|
||||||
tr("Unknown event"));
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const QString backgroundEventType = "org.eu.encom.spectral.background";
|
|
||||||
|
|
||||||
QString m_cachedInput;
|
QString m_cachedInput;
|
||||||
QSet<const QMatrixClient::RoomEvent*> highlights;
|
QSet<const QMatrixClient::RoomEvent*> highlights;
|
||||||
|
|
||||||
bool m_hasFileUploading = false;
|
bool m_hasFileUploading = false;
|
||||||
int m_fileUploadingProgress = 0;
|
int m_fileUploadingProgress = 0;
|
||||||
|
|
||||||
bool m_busy = false;
|
|
||||||
|
|
||||||
void checkForHighlights(const QMatrixClient::TimelineItem& ti);
|
void checkForHighlights(const QMatrixClient::TimelineItem& ti);
|
||||||
|
|
||||||
void onAddNewTimelineEvents(timeline_iter_t from) override;
|
void onAddNewTimelineEvents(timeline_iter_t from) override;
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ void UserListModel::setRoom(QMatrixClient::Room* room) {
|
|||||||
emit roomChanged();
|
emit roomChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
QMatrixClient::User* UserListModel::userAt(QModelIndex index) {
|
QMatrixClient::User* UserListModel::userAt(QModelIndex index) const {
|
||||||
if (index.row() < 0 || index.row() >= m_users.size())
|
if (index.row() < 0 || index.row() >= m_users.size())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return m_users.at(index.row());
|
return m_users.at(index.row());
|
||||||
@@ -133,9 +133,11 @@ int UserListModel::findUserPos(const QString& username) const {
|
|||||||
|
|
||||||
QHash<int, QByteArray> UserListModel::roleNames() const {
|
QHash<int, QByteArray> UserListModel::roleNames() const {
|
||||||
QHash<int, QByteArray> roles;
|
QHash<int, QByteArray> roles;
|
||||||
|
|
||||||
roles[NameRole] = "name";
|
roles[NameRole] = "name";
|
||||||
roles[UserIDRole] = "userId";
|
roles[UserIDRole] = "userId";
|
||||||
roles[AvatarRole] = "avatar";
|
roles[AvatarRole] = "avatar";
|
||||||
roles[ObjectRole] = "user";
|
roles[ObjectRole] = "user";
|
||||||
|
|
||||||
return roles;
|
return roles;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ class UserListModel : public QAbstractListModel {
|
|||||||
|
|
||||||
UserListModel(QObject* parent = nullptr);
|
UserListModel(QObject* parent = nullptr);
|
||||||
|
|
||||||
QMatrixClient::Room* room() { return m_currentRoom; }
|
QMatrixClient::Room* room() const { return m_currentRoom; }
|
||||||
void setRoom(QMatrixClient::Room* room);
|
void setRoom(QMatrixClient::Room* room);
|
||||||
User* userAt(QModelIndex index);
|
User* userAt(QModelIndex index) const;
|
||||||
|
|
||||||
QVariant data(const QModelIndex& index, int role = NameRole) const override;
|
QVariant data(const QModelIndex& index, int role = NameRole) const override;
|
||||||
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
|
||||||
|
|||||||
Reference in New Issue
Block a user