Move NeoChatConnection and NeoChatRoom to LibNeoChat

Move `NeoChatConnection` and `NeoChatRoom` to `LibNeoChat` along with any required dependencies.
This commit is contained in:
James Graham
2025-04-07 18:52:15 +00:00
parent 8327b4369e
commit aef4f75c33
54 changed files with 57 additions and 72 deletions

View File

@@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: 2021-2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "imagepackevent.h"
#include <QJsonObject>
using namespace Quotient;
ImagePackEventContent::ImagePackEventContent(const QJsonObject &json)
{
if (json.contains("pack"_L1)) {
pack = ImagePackEventContent::Pack{
fromJson<std::optional<QString>>(json["pack"_L1].toObject()["display_name"_L1]),
fromJson<std::optional<QUrl>>(json["pack"_L1].toObject()["avatar_url"_L1]),
fromJson<std::optional<QStringList>>(json["pack"_L1].toObject()["usage"_L1]),
fromJson<std::optional<QString>>(json["pack"_L1].toObject()["attribution"_L1]),
};
} else {
pack = std::nullopt;
}
const auto &keys = json["images"_L1].toObject().keys();
for (const auto &k : keys) {
std::optional<EventContent::ImageInfo> info;
if (json["images"_L1][k].toObject().contains("info"_L1)) {
info = EventContent::ImageInfo(QUrl(json["images"_L1][k]["url"_L1].toString()), json["images"_L1][k]["info"_L1].toObject(), k);
} else {
info = std::nullopt;
}
images += ImagePackImage{
k,
fromJson<QUrl>(json["images"_L1][k]["url"_L1].toString()),
fromJson<std::optional<QString>>(json["images"_L1][k]["body"_L1]),
info,
fromJson<std::optional<QStringList>>(json["images"_L1][k]["usage"_L1]),
};
}
}
void ImagePackEventContent::fillJson(QJsonObject *o) const
{
if (pack) {
QJsonObject packJson;
if (pack->displayName) {
packJson["display_name"_L1] = *pack->displayName;
}
if (pack->usage) {
QJsonArray usageJson;
for (const auto &usage : *pack->usage) {
usageJson += usage;
}
packJson["usage"_L1] = usageJson;
}
if (pack->avatarUrl) {
packJson["avatar_url"_L1] = pack->avatarUrl->toString();
}
if (pack->attribution) {
packJson["attribution"_L1] = *pack->attribution;
}
(*o)["pack"_L1] = packJson;
}
QJsonObject imagesJson;
for (const auto &image : images) {
QJsonObject imageJson;
imageJson["url"_L1] = image.url.toString();
if (image.body) {
imageJson["body"_L1] = *image.body;
}
if (image.usage) {
QJsonArray usageJson;
for (const auto &usage : *image.usage) {
usageJson += usage;
}
imageJson["usage"_L1] = usageJson;
}
if (image.info.has_value()) {
imageJson["info"_L1] = Quotient::EventContent::toInfoJson(*image.info);
}
imagesJson[image.shortcode] = imageJson;
}
(*o)["images"_L1] = imagesJson;
}

View File

@@ -0,0 +1,92 @@
// SPDX-FileCopyrightText: 2021-2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include <QList>
#include <Quotient/events/eventcontent.h>
#include <Quotient/events/stateevent.h>
namespace Quotient
{
/**
* @class ImagePackEventContent
*
* A class to define the content of an image pack event.
*
* See Matrix MSC2545 for more details.
* https://github.com/Sorunome/matrix-doc/blob/soru/emotes/proposals/2545-emotes.md
*
* @sa ImagePackEvent
*/
class ImagePackEventContent
{
public:
/**
* @brief Defines the properties of an image pack.
*/
struct Pack {
std::optional<QString> displayName; /**< The display name of the pack. */
std::optional<QUrl> avatarUrl; /**< The source mxc URL for the pack avatar. */
std::optional<QStringList> usage; /**< An array of the usages for this pack. Possible usages are "emoticon" and "sticker". */
std::optional<QString> attribution; /**< The attribution for the pack author(s). */
};
/**
* @brief Defines the properties of an image pack image.
*/
struct ImagePackImage {
QString shortcode; /**< The shortcode for the image. */
QUrl url; /**< The mxc URL for this image. */
std::optional<QString> body; /**< An optional text body for this image. */
std::optional<Quotient::EventContent::ImageInfo> info; /**< The ImageInfo object used for the info block of m.sticker events. */
/**
* @brief An array of the usages for this image.
*
* The possible values match those of the usage key of a pack object.
*/
std::optional<QStringList> usage;
};
/**
* @brief Return the pack properties.
*
* @sa Pack
*/
std::optional<Pack> pack;
/**
* @brief Return a vector of images in the pack.
*
* @sa ImagePackImage
*/
QList<ImagePackEventContent::ImagePackImage> images;
explicit ImagePackEventContent(const QJsonObject &o);
/**
* @brief The definition of how to convert the content to Json.
*
* This is a specialization of the standard fillJson function from libQuotient.
*
* @sa Quotient::converters
*/
void fillJson(QJsonObject *o) const;
};
/**
* @class ImagePackEvent
*
* Class to define an image pack state event.
*
* The event content is ImagePackEventContent.
*
* @sa Quotient::StateEvent, ImagePackEventContent
*/
class ImagePackEvent : public KeyedStateEventBase<ImagePackEvent, ImagePackEventContent>
{
public:
QUO_EVENT(ImagePackEvent, "im.ponies.room_emotes")
using KeyedStateEventBase::KeyedStateEventBase;
};
}

