Introduce the ActionsHandler
This commit is contained in:
@@ -326,7 +326,6 @@ ToolBar {
|
||||
room: currentRoom ?? null
|
||||
}
|
||||
|
||||
|
||||
property int lineHeight: contentHeight / lineCount
|
||||
|
||||
wrapMode: Text.Wrap
|
||||
@@ -470,12 +469,8 @@ ToolBar {
|
||||
}
|
||||
|
||||
function postMessage() {
|
||||
// Qt wraps lines so we need to use a small hack
|
||||
// to remove the wrapped lines but not break the empty
|
||||
// lines.
|
||||
const updatedText = inputField.text.trim()
|
||||
.replace(/@([^: ]*):([^ ]*\.[^ ]*)/, "[@$1:$2](https://matrix.to/#/@$1:$2)");
|
||||
documentHandler.postMessage(updatedText, attachmentPath, replyEventID, editEventId);
|
||||
roomManager.actionsHandler.postMessage(inputField.text.trim(), attachmentPath,
|
||||
replyEventID, editEventId);
|
||||
clearAttachment();
|
||||
currentRoom.markAllMessagesAsRead();
|
||||
clear();
|
||||
|
||||
@@ -36,11 +36,11 @@ Kirigami.OverlaySheet {
|
||||
|
||||
Button {
|
||||
id: okButton
|
||||
|
||||
text: i18nc("@action:button", "Ok")
|
||||
onClicked: {
|
||||
Controller.createRoom(Controller.activeConnection, roomNameField.text, roomTopicField.text)
|
||||
roomManager.actionsHandler.createRoom(roomNameField.text, roomTopicField.text);
|
||||
root.close();
|
||||
// TODO investigate how to join the new room automatically
|
||||
root.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,6 @@ Kirigami.ScrollablePage {
|
||||
property alias keyword: identifierField.text
|
||||
property string server
|
||||
|
||||
signal joinRoom(string room)
|
||||
|
||||
title: i18n("Explore Rooms")
|
||||
|
||||
header: Control {
|
||||
@@ -51,9 +49,9 @@ Kirigami.ScrollablePage {
|
||||
|
||||
onClicked: {
|
||||
if (!identifierField.isJoined) {
|
||||
Controller.joinRoom(connection, identifierField.text);
|
||||
roomManager.actionsHandler.joinRoom(identifierField.text);
|
||||
// When joining the room, the room will be opened
|
||||
}
|
||||
roomManager.enterRoom(connection.room(identifierField.room));
|
||||
applicationWindow().pageStack.layers.pop();
|
||||
}
|
||||
}
|
||||
@@ -104,12 +102,12 @@ Kirigami.ScrollablePage {
|
||||
width: publicRoomsListView.width
|
||||
onClicked: {
|
||||
if (!isJoined) {
|
||||
Controller.joinRoom(connection, roomID)
|
||||
roomManager.actionsHandler.joinRoom(connection, roomID)
|
||||
justJoined = true;
|
||||
} else {
|
||||
roomManager.enterRoom(connection.room(roomID))
|
||||
applicationWindow().pageStack.layers.pop();
|
||||
}
|
||||
applicationWindow().pageStack.layers.pop();
|
||||
}
|
||||
contentItem: RowLayout {
|
||||
Kirigami.Avatar {
|
||||
|
||||
@@ -22,9 +22,6 @@ Kirigami.ScrollablePage {
|
||||
property var enteredRoom
|
||||
required property var activeConnection
|
||||
|
||||
signal enterRoom(var room)
|
||||
signal leaveRoom(var room)
|
||||
|
||||
function goToNextRoom() {
|
||||
do {
|
||||
listView.incrementCurrentIndex();
|
||||
|
||||
@@ -28,7 +28,27 @@ Kirigami.ScrollablePage {
|
||||
signal switchRoomUp()
|
||||
signal switchRoomDown()
|
||||
|
||||
title: currentRoom.name
|
||||
Connections {
|
||||
target: roomManager.actionsHandler
|
||||
onShowMessage: {
|
||||
page.header.contentItem.text = message;
|
||||
page.header.contentItem.type = messageType === ActionsHandler.Error ? Kirigami.MessageType.Error : Kirigami.MessageType.Information;
|
||||
page.header.contentItem.visible = true;
|
||||
}
|
||||
|
||||
onHideMessage: page.header.contentItem.visible = false
|
||||
}
|
||||
|
||||
header: QQC2.Control {
|
||||
visible: contentItem.visible
|
||||
padding: Kirigami.Units.smallSpacing
|
||||
contentItem: Kirigami.InlineMessage {
|
||||
showCloseButton: true
|
||||
visible: false
|
||||
}
|
||||
}
|
||||
|
||||
title: currentRoom.displayName
|
||||
titleDelegate: Component {
|
||||
RowLayout {
|
||||
visible: !Kirigami.Settings.isMobile
|
||||
|
||||
@@ -42,7 +42,10 @@ Kirigami.ScrollablePage {
|
||||
text: i18n("Chat")
|
||||
highlighted: true
|
||||
|
||||
onClicked: Controller.createDirectChat(connection, identifierField.text)
|
||||
onClicked: {
|
||||
connection.requestDirectChat(identifierField.text);
|
||||
applicationWindow().pageStack.layers.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,23 +106,27 @@ Kirigami.ScrollablePage {
|
||||
}
|
||||
|
||||
Button {
|
||||
id: joinChatButton
|
||||
Layout.alignment: Qt.AlignRight
|
||||
visible: directChats != null
|
||||
visible: directChats && directChats.length > 0
|
||||
|
||||
icon.name: "document-send"
|
||||
onClicked: {
|
||||
roomListForm.joinRoom(connection.room(directChats[0]))
|
||||
root.close()
|
||||
connection.requestDirectChat(userID);
|
||||
applicationWindow().pageStack.layers.pop();
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.alignment: Qt.AlignRight
|
||||
icon.name: "irc-join-channel"
|
||||
// We wants to make sure an user can't start more than one
|
||||
// chat with someone.
|
||||
visible: !joinChatButton.visible
|
||||
|
||||
onClicked: {
|
||||
Controller.createDirectChat(connection, userID)
|
||||
root.close()
|
||||
connection.requestDirectChat(userID);
|
||||
applicationWindow().pageStack.layers.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
21
qml/main.qml
21
qml/main.qml
@@ -54,10 +54,19 @@ Kirigami.ApplicationWindow {
|
||||
|
||||
/**
|
||||
* Manage opening and close rooms
|
||||
* TODO this should probably be moved to C++
|
||||
*/
|
||||
QtObject {
|
||||
id: roomManager
|
||||
|
||||
property var actionsHandler: ActionsHandler {
|
||||
room: roomManager.currentRoom
|
||||
connection: Controller.activeConnection
|
||||
onRoomJoined: {
|
||||
roomManager.enterRoom(Controller.activeConnection.room(roomName))
|
||||
}
|
||||
}
|
||||
|
||||
property var currentRoom: null
|
||||
property alias pageStack: root.pageStack
|
||||
property bool invitationOpen: false
|
||||
@@ -262,6 +271,11 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
function onRoomJoined(roomId) {
|
||||
const room = Controller.activeConnection.room(roomId);
|
||||
return roomManager.enterRoom(room);
|
||||
}
|
||||
|
||||
function onConnectionDropped() {
|
||||
if (Controller.accountCount === 0) {
|
||||
pageStack.clear();
|
||||
@@ -287,6 +301,13 @@ Kirigami.ApplicationWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Controller.activeConnection
|
||||
onDirectChatAvailable: {
|
||||
roomManager.enterRoom(Controller.activeConnection.room(directChat.id));
|
||||
}
|
||||
}
|
||||
|
||||
Kirigami.OverlaySheet {
|
||||
id: consentSheet
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
add_executable(neochat
|
||||
accountlistmodel.cpp
|
||||
controller.cpp
|
||||
actionshandler.cpp
|
||||
emojimodel.cpp
|
||||
clipboard.cpp
|
||||
matriximageprovider.cpp
|
||||
|
||||
325
src/actionshandler.cpp
Normal file
325
src/actionshandler.cpp
Normal file
@@ -0,0 +1,325 @@
|
||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
|
||||
//
|
||||
// SPDX-License-Identifier: GPl-3.0-or-later
|
||||
|
||||
#include "actionshandler.h"
|
||||
|
||||
#include "csapi/joining.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <QStringBuilder>
|
||||
#include <QDebug>
|
||||
|
||||
ActionsHandler::ActionsHandler(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
ActionsHandler::~ActionsHandler()
|
||||
{};
|
||||
|
||||
NeoChatRoom *ActionsHandler::room() const
|
||||
{
|
||||
return m_room;
|
||||
}
|
||||
|
||||
void ActionsHandler::setRoom(NeoChatRoom *room)
|
||||
{
|
||||
if (m_room == room) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_room = room;
|
||||
Q_EMIT roomChanged();
|
||||
}
|
||||
|
||||
Connection *ActionsHandler::connection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
void ActionsHandler::setConnection(Connection *connection)
|
||||
{
|
||||
if (m_connection == connection) {
|
||||
return;
|
||||
}
|
||||
if (m_connection != nullptr) {
|
||||
disconnect(m_connection, &Connection::directChatAvailable, nullptr, nullptr);
|
||||
}
|
||||
m_connection = connection;
|
||||
if (m_connection != nullptr) {
|
||||
connect(m_connection, &Connection::directChatAvailable,
|
||||
this, [this](Quotient::Room *room) {
|
||||
room->setDisplayed(true);
|
||||
Q_EMIT roomJoined(room->id());
|
||||
});
|
||||
}
|
||||
Q_EMIT connectionChanged();
|
||||
}
|
||||
|
||||
QVariantList ActionsHandler::commands() const
|
||||
{
|
||||
QVariantList commands;
|
||||
// Messages commands
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/shrug "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<message>"),
|
||||
QStringLiteral("help"), i18n("Prepends ¯\\_(ツ)_/¯ to a plain-text message")
|
||||
});
|
||||
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/lenny "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<message>"),
|
||||
QStringLiteral("help"), i18n("Prepends ( ͡° ͜ʖ ͡°) to a plain-text message")
|
||||
});
|
||||
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/plain "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<message>"),
|
||||
QStringLiteral("help"), i18n("Sends a message as plain text, without interpreting it as markdown")
|
||||
});
|
||||
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/html "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<message>"),
|
||||
QStringLiteral("help"), i18n("Sends a message as html, without interpreting it as markdown")
|
||||
});
|
||||
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/rainbow "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<message>"),
|
||||
QStringLiteral("help"), i18n("Sends the given message coloured as a rainbow")
|
||||
});
|
||||
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/rainbowme "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<message>"),
|
||||
QStringLiteral("help"), i18n("Sends the given emote coloured as a rainbow")
|
||||
});
|
||||
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/me "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<message>"),
|
||||
QStringLiteral("help"), i18n("Displays action")
|
||||
});
|
||||
|
||||
// Actions commands
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/join "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<room-address>"),
|
||||
QStringLiteral("help"), i18n("Joins room with given address")
|
||||
});
|
||||
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/part "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "[<room-address>]"),
|
||||
QStringLiteral("help"), i18n("Leave room")
|
||||
});
|
||||
|
||||
commands.append({
|
||||
QStringLiteral("prefix"), QStringLiteral("/invite "),
|
||||
QStringLiteral("parameter"), i18nc("@label Parameter of a command", "<user-id>"),
|
||||
QStringLiteral("help"), i18n("Invites user with given id to current room")
|
||||
});
|
||||
|
||||
// TODO more see elements /help action
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
void ActionsHandler::joinRoom(const QString &alias)
|
||||
{
|
||||
if (!alias.contains(":")) {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("The room id you are trying to join is not valid"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto knownServer = alias.mid(alias.indexOf(":") + 1);
|
||||
auto joinRoomJob = m_connection->joinRoom(alias, QStringList{knownServer});
|
||||
|
||||
Quotient::JoinRoomJob::connect(joinRoomJob, &JoinRoomJob::failure, [=] {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("Serveur error when joining the room \"%1\": %2",
|
||||
joinRoomJob->errorString()));
|
||||
});
|
||||
Quotient::JoinRoomJob::connect(joinRoomJob, &JoinRoomJob::success, [this, joinRoomJob] {
|
||||
qDebug() << "joined" << joinRoomJob->roomId();
|
||||
Q_EMIT roomJoined(joinRoomJob->roomId());
|
||||
});
|
||||
}
|
||||
|
||||
void ActionsHandler::createRoom(const QString &name, const QString &topic)
|
||||
{
|
||||
auto createRoomJob = m_connection->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
|
||||
Quotient::CreateRoomJob::connect(createRoomJob, &CreateRoomJob::failure, [=] {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("Room creation failed: \"%1\"", createRoomJob->errorString()));
|
||||
});
|
||||
Quotient::CreateRoomJob::connect(createRoomJob, &CreateRoomJob::success, [=] {
|
||||
Q_EMIT roomJoined(createRoomJob->roomId());
|
||||
});
|
||||
}
|
||||
|
||||
void ActionsHandler::postMessage(const QString &text,
|
||||
const QString &attachementPath, const QString &replyEventId, const QString &editEventId)
|
||||
{
|
||||
QString rawText = text;
|
||||
QString cleanedText = text;
|
||||
cleanedText = cleanedText.replace(QRegularExpression("@([^: ]*):([^ ]*\\.[^ ]*)"),
|
||||
"[@$1:$2](https://matrix.to/#/@$1:$2)");
|
||||
|
||||
if (attachementPath.length() > 0) {
|
||||
m_room->uploadFile(attachementPath, cleanedText);
|
||||
}
|
||||
|
||||
if (cleanedText.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto messageEventType = RoomMessageEvent::MsgType::Text;
|
||||
|
||||
// Message commands
|
||||
static const QString shrugPrefix = QStringLiteral("/shrug ");
|
||||
static const QString lennyPrefix = QStringLiteral("/lenny ");
|
||||
static const QString plainPrefix = QStringLiteral("/plain "); // TODO
|
||||
static const QString htmlPrefix = QStringLiteral("/html "); // TODO
|
||||
static const QString rainbowPrefix = QStringLiteral("/rainbow ");
|
||||
static const QString rainbowmePrefix = QStringLiteral("/rainbowme ");
|
||||
static const QString mePrefix = QStringLiteral("/me ");
|
||||
static const QString noticePrefix = QStringLiteral("/notice ");
|
||||
|
||||
// Actions commands
|
||||
static const QString ddgPrefix = QStringLiteral("/ddg "); // TODO
|
||||
static const QString nickPrefix = QStringLiteral("/nick "); // TODO
|
||||
static const QString meroomnickPrefix = QStringLiteral("/myroomnick "); // TODO
|
||||
static const QString roomavatarPrefix = QStringLiteral("/roomavatar "); // TODO
|
||||
static const QString myroomavatarPrefix = QStringLiteral("/myroomavatar "); // TODO
|
||||
static const QString myavatarPrefix = QStringLiteral("/myavatar "); // TODO
|
||||
static const QString invitePrefix = QStringLiteral("/invite ");
|
||||
static const QString joinPrefix = QStringLiteral("/join ");
|
||||
static const QString partPrefix = QStringLiteral("/part");
|
||||
static const QString ignorePrefix = QStringLiteral("/ignore ");
|
||||
static const QString unignorePrefix = QStringLiteral("/unignore ");
|
||||
static const QString queryPrefix = QStringLiteral("/query "); // TODO
|
||||
static const QString msgPrefix = QStringLiteral("/msg "); // TODO
|
||||
|
||||
// Admin commands
|
||||
|
||||
static QStringList rainbowColors{"#ff2b00", "#ff5500", "#ff8000", "#ffaa00", "#ffd500",
|
||||
"#ffff00", "#d4ff00", "#aaff00", "#80ff00", "#55ff00", "#2bff00", "#00ff00", "#00ff2b",
|
||||
"#00ff55", "#00ff80", "#00ffaa", "#00ffd5", "#00ffff", "#00d4ff", "#00aaff", "#007fff",
|
||||
"#0055ff", "#002bff", "#0000ff", "#2a00ff", "#5500ff", "#7f00ff", "#aa00ff", "#d400ff",
|
||||
"#ff00ff", "#ff00d4", "#ff00aa", "#ff0080", "#ff0055", "#ff002b", "#ff0000"};
|
||||
|
||||
if (cleanedText.indexOf(shrugPrefix) == 0) {
|
||||
cleanedText = QStringLiteral("¯\\\\_(ツ)\\_/¯") % cleanedText.remove(0, shrugPrefix.length());
|
||||
m_room->postHtmlMessage(cleanedText, cleanedText, messageEventType, replyEventId, editEventId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleanedText.indexOf(lennyPrefix) == 0) {
|
||||
cleanedText = QStringLiteral("( ͡° ͜ʖ ͡°)") % cleanedText.remove(0, lennyPrefix.length());
|
||||
m_room->postHtmlMessage(cleanedText, cleanedText, messageEventType, replyEventId, editEventId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleanedText.indexOf(rainbowPrefix) == 0) {
|
||||
cleanedText = cleanedText.remove(0, rainbowPrefix.length());
|
||||
QString rainbowText;
|
||||
for (int i = 0; i < cleanedText.length(); i++) {
|
||||
rainbowText = rainbowText % QStringLiteral("<font color='") % rainbowColors.at(i % rainbowColors.length()) % "'>" % cleanedText.at(i) % "</font>";
|
||||
}
|
||||
m_room->postHtmlMessage(cleanedText, rainbowText, RoomMessageEvent::MsgType::Notice, replyEventId, editEventId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleanedText.indexOf(rainbowmePrefix) == 0) {
|
||||
cleanedText = cleanedText.remove(0, rainbowmePrefix.length());
|
||||
QString rainbowText;
|
||||
for (int i = 0; i < cleanedText.length(); i++) {
|
||||
rainbowText = rainbowText % QStringLiteral("<font color='") % rainbowColors.at(i % rainbowColors.length()) % "'>" % cleanedText.at(i) % "</font>";
|
||||
}
|
||||
m_room->postHtmlMessage(cleanedText, rainbowText, messageEventType, replyEventId, editEventId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rawText.indexOf(joinPrefix) == 0) {
|
||||
rawText = rawText.remove(0, joinPrefix.length());
|
||||
const QStringList splittedText = rawText.split(" ");
|
||||
if (text.count() == 0) {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("Invalid command"));
|
||||
return;
|
||||
}
|
||||
joinRoom(splittedText[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rawText.indexOf(invitePrefix) == 0) {
|
||||
rawText = rawText.remove(0, invitePrefix.length());
|
||||
const QStringList splittedText = rawText.split(" ");
|
||||
if (splittedText.count() == 0) {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("Invalid command"));
|
||||
return;
|
||||
}
|
||||
m_room->inviteToRoom(splittedText[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rawText.indexOf(partPrefix) == 0) {
|
||||
rawText = rawText.remove(0, partPrefix.length());
|
||||
const QStringList splittedText = rawText.split(" ");
|
||||
qDebug() << m_room;
|
||||
qDebug() << "m_room";
|
||||
qDebug() << splittedText;
|
||||
if (splittedText.count() == 0 || splittedText[0].isEmpty()) {
|
||||
// leave current room
|
||||
m_connection->leaveRoom(m_room);
|
||||
return;
|
||||
}
|
||||
m_connection->leaveRoom(m_connection->room(splittedText[0]));
|
||||
return;
|
||||
}
|
||||
|
||||
if (rawText.indexOf(ignorePrefix) == 0) {
|
||||
rawText = rawText.remove(0, ignorePrefix.length());
|
||||
const QStringList splittedText = rawText.split(" ");
|
||||
if (splittedText.count() == 0) {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("Invalid command"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_connection->users().contains(splittedText[0])) {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("Invalid command"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *user = m_connection->users()[splittedText[0]];
|
||||
m_connection->addToIgnoredUsers(user);
|
||||
return;
|
||||
}
|
||||
|
||||
if (rawText.indexOf(unignorePrefix) == 0) {
|
||||
rawText = rawText.remove(0, unignorePrefix.length());
|
||||
const QStringList splittedText = rawText.split(" ");
|
||||
if (splittedText.count() == 0) {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("Invalid command"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_connection->users().contains(splittedText[0])) {
|
||||
Q_EMIT showMessage(MessageType::Error, i18n("Invalid command"));
|
||||
return;
|
||||
}
|
||||
|
||||
const auto *user = m_connection->users()[splittedText[0]];
|
||||
m_connection->removeFromIgnoredUsers(user);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleanedText.indexOf(mePrefix) == 0) {
|
||||
cleanedText = cleanedText.remove(0, mePrefix.length());
|
||||
messageEventType = RoomMessageEvent::MsgType::Emote;
|
||||
} else if (cleanedText.indexOf(noticePrefix) == 0) {
|
||||
cleanedText = cleanedText.remove(0, noticePrefix.length());
|
||||
messageEventType = RoomMessageEvent::MsgType::Notice;
|
||||
}
|
||||
m_room->postMessage(cleanedText, messageEventType, replyEventId, editEventId);
|
||||
}
|
||||
78
src/actionshandler.h
Normal file
78
src/actionshandler.h
Normal file
@@ -0,0 +1,78 @@
|
||||
// SPDX-FileCopyrightText: 2020 Carl Schwan <carlschwan@kde.org>
|
||||
//
|
||||
// SPDX-License-Identifier: GPl-3.0-or-later
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "connection.h"
|
||||
#include "neochatroom.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
/// \brief Handles user interactions with NeoChat (joining room, creating room,
|
||||
/// sending message). Account management is handled by Controller.
|
||||
class ActionsHandler : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
/// \brief List of command definition. Usefull for buiding an autcompletion
|
||||
/// engine or an help dialog.
|
||||
Q_PROPERTY(QVariantList commands READ commands CONSTANT)
|
||||
|
||||
/// \brief The connection that will handle sending the message.
|
||||
Q_PROPERTY(Connection *connection READ connection WRITE setConnection NOTIFY connectionChanged)
|
||||
|
||||
/// \brief The connection that will handle sending the message.
|
||||
Q_PROPERTY(NeoChatRoom *room READ room WRITE setRoom NOTIFY roomChanged)
|
||||
|
||||
public:
|
||||
enum MessageType {
|
||||
Info,
|
||||
Error,
|
||||
};
|
||||
Q_ENUM(MessageType);
|
||||
|
||||
explicit ActionsHandler(QObject *parent = nullptr);
|
||||
~ActionsHandler();
|
||||
|
||||
QVariantList commands() const;
|
||||
|
||||
[[nodiscard]] Connection *connection() const;
|
||||
void setConnection(Connection *connection);
|
||||
|
||||
[[nodiscard]] NeoChatRoom *room() const;
|
||||
void setRoom(NeoChatRoom *room);
|
||||
|
||||
Q_SIGNALS:
|
||||
/// \brief Show error or information message.
|
||||
///
|
||||
/// These messages will be displayed in the room view header.
|
||||
void showMessage(MessageType messageType, QString message);
|
||||
|
||||
/// \brief Emmited when an action made the user join a room.
|
||||
///
|
||||
/// Either when a new room was created, a direct chat was started
|
||||
/// or a group chat was joined. The UI will react to this signal
|
||||
/// and switch to the newly joined room.
|
||||
void roomJoined(QString roomName);
|
||||
|
||||
void roomChanged();
|
||||
void connectionChanged();
|
||||
|
||||
public Q_SLOTS:
|
||||
/// \brief Create new room for a group chat.
|
||||
void createRoom(const QString &name, const QString &topic);
|
||||
|
||||
/// \brief Join a room.
|
||||
void joinRoom(const QString &alias);
|
||||
|
||||
/// \brief Post a message.
|
||||
///
|
||||
/// This also interprets commands if any.
|
||||
void postMessage(const QString &text, const QString &attachementPath,
|
||||
const QString &replyEventId, const QString &editEventId);
|
||||
|
||||
private:
|
||||
Connection *m_connection = nullptr;
|
||||
NeoChatRoom *m_room = nullptr;
|
||||
};
|
||||
@@ -167,53 +167,6 @@ QVariantMap ChatDocumentHandler::getAutocompletionInfo()
|
||||
};
|
||||
}
|
||||
|
||||
void ChatDocumentHandler::postMessage(const QString &text, const QString &attachementPath, const QString &replyEventId, const QString &editEventId) const
|
||||
{
|
||||
if (!m_room || !m_document) {
|
||||
return;
|
||||
}
|
||||
|
||||
QString cleanedText = text;
|
||||
|
||||
cleanedText = cleanedText.trimmed();
|
||||
|
||||
if (attachementPath.length() > 0) {
|
||||
m_room->uploadFile(attachementPath, cleanedText);
|
||||
}
|
||||
|
||||
if (cleanedText.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto messageEventType = RoomMessageEvent::MsgType::Text;
|
||||
|
||||
const QString rainbowPrefix = QStringLiteral("/rainbow ");
|
||||
const QString mePrefix = QStringLiteral("/me ");
|
||||
const QString noticePrefix = QStringLiteral("/notice ");
|
||||
|
||||
if (cleanedText.indexOf(rainbowPrefix) == 0) {
|
||||
cleanedText = cleanedText.remove(0, rainbowPrefix.length());
|
||||
QString rainbowText;
|
||||
QStringList rainbowColors{"#ff2b00", "#ff5500", "#ff8000", "#ffaa00", "#ffd500", "#ffff00", "#d4ff00", "#aaff00", "#80ff00", "#55ff00", "#2bff00", "#00ff00", "#00ff2b", "#00ff55", "#00ff80", "#00ffaa", "#00ffd5", "#00ffff",
|
||||
"#00d4ff", "#00aaff", "#007fff", "#0055ff", "#002bff", "#0000ff", "#2a00ff", "#5500ff", "#7f00ff", "#aa00ff", "#d400ff", "#ff00ff", "#ff00d4", "#ff00aa", "#ff0080", "#ff0055", "#ff002b", "#ff0000"};
|
||||
|
||||
for (int i = 0; i < cleanedText.length(); i++) {
|
||||
rainbowText = rainbowText % QStringLiteral("<font color='") % rainbowColors.at(i % rainbowColors.length()) % "'>" % cleanedText.at(i) % "</font>";
|
||||
}
|
||||
m_room->postHtmlMessage(cleanedText, rainbowText, messageEventType, replyEventId, editEventId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cleanedText.indexOf(mePrefix) == 0) {
|
||||
cleanedText = cleanedText.remove(0, mePrefix.length());
|
||||
messageEventType = RoomMessageEvent::MsgType::Emote;
|
||||
} else if (cleanedText.indexOf(noticePrefix) == 0) {
|
||||
cleanedText = cleanedText.remove(0, noticePrefix.length());
|
||||
messageEventType = RoomMessageEvent::MsgType::Notice;
|
||||
}
|
||||
m_room->postMessage(cleanedText, messageEventType, replyEventId, editEventId);
|
||||
}
|
||||
|
||||
void ChatDocumentHandler::replaceAutoComplete(const QString &word)
|
||||
{
|
||||
QTextCursor cursor = textCursor();
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
class QTextDocument;
|
||||
class QQuickTextDocument;
|
||||
class NeoChatRoom;
|
||||
class Controller;
|
||||
|
||||
class ChatDocumentHandler : public QObject
|
||||
{
|
||||
@@ -51,8 +52,6 @@ public:
|
||||
[[nodiscard]] NeoChatRoom *room() const;
|
||||
void setRoom(NeoChatRoom *room);
|
||||
|
||||
Q_INVOKABLE void postMessage(const QString &text, const QString &attachementPath, const QString &replyEventId, const QString &editEventId) const;
|
||||
|
||||
/// This function will look at the current QTextCursor and determine if there
|
||||
/// is the posibility to autocomplete it.
|
||||
Q_INVOKABLE QVariantMap getAutocompletionInfo();
|
||||
@@ -64,6 +63,7 @@ Q_SIGNALS:
|
||||
void selectionStartChanged();
|
||||
void selectionEndChanged();
|
||||
void roomChanged();
|
||||
void joinRoom(QString roomName);
|
||||
|
||||
private:
|
||||
[[nodiscard]] QTextCursor textCursor() const;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <KConfig>
|
||||
#include <KConfigGroup>
|
||||
#include <KWindowConfig>
|
||||
|
||||
#include <KLocalizedString>
|
||||
|
||||
#include <QClipboard>
|
||||
@@ -23,7 +22,6 @@
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QStandardPaths>
|
||||
#include <QStringBuilder>
|
||||
#include <QSysInfo>
|
||||
#include <QTimer>
|
||||
#include <QCloseEvent>
|
||||
@@ -32,11 +30,11 @@
|
||||
#include <QPixmap>
|
||||
#include <QAuthenticator>
|
||||
#include <QNetworkReply>
|
||||
#include <QStringBuilder>
|
||||
#include <utility>
|
||||
|
||||
#include "csapi/account-data.h"
|
||||
#include "csapi/content-repo.h"
|
||||
#include "csapi/joining.h"
|
||||
#include "csapi/logout.h"
|
||||
#include "csapi/profile.h"
|
||||
#include "csapi/registration.h"
|
||||
@@ -399,34 +397,6 @@ bool Controller::saveAccessTokenToKeyChain(const AccountSettings &account, const
|
||||
return true;
|
||||
}
|
||||
|
||||
void Controller::joinRoom(Connection *c, const QString &alias)
|
||||
{
|
||||
if (!alias.contains(":")) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto knownServer = alias.mid(alias.indexOf(":") + 1);
|
||||
auto joinRoomJob = c->joinRoom(alias, QStringList{knownServer});
|
||||
Quotient::JoinRoomJob::connect(joinRoomJob, &JoinRoomJob::failure, [=] {
|
||||
Q_EMIT errorOccured("Join Room Failed", joinRoomJob->errorString());
|
||||
});
|
||||
}
|
||||
|
||||
void Controller::createRoom(Connection *c, const QString &name, const QString &topic)
|
||||
{
|
||||
auto createRoomJob = c->createRoom(Connection::PublishRoom, "", name, topic, QStringList());
|
||||
Quotient::CreateRoomJob::connect(createRoomJob, &CreateRoomJob::failure, [=] {
|
||||
Q_EMIT errorOccured("Create Room Failed", createRoomJob->errorString());
|
||||
});
|
||||
}
|
||||
|
||||
void Controller::createDirectChat(Connection *c, const QString &userID)
|
||||
{
|
||||
auto createRoomJob = c->createDirectChat(userID);
|
||||
Quotient::CreateRoomJob::connect(createRoomJob, &CreateRoomJob::failure, [=] {
|
||||
Q_EMIT errorOccured("Create Direct Chat Failed", createRoomJob->errorString());
|
||||
});
|
||||
}
|
||||
|
||||
void Controller::playAudio(const QUrl &localFile)
|
||||
{
|
||||
@@ -574,6 +544,7 @@ void Controller::saveWindowGeometry(QQuickWindow *window)
|
||||
dataResource.sync();
|
||||
}
|
||||
|
||||
|
||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
|
||||
: Quotient::BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId))
|
||||
{
|
||||
|
||||
@@ -113,9 +113,6 @@ Q_SIGNALS:
|
||||
|
||||
public Q_SLOTS:
|
||||
void logout(Quotient::Connection *conn, bool serverSideLogout);
|
||||
void joinRoom(Quotient::Connection *c, const QString &alias);
|
||||
void createRoom(Quotient::Connection *c, const QString &name, const QString &topic);
|
||||
void createDirectChat(Quotient::Connection *c, const QString &userID);
|
||||
static void playAudio(const QUrl &localFile);
|
||||
void changeAvatar(Quotient::Connection *conn, const QUrl &localFile);
|
||||
static void markAllMessagesAsRead(Quotient::Connection *conn);
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
#include "sortfilterroomlistmodel.h"
|
||||
#include "userdirectorylistmodel.h"
|
||||
#include "userlistmodel.h"
|
||||
#include "actionshandler.h"
|
||||
|
||||
using namespace Quotient;
|
||||
|
||||
@@ -97,6 +98,7 @@ int main(int argc, char *argv[])
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "Config", config);
|
||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "FileType", &fileTypeSingleton);
|
||||
qmlRegisterType<AccountListModel>("org.kde.neochat", 1, 0, "AccountListModel");
|
||||
qmlRegisterType<ActionsHandler>("org.kde.neochat", 1, 0, "ActionsHandler");
|
||||
qmlRegisterType<ChatDocumentHandler>("org.kde.neochat", 1, 0, "ChatDocumentHandler");
|
||||
qmlRegisterType<RoomListModel>("org.kde.neochat", 1, 0, "RoomListModel");
|
||||
qmlRegisterType<UserListModel>("org.kde.neochat", 1, 0, "UserListModel");
|
||||
|
||||
Reference in New Issue
Block a user