Introduce the ActionsHandler
This commit is contained in:
@@ -326,7 +326,6 @@ ToolBar {
|
|||||||
room: currentRoom ?? null
|
room: currentRoom ?? null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
property int lineHeight: contentHeight / lineCount
|
property int lineHeight: contentHeight / lineCount
|
||||||
|
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
@@ -470,12 +469,8 @@ ToolBar {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function postMessage() {
|
function postMessage() {
|
||||||
// Qt wraps lines so we need to use a small hack
|
roomManager.actionsHandler.postMessage(inputField.text.trim(), attachmentPath,
|
||||||
// to remove the wrapped lines but not break the empty
|
replyEventID, editEventId);
|
||||||
// lines.
|
|
||||||
const updatedText = inputField.text.trim()
|
|
||||||
.replace(/@([^: ]*):([^ ]*\.[^ ]*)/, "[@$1:$2](https://matrix.to/#/@$1:$2)");
|
|
||||||
documentHandler.postMessage(updatedText, attachmentPath, replyEventID, editEventId);
|
|
||||||
clearAttachment();
|
clearAttachment();
|
||||||
currentRoom.markAllMessagesAsRead();
|
currentRoom.markAllMessagesAsRead();
|
||||||
clear();
|
clear();
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ Kirigami.OverlaySheet {
|
|||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: okButton
|
id: okButton
|
||||||
|
|
||||||
text: i18nc("@action:button", "Ok")
|
text: i18nc("@action:button", "Ok")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
Controller.createRoom(Controller.activeConnection, roomNameField.text, roomTopicField.text)
|
roomManager.actionsHandler.createRoom(roomNameField.text, roomTopicField.text);
|
||||||
root.close();
|
root.close();
|
||||||
// TODO investigate how to join the new room automatically
|
|
||||||
root.destroy();
|
root.destroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ Kirigami.ScrollablePage {
|
|||||||
property alias keyword: identifierField.text
|
property alias keyword: identifierField.text
|
||||||
property string server
|
property string server
|
||||||
|
|
||||||
signal joinRoom(string room)
|
|
||||||
|
|
||||||
title: i18n("Explore Rooms")
|
title: i18n("Explore Rooms")
|
||||||
|
|
||||||
header: Control {
|
header: Control {
|
||||||
@@ -51,9 +49,9 @@ Kirigami.ScrollablePage {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!identifierField.isJoined) {
|
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();
|
applicationWindow().pageStack.layers.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,12 +102,12 @@ Kirigami.ScrollablePage {
|
|||||||
width: publicRoomsListView.width
|
width: publicRoomsListView.width
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!isJoined) {
|
if (!isJoined) {
|
||||||
Controller.joinRoom(connection, roomID)
|
roomManager.actionsHandler.joinRoom(connection, roomID)
|
||||||
justJoined = true;
|
justJoined = true;
|
||||||
} else {
|
} else {
|
||||||
roomManager.enterRoom(connection.room(roomID))
|
roomManager.enterRoom(connection.room(roomID))
|
||||||
applicationWindow().pageStack.layers.pop();
|
|
||||||
}
|
}
|
||||||
|
applicationWindow().pageStack.layers.pop();
|
||||||
}
|
}
|
||||||
contentItem: RowLayout {
|
contentItem: RowLayout {
|
||||||
Kirigami.Avatar {
|
Kirigami.Avatar {
|
||||||
|
|||||||
@@ -22,9 +22,6 @@ Kirigami.ScrollablePage {
|
|||||||
property var enteredRoom
|
property var enteredRoom
|
||||||
required property var activeConnection
|
required property var activeConnection
|
||||||
|
|
||||||
signal enterRoom(var room)
|
|
||||||
signal leaveRoom(var room)
|
|
||||||
|
|
||||||
function goToNextRoom() {
|
function goToNextRoom() {
|
||||||
do {
|
do {
|
||||||
listView.incrementCurrentIndex();
|
listView.incrementCurrentIndex();
|
||||||
|
|||||||
@@ -28,7 +28,27 @@ Kirigami.ScrollablePage {
|
|||||||
signal switchRoomUp()
|
signal switchRoomUp()
|
||||||
signal switchRoomDown()
|
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 {
|
titleDelegate: Component {
|
||||||
RowLayout {
|
RowLayout {
|
||||||
visible: !Kirigami.Settings.isMobile
|
visible: !Kirigami.Settings.isMobile
|
||||||
|
|||||||
@@ -42,7 +42,10 @@ Kirigami.ScrollablePage {
|
|||||||
text: i18n("Chat")
|
text: i18n("Chat")
|
||||||
highlighted: true
|
highlighted: true
|
||||||
|
|
||||||
onClicked: Controller.createDirectChat(connection, identifierField.text)
|
onClicked: {
|
||||||
|
connection.requestDirectChat(identifierField.text);
|
||||||
|
applicationWindow().pageStack.layers.pop();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,23 +106,27 @@ Kirigami.ScrollablePage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
|
id: joinChatButton
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
visible: directChats != null
|
visible: directChats && directChats.length > 0
|
||||||
|
|
||||||
icon.name: "document-send"
|
icon.name: "document-send"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
roomListForm.joinRoom(connection.room(directChats[0]))
|
connection.requestDirectChat(userID);
|
||||||
root.close()
|
applicationWindow().pageStack.layers.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
icon.name: "irc-join-channel"
|
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: {
|
onClicked: {
|
||||||
Controller.createDirectChat(connection, userID)
|
connection.requestDirectChat(userID);
|
||||||
root.close()
|
applicationWindow().pageStack.layers.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
qml/main.qml
21
qml/main.qml
@@ -54,10 +54,19 @@ Kirigami.ApplicationWindow {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Manage opening and close rooms
|
* Manage opening and close rooms
|
||||||
|
* TODO this should probably be moved to C++
|
||||||
*/
|
*/
|
||||||
QtObject {
|
QtObject {
|
||||||
id: roomManager
|
id: roomManager
|
||||||
|
|
||||||
|
property var actionsHandler: ActionsHandler {
|
||||||
|
room: roomManager.currentRoom
|
||||||
|
connection: Controller.activeConnection
|
||||||
|
onRoomJoined: {
|
||||||
|
roomManager.enterRoom(Controller.activeConnection.room(roomName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
property var currentRoom: null
|
property var currentRoom: null
|
||||||
property alias pageStack: root.pageStack
|
property alias pageStack: root.pageStack
|
||||||
property bool invitationOpen: false
|
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() {
|
function onConnectionDropped() {
|
||||||
if (Controller.accountCount === 0) {
|
if (Controller.accountCount === 0) {
|
||||||
pageStack.clear();
|
pageStack.clear();
|
||||||
@@ -287,6 +301,13 @@ Kirigami.ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: Controller.activeConnection
|
||||||
|
onDirectChatAvailable: {
|
||||||
|
roomManager.enterRoom(Controller.activeConnection.room(directChat.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Kirigami.OverlaySheet {
|
Kirigami.OverlaySheet {
|
||||||
id: consentSheet
|
id: consentSheet
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
add_executable(neochat
|
add_executable(neochat
|
||||||
accountlistmodel.cpp
|
accountlistmodel.cpp
|
||||||
controller.cpp
|
controller.cpp
|
||||||
|
actionshandler.cpp
|
||||||
emojimodel.cpp
|
emojimodel.cpp
|
||||||
clipboard.cpp
|
clipboard.cpp
|
||||||
matriximageprovider.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)
|
void ChatDocumentHandler::replaceAutoComplete(const QString &word)
|
||||||
{
|
{
|
||||||
QTextCursor cursor = textCursor();
|
QTextCursor cursor = textCursor();
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
class QTextDocument;
|
class QTextDocument;
|
||||||
class QQuickTextDocument;
|
class QQuickTextDocument;
|
||||||
class NeoChatRoom;
|
class NeoChatRoom;
|
||||||
|
class Controller;
|
||||||
|
|
||||||
class ChatDocumentHandler : public QObject
|
class ChatDocumentHandler : public QObject
|
||||||
{
|
{
|
||||||
@@ -51,8 +52,6 @@ public:
|
|||||||
[[nodiscard]] NeoChatRoom *room() const;
|
[[nodiscard]] NeoChatRoom *room() const;
|
||||||
void setRoom(NeoChatRoom *room);
|
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
|
/// This function will look at the current QTextCursor and determine if there
|
||||||
/// is the posibility to autocomplete it.
|
/// is the posibility to autocomplete it.
|
||||||
Q_INVOKABLE QVariantMap getAutocompletionInfo();
|
Q_INVOKABLE QVariantMap getAutocompletionInfo();
|
||||||
@@ -64,6 +63,7 @@ Q_SIGNALS:
|
|||||||
void selectionStartChanged();
|
void selectionStartChanged();
|
||||||
void selectionEndChanged();
|
void selectionEndChanged();
|
||||||
void roomChanged();
|
void roomChanged();
|
||||||
|
void joinRoom(QString roomName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
[[nodiscard]] QTextCursor textCursor() const;
|
[[nodiscard]] QTextCursor textCursor() const;
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
#include <KConfig>
|
#include <KConfig>
|
||||||
#include <KConfigGroup>
|
#include <KConfigGroup>
|
||||||
#include <KWindowConfig>
|
#include <KWindowConfig>
|
||||||
|
|
||||||
#include <KLocalizedString>
|
#include <KLocalizedString>
|
||||||
|
|
||||||
#include <QClipboard>
|
#include <QClipboard>
|
||||||
@@ -23,7 +22,6 @@
|
|||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
#include <QStringBuilder>
|
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
@@ -32,11 +30,11 @@
|
|||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
#include <QAuthenticator>
|
#include <QAuthenticator>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
#include <QStringBuilder>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#include "csapi/account-data.h"
|
#include "csapi/account-data.h"
|
||||||
#include "csapi/content-repo.h"
|
#include "csapi/content-repo.h"
|
||||||
#include "csapi/joining.h"
|
|
||||||
#include "csapi/logout.h"
|
#include "csapi/logout.h"
|
||||||
#include "csapi/profile.h"
|
#include "csapi/profile.h"
|
||||||
#include "csapi/registration.h"
|
#include "csapi/registration.h"
|
||||||
@@ -399,34 +397,6 @@ bool Controller::saveAccessTokenToKeyChain(const AccountSettings &account, const
|
|||||||
return true;
|
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)
|
void Controller::playAudio(const QUrl &localFile)
|
||||||
{
|
{
|
||||||
@@ -574,6 +544,7 @@ void Controller::saveWindowGeometry(QQuickWindow *window)
|
|||||||
dataResource.sync();
|
dataResource.sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
|
NeochatDeleteDeviceJob::NeochatDeleteDeviceJob(const QString &deviceId, const Omittable<QJsonObject> &auth)
|
||||||
: Quotient::BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId))
|
: Quotient::BaseJob(HttpVerb::Delete, QStringLiteral("DeleteDeviceJob"), QStringLiteral("/_matrix/client/r0/devices/%1").arg(deviceId))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -113,9 +113,6 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void logout(Quotient::Connection *conn, bool serverSideLogout);
|
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);
|
static void playAudio(const QUrl &localFile);
|
||||||
void changeAvatar(Quotient::Connection *conn, const QUrl &localFile);
|
void changeAvatar(Quotient::Connection *conn, const QUrl &localFile);
|
||||||
static void markAllMessagesAsRead(Quotient::Connection *conn);
|
static void markAllMessagesAsRead(Quotient::Connection *conn);
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "sortfilterroomlistmodel.h"
|
#include "sortfilterroomlistmodel.h"
|
||||||
#include "userdirectorylistmodel.h"
|
#include "userdirectorylistmodel.h"
|
||||||
#include "userlistmodel.h"
|
#include "userlistmodel.h"
|
||||||
|
#include "actionshandler.h"
|
||||||
|
|
||||||
using namespace Quotient;
|
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, "Config", config);
|
||||||
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "FileType", &fileTypeSingleton);
|
qmlRegisterSingletonInstance("org.kde.neochat", 1, 0, "FileType", &fileTypeSingleton);
|
||||||
qmlRegisterType<AccountListModel>("org.kde.neochat", 1, 0, "AccountListModel");
|
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<ChatDocumentHandler>("org.kde.neochat", 1, 0, "ChatDocumentHandler");
|
||||||
qmlRegisterType<RoomListModel>("org.kde.neochat", 1, 0, "RoomListModel");
|
qmlRegisterType<RoomListModel>("org.kde.neochat", 1, 0, "RoomListModel");
|
||||||
qmlRegisterType<UserListModel>("org.kde.neochat", 1, 0, "UserListModel");
|
qmlRegisterType<UserListModel>("org.kde.neochat", 1, 0, "UserListModel");
|
||||||
|
|||||||
Reference in New Issue
Block a user