Compare commits

..

6 Commits

Author SHA1 Message Date
Tomaz Canabrava
7cc68d2658 Adapt to newer API 2024-04-19 10:42:03 +02:00
Tomaz Canabrava
f4b87caefe Adapt to new AUP 2024-04-19 10:18:39 +02:00
Tomaz Canabrava
07a9497f4c Fix bad commit 2024-04-19 10:18:31 +02:00
Tomaz Canabrava
35f1ace458 Adapt to newer API
TODO: There are some missing methods and I do not know what to do there
2024-04-19 10:04:13 +02:00
Tomaz Canabrava
11dd0ee151 Adapt to new Avatar API 2024-04-19 10:03:49 +02:00
Tomaz Canabrava
07e200c74f Adapt to breaking changes in libQuotient
localUser() -> localMember()
2024-04-19 09:45:11 +02:00
135 changed files with 8350 additions and 10216 deletions

View File

@@ -110,7 +110,7 @@
{
"type": "git",
"url": "https://github.com/quotient-im/libQuotient.git",
"branch": "0.8.x",
"branch": "dev",
"disable-submodules": true
}
],

View File

@@ -9,7 +9,7 @@ cmake_minimum_required(VERSION 3.16)
# KDE Applications version, managed by release script.
set(RELEASE_SERVICE_VERSION_MAJOR "24")
set(RELEASE_SERVICE_VERSION_MINOR "04")
set(RELEASE_SERVICE_VERSION_MICRO "80")
set(RELEASE_SERVICE_VERSION_MICRO "70")
set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_VERSION_MINOR}.${RELEASE_SERVICE_VERSION_MICRO}")
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})

View File

@@ -105,7 +105,7 @@ void EventHandlerTest::author()
auto eventHandlerAuthor = eventHandler.getAuthor();
QCOMPARE(eventHandlerAuthor["isLocalUser"_ls], author->id() == room->localUser()->id());
QCOMPARE(eventHandlerAuthor["isLocalUser"_ls], author->id() == room->localMember().id());
QCOMPARE(eventHandlerAuthor["id"_ls], author->id());
QCOMPARE(eventHandlerAuthor["displayName"_ls], author->displayname(room));
QCOMPARE(eventHandlerAuthor["avatarSource"_ls], room->avatarForMember(author));
@@ -390,7 +390,7 @@ void EventHandlerTest::replyAuthor()
auto eventHandlerReplyAuthor = eventHandler.getReplyAuthor();
QCOMPARE(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localUser()->id());
QCOMPARE(eventHandlerReplyAuthor["isLocalUser"_ls], replyAuthor->id() == room->localMember().id());
QCOMPARE(eventHandlerReplyAuthor["id"_ls], replyAuthor->id());
QCOMPARE(eventHandlerReplyAuthor["displayName"_ls], replyAuthor->displayname(room));
QCOMPARE(eventHandlerReplyAuthor["avatarSource"_ls], room->avatarForMember(replyAuthor));

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -204,6 +204,7 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/InviteUserPage.qml
qml/ImageEditorPage.qml
qml/NeochatMaximizeComponent.qml
qml/FancyEffectsContainer.qml
qml/TypingPane.qml
qml/QuickSwitcher.qml
qml/HoverActions.qml
@@ -280,6 +281,9 @@ qt_add_qml_module(neochat URI org.kde.neochat NO_PLUGIN
qml/ConfirmLeaveDialog.qml
qml/CodeMaximizeComponent.qml
qml/EditStateDialog.qml
RESOURCES
qml/confetti.png
qml/glowdot.png
)
add_subdirectory(settings)

View File