View File

@@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <Quotient/events/simplestateevents.h>
namespace Quotient
{
// Defined so we can directly switch on type.
DEFINE_SIMPLE_STATE_EVENT(LocationBeaconEvent, "org.matrix.msc3672.beacon_info", QString, body, "body")
} // namespace Quotient

View File

@@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "pollevent.h"
#include <Quotient/converters.h>
using namespace Quotient;
PollKind::Kind PollStartEvent::kind() const
{
return content().kind;
}
int PollStartEvent::maxSelections() const
{
return content().maxSelection > 0 ? content().maxSelection : 1;
}
QString PollStartEvent::question() const
{
return content().question;
}
QList<EventContent::Answer> PollStartEvent::answers() const
{
return content().answers;
}
PollResponseEvent::PollResponseEvent(const QJsonObject &obj)
: RoomEvent(obj)
{
}
PollResponseEvent::PollResponseEvent(const QString &pollStartEventId, QStringList responses)
: RoomEvent(basicJson(TypeId,
{{"org.matrix.msc3381.poll.response"_L1, QJsonObject{{"answers"_L1, QJsonArray::fromStringList(responses)}}},
{"m.relates_to"_L1, QJsonObject{{"rel_type"_L1, "m.reference"_L1}, {"event_id"_L1, pollStartEventId}}}}))
{
}
QStringList PollResponseEvent::selections() const
{
const auto jsonSelections = contentPart<QJsonObject>("org.matrix.msc3381.poll.response"_L1)["answers"_L1].toArray();
QStringList selections;
for (const auto &selection : jsonSelections) {
selections += selection.toString();
}
return selections;
}
std::optional<EventRelation> PollResponseEvent::relatesTo() const
{
return contentPart<std::optional<EventRelation>>(RelatesToKey);
}
PollEndEvent::PollEndEvent(const QJsonObject &obj)
: RoomEvent(obj)
{
}
PollEndEvent::PollEndEvent(const QString &pollStartEventId, const QString &endText)
: RoomEvent(basicJson(TypeId,
{{"org.matrix.msc1767.text"_L1, endText},
{"org.matrix.msc3381.poll.end"_L1, QJsonObject{}},
{"m.relates_to"_L1, QJsonObject{{"rel_type"_L1, "m.reference"_L1}, {"event_id"_L1, pollStartEventId}}}}))
{
}
std::optional<EventRelation> PollEndEvent::relatesTo() const
{
return contentPart<std::optional<EventRelation>>(RelatesToKey);
}

View File

