Add a way to view server support information
This is useful if your server has said information, for matrix.org includes abuse and administrator e-mails. See #707
This commit is contained in:
@@ -37,6 +37,8 @@ qt_add_library(neochat STATIC
|
|||||||
texttospeechhelper.cpp
|
texttospeechhelper.cpp
|
||||||
models/limitermodel.cpp
|
models/limitermodel.cpp
|
||||||
models/limitermodel.h
|
models/limitermodel.h
|
||||||
|
supportcontroller.cpp
|
||||||
|
supportcontroller.h
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
set_source_files_properties(qml/OsmLocationPlugin.qml PROPERTIES
|
||||||
@@ -107,6 +109,7 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
|
|||||||
qml/UserMenu.qml
|
qml/UserMenu.qml
|
||||||
qml/MeetingDialog.qml
|
qml/MeetingDialog.qml
|
||||||
qml/SeenByDialog.qml
|
qml/SeenByDialog.qml
|
||||||
|
qml/SupportDialog.qml
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
QtCore
|
QtCore
|
||||||
QtQuick
|
QtQuick
|
||||||
|
|||||||
@@ -118,6 +118,16 @@ KirigamiComponents.ConvergentContextMenu {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Kirigami.Action {
|
||||||
|
text: i18nc("@action:inmenu Open support dialog", "Support")
|
||||||
|
icon.name: "help-contents-symbolic"
|
||||||
|
onTriggered: {
|
||||||
|
Qt.createComponent("org.kde.neochat", "SupportDialog").createObject(QQC2.Overlay.overlay, {
|
||||||
|
connection: root.connection,
|
||||||
|
}).open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
text: i18nc("@action:inmenu", "Logout…")
|
text: i18nc("@action:inmenu", "Logout…")
|
||||||
icon.name: "im-kick-user"
|
icon.name: "im-kick-user"
|
||||||
|
|||||||
121
src/app/qml/SupportDialog.qml
Normal file
121
src/app/qml/SupportDialog.qml
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls as QQC2
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
|
import org.kde.kirigami as Kirigami
|
||||||
|
import org.kde.kirigamiaddons.formcard as FormCard
|
||||||
|
|
||||||
|
import org.kde.neochat
|
||||||
|
|
||||||
|
Kirigami.Dialog {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property NeoChatConnection connection
|
||||||
|
|
||||||
|
readonly property SupportController supportController: SupportController {
|
||||||
|
connection: root.connection
|
||||||
|
}
|
||||||
|
readonly property bool hasSupportResources: supportController.supportPage.length > 0 && supportController.contacts.length > 0
|
||||||
|
|
||||||
|
title: i18nc("@title Support information", "Support")
|
||||||
|
width: Math.min(Kirigami.Units.gridUnit * 30, QQC2.ApplicationWindow.window.width)
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
FormCard.FormTextDelegate {
|
||||||
|
id: explanationTextDelegate
|
||||||
|
|
||||||
|
text: root.hasSupportResources ?
|
||||||
|
i18nc("@info:label %1 is the domain of the server", "Offical support resources provided by %1:", root.connection.domain)
|
||||||
|
: i18nc("@info:label %1 is the domain of the server", "%1 has no support resources.", root.connection.domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
FormCard.FormDelegateSeparator {
|
||||||
|
above: explanationTextDelegate
|
||||||
|
below: openSupportPageDelegate
|
||||||
|
visible: openSupportPageDelegate.visible
|
||||||
|
}
|
||||||
|
|
||||||
|
FormCard.FormLinkDelegate {
|
||||||
|
id: openSupportPageDelegate
|
||||||
|
|
||||||
|
icon.name: "help-contents-symbolic"
|
||||||
|
text: i18nc("@action:button Open support webpage", "Open Support")
|
||||||
|
url: root.supportController.supportPage
|
||||||
|
visible: root.supportController.supportPage.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
FormCard.FormDelegateSeparator {
|
||||||
|
above: openSupportPageDelegate
|
||||||
|
visible: root.supportController.contacts.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.supportController.contacts
|
||||||
|
|
||||||
|
delegate: FormCard.AbstractFormDelegate {
|
||||||
|
id: contactDelegate
|
||||||
|
|
||||||
|
required property string role
|
||||||
|
required property string matrixId
|
||||||
|
required property string emailAddress
|
||||||
|
|
||||||
|
background: null
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
|
||||||
|
contentItem: RowLayout {
|
||||||
|
spacing: Kirigami.Units.largeSpacing
|
||||||
|
|
||||||
|
Kirigami.Icon {
|
||||||
|
source: "user"
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.Label {
|
||||||
|
text: {
|
||||||
|
// Translate known keys
|
||||||
|
if (contactDelegate.role === "m.role.admin") {
|
||||||
|
return i18nc("@info:label Adminstrator contact", "Admin")
|
||||||
|
} else if (contactDelegate.role === "m.role.security") {
|
||||||
|
return i18nc("@info:label Security contact", "Security")
|
||||||
|
}
|
||||||
|
return contactDelegate.role;
|
||||||
|
}
|
||||||
|
elide: Text.ElideRight
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.ToolButton {
|
||||||
|
visible: contactDelegate.matrixId.length > 0
|
||||||
|
icon.name: "document-send-symbolic"
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
root.close();
|
||||||
|
root.connection.requestDirectChat(contactDelegate.matrixId);
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
QQC2.ToolTip.visible: hovered
|
||||||
|
QQC2.ToolTip.text: i18nc("@info:tooltip %1 is a Matrix ID", "Contact via Matrix (%1)", contactDelegate.matrixId)
|
||||||
|
}
|
||||||
|
|
||||||
|
QQC2.ToolButton {
|
||||||
|
visible: contactDelegate.emailAddress.length > 0
|
||||||
|
icon.name: "mail-sent-symbolic"
|
||||||
|
|
||||||
|
onClicked: Qt.openUrlExternally("mailto:%1".arg(contactDelegate.emailAddress))
|
||||||
|
|
||||||
|
QQC2.ToolTip.delay: Kirigami.Units.toolTipDelay
|
||||||
|
QQC2.ToolTip.visible: hovered
|
||||||
|
QQC2.ToolTip.text: i18nc("@info:tooltip %1 is an e-mail address", "Contact via e-mail (%1)", contactDelegate.emailAddress)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
66
src/app/supportcontroller.cpp
Normal file
66
src/app/supportcontroller.cpp
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
#include "supportcontroller.h"
|
||||||
|
|
||||||
|
#include <Quotient/csapi/support.h>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
using namespace Quotient;
|
||||||
|
|
||||||
|
void SupportController::setConnection(NeoChatConnection *connection)
|
||||||
|
{
|
||||||
|
if (m_connection != connection) {
|
||||||
|
m_connection = connection;
|
||||||
|
Q_EMIT connectionChanged();
|
||||||
|
|
||||||
|
load();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NeoChatConnection *SupportController::connection() const
|
||||||
|
{
|
||||||
|
return m_connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SupportController::supportPage() const
|
||||||
|
{
|
||||||
|
return m_supportPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<SupportContact> SupportController::contacts() const
|
||||||
|
{
|
||||||
|
return m_contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SupportController::load()
|
||||||
|
{
|
||||||
|
if (!m_connection) {
|
||||||
|
qWarning() << "Tried to load support information without a valid connection?";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_connection->callApi<GetWellknownSupportJob>()
|
||||||
|
.onResult([this](const auto &job) {
|
||||||
|
m_supportPage = job->supportPage();
|
||||||
|
m_contacts.reserve(job->contacts().size());
|
||||||
|
for (const auto &contact : job->contacts()) {
|
||||||
|
m_contacts.push_back(SupportContact{
|
||||||
|
.role = contact.role,
|
||||||
|
.matrixId = contact.matrixId,
|
||||||
|
.emailAddress = contact.emailAddress,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_EMIT loaded();
|
||||||
|
})
|
||||||
|
.onFailure([this](const auto &job) {
|
||||||
|
Q_UNUSED(job)
|
||||||
|
|
||||||
|
// Just do nothing, our properties will be empty.
|
||||||
|
Q_EMIT loaded();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_supportcontroller.cpp"
|
||||||
48
src/app/supportcontroller.h
Normal file
48
src/app/supportcontroller.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// SPDX-FileCopyrightText: 2026 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "neochatconnection.h"
|
||||||
|
|
||||||
|
class SupportContact
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
Q_PROPERTY(QString role MEMBER role)
|
||||||
|
Q_PROPERTY(QString matrixId MEMBER matrixId)
|
||||||
|
Q_PROPERTY(QString emailAddress MEMBER emailAddress)
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString role;
|
||||||
|
QString matrixId;
|
||||||
|
QString emailAddress;
|
||||||
|
};
|
||||||
|
|
||||||
|
class SupportController : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
QML_ELEMENT
|
||||||
|
|
||||||
|
Q_PROPERTY(NeoChatConnection *connection READ connection WRITE setConnection NOTIFY connectionChanged REQUIRED)
|
||||||
|
Q_PROPERTY(QString supportPage READ supportPage NOTIFY loaded)
|
||||||
|
Q_PROPERTY(QList<SupportContact> contacts READ contacts NOTIFY loaded)
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setConnection(NeoChatConnection *connection);
|
||||||
|
NeoChatConnection *connection() const;
|
||||||
|
|
||||||
|
QString supportPage() const;
|
||||||
|
QList<SupportContact> contacts() const;
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void connectionChanged();
|
||||||
|
void loaded();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void load();
|
||||||
|
|
||||||
|
QPointer<NeoChatConnection> m_connection = nullptr;
|
||||||
|
QList<SupportContact> m_contacts;
|
||||||
|
QString m_supportPage;
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user