@@ -14,7 +14,6 @@
#include "models/actionsmodel.h"
#include "neochatconfig.h"
#include "texthandler.h"
#include "utils.h"
using namespace Quotient;
@@ -92,7 +91,7 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
for (auto it = m_room->messageEvents().crbegin(); it != m_room->messageEvents().crend(); it++) {
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
if (event->senderId() == m_room->localUser()->id() && event->hasTextContent()) {
if (event->senderId() == m_room->localMember().id() && event->hasTextContent()) {
QString originalString;
if (event->content()) {
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
@@ -146,26 +145,6 @@ void ActionsHandler::handleMessage(const QString &text, QString handledText, Cha
return;
}
// We want to add back the <mx-reply> if it's in the original message but not in the edit, to preserve the reply.
for (auto it = m_room->messageEvents().crbegin(); it != m_room->messageEvents().crend(); it++) {
if (const auto event = eventCast<const RoomMessageEvent>(&**it)) {
if (event->senderId() == m_room->localUser()->id() && event->hasTextContent()) {
QString originalString;
if (event->content()) {
originalString = static_cast<const Quotient::EventContent::TextContent *>(event->content())->body;
} else {
originalString = event->plainBody();
}
const QRegularExpression exp(TextRegex::removeRichReply);
const auto match = exp.match(originalString);
if (match.hasCaptured(0) && !handledText.contains(TextRegex::removeRichReply)) {
handledText.prepend(match.captured(0));
}
}
}
}
m_room->postMessage(text, handledText, messageType, chatBarCache->replyId(), chatBarCache->editId(), chatBarCache->threadId());
}

View File

@@ -19,6 +19,7 @@
#include <signal.h>
#include <Quotient/accountregistry.h>
#include <Quotient/connection.h>
#include <Quotient/csapi/logout.h>
#include <Quotient/csapi/notifications.h>
#include <Quotient/eventstats.h>

View File

@@ -117,7 +117,7 @@ private:
Quotient::AccountRegistry m_accountRegistry;
QStringList m_accountsLoading;
QMap<QString, QPointer<NeoChatConnection>> m_connectionsLoading;
QMap<QString, QPointer<Quotient::Connection>> m_connectionsLoading;
QString m_endpoint;
private Q_SLOTS:

View File

@@ -15,12 +15,6 @@ FormCard.FormCardPage {
FormCard.FormCard {
Layout.topMargin: Kirigami.Units.largeSpacing
FormCard.FormCheckDelegate {
text: i18nc("@option:check", "Show hidden events in the timeline")
checked: Config.showAllEvents
onToggled: Config.showAllEvents = checked
}
FormCard.FormCheckDelegate {
id: roomAccountDataVisibleCheck
text: i18nc("@option:check Enable the matrix 'threads' feature", "Always allow device verification")
@@ -29,14 +23,5 @@ FormCard.FormCardPage {
onToggled: Config.alwaysVerifyDevice = checked
}
FormCard.FormCheckDelegate {
text: i18nc("@option:check", "Show focus in window header")
checked: Config.windowTitleFocus
onToggled: {
Config.windowTitleFocus = checked;
Config.save();
}
}
}
}

View File

@@ -25,10 +25,9 @@ ColumnLayout {
text: i18n("Room")
textRole: "escapedDisplayName"
valueRole: "roomId"
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.EscapedDisplayNameRole)
displayText: RoomManager.roomListModel.data(RoomManager.roomListModel.index(currentIndex, 0), RoomListModel.DisplayNameRole)
model: RoomManager.roomListModel
currentIndex: 0
displayMode: FormCard.FormComboBoxDelegate.Page
Component.onCompleted: currentIndex = RoomManager.roomListModel.rowForRoom(root.room)
onCurrentValueChanged: root.room = RoomManager.roomListModel.roomByAliasOrId(roomComboBox.currentValue)
}

View File

@@ -21,6 +21,7 @@ public:
* @brief Defines the room list categories a room can be assigned.
*/
enum Types {
Search = 0, /**< So we can show a search delegate if needed, e.g. collapsed mode. */
Invited, /**< The user has been invited to the room. */
Favorite, /**< The room is set as a favourite. */
Direct, /**< The room is a direct chat. */
@@ -67,6 +68,8 @@ public:
return i18n("Low priority");
case NeoChatRoomType::Space:
return i18n("Spaces");
case NeoChatRoomType::Search:
return i18n("Search");
default:
return {};
}
@@ -86,6 +89,8 @@ public:
return QStringLiteral("object-order-lower");
case NeoChatRoomType::Space:
return QStringLiteral("group");
case NeoChatRoomType::Search:
return QStringLiteral("search");
default:
return QStringLiteral("tools-report-bug");
}

View File

@@ -73,7 +73,7 @@ QVariantMap EventHandler::getAuthor(bool isPending) const
return m_room->getUser(nullptr);
}
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
const auto author = isPending ? m_room->localMember() : m_room->user(m_event->senderId());
return m_room->getUser(author);
}
@@ -96,7 +96,7 @@ QString EventHandler::getAuthorDisplayName(bool isPending) const
}
return previousDisplayName;
} else {
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
const auto author = isPending ? m_room->localMember() : m_room->user(m_event->senderId());
return m_room->htmlSafeMemberName(author->id());
}
}
@@ -112,7 +112,7 @@ QString EventHandler::singleLineAuthorDisplayname(bool isPending) const
return {};
}
const auto author = isPending ? m_room->localUser() : m_room->user(m_event->senderId());
const auto author = isPending ? m_room->localMember() : m_room->user(m_event->senderId());
auto displayName = m_room->safeMemberName(author->id());
displayName.replace(QStringLiteral("<br>\n"), QStringLiteral(" "));
displayName.replace(QStringLiteral("<br>"), QStringLiteral(" "));
@@ -963,7 +963,7 @@ bool EventHandler::hasReadMarkers() const
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localUser()->id());
userIds.remove(m_room->localMember().id());
return userIds.size() > 0;
}
@@ -979,7 +979,7 @@ QVariantList EventHandler::getReadMarkers(int maxMarkers) const
}
auto userIds_temp = m_room->userIdsAtEvent(m_event->id());
userIds_temp.remove(m_room->localUser()->id());
userIds_temp.remove(m_room->localMember().id());
auto userIds = userIds_temp.values();
if (userIds.count() > maxMarkers) {
@@ -1008,7 +1008,7 @@ QString EventHandler::getNumberExcessReadMarkers(int maxMarkers) const
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localUser()->id());
userIds.remove(m_room->localMember().id());
if (userIds.count() > maxMarkers) {
return QStringLiteral("+ ") + QString::number(userIds.count() - maxMarkers);
@@ -1029,7 +1029,7 @@ QString EventHandler::getReadMarkersString() const
}
auto userIds = m_room->userIdsAtEvent(m_event->id());
userIds.remove(m_room->localUser()->id());
userIds.remove(m_room->localMember().id());
/**
* The string ends up in the form

View File

@@ -4,6 +4,7 @@
#include "login.h"
#include <Quotient/accountregistry.h>
#include <Quotient/connection.h>
#include <Quotient/qt_connection_util.h>
#include "controller.h"
@@ -53,7 +54,7 @@ void LoginHelper::init()
m_connection = new NeoChatConnection();
}
m_connection->resolveServer(m_matrixId);
connectSingleShot(m_connection.get(), &Connection::loginFlowsChanged, this, [this]() {
connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
setHomeserverReachable(true);
m_testing = false;
Q_EMIT testingChanged();
@@ -99,7 +100,7 @@ void LoginHelper::init()
Q_EMIT Controller::instance().errorOccured(i18n("Network Error"), std::move(error));
});
connectSingleShot(m_connection.get(), &Connection::syncDone, this, [this]() {
connectSingleShot(m_connection, &Connection::syncDone, this, [this]() {
Q_EMIT loaded();
});
}
@@ -181,7 +182,7 @@ QUrl LoginHelper::ssoUrl() const
void LoginHelper::loginWithSso()
{
m_connection->resolveServer(m_matrixId);
connectSingleShot(m_connection.get(), &Connection::loginFlowsChanged, this, [this]() {
connectSingleShot(m_connection, &Connection::loginFlowsChanged, this, [this]() {
SsoSession *session = m_connection->prepareForSso(m_deviceName);
m_ssoUrl = session->ssoUrl();
Q_EMIT ssoUrlChanged();

View File

@@ -146,7 +146,7 @@ private:
QString m_deviceName;
bool m_supportsSso = false;
bool m_supportsPassword = false;
QPointer<NeoChatConnection> m_connection;
NeoChatConnection *m_connection = nullptr;
QUrl m_ssoUrl;
bool m_testing = false;
bool m_isLoggingIn = false;

View File

@@ -14,6 +14,8 @@
#include "neochatconnection.h"
#include <Quotient/connection.h>
using namespace Quotient;
ThumbnailResponse::ThumbnailResponse(QString id, QSize size, NeoChatConnection *connection)

View File

@@ -35,7 +35,7 @@ private:
QSize requestedSize;
const QString localFile;
Quotient::MediaThumbnailJob *job = nullptr;
QPointer<NeoChatConnection> m_connection;
NeoChatConnection *m_connection;
QImage image;
QString errorStr;
@@ -75,6 +75,6 @@ public:
QQuickImageResponse *requestImageResponse(const QString &id, const QSize &requestedSize) override;
private:
QPointer<NeoChatConnection> m_connection;
NeoChatConnection *m_connection = nullptr;
MatrixImageProvider() = default;
};

View File

@@ -10,8 +10,6 @@
#include <Quotient/events/eventcontent.h>
#include <qcoro/qcorosignal.h>
#include "neochatconnection.h"
using namespace Quotient;
AccountEmoticonModel::AccountEmoticonModel(QObject *parent)
@@ -79,12 +77,12 @@ QHash<int, QByteArray> AccountEmoticonModel::roleNames() const
};
}
NeoChatConnection *AccountEmoticonModel::connection() const
Connection *AccountEmoticonModel::connection() const
{
return m_connection;
}
void AccountEmoticonModel::setConnection(NeoChatConnection *connection)
void AccountEmoticonModel::setConnection(Connection *connection)
{
if (m_connection) {
disconnect(m_connection, nullptr, this, nullptr);

View File

@@ -12,7 +12,7 @@
#include <QPointer>
#include <QQmlEngine>
class NeoChatConnection;
#include <Quotient/connection.h>
/**
* @class AccountEmoticonModel
@@ -29,7 +29,7 @@ class AccountEmoticonModel : public QAbstractListModel
/**
* @brief The connection to get emoticons from.
*/
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
public:
enum Roles {
@@ -63,8 +63,8 @@ public:
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *connection);
/**
* @brief Deletes the emoticon at the given index.
@@ -96,7 +96,7 @@ Q_SIGNALS:
private:
std::optional<Quotient::ImagePackEventContent> m_images;
QPointer<NeoChatConnection> m_connection;
QPointer<Quotient::Connection> m_connection;
QCoro::Task<void> doSetEmoticonImage(int index, QUrl source);
QCoro::Task<void> doAddEmoticon(QUrl source, QString shortcode, QString description, QString type);

View File

@@ -4,7 +4,6 @@
#include "actionsmodel.h"
#include "chatbarcache.h"
#include "neochatconnection.h"
#include "neochatroom.h"
#include "roommanager.h"
#include <Quotient/events/roommemberevent.h>
@@ -202,7 +201,7 @@ QList<ActionsModel::Action> actions{
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("<user> is banned from this room.", "%1 is banned from this room.", text));
return QString();
}
if (room->localUser()->id() == text) {
if (room->localMember().id() == text) {
Q_EMIT room->showMessage(NeoChatRoom::Positive, i18n("You are already in this room."));
return QString();
}
@@ -261,7 +260,7 @@ QList<ActionsModel::Action> actions{
return QString();
}
Q_EMIT room->showMessage(NeoChatRoom::Info, i18nc("Knocking room <roomname>.", "Knocking room %1.", text));
auto connection = dynamic_cast<NeoChatConnection *>(room->connection());
auto connection = room->connection();
const auto knownServer = roomName.mid(roomName.indexOf(":"_ls) + 1);
if (parts.length() >= 2) {
RoomManager::instance().knockRoom(connection, roomName, parts[1], QStringList{knownServer});
@@ -431,11 +430,11 @@ QList<ActionsModel::Action> actions{
if (!plEvent) {
return QString();
}
if (plEvent->ban() > plEvent->powerLevelForUser(room->localUser()->id())) {
if (plEvent->ban() > plEvent->powerLevelForUser(room->localMember().id())) {
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to ban users from this room."));
return QString();
}
if (plEvent->powerLevelForUser(room->localUser()->id()) <= plEvent->powerLevelForUser(parts[0])) {
if (plEvent->powerLevelForUser(room->localMember().id()) <= plEvent->powerLevelForUser(parts[0])) {
Q_EMIT room->showMessage(
NeoChatRoom::Error,
i18nc("You are not allowed to ban <username> from this room.", "You are not allowed to ban %1 from this room.", parts[0]));
@@ -464,7 +463,7 @@ QList<ActionsModel::Action> actions{
if (!plEvent) {
return QString();
}
if (plEvent->ban() > plEvent->powerLevelForUser(room->localUser()->id())) {
if (plEvent->ban() > plEvent->powerLevelForUser(room->localMember().id())) {
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to unban users from this room."));
return QString();
}
@@ -495,7 +494,7 @@ QList<ActionsModel::Action> actions{
i18nc("'<text>' does not look like a matrix id.", "'%1' does not look like a matrix id.", parts[0]));
return QString();
}
if (parts[0] == room->localUser()->id()) {
if (parts[0] == room->localMember().id()) {
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You cannot kick yourself from the room."));
return QString();
}
@@ -508,11 +507,11 @@ QList<ActionsModel::Action> actions{
return QString();
}
auto kick = plEvent->kick();
if (plEvent->powerLevelForUser(room->localUser()->id()) < kick) {
if (plEvent->powerLevelForUser(room->localMember().id()) < kick) {
Q_EMIT room->showMessage(NeoChatRoom::Error, i18n("You are not allowed to kick users from this room."));
return QString();
}
if (plEvent->powerLevelForUser(room->localUser()->id()) <= plEvent->powerLevelForUser(parts[0])) {
if (plEvent->powerLevelForUser(room->localMember().id()) <= plEvent->powerLevelForUser(parts[0])) {
Q_EMIT room->showMessage(
NeoChatRoom::Error,
i18nc("You are not allowed to kick <username> from this room", "You are not allowed to kick %1 from this room.", parts[0]));

View File

@@ -110,7 +110,7 @@ Q_SIGNALS:
private:
explicit CustomEmojiModel(QObject *parent = nullptr);
QList<CustomEmoji> m_emojis;
QPointer<NeoChatConnection> m_connection;
NeoChatConnection *m_connection = nullptr;
void fetchEmojis();
};

View File

@@ -5,8 +5,7 @@
#include "customemojimodel.h"
#include <QRegularExpression>
class NeoChatConnection;
#include <connection.h>
struct CustomEmoji {
QString name; // with :semicolons:
@@ -15,6 +14,6 @@ struct CustomEmoji {
};
struct CustomEmojiModel::Private {
QPointer<NeoChatConnection> connection;
Quotient::Connection *conn = nullptr;
QList<CustomEmoji> emojies;
};

View File

@@ -11,10 +11,9 @@
#include <KLocalizedString>
#include <Quotient/csapi/device_management.h>
#include <Quotient/connection.h>
#include <Quotient/user.h>
#include "neochatconnection.h"
using namespace Quotient;
DevicesModel::DevicesModel(QObject *parent)
@@ -153,12 +152,12 @@ void DevicesModel::setName(const QString &deviceId, const QString &name)
});
}
NeoChatConnection *DevicesModel::connection() const
Connection *DevicesModel::connection() const
{
return m_connection;
}
void DevicesModel::setConnection(NeoChatConnection *connection)
void DevicesModel::setConnection(Connection *connection)
{
if (m_connection) {
disconnect(m_connection, nullptr, this, nullptr);

View File

@@ -9,7 +9,10 @@
#include <Quotient/csapi/definitions/client_device.h>
class NeoChatConnection;
namespace Quotient
{
class Connection;
}
/**
* @class DevicesModel
@@ -28,7 +31,7 @@ class DevicesModel : public QAbstractListModel
/**
* @brief The current connection that the model is getting its devices from.
*/
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged REQUIRED)
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged REQUIRED)
public:
/**
@@ -85,8 +88,9 @@ public:
explicit DevicesModel(QObject *parent = nullptr);
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *connection);
Q_SIGNALS:
void connectionChanged();
@@ -95,5 +99,5 @@ Q_SIGNALS:
private:
void fetchDevices();
QList<Quotient::Device> m_devices;
QPointer<NeoChatConnection> m_connection;
QPointer<Quotient::Connection> m_connection;
};

View File

@@ -246,86 +246,70 @@ void MessageContentModel::updateComponents(bool isEditing)
if (eventCast<const Quotient::RoomMessageEvent>(m_event)
&& eventCast<const Quotient::RoomMessageEvent>(m_event)->rawMsgtype() == QStringLiteral("m.key.verification.request")) {
m_components += MessageComponent{MessageComponentType::Verification, QString(), {}};
endResetModel();
return;
}
if (m_event->isRedacted()) {
m_components += MessageComponent{MessageComponentType::Text, QString(), {}};
endResetModel();
return;
}
EventHandler eventHandler(m_room, m_event);
if (eventHandler.hasReply()) {
if (m_room->findInTimeline(eventHandler.getReplyId()) == m_room->historyEdge()) {
m_components += MessageComponent{MessageComponentType::ReplyLoad, QString(), {}};
m_room->loadReply(m_event->id(), eventHandler.getReplyId());
} else {
m_components += MessageComponent{MessageComponentType::Reply, QString(), {}};
}
}
if (isEditing) {
m_components += MessageComponent{MessageComponentType::Edit, QString(), {}};
} else {
m_components.append(componentsForType(eventHandler.messageComponentType()));
}
EventHandler eventHandler(m_room, m_event);
if (eventHandler.hasReply()) {
if (m_room->findInTimeline(eventHandler.getReplyId()) == m_room->historyEdge()) {
m_components += MessageComponent{MessageComponentType::ReplyLoad, QString(), {}};
m_room->loadReply(m_event->id(), eventHandler.getReplyId());
} else {
m_components += MessageComponent{MessageComponentType::Reply, QString(), {}};
}
}
if (m_linkPreviewer != nullptr) {
if (m_linkPreviewer->loaded()) {
m_components += MessageComponent{MessageComponentType::LinkPreview, QString(), {}};
if (isEditing) {
m_components += MessageComponent{MessageComponentType::Edit, QString(), {}};
} else if (m_event->isRedacted()) {
m_components += MessageComponent{MessageComponentType::Text, QString(), {}};
} else {
m_components += MessageComponent{MessageComponentType::LinkPreviewLoad, QString(), {}};
if (eventHandler.messageComponentType() == MessageComponentType::Text) {
const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event);
auto body = EventHandler::rawMessageBody(*event);
m_components.append(TextHandler().textComponents(body, EventHandler::messageBodyInputFormat(*event), m_room, event, event->isReplaced()));
} else if (eventHandler.messageComponentType() == MessageComponentType::File) {
m_components += MessageComponent{MessageComponentType::File, QString(), {}};
if (m_emptyItinerary) {
auto fileTransferInfo = fileInfo();
#ifndef Q_OS_ANDROID
KSyntaxHighlighting::Repository repository;
const auto definitionForFile = repository.definitionForFileName(fileTransferInfo.localPath.toString());
if (definitionForFile.isValid() || QFileInfo(fileTransferInfo.localPath.path()).suffix() == QStringLiteral("txt")) {
QFile file(fileTransferInfo.localPath.path());
file.open(QIODevice::ReadOnly);
m_components += MessageComponent{MessageComponentType::Code,
QString::fromStdString(file.readAll().toStdString()),
{{QStringLiteral("class"), definitionForFile.name()}}};
}
#endif
if (FileType::instance().fileHasImage(fileTransferInfo.localPath)) {
QImageReader reader(fileTransferInfo.localPath.path());
m_components += MessageComponent{MessageComponentType::Pdf, QString(), {{QStringLiteral("size"), reader.size()}}};
}
} else {
updateItineraryModel();
if (m_itineraryModel != nullptr) {
m_components += MessageComponent{MessageComponentType::Itinerary, QString(), {}};
}
}
} else {
m_components += MessageComponent{eventHandler.messageComponentType(), QString(), {}};
}
}
if (m_linkPreviewer != nullptr) {
if (m_linkPreviewer->loaded()) {
m_components += MessageComponent{MessageComponentType::LinkPreview, QString(), {}};
} else {
m_components += MessageComponent{MessageComponentType::LinkPreviewLoad, QString(), {}};
}
}
}
endResetModel();
}
QList<MessageComponent> MessageContentModel::componentsForType(MessageComponentType::Type type)
{
switch (type) {
case MessageComponentType::Text: {
const auto event = eventCast<const Quotient::RoomMessageEvent>(m_event);
auto body = EventHandler::rawMessageBody(*event);
return TextHandler().textComponents(body, EventHandler::messageBodyInputFormat(*event), m_room, event, event->isReplaced());
}
case MessageComponentType::File: {
QList<MessageComponent> components;
components += MessageComponent{MessageComponentType::File, QString(), {}};
if (m_emptyItinerary) {
auto fileTransferInfo = fileInfo();
#ifndef Q_OS_ANDROID
KSyntaxHighlighting::Repository repository;
const auto definitionForFile = repository.definitionForFileName(fileTransferInfo.localPath.toString());
if (definitionForFile.isValid() || QFileInfo(fileTransferInfo.localPath.path()).suffix() == QStringLiteral("txt")) {
QFile file(fileTransferInfo.localPath.path());
file.open(QIODevice::ReadOnly);
components += MessageComponent{MessageComponentType::Code,
QString::fromStdString(file.readAll().toStdString()),
{{QStringLiteral("class"), definitionForFile.name()}}};
}
#endif
if (FileType::instance().fileHasImage(fileTransferInfo.localPath)) {
QImageReader reader(fileTransferInfo.localPath.path());
components += MessageComponent{MessageComponentType::Pdf, QString(), {{QStringLiteral("size"), reader.size()}}};
}
} else {
updateItineraryModel();
if (m_itineraryModel != nullptr) {
components += MessageComponent{MessageComponentType::Itinerary, QString(), {}};
}
}
return components;
}
default:
return {MessageComponent{type, QString(), {}}};
}
}
void MessageContentModel::updateLinkPreviewer()
{
if (m_room == nullptr || m_event == nullptr) {

View File

@@ -98,8 +98,6 @@ private:
QPointer<LinkPreviewer> m_linkPreviewer;
ItineraryModel *m_itineraryModel = nullptr;
QList<MessageComponent> componentsForType(MessageComponentType::Type type);
void updateLinkPreviewer();
void updateItineraryModel();
bool m_emptyItinerary = false;

View File

@@ -7,6 +7,7 @@
#include "neochatconfig.h"
#include <Quotient/connection.h>
#include <Quotient/csapi/rooms.h>
#include <Quotient/events/redactionevent.h>
#include <Quotient/events/roommessageevent.h>
@@ -116,6 +117,34 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
if (message != nullptr) {
createEventObjects(message);
if (NeoChatConfig::self()->showFancyEffects()) {
QString planBody = message->plainBody();
// snowflake
const QString snowlakeEmoji = QString::fromUtf8("\xE2\x9D\x84");
if (planBody.contains(snowlakeEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("snowflake"));
}
// fireworks
const QString fireworksEmoji = QString::fromUtf8("\xF0\x9F\x8E\x86");
if (planBody.contains(fireworksEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("fireworks"));
}
// sparkler
const QString sparklerEmoji = QString::fromUtf8("\xF0\x9F\x8E\x87");
if (planBody.contains(sparklerEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("fireworks"));
}
// party pooper
const QString partyEmoji = QString::fromUtf8("\xF0\x9F\x8E\x89");
if (planBody.contains(partyEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("confetti"));
}
// confetti ball
const QString confettiEmoji = QString::fromUtf8("\xF0\x9F\x8E\x8A");
if (planBody.contains(confettiEmoji)) {
Q_EMIT fancyEffectsReasonFound(QStringLiteral("confetti"));
}
}
}
if (event->is<PollStartEvent>()) {
m_currentRoom->createPollHandler(eventCast<const PollStartEvent>(event.get()));
@@ -222,7 +251,7 @@ void MessageEventModel::setRoom(NeoChatRoom *room)
beginResetModel();
endResetModel();
});
qCDebug(MessageEvent) << "Connected to room" << room->id() << "as" << room->localUser()->id();
qCDebug(MessageEvent) << "Connected to room" << room->id() << "as" << room->localMember().id();
} else {
lastReadEventId.clear();
}
@@ -592,7 +621,7 @@ QVariant MessageEventModel::data(const QModelIndex &idx, int role) const
}
if (role == IsEditableRole) {
return eventHandler.messageComponentType() == MessageComponentType::Text && evt.senderId() == m_currentRoom->localUser()->id();
return eventHandler.messageComponentType() == MessageComponentType::Text && evt.senderId() == m_currentRoom->localMember().id();
}
return {};

View File

@@ -140,4 +140,5 @@ private:
Q_SIGNALS:
void roomChanged();
void fancyEffectsReasonFound(const QString &fancyEffect);
};

View File

@@ -36,14 +36,6 @@ MessageFilterModel::MessageFilterModel(QObject *parent, TimelineModel *sourceMod
}
bool MessageFilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
if (NeoChatConfig::self()->showAllEvents()) {
return true;
}
return eventIsVisible(sourceRow, sourceParent);
}
bool MessageFilterModel::eventIsVisible(int sourceRow, const QModelIndex &sourceParent) const
{
const QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
@@ -67,8 +59,9 @@ bool MessageFilterModel::eventIsVisible(int sourceRow, const QModelIndex &source
// Don't show state events that are not the first in a consecutive group on the
// same day as they will be grouped as a single delegate.
const bool notLastRow = sourceRow < sourceModel()->rowCount() - 1;
const bool previousEventIsState =
notLastRow ? sourceModel()->data(sourceModel()->index(sourceRow + 1, 0), MessageEventModel::DelegateTypeRole) == DelegateType::State : false;
const bool previousEventIsState = notLastRow
? sourceModel()->data(sourceModel()->index(sourceRow + 1, 0), MessageEventModel::DelegateTypeRole) == DelegateType::State
: false;
const bool newDay = sourceModel()->data(sourceModel()->index(sourceRow, 0), MessageEventModel::ShowSectionRole).toBool();
if (eventType == DelegateType::State && notLastRow && previousEventIsState && !newDay) {
return false;
@@ -79,11 +72,7 @@ bool MessageFilterModel::eventIsVisible(int sourceRow, const QModelIndex &source
QVariant MessageFilterModel::data(const QModelIndex &index, int role) const
{
if (role == MessageEventModel::DelegateTypeRole && NeoChatConfig::self()->showAllEvents()) {
if (!eventIsVisible(index.row(), index.parent())) {
return DelegateType::Other;
}
} else if (role == AggregateDisplayRole) {
if (role == AggregateDisplayRole) {
return aggregateEventToString(mapToSource(index).row());
} else if (role == StateEventsRole) {
return stateEventsList(mapToSource(index).row());

View File

@@ -60,8 +60,6 @@ public:
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
private:
bool eventIsVisible(int sourceRow, const QModelIndex &sourceParent) const;
/**
* @brief Aggregation of the text of consecutive state events starting at row.
*

View File

@@ -3,6 +3,7 @@
#include "notificationsmodel.h"
#include <Quotient/connection.h>
#include <Quotient/events/event.h>
#include <Quotient/uri.h>

View File

@@ -3,7 +3,8 @@
#include "publicroomlistmodel.h"
#include "neochatconnection.h"
#include <Quotient/connection.h>
#include "publicroomlist_logging.h"
using namespace Quotient;
@@ -13,14 +14,14 @@ PublicRoomListModel::PublicRoomListModel(QObject *parent)
{
}
NeoChatConnection *PublicRoomListModel::connection() const
Quotient::Connection *PublicRoomListModel::connection() const
{
return m_connection;
}
void PublicRoomListModel::setConnection(NeoChatConnection *connection)
void PublicRoomListModel::setConnection(Connection *conn)
{
if (m_connection == connection) {
if (m_connection == conn) {
return;
}
@@ -37,7 +38,7 @@ void PublicRoomListModel::setConnection(NeoChatConnection *connection)
endResetModel();
m_connection = connection;
m_connection = conn;
if (job) {
job->abandon();

View File

@@ -9,7 +9,10 @@
#include <Quotient/csapi/list_public_rooms.h>
class NeoChatConnection;
namespace Quotient
{
class Connection;
}
/**
* @class PublicRoomListModel
@@ -30,7 +33,7 @@ class PublicRoomListModel : public QAbstractListModel
/**
* @brief The current connection that the model is getting its rooms from.
*/
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
/**
* @brief The server to get the public room list from.
@@ -92,8 +95,8 @@ public:
*/
[[nodiscard]] QHash<int, QByteArray> roleNames() const override;
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *conn);
[[nodiscard]] QString server() const;
void setServer(const QString &value);
@@ -114,7 +117,7 @@ public:
Q_INVOKABLE void search(int limit = 50);
private:
QPointer<NeoChatConnection> m_connection = nullptr;
QPointer<Quotient::Connection> m_connection = nullptr;
QString m_server;
QString m_searchText;
bool m_showOnlySpaces = false;