@@ -0,0 +1,235 @@
// SPDX-FileCopyrightText: 2022 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include <QQmlEngine>
#include <Quotient/converters.h>
#include <Quotient/events/eventrelation.h>
#include <Quotient/events/roomevent.h>
#include <Quotient/quotient_common.h>
using namespace Qt::StringLiterals;
/**
* @class PollKind
*
* This class is designed to define the PollKind enumeration.
*/
class PollKind : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
public:
/**
* @brief Enum representing the available poll kinds.
*/
enum Kind {
Disclosed, /**< The poll results can been seen after the user votes. */
Undisclosed, /**< The poll results can only been seen after the poll ends. */
};
Q_ENUM(Kind);
/**
* @brief Return the string for the given Kind.
*
* @sa Kind
*/
static QString stringForKind(Kind kind)
{
switch (kind) {
case Undisclosed:
return "org.matrix.msc3381.poll.undisclosed"_L1;
default:
return "org.matrix.msc3381.poll.disclosed"_L1;
}
}
/**
* @brief Return the Kind for the given string.
*
* @sa Kind
*/
static Kind kindForString(const QString &kindString)
{
if (kindString == "org.matrix.msc3381.poll.undisclosed"_L1) {
return Undisclosed;
}
return Disclosed;
}
};
namespace Quotient
{
namespace EventContent
{
/**
* @brief An answer to the poll.
*/
struct Answer {
Q_GADGET
Q_PROPERTY(QString id MEMBER id CONSTANT)
Q_PROPERTY(QString text MEMBER text CONSTANT)
public:
QString id;
QString text;
int operator==(const Answer &right) const
{
return id == right.id && text == right.text;
}
};
/**
* @brief Struct representing the content of a poll event.
*/
struct PollStartContent {
PollKind::Kind kind;
int maxSelection;
QString question;
QList<EventContent::Answer> answers;
};
} // namespace EventContent
template<>
inline EventContent::Answer fromJson(const QJsonObject &jo)
{
return EventContent::Answer{fromJson<QString>(jo["id"_L1]), fromJson<QString>(jo["org.matrix.msc1767.text"_L1])};
}
template<>
inline auto toJson(const EventContent::Answer &c)
{
QJsonObject jo;
addParam<IfNotEmpty>(jo, "id"_L1, c.id);
addParam<IfNotEmpty>(jo, "org.matrix.msc1767.text"_L1, c.text);
return jo;
}
template<>
inline EventContent::PollStartContent fromJson(const QJsonObject &jo)
{
return EventContent::PollStartContent{
PollKind::kindForString(jo["org.matrix.msc3381.poll.start"_L1]["kind"_L1].toString()),
fromJson<int>(jo["org.matrix.msc3381.poll.start"_L1]["max_selections"_L1]),
fromJson<QString>(jo["org.matrix.msc3381.poll.start"_L1]["question"_L1]["org.matrix.msc1767.text"_L1]),
fromJson<QList<EventContent::Answer>>(jo["org.matrix.msc3381.poll.start"_L1]["answers"_L1]),
};
}
template<>
inline auto toJson(const EventContent::PollStartContent &c)
{
QJsonObject innerJo;
addParam<IfNotEmpty>(innerJo, "kind"_L1, PollKind::stringForKind(c.kind));
addParam(innerJo, "max_selections"_L1, c.maxSelection);
if (innerJo["max_selections"_L1].toInt() < 1) {
innerJo["max_selections"_L1] = 1;
}
innerJo.insert("question"_L1, QJsonObject{{"org.matrix.msc1767.text"_L1, c.question}});
addParam<IfNotEmpty>(innerJo, "answers"_L1, c.answers);
QJsonObject jo;
auto textString = c.question;
for (int i = 0; i < c.answers.length(); ++i) {
textString.append("\n%1. %2"_L1.arg(QString::number(i + 1), c.answers.at(i).text));
}
addParam<IfNotEmpty>(jo, "org.matrix.msc1767.text"_L1, textString);
jo.insert("org.matrix.msc3381.poll.start"_L1, innerJo);
return jo;
}
/**
* @class PollStartEvent
*
* Class to define a poll start event.
*
* See MSC3381 for full details on polls in the matrix spec
* https://github.com/matrix-org/matrix-spec-proposals/blob/travis/msc/polls/proposals/3381-polls.md.
*
* @sa Quotient::RoomEvent
*/
class PollStartEvent : public EventTemplate<PollStartEvent, RoomEvent, EventContent::PollStartContent>
{
public:
QUO_EVENT(PollStartEvent, "org.matrix.msc3381.poll.start");
using EventTemplate::EventTemplate;
/**
* @brief The poll kind.
*/
PollKind::Kind kind() const;
/**
* @brief The maximum number of options a user can select in a poll.
*/
int maxSelections() const;
/**
* @brief The question being asked in the poll.
*/
QString question() const;
/**
* @brief The list of answers to the poll.
*/
QList<EventContent::Answer> answers() const;
};
/**
* @class PollResponseEvent
*
* Class to define a poll response event.
*
* See MSC3381 for full details on polls in the matrix spec
* https://github.com/matrix-org/matrix-spec-proposals/blob/travis/msc/polls/proposals/3381-polls.md.
*
* @sa Quotient::RoomEvent
*/
class PollResponseEvent : public RoomEvent
{
public:
QUO_EVENT(PollResponseEvent, "org.matrix.msc3381.poll.response");
explicit PollResponseEvent(const QJsonObject &obj);
explicit PollResponseEvent(const QString &pollStartEventId, QStringList responses);
/**
* @brief The selected answers to the poll.
*/
QStringList selections() const;
/**
* @brief The EventRelation pointing to the PollStartEvent.
*/
std::optional<EventRelation> relatesTo() const;
};
/**
* @class PollEndEvent
*
* Class to define a poll end event.
*
* See MSC3381 for full details on polls in the matrix spec
* https://github.com/matrix-org/matrix-spec-proposals/blob/travis/msc/polls/proposals/3381-polls.md.
*
* @sa Quotient::RoomEvent
*/
class PollEndEvent : public RoomEvent
{
public:
QUO_EVENT(PollEndEvent, "org.matrix.msc3381.poll.end");
explicit PollEndEvent(const QJsonObject &obj);
explicit PollEndEvent(const QString &pollStartEventId, const QString &endText);
/**
* @brief The EventRelation pointing to the PollStartEvent.
*/
std::optional<EventRelation> relatesTo() const;
};
}

View File

@@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: 2024 James Graham <james.h.graham@protonmail.com>
// SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
#pragma once
#include <Quotient/events/simplestateevents.h>
namespace Quotient
{
// Defined so we can directly switch on type.
DEFINE_SIMPLE_STATE_EVENT(WidgetEvent, "im.vector.modular.widgets", QString, name, "name")
} // namespace Quotient