View File

@@ -5,13 +5,13 @@
#include <QDebug>
#include <Quotient/connection.h>
#include <Quotient/converters.h>
#include <Quotient/csapi/definitions/push_ruleset.h>
#include <Quotient/csapi/pushrules.h>
#include <Quotient/jobs/basejob.h>
#include "neochatconfig.h"
#include "neochatconnection.h"
#include <KLazyLocalizedString>
@@ -454,7 +454,7 @@ void PushRuleModel::setConnection(NeoChatConnection *connection)
Q_EMIT connectionChanged();
if (m_connection) {
connect(m_connection, &NeoChatConnection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
connect(m_connection, &Quotient::Connection::accountDataChanged, this, &PushRuleModel::updateNotificationRules);
updateNotificationRules(QStringLiteral("m.push_rules"));
}
}

View File

@@ -126,7 +126,7 @@ private Q_SLOTS:
private:
PushRuleAction::Action m_defaultKeywordAction;
QList<Rule> m_rules;
QPointer<NeoChatConnection> m_connection;
NeoChatConnection *m_connection;
void setRules(QList<Quotient::PushRule> rules, PushRuleKind::Kind kind);

View File

@@ -90,7 +90,7 @@ QVariant ReactionModel::data(const QModelIndex &index, int role) const
if (role == HasLocalUser) {
for (auto author : reaction.authors) {
if (author.toMap()[QStringLiteral("id")] == m_room->localUser()->id()) {
if (author.toMap()[QStringLiteral("id")] == m_room->localMember().id()) {
return true;
}
}

View File

@@ -25,12 +25,12 @@ RoomListModel::RoomListModel(QObject *parent)
RoomListModel::~RoomListModel() = default;
NeoChatConnection *RoomListModel::connection() const
Quotient::Connection *RoomListModel::connection() const
{
return m_connection;
}
void RoomListModel::setConnection(NeoChatConnection *connection)
void RoomListModel::setConnection(Connection *connection)
{
if (connection == m_connection) {
return;

View File

@@ -12,11 +12,10 @@ class NeoChatRoom;
namespace Quotient
{
class Connection;
class Room;
}
class NeoChatConnection;
/**
* @class RoomListModel
*
@@ -30,7 +29,7 @@ class RoomListModel : public QAbstractListModel
/**
* @brief The current connection that the model is getting its rooms from.
*/
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
public:
/**
@@ -61,8 +60,8 @@ public:
explicit RoomListModel(QObject *parent = nullptr);
~RoomListModel() override;
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *connection);
/**
* @brief Get the given role value at the given index.
@@ -110,7 +109,7 @@ private Q_SLOTS:
void refresh(NeoChatRoom *room, const QList<int> &roles = {});
private:
QPointer<NeoChatConnection> m_connection;
Quotient::Connection *m_connection = nullptr;
QList<NeoChatRoom *> m_rooms;
QString m_activeSpaceId;

View File

@@ -3,6 +3,7 @@
#include "roomtreemodel.h"
#include <Quotient/connection.h>
#include <Quotient/room.h>
#include "eventhandler.h"
@@ -299,6 +300,9 @@ QVariant RoomTreeModel::data(const QModelIndex &index, int role) const
return NeoChatRoomType::typeName(index.row());
}
if (role == DelegateTypeRole) {
if (index.row() == NeoChatRoomType::Search) {
return QStringLiteral("search");
}
if (index.row() == NeoChatRoomType::AddDirect) {
return QStringLiteral("addDirect");
}

View File

@@ -10,6 +10,7 @@
#include <QGuiApplication>
#include <Quotient/connection.h>
#include <Quotient/events/stickerevent.h>
#include <KLocalizedString>

View File

@@ -3,6 +3,8 @@
#include "serverlistmodel.h"
#include <Quotient/connection.h>
#include <QDebug>
#include <KConfig>

View File

@@ -110,7 +110,7 @@ Q_SIGNALS:
private:
QList<Server> m_servers;
QPointer<Quotient::QueryPublicRoomsJob> m_checkServerJob = nullptr;
QPointer<NeoChatConnection> m_connection;
NeoChatConnection *m_connection = nullptr;
void initialize();
};

View File

@@ -5,8 +5,6 @@
#include "roomlistmodel.h"
#include "neochatconnection.h"
SortFilterRoomListModel::SortFilterRoomListModel(RoomListModel *sourceModel, QObject *parent)
: QSortFilterProxyModel(parent)
{

View File

@@ -129,6 +129,10 @@ QString SortFilterRoomTreeModel::filterText() const
bool SortFilterRoomTreeModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
if (!source_parent.isValid()) {
if (sourceModel()->data(sourceModel()->index(source_row, 0), RoomTreeModel::CategoryRole).toInt() == NeoChatRoomType::Search
&& NeoChatConfig::collapsed()) {
return true;
}
if (sourceModel()->data(sourceModel()->index(source_row, 0), RoomTreeModel::CategoryRole).toInt() == NeoChatRoomType::AddDirect
&& m_mode == DirectChats) {
return true;
@@ -201,14 +205,4 @@ void SortFilterRoomTreeModel::setMode(SortFilterRoomTreeModel::Mode mode)
invalidate();
}
QModelIndex SortFilterRoomTreeModel::currentRoomIndex() const
{
const auto roomModel = dynamic_cast<RoomTreeModel *>(sourceModel());
if (roomModel == nullptr) {
return {};
}
return mapFromSource(roomModel->indexForRoom(RoomManager::instance().currentRoom()));
}
#include "moc_sortfilterroomtreemodel.cpp"

View File

@@ -76,8 +76,6 @@ public:
Mode mode() const;
void setMode(Mode mode);
Q_INVOKABLE QModelIndex currentRoomIndex() const;
protected:
/**
* @brief Returns true if the value of source_left is less than source_right.

View File

@@ -3,6 +3,7 @@
#include "spacechildrenmodel.h"
#include <Quotient/connection.h>
#include <Quotient/jobs/basejob.h>
#include <Quotient/room.h>
@@ -46,7 +47,7 @@ void SpaceChildrenModel::setSpace(NeoChatRoom *space)
}
auto connection = m_space->connection();
connect(connection, &NeoChatConnection::loadedRoomState, this, [this](Quotient::Room *room) {
connect(connection, &Quotient::Connection::loadedRoomState, this, [this](Quotient::Room *room) {
if (m_pendingChildren.contains(room->name())) {
m_pendingChildren.removeAll(room->name());
refreshModel();

View File

@@ -1,8 +1,6 @@
// SPDX-FileCopyrightText: 2023 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#include <QPointer>
#include <Quotient/csapi/space_hierarchy.h>
#include <Quotient/events/stateevent.h>
@@ -151,7 +149,7 @@ public:
bool isSuggested() const;
private:
QPointer<NeoChatConnection> m_connection;
NeoChatConnection *m_connection;
std::vector<std::unique_ptr<SpaceTreeItem>> m_children;
SpaceTreeItem *m_parentItem;

View File

@@ -3,10 +3,9 @@
#include "userdirectorylistmodel.h"
#include <Quotient/connection.h>
#include <Quotient/room.h>
#include "neochatconnection.h"
using namespace Quotient;
UserDirectoryListModel::UserDirectoryListModel(QObject *parent)
@@ -14,14 +13,14 @@ UserDirectoryListModel::UserDirectoryListModel(QObject *parent)
{
}
NeoChatConnection *UserDirectoryListModel::connection() const
Quotient::Connection *UserDirectoryListModel::connection() const
{
return m_connection;
}
void UserDirectoryListModel::setConnection(NeoChatConnection *connection)
void UserDirectoryListModel::setConnection(Connection *conn)
{
if (m_connection == connection) {
if (m_connection == conn) {
return;
}
@@ -36,7 +35,7 @@ void UserDirectoryListModel::setConnection(NeoChatConnection *connection)
endResetModel();
m_connection = connection;
m_connection = conn;
Q_EMIT connectionChanged();
if (m_job) {

View File

@@ -9,7 +9,10 @@
#include <Quotient/csapi/users.h>
class NeoChatConnection;
namespace Quotient
{
class Connection;
}
/**
* @class UserDirectoryListModel
@@ -29,7 +32,7 @@ class UserDirectoryListModel : public QAbstractListModel
/**
* @brief The current connection that the model is getting users from.
*/
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
Q_PROPERTY(Quotient::Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
/**
* @brief The text to search the public room list for.
@@ -54,8 +57,8 @@ public:
explicit UserDirectoryListModel(QObject *parent = nullptr);
[[nodiscard]] NeoChatConnection *connection() const;
void setConnection(NeoChatConnection *connection);
[[nodiscard]] Quotient::Connection *connection() const;
void setConnection(Quotient::Connection *conn);
[[nodiscard]] QString searchText() const;
void setSearchText(const QString &searchText);
@@ -96,7 +99,7 @@ Q_SIGNALS:
void searchingChanged();
private:
QPointer<NeoChatConnection> m_connection;
Quotient::Connection *m_connection = nullptr;
QString m_searchText;
bool attempted = false;

View File

@@ -5,6 +5,7 @@
#include <QGuiApplication>
#include <Quotient/connection.h>
#include <Quotient/events/roompowerlevelsevent.h>
#include "neochatroom.h"

View File

@@ -100,6 +100,10 @@
<label>Minimize to system tray on startup</label>
<default>false</default>
</entry>
<entry name="ShowFancyEffects" type="bool">
<label>Show Fancy Effects</label>
<default>true</default>
</entry>
<entry name="MediaMaxWidth" type="int">
<label>The maximum width any media item in the timeline can be.</label>
<default>540</default>
@@ -157,18 +161,10 @@
</entry>
</group>
<group name="Debug">
<entry name="ShowAllEvents" type="bool">
<label>Don't hide any events in the timeline</label>
<default>false</default>
</entry>
<entry name="AlwaysVerifyDevice" type="bool">
<label>Always allow device verification</label>
<default>false</default>
</entry>
<entry name="WindowTitleFocus" type="bool">
<label>Show the current focus item in the window title</label>
<default>false</default>
</entry>
</group>
<group name="FeatureFlags">
<entry name="Threads" type="bool">

View File

@@ -101,15 +101,17 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
if (this->joinState() != JoinState::Invite) {
return;
}
auto roomMemberEvent = currentState().get<RoomMemberEvent>(localUser()->id());
auto roomMemberEvent = currentState().get<RoomMemberEvent>(localMember().id());
QImage avatar_image;
if (roomMemberEvent && !user(roomMemberEvent->senderId())->avatarUrl(this).isEmpty()) {
avatar_image = user(roomMemberEvent->senderId())->avatar(128, this);
if (roomMemberEvent && !member(roomMemberEvent->senderId()).avatarUrl().isEmpty()) {
// TODO: Fix acessing Avatar Image.
// avatar_image = member(roomMemberEvent->senderId()).avatarMediaId();
avatar_image = avatar(128);
} else {
qWarning() << "using this room's avatar";
avatar_image = avatar(128);
}
NotificationsManager::instance().postInviteNotification(this, displayName(), htmlSafeMemberName(roomMemberEvent->senderId()), avatar_image);
NotificationsManager::instance().postInviteNotification(this, displayName(), member(roomMemberEvent->senderId()).htmlSafeDisplayName(), avatar_image);
});
connect(this, &Room::changed, this, [this] {
Q_EMIT canEncryptRoomChanged();
@@ -257,18 +259,18 @@ void NeoChatRoom::forget()
QVariantList NeoChatRoom::getUsersTyping() const
{
auto users = usersTyping();
users.removeAll(localUser());
auto users = membersTyping();
users.removeAll(localMember());
QVariantList userVariants;
for (const auto &user : users) {
if (connection()->isIgnored(user->id())) {
if (connection()->isIgnored(user.id())) {
continue;
}
userVariants.append(QVariantMap{
{"id"_ls, user->id()},
{"avatarMediaId"_ls, user->avatarMediaId(this)},
{"displayName"_ls, user->displayname(this)},
{"display"_ls, user->name()},
{"id"_ls, user.id()},
{"avatarMediaId"_ls, user.avatarMediaId()},
{"displayName"_ls, user.displayName()},
{"display"_ls, user.name()},
});
}
return userVariants;
@@ -276,7 +278,7 @@ QVariantList NeoChatRoom::getUsersTyping() const
void NeoChatRoom::sendTypingNotification(bool isTyping)
{
connection()->callApi<SetTypingJob>(BackgroundRequest, localUser()->id(), id(), isTyping, 10000);
connection()->callApi<SetTypingJob>(BackgroundRequest, localMember().id(), id(), isTyping, 10000);
}
const RoomEvent *NeoChatRoom::lastEvent() const
@@ -314,7 +316,7 @@ const RoomEvent *NeoChatRoom::lastEvent() const
}
}
if (connection()->isIgnored(user(event->senderId()))) {
if (connection()->isIgnored(event->senderId())) {
continue;
}
@@ -374,13 +376,13 @@ bool NeoChatRoom::isEventHighlighted(const RoomEvent *e) const
void NeoChatRoom::checkForHighlights(const Quotient::TimelineItem &ti)
{
auto localUserId = localUser()->id();
if (ti->senderId() == localUserId) {
auto localMemberId = localMember().id();
if (ti->senderId() == localMemberId) {
return;
}
if (auto *e = ti.viewAs<RoomMessageEvent>()) {
const auto &text = e->plainBody();
if (text.contains(localUserId) || text.contains(safeMemberName(localUserId))) {
if (text.contains(localMemberId) || text.contains(member(localMemberId).htmlSafeDisplayName())) {
highlights.insert(e);
}
}
@@ -439,7 +441,8 @@ static const QVariantMap emptyUser = {
QVariantMap NeoChatRoom::getUser(const QString &userID) const
{
return getUser(user(userID));
auto u = User(userID, connection());
return getUser(&u);
}
QVariantMap NeoChatRoom::getUser(User *user) const
@@ -449,13 +452,13 @@ QVariantMap NeoChatRoom::getUser(User *user) const
}
return QVariantMap{
{QStringLiteral("isLocalUser"), user->id() == localUser()->id()},
{QStringLiteral("isLocalUser"), user->id() == localMember().id()},
{QStringLiteral("id"), user->id()},
{QStringLiteral("displayName"), user->displayname(this)},
{QStringLiteral("escapedDisplayName"), htmlSafeMemberName(user->id())},
{QStringLiteral("displayName"), user->displayname()},
{QStringLiteral("escapedDisplayName"), member(user->id()).htmlSafeDisplayName()},
{QStringLiteral("avatarSource"), avatarForMember(user)},
{QStringLiteral("avatarMediaId"), user->avatarMediaId(this)},
{QStringLiteral("color"), Utils::getUserColor(user->hueF())},
{QStringLiteral("avatarMediaId"), user->avatarMediaId()},
{QStringLiteral("color"), member(user->id()).hueF()},
{QStringLiteral("object"), QVariant::fromValue(user)},
};
}
@@ -467,10 +470,10 @@ QString NeoChatRoom::avatarMediaId() const
}
// Use the first (excluding self) user's avatar for direct chats
const auto dcUsers = directChatUsers();
const auto dcUsers = directChatMembers();
for (const auto u : dcUsers) {
if (u != localUser()) {
return u->avatarMediaId(this);
if (u != localMember()) {
return u.avatarMediaId();
}
}
@@ -637,7 +640,7 @@ void NeoChatRoom::toggleReaction(const QString &eventId, const QString &reaction
continue;
}
if (e->senderId() == localUser()->id()) {
if (e->senderId() == localMember().id()) {
redactEventIds.push_back(e->id());
break;
}
@@ -666,7 +669,7 @@ bool NeoChatRoom::canSendEvent(const QString &eventType) const
return false;
}
auto pl = plEvent->powerLevelForEvent(eventType);
auto currentPl = plEvent->powerLevelForUser(localUser()->id());
auto currentPl = plEvent->powerLevelForUser(localMember().id());
return currentPl >= pl;
}
@@ -678,7 +681,7 @@ bool NeoChatRoom::canSendState(const QString &eventType) const
return false;
}
auto pl = plEvent->powerLevelForState(eventType);
auto currentPl = plEvent->powerLevelForUser(localUser()->id());
auto currentPl = plEvent->powerLevelForUser(localMember().id());
return currentPl >= pl;
}
@@ -856,7 +859,7 @@ void NeoChatRoom::setUrlPreviewEnabled(const bool &urlPreviewEnabled)
* "type": "org.matrix.room.preview_urls",
* }
*/
connection()->callApi<SetAccountDataPerRoomJob>(localUser()->id(),
connection()->callApi<SetAccountDataPerRoomJob>(localMember().id(),
id(),
"org.matrix.room.preview_urls"_ls,
QJsonObject{{"disable"_ls, !urlPreviewEnabled}});
@@ -1768,7 +1771,7 @@ void NeoChatRoom::editLastMessage()
}
// check if the current message's sender's id is same as the user's id
if ((*it)->senderId() == localUser()->id()) {
if ((*it)->senderId() == localMember().id()) {
auto content = (*it)->contentJson();
if (e->msgtype() != MessageEventType::Unknown) {
@@ -1933,16 +1936,16 @@ QByteArray NeoChatRoom::roomAcountDataJson(const QString &eventType)
QUrl NeoChatRoom::avatarForMember(Quotient::User *user) const
{
const auto &url = memberAvatarUrl(user->id());
if (url.isEmpty() || url.scheme() != "mxc"_ls) {
const auto &avatar = memberAvatar(user->id());
if (avatar.url().isEmpty() || avatar.url().scheme() != "mxc"_ls) {
return {};
}
auto avatar = connection()->makeMediaUrl(url);
if (avatar.isValid() && avatar.scheme() == QStringLiteral("mxc")) {
return avatar;
} else {
auto localFile = connection()->makeMediaUrl(avatar.url());
if (!localFile.isValid() || localFile.scheme() != QStringLiteral("mxc")) {
return QUrl();
}
return localFile;
}
const RoomEvent *NeoChatRoom::getReplyForEvent(const RoomEvent &event) const

View File

@@ -213,7 +213,7 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
if (!room) {
return;
}
auto connection = dynamic_cast<NeoChatConnection *>(Controller::instance().accounts().get(room->localUser()->id()));
auto connection = dynamic_cast<NeoChatConnection *>(Controller::instance().accounts().get(room->localMember().id()));
Controller::instance().setActiveConnection(connection);
RoomManager::instance().setConnection(connection);
RoomManager::instance().resolveResource(room->id());
@@ -230,7 +230,7 @@ void NotificationsManager::postNotification(NeoChatRoom *room,
notification->setReplyAction(std::move(replyAction));
}
notification->setHint(QStringLiteral("x-kde-origin-name"), room->localUser()->id());
notification->setHint(QStringLiteral("x-kde-origin-name"), room->localMember().id());
notification->sendEvent();
}
@@ -286,7 +286,7 @@ void NotificationsManager::postInviteNotification(NeoChatRoom *rawRoom, const QS
m_invitations.remove(room->id());
});
notification->setHint(QStringLiteral("x-kde-origin-name"), room->localUser()->id());
notification->setHint(QStringLiteral("x-kde-origin-name"), room->localMember().id());
notification->sendEvent();
m_invitations.insert(room->id(), notification);

View File

@@ -154,7 +154,7 @@ void PollHandler::sendPollAnswer(const QString &eventId, const QString &answerId
return;
}
QStringList ownAnswers;
for (const auto &answer : m_answers[room->localUser()->id()].toArray()) {
for (const auto &answer : m_answers[room->localMember().id()].toArray()) {
ownAnswers += answer.toString();
}
if (ownAnswers.contains(answerId)) {
@@ -169,7 +169,7 @@ void PollHandler::sendPollAnswer(const QString &eventId, const QString &answerId
}
auto response = new PollResponseEvent(eventId, ownAnswers);
handleAnswer(response->contentJson(), room->localUser()->id(), QDateTime::currentDateTime());
handleAnswer(response->contentJson(), room->localMember().id(), QDateTime::currentDateTime());
room->postEvent(response);
}

View File

@@ -18,7 +18,6 @@
"Name[nl]": "Tobias Fella",
"Name[pl]": "Tobias Fella",
"Name[sl]": "Tobias Fella",
"Name[ta]": "டோபியாஸ் ஃபெல்லா",
"Name[tr]": "Tobias Fella",
"Name[uk]": "Tobias Fella",
"Name[x-test]": "xxTobias Fellaxx",
@@ -41,7 +40,6 @@
"Description[nl]": "Delen via NeoChat",
"Description[pl]": "Udostępnij przez NeoChat",
"Description[sl]": "Deli prek NeoChat",
"Description[ta]": "நியோச்சாட் மூலம் பகிர்",
"Description[tr]": "NeoChat ile Paylaş",
"Description[uk]": "Оприлюднити за допомогою NeoChat",
"Description[x-test]": "xxShare via NeoChatxx",
@@ -65,7 +63,6 @@
"Name[nl]": "NeoChat",
"Name[pl]": "NeoChat",
"Name[sl]": "NeoChat",
"Name[ta]": "நியோச்சாட்",
"Name[tr]": "NeoChat",
"Name[uk]": "NeoChat",
"Name[x-test]": "xxNeoChatxx",

View File

@@ -278,8 +278,6 @@ QQC2.Control {
Keys.onTabPressed: {
if (completionMenu.visible) {
completionMenu.complete();
} else {
contextDrawer.handle.children[0].forceActiveFocus()
}
}
Keys.onPressed: event => {

View File

@@ -48,10 +48,10 @@ QQC2.ItemDelegate {
background: Rectangle {
color: root.checked ? Kirigami.Theme.highlightColor : Kirigami.Theme.backgroundColor
radius: Kirigami.Units.cornerRadius
radius: Kirigami.Units.smallSpacing
Rectangle {
radius: Kirigami.Units.cornerRadius
radius: Kirigami.Units.smallSpacing
anchors.fill: parent
color: Kirigami.Theme.highlightColor
opacity: root.hovered && !root.pressed ? 0.2 : 0

View File

@@ -40,7 +40,7 @@ QQC2.Popup {
background: Kirigami.ShadowedRectangle {
Kirigami.Theme.colorSet: Kirigami.Theme.View
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.cornerRadius
radius: Kirigami.Units.mediumSpacing
shadow {
size: Kirigami.Units.largeSpacing
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)

View File

@@ -30,7 +30,7 @@ QQC2.Popup {
onOpened: x = Math.min(parent.mapFromGlobal(QQC2.Overlay.overlay.width - root.width, 0).x, -(width - parent.width) / 2)
background: Kirigami.ShadowedRectangle {
color: Kirigami.Theme.backgroundColor
radius: Kirigami.Units.cornerRadius
radius: Kirigami.Units.mediumSpacing
shadow {
size: Kirigami.Units.largeSpacing
color: Qt.rgba(0.0, 0.0, 0.0, 0.3)

View File

@@ -17,7 +17,7 @@ RowLayout {
property bool collapsed: false
required property NeoChatConnection connection
signal search
property alias roomSearchFieldFocussed: roomSearchField.activeFocus
property Kirigami.Action exploreAction: Kirigami.Action {
text: i18n("Explore rooms")
@@ -83,30 +83,15 @@ RowLayout {
*/
signal textChanged(string newText)
Item {
Layout.preferredWidth: Kirigami.Units.largeSpacing
}
Kirigami.Heading {
Kirigami.SearchField {
id: roomSearchField
Layout.topMargin: Kirigami.Units.smallSpacing
Layout.bottomMargin: Kirigami.Units.smallSpacing
Layout.fillWidth: true
Layout.preferredWidth: root.desiredWidth ? root.desiredWidth - menuButton.width - root.spacing : -1
visible: !root.collapsed
text: i18nc("@title", "Rooms")
}
Item {
Layout.fillWidth: true
visible: root.collapsed
}
QQC2.ToolButton {
id: searchButton
display: QQC2.AbstractButton.IconOnly
onClicked: root.search();
icon.name: "search"
text: i18nc("@action", "Search Room")
Shortcut {
sequence: "Ctrl+F"
onActivated: searchButton.clicked()
}
onTextChanged: root.textChanged(text)
KeyNavigation.tab: treeView
}
QQC2.ToolButton {
@@ -115,8 +100,8 @@ RowLayout {
display: QQC2.AbstractButton.IconOnly
checkable: true
action: Kirigami.Action {
text: i18nc("@action:button", "Show Menu")
icon.name: "application-menu-symbolic"
text: i18n("Create rooms and chats")
icon.name: "irc-join-channel"
onTriggered: {
if (Kirigami.isMobile) {
const menu = mobileMenu.createObject();

View File

@@ -0,0 +1,304 @@
// SPDX-FileCopyrightText: 2021 Alexey Andreyev <aa13q@ya.ru>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
import QtQuick
import QtQuick.Layouts
import QtQuick.Particles
import org.kde.kirigami as Kirigami
Item {
id: root
property bool enabled: false
property int effectInterval: Kirigami.Units.veryLongDuration * 10
property color darkSnowColor: "grey"
property bool isThemeDark: Kirigami.Theme.backgroundColor.hslLightness <= darkSnowColor.hslLightness
function showConfettiEffect() {
confettiTimer.start();
}
function showSnowEffect() {
snowTimer.start();
}
function showFireworksEffect() {
fireworksTimer.start();
}
// Confetti
Timer {
id: confettiTimer
interval: root.effectInterval
running: false
repeat: false
triggeredOnStart: true
onTriggered: {
if (root.enabled) {
confettiSystem.running = !confettiSystem.running;
}
}
}
ParticleSystem {
id: confettiSystem
anchors.fill: parent
running: false
onRunningChanged: {
if (running) {
opacity = 1;
} else {
opacity = 0;
}
}
Behavior on opacity {
SequentialAnimation {
NumberAnimation {
duration: Kirigami.Units.longDuration
}
}
}
ImageParticle {
source: "qrc:/qt/qml/org/kde/neochat/qml/confetti.png"
entryEffect: ImageParticle.Scale
rotationVariation: 360
rotationVelocity: 90
color: Qt.hsla(Math.random(), 0.5, 0.6, 1)
colorVariation: 1
}
Emitter {
anchors {
left: parent.left
right: parent.right
top: parent.top
}
sizeVariation: Kirigami.Units.iconSizes.small / 2
lifeSpan: Kirigami.Units.veryLongDuration * 10
size: Kirigami.Units.iconSizes.small
velocity: AngleDirection {
angle: 90
angleVariation: 42
magnitude: 500
}
}
}
// Snow
Timer {
id: snowTimer
interval: root.effectInterval
running: false
repeat: false
triggeredOnStart: true
onTriggered: {
if (root.enabled) {
snowSystem.running = !snowSystem.running;
}
}
}
ParticleSystem {
id: snowSystem
anchors.fill: parent
running: false
onRunningChanged: {
if (running) {
opacity = 1;
} else {
opacity = 0;
}
}
Behavior on opacity {
SequentialAnimation {
NumberAnimation {
duration: Kirigami.Units.longDuration
}
}
}
ItemParticle {
delegate: Rectangle {
width: 10
height: width
radius: width
color: root.isThemeDark ? "white" : darkSnowColor
scale: Math.random()
opacity: Math.random()
}
}
Emitter {
anchors {
left: parent.left
right: parent.right
top: parent.top
}
sizeVariation: Kirigami.Units.iconSizes.medium
lifeSpan: Kirigami.Units.veryLongDuration * 10
size: Kirigami.Units.iconSizes.large
emitRate: 42
velocity: AngleDirection {
angle: 90
angleVariation: 10
magnitude: 300
}
}
}
// Fireworks
Timer {
id: fireworksTimer
interval: root.effectInterval
running: false
repeat: false
triggeredOnStart: true
onTriggered: {
if (root.enabled) {
fireworksInternalTimer.running = !fireworksInternalTimer.running;
}
}
}
Timer {
id: fireworksInternalTimer
interval: 300
triggeredOnStart: true
running: false
repeat: true
onTriggered: {
var x = Math.random() * parent.width;
var y = Math.random() * parent.height;
customEmit(x, y);
customEmit(x, y);
customEmit(x, y);
}
}
ParticleSystem {
id: fireworksSystem
anchors.fill: parent
running: fireworksInternalTimer.running
onRunningChanged: {
if (running) {
opacity = 1;
} else {
opacity = 0;
}
}
Behavior on opacity {
SequentialAnimation {
NumberAnimation {
duration: Kirigami.Units.longDuration
}
}
}
}
ImageParticle {
id: fireworksParticleA
system: fireworksSystem
source: "qrc:/qt/qml/org/kde/neochat/qml/glowdot.png"
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["a"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
rotationVariation: 360
}
ImageParticle {
system: fireworksSystem
source: "qrc:/qt/qml/org/kde/neochat/qml/glowdot.png"
color: root.isThemeDark ? "white" : "gold"
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["light"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
rotationVariation: 360
}
ImageParticle {
id: fireworksParticleB
system: fireworksSystem
source: "qrc:/qt/qml/org/kde/neochat/qml/glowdot.png"
alphaVariation: root.isThemeDark ? 0.1 : 0.1
alpha: root.isThemeDark ? 0.5 : 1
groups: ["b"]
opacity: fireworksSystem.opacity
entryEffect: ImageParticle.Scale
rotationVariation: 360
}
Component {
id: emitterComp
Emitter {
id: container
property int life: 23
property real targetX: 0
property real targetY: 0
width: 1
height: 1
system: fireworksSystem
size: 16
endSize: 8
sizeVariation: 5
Timer {
interval: life
running: true
onTriggered: {
container.destroy();
var randomHue = Math.random();
var lightness = root.isThemeDark ? 0.8 : 0.7;
fireworksParticleA.color = Qt.hsla(randomHue, 0.8, lightness, 1);
fireworksParticleB.color = Qt.hsla(1 - randomHue, 0.8, lightness, 1);
}
}
velocity: AngleDirection {
angleVariation: 360
magnitude: 200
}
}
}
function customEmit(x, y) {
var currentSize = Math.round(Math.random() * 200) + 40;
var currentLifeSpan = Math.round(Math.random() * 1000) + 100;
for (var i = 0; i < 8; i++) {
var obj = emitterComp.createObject(parent);
obj.x = x;
obj.y = y;
obj.targetX = Math.random() * currentSize - currentSize / 2 + obj.x;
obj.targetY = Math.random() * currentSize - currentSize / 2 + obj.y;
obj.life = Math.round(Math.random() * 23) + 150;
obj.emitRate = Math.round(Math.random() * 32) + 5;
obj.lifeSpan = currentLifeSpan;
const group = Math.round(Math.random() * 3);
switch (group) {
case 0:
obj.group = "light";
break;
case 1:
obj.group = "a";
break;
case 2:
obj.group = "b";
break;
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More