Allow editing aliases

pull/1062/head
Nicolas Werner 2 years ago
parent 42b53817e0
commit 931855441a
No known key found for this signature in database
GPG Key ID: C8D75E610773F2D9
  1. 4
      CMakeLists.txt
  2. 2
      io.github.NhekoReborn.Nheko.yaml
  3. 1
      resources/icons/ui/building-shop.svg
  4. 1
      resources/icons/ui/room-directory.svg
  5. 2
      resources/qml/RoomList.qml
  6. 27
      resources/qml/Root.qml
  7. 172
      resources/qml/dialogs/AliasEditor.qml
  8. 12
      resources/qml/dialogs/RoomSettings.qml
  9. 3
      resources/res.qrc
  10. 336
      src/AliasEditModel.cpp
  11. 79
      src/AliasEditModel.h
  12. 8
      src/MainWindow.cpp
  13. 5
      src/ui/NhekoGlobalObject.h

@ -420,6 +420,8 @@ set(SRC_FILES
src/dock/Dock.cpp
src/dock/Dock.h
src/AliasEditModel.cpp
src/AliasEditModel.h
src/AvatarProvider.cpp
src/AvatarProvider.h
src/BlurhashProvider.cpp
@ -579,7 +581,7 @@ if(USE_BUNDLED_MTXCLIENT)
FetchContent_Declare(
MatrixClient
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
GIT_TAG e93779692fcc00de136234dd48d0af354717b0a1
GIT_TAG 842e10c4ae36aba23a20849e766f0c54b19fd4b6
)
set(BUILD_LIB_EXAMPLES OFF CACHE INTERNAL "")
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")

@ -203,7 +203,7 @@ modules:
buildsystem: cmake-ninja
name: mtxclient
sources:
- commit: e93779692fcc00de136234dd48d0af354717b0a1
- commit: 842e10c4ae36aba23a20849e766f0c54b19fd4b6
#tag: v0.7.0
type: git
url: https://github.com/Nheko-Reborn/mtxclient.git

@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M18 2a.75.75 0 0 1 .474.169l.076.07 3.272 3.53.03.038c.102.136.148.29.148.44L22 8.168c0 .994-.379 1.9-1 2.58V21.25a.75.75 0 0 1-.649.743L20.25 22H3.75a.75.75 0 0 1-.743-.648l-.007-.102V10.748a3.818 3.818 0 0 1-.993-2.353L2 8.167V6.29a.728.728 0 0 1 .096-.408l.065-.095.04-.046L5.45 2.24a.75.75 0 0 1 .447-.233L6 2h12Zm-2.918 8.442-.012.018A3.827 3.827 0 0 1 11.999 12a3.827 3.827 0 0 1-3.083-1.556A3.825 3.825 0 0 1 5.834 12c-.47 0-.919-.084-1.334-.238v8.738H6v-6.748a.75.75 0 0 1 .648-.743L6.75 13h4.496a.75.75 0 0 1 .743.648l.007.102v6.748h7.502v-8.737a3.827 3.827 0 0 1-4.416-1.32Zm-4.587 4.059H7.5v5.998h2.995v-5.998Zm6.76-1.5a.75.75 0 0 1 .743.648l.007.102v3.502a.75.75 0 0 1-.649.743l-.101.007h-3.502a.75.75 0 0 1-.743-.648l-.007-.102v-3.502a.75.75 0 0 1 .648-.743l.102-.007h3.502Zm-.751 1.5h-2.001v2.002h2v-2.002ZM8.166 7.002H3.5v1.165l.006.17.029.232.032.156.05.172.054.148.04.094c.032.068.066.134.104.198l.102.162.055.074.129.156.141.144.097.085.042.034c.314.25.695.422 1.111.483l.18.019.16.005c1.235 0 2.246-.959 2.328-2.173l.005-.16V7.003Zm6.165 0H9.666v1.165c0 1.18.878 2.157 2.016 2.311l.157.016.16.005c1.234 0 2.245-.959 2.327-2.173l.005-.16V7.003Zm6.167 0h-4.665v1.165c0 1.18.878 2.157 2.017 2.311l.156.016.16.005c.564 0 1.082-.2 1.485-.534l.09-.078.116-.113.146-.17c.054-.069.105-.14.15-.216l.104-.186.063-.138.058-.155.03-.096.038-.152.029-.157.018-.167.006-.17-.001-1.165ZM9.062 3.499H6.327L4.469 5.502h3.977l.616-2.003Zm4.306 0H10.63l-.616 2.003h3.97l-.616-2.003Zm4.304 0h-2.735l.617 2.003h3.976l-1.858-2.003Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

@ -0,0 +1 @@
<svg width="24" height="24" fill="none" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M8.5 5.5a1 1 0 1 0 0 2 1 1 0 0 0 0-2ZM7.5 13.5a1 1 0 1 1 2 0 1 1 0 0 1-2 0ZM8.5 9a1 1 0 1 0 0 2 1 1 0 0 0 0-2ZM11 6.5a1 1 0 1 1 2 0 1 1 0 0 1-2 0ZM12 12.5a1 1 0 1 0 0 2 1 1 0 0 0 0-2ZM14.5 13.5a1 1 0 1 1 2 0 1 1 0 0 1-2 0ZM12 9a1 1 0 1 0 0 2 1 1 0 0 0 0-2Z" fill="#212121"/><path d="M6.25 2A2.25 2.25 0 0 0 4 4.25v16.5c0 .414.336.75.75.75h14.503a.75.75 0 0 0 .75-.75v-9a2.25 2.25 0 0 0-2.25-2.25H16.5V4.25A2.25 2.25 0 0 0 14.25 2h-8ZM5.5 4.25a.75.75 0 0 1 .75-.75h8a.75.75 0 0 1 .75.75v6c0 .414.336.75.75.75h2.003a.75.75 0 0 1 .75.75V20H16.5v-2.75a.75.75 0 0 0-.75-.75h-7.5a.75.75 0 0 0-.75.75V20h-2V4.25ZM15 18v2h-2.25v-2H15Zm-3.75 0v2H9v-2h2.25Z" fill="#212121"/></svg>

After

Width:  |  Height:  |  Size: 775 B

@ -750,7 +750,7 @@ Page {
hoverEnabled: true
width: 22
height: 22
image: ":/icons/icons/ui/speech-bubbles.svg"
image: ":/icons/icons/ui/room-directory.svg"
ToolTip.visible: hovered
ToolTip.delay: Nheko.tooltipDelay
ToolTip.text: qsTr("Room directory")

@ -55,13 +55,28 @@ Pane {
}
function showPLEditor(settings) {
var dialog = plEditor.createObject(timelineRoot, {
"roomSettings": settings
});
dialog.show();
destroyOnClose(dialog);
function showAliasEditor(settings) {
var dialog = aliasEditor.createObject(timelineRoot, {
"roomSettings": settings
});
dialog.show();
destroyOnClose(dialog);
}
Component {
id: aliasEditor
AliasEditor {
}
}
function showPLEditor(settings) {
var dialog = plEditor.createObject(timelineRoot, {
"roomSettings": settings
});
dialog.show();
destroyOnClose(dialog);
}
Component {
id: plEditor

@ -0,0 +1,172 @@
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
import ".."
import "../components"
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.3
import im.nheko 1.0
ApplicationWindow {
id: aliasEditorW
property var roomSettings
property var editingModel: Nheko.editAliases(roomSettings.roomId)
modality: Qt.NonModal
flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint
minimumWidth: 300
minimumHeight: 400
height: 600
width: 500
title: qsTr("Aliases to %1").arg(roomSettings.roomName);
// Shortcut {
// sequence: StandardKey.Cancel
// onActivated: dbb.rejected()
// }
ColumnLayout {
anchors.margins: Nheko.paddingMedium
anchors.fill: parent
spacing: 0
MatrixText {
text: qsTr("List of aliases to this room. Usually you can only add aliases on your server. You can have one canonical alias and many alternate aliases.")
font.pixelSize: Math.floor(fontMetrics.font.pixelSize * 1.1)
Layout.fillWidth: true
Layout.fillHeight: false
color: Nheko.colors.text
Layout.bottomMargin: Nheko.paddingMedium
}
ListView {
Layout.fillWidth: true
Layout.fillHeight: true
id: view
clip: true
ScrollHelper {
flickable: parent
anchors.fill: parent
}
model: editingModel
spacing: 4
cacheBuffer: 50
delegate: RowLayout {
anchors.left: parent.left
anchors.right: parent.right
Text {
Layout.fillWidth: true
text: model.name
color: model.isPublished ? Nheko.colors.text : Nheko.theme.error
textFormat: Text.PlainText
}
ImageButton {
Layout.alignment: Qt.AlignRight
Layout.margins: 2
image: ":/icons/icons/ui/star.svg"
hoverEnabled: true
buttonTextColor: model.isCanonical ? Nheko.colors.highlight : Nheko.colors.text
highlightColor: editingModel.canAdvertize ? Nheko.colors.highlight : buttonTextColor
ToolTip.visible: hovered
ToolTip.text: model.isCanonical ? qsTr("Primary alias") : qsTr("Make primary alias")
onClicked: editingModel.makeCanonical(model.index)
}
ImageButton {
Layout.alignment: Qt.AlignRight
Layout.margins: 2
image: ":/icons/icons/ui/building-shop.svg"
hoverEnabled: true
buttonTextColor: model.isAdvertized ? Nheko.colors.highlight : Nheko.colors.text
highlightColor: editingModel.canAdvertize ? Nheko.colors.highlight : buttonTextColor
ToolTip.visible: hovered
ToolTip.text: qsTr("Advertise as an alias in this room")
onClicked: editingModel.toggleAdvertize(model.index)
}
ImageButton {
Layout.alignment: Qt.AlignRight
Layout.margins: 2
image: ":/icons/icons/ui/room-directory.svg"
hoverEnabled: true
buttonTextColor: model.isPublished ? Nheko.colors.highlight : Nheko.colors.text
ToolTip.visible: hovered
ToolTip.text: qsTr("Publish in room directory")
onClicked: editingModel.togglePublish(model.index)
}
ImageButton {
Layout.alignment: Qt.AlignRight
Layout.margins: 2
image: ":/icons/icons/ui/dismiss.svg"
hoverEnabled: true
ToolTip.visible: hovered
ToolTip.text: qsTr("Remove this alias")
onClicked: editingModel.deleteAlias(model.index)
}
}
}
RowLayout {
spacing: Nheko.paddingMedium
Layout.fillWidth: true
TextField {
id: newAliasVal
Layout.fillWidth: true
placeholderText: qsTr("#new-alias:server.tld")
Keys.onPressed: {
if (event.matches(StandardKey.InsertParagraphSeparator)) {
editingModel.addAlias(newAliasVal.text);
newAliasVal.clear();
}
}
}
Button {
text: qsTr("Add")
Layout.preferredWidth: 100
onClicked: {
editingModel.addAlias(newAliasVal.text);
newAliasVal.clear();
}
}
}
}
footer: DialogButtonBox {
id: dbb
standardButtons: DialogButtonBox.Ok | DialogButtonBox.Cancel
onAccepted: {
editingModel.commit();
aliasEditorW.close();
}
onRejected: aliasEditorW.close();
}
}

@ -352,6 +352,18 @@ ApplicationWindow {
Layout.alignment: Qt.AlignRight
}
Label {
text: qsTr("Addresses")
color: Nheko.colors.text
}
Button {
text: qsTr("Configure")
ToolTip.text: qsTr("View and change the addresses/aliases of this room")
onClicked: timelineRoot.showAliasEditor(roomSettings)
Layout.alignment: Qt.AlignRight
}
Label {
text: qsTr("Sticker & Emote Settings")
color: Nheko.colors.text

@ -4,6 +4,7 @@
<file>icons/ui/angle-arrow-left.svg</file>
<file>icons/ui/attach.svg</file>
<file>icons/ui/ban.svg</file>
<file>icons/ui/building-shop.svg</file>
<file>icons/ui/chat.svg</file>
<file>icons/ui/checkmark.svg</file>
<file>icons/ui/clock.svg</file>
@ -36,6 +37,7 @@
<file>icons/ui/reply.svg</file>
<file>icons/ui/ribbon.svg</file>
<file>icons/ui/ribbon_star.svg</file>
<file>icons/ui/room-directory.svg</file>
<file>icons/ui/round-remove-button.svg</file>
<file>icons/ui/screen-share.svg</file>
<file>icons/ui/search.svg</file>
@ -147,6 +149,7 @@
<file>qml/device-verification/NewVerificationRequest.qml</file>
<file>qml/device-verification/Success.qml</file>
<file>qml/device-verification/Waiting.qml</file>
<file>qml/dialogs/AliasEditor.qml</file>
<file>qml/dialogs/CreateDirect.qml</file>
<file>qml/dialogs/CreateRoom.qml</file>
<file>qml/dialogs/HiddenEventsDialog.qml</file>

@ -0,0 +1,336 @@
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#include "AliasEditModel.h"
#include <QSharedPointer>
#include <set>
#include <mtx/responses/common.hpp>
#include "Cache.h"
#include "Cache_p.h"
#include "ChatPage.h"
#include "Logging.h"
#include "MatrixClient.h"
#include "timeline/Permissions.h"
#include "timeline/TimelineModel.h"
AliasEditingModel::AliasEditingModel(const std::string &rid, QObject *parent)
: QAbstractListModel(parent)
, room_id(rid)
, aliasEvent(cache::client()
->getStateEvent<mtx::events::state::CanonicalAlias>(room_id)
.value_or(mtx::events::StateEvent<mtx::events::state::CanonicalAlias>{})
.content)
, canSendStateEvent(
Permissions(QString::fromStdString(rid)).canChange(qml_mtx_events::CanonicalAlias))
{
std::set<std::string> seen_aliases;
if (!aliasEvent.alias.empty()) {
aliases.push_back(Entry{aliasEvent.alias, true, true, false});
seen_aliases.insert(aliasEvent.alias);
}
for (const auto &alias : aliasEvent.alt_aliases) {
if (!seen_aliases.count(alias)) {
aliases.push_back(Entry{aliasEvent.alias, false, true, false});
seen_aliases.insert(aliasEvent.alias);
}
}
for (const auto &alias : aliases) {
fetchAliasesStatus(alias.alias);
}
fetchPublishedAliases();
}
void
AliasEditingModel::fetchPublishedAliases()
{
auto job = QSharedPointer<FetchPublishedAliasesJob>::create();
connect(job.data(),
&FetchPublishedAliasesJob::advertizedAliasesFetched,
this,
&AliasEditingModel::updatePublishedAliases);
http::client()->list_room_aliases(
room_id, [job](const mtx::responses::Aliases &aliasesFetched, mtx::http::RequestErr) {
emit job->advertizedAliasesFetched(std::move(aliasesFetched.aliases));
});
}
void
AliasEditingModel::fetchAliasesStatus(const std::string &alias)
{
auto job = QSharedPointer<FetchPublishedAliasesJob>::create();
connect(
job.data(), &FetchPublishedAliasesJob::aliasFetched, this, &AliasEditingModel::updateAlias);
http::client()->resolve_room_alias(
alias, [job, alias](const mtx::responses::RoomId &roomIdFetched, mtx::http::RequestErr e) {
if (!e)
emit job->aliasFetched(alias, std::move(roomIdFetched.room_id));
});
}
QHash<int, QByteArray>
AliasEditingModel::roleNames() const
{
return {
{Name, "name"},
{IsPublished, "isPublished"},
{IsCanonical, "isCanonical"},
{IsAdvertized, "isAdvertized"},
};
}
QVariant
AliasEditingModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid() || index.row() >= aliases.size())
return {};
const auto &entry = aliases.at(index.row());
switch (role) {
case Name:
return QString::fromStdString(entry.alias);
case IsPublished:
return entry.published;
case IsCanonical:
return entry.canonical;
case IsAdvertized:
return entry.advertized;
}
return {};
}
bool
AliasEditingModel::deleteAlias(int row)
{
if (row < 0 || row >= aliases.size() || aliases.at(row).alias.empty())
return false;
auto alias = aliases.at(row);
beginRemoveRows(QModelIndex(), row, row);
aliases.remove(row);
endRemoveRows();
if (alias.published)
http::client()->delete_room_alias(alias.alias, [alias](mtx::http::RequestErr e) {
if (e) {
nhlog::net()->error("Failed to delete {}: {}", alias.alias, *e);
ChatPage::instance()->showNotification(
tr("Failed to unpublish alias %1: %2")
.arg(QString::fromStdString(alias.alias),
QString::fromStdString(e->matrix_error.error)));
}
});
if (aliasEvent.alias == alias.alias)
aliasEvent.alias.clear();
for (size_t i = 0; i < aliasEvent.alt_aliases.size(); i++) {
if (aliasEvent.alt_aliases[i] == alias.alias) {
aliasEvent.alt_aliases.erase(aliasEvent.alt_aliases.begin() + i);
break;
}
}
return true;
}
void
AliasEditingModel::addAlias(QString newAlias)
{
const auto aliasStr = newAlias.toStdString();
for (const auto &e : aliases) {
if (e.alias == aliasStr) {
return;
}
}
beginInsertRows(QModelIndex(), aliases.length(), aliases.length());
if (aliasEvent.alias.empty())
aliasEvent.alias = aliasStr;
else
aliasEvent.alt_aliases.push_back(aliasStr);
aliases.push_back(
Entry{aliasStr, aliasEvent.alias.empty() && canSendStateEvent, canSendStateEvent, false});
endInsertRows();
auto job = QSharedPointer<FetchPublishedAliasesJob>::create();
connect(
job.data(), &FetchPublishedAliasesJob::aliasFetched, this, &AliasEditingModel::updateAlias);
auto room = room_id;
http::client()->add_room_alias(
aliasStr, room_id, [job, aliasStr, room](mtx::http::RequestErr e) {
if (e) {
nhlog::net()->error("Failed to publish {}: {}", aliasStr, *e);
ChatPage::instance()->showNotification(
tr("Failed to unpublish alias %1: %2")
.arg(QString::fromStdString(aliasStr),
QString::fromStdString(e->matrix_error.error)));
emit job->aliasFetched(aliasStr, "");
} else {
emit job->aliasFetched(aliasStr, room);
}
});
}
void
AliasEditingModel::makeCanonical(int row)
{
if (!canSendStateEvent || row < 0 || row >= aliases.size() || aliases.at(row).alias.empty())
return;
auto moveAlias = aliases.at(row).alias;
if (!aliasEvent.alias.empty()) {
for (qsizetype i = 0; i < aliases.size(); i++) {
if (moveAlias == aliases[i].alias) {
if (aliases[i].canonical) {
aliases[i].canonical = false;
aliasEvent.alt_aliases.push_back(aliasEvent.alias);
emit dataChanged(index(i), index(i), {IsCanonical});
}
break;
}
}
}
aliasEvent.alias = moveAlias;
for (auto i = aliasEvent.alt_aliases.begin(); i != aliasEvent.alt_aliases.end(); ++i) {
if (*i == moveAlias) {
aliasEvent.alt_aliases.erase(i);
break;
}
}
aliases[row].canonical = true;
aliases[row].advertized = true;
emit dataChanged(index(row), index(row), {IsCanonical, IsAdvertized});
}
void
AliasEditingModel::togglePublish(int row)
{
if (row < 0 || row >= aliases.size() || aliases.at(row).alias.empty())
return;
auto aliasStr = aliases[row].alias;
auto job = QSharedPointer<FetchPublishedAliasesJob>::create();
connect(
job.data(), &FetchPublishedAliasesJob::aliasFetched, this, &AliasEditingModel::updateAlias);
auto room = room_id;
if (!aliases[row].published)
http::client()->add_room_alias(
aliasStr, room_id, [job, aliasStr, room](mtx::http::RequestErr e) {
if (e) {
nhlog::net()->error("Failed to publish {}: {}", aliasStr, *e);
ChatPage::instance()->showNotification(
tr("Failed to unpublish alias %1: %2")
.arg(QString::fromStdString(aliasStr),
QString::fromStdString(e->matrix_error.error)));
emit job->aliasFetched(aliasStr, "");
} else {
emit job->aliasFetched(aliasStr, room);
}
});
else
http::client()->delete_room_alias(aliasStr, [job, aliasStr, room](mtx::http::RequestErr e) {
if (e) {
nhlog::net()->error("Failed to unpublish {}: {}", aliasStr, *e);
ChatPage::instance()->showNotification(
tr("Failed to unpublish alias %1: %2")
.arg(QString::fromStdString(aliasStr),
QString::fromStdString(e->matrix_error.error)));
emit job->aliasFetched(aliasStr, room);
} else {
emit job->aliasFetched(aliasStr, "");
}
});
}
void
AliasEditingModel::toggleAdvertize(int row)
{
if (!canSendStateEvent || row < 0 || row >= aliases.size() || aliases.at(row).alias.empty())
return;
auto &moveAlias = aliases[row];
if (aliasEvent.alias == moveAlias.alias) {
moveAlias.canonical = false;
moveAlias.advertized = false;
aliasEvent.alias.clear();
emit dataChanged(index(row), index(row), {IsAdvertized, IsCanonical});
} else if (moveAlias.advertized) {
for (auto i = aliasEvent.alt_aliases.begin(); i != aliasEvent.alt_aliases.end(); ++i) {
if (*i == moveAlias.alias) {
aliasEvent.alt_aliases.erase(i);
moveAlias.advertized = false;
emit dataChanged(index(row), index(row), {IsAdvertized});
break;
}
}
} else {
aliasEvent.alt_aliases.push_back(moveAlias.alias);
moveAlias.advertized = true;
emit dataChanged(index(row), index(row), {IsAdvertized});
}
}
void
AliasEditingModel::updateAlias(std::string alias, std::string target)
{
for (qsizetype i = 0; i < aliases.size(); i++) {
auto &e = aliases[i];
if (e.alias == alias) {
e.published = (target == room_id);
emit dataChanged(index(i), index(i), {IsPublished});
}
}
}
void
AliasEditingModel::updatePublishedAliases(std::vector<std::string> advAliases)
{
for (const auto &advAlias : advAliases) {
bool found = false;
for (qsizetype i = 0; i < aliases.size(); i++) {
auto &alias = aliases[i];
if (alias.alias == advAlias) {
alias.published = true;
emit dataChanged(index(i), index(i), {IsPublished});
found = true;
break;
}
if (!found) {
beginInsertRows(QModelIndex(), aliases.size(), aliases.size());
aliases.push_back(Entry{advAlias, false, false, true});
endInsertRows();
}
}
}
}
void
AliasEditingModel::commit()
{
if (!canSendStateEvent)
return;
http::client()->send_state_event(
room_id, aliasEvent, [](const mtx::responses::EventId &, mtx::http::RequestErr e) {
if (e) {
nhlog::net()->error("Failed to send Alias event: {}", *e);
ChatPage::instance()->showNotification(
tr("Failed to update aliases: %1")
.arg(QString::fromStdString(e->matrix_error.error)));
}
});
}

@ -0,0 +1,79 @@
// SPDX-FileCopyrightText: 2022 Nheko Contributors
//
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <QAbstractListModel>
#include <QVector>
#include <mtx/events/canonical_alias.hpp>
#include "CacheStructs.h"
class FetchPublishedAliasesJob : public QObject
{
Q_OBJECT
public:
explicit FetchPublishedAliasesJob(QObject *p = nullptr)
: QObject(p)
{}
signals:
void aliasFetched(std::string alias, std::string target);
void advertizedAliasesFetched(std::vector<std::string> aliases);
};
class AliasEditingModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(bool canAdvertize READ canAdvertize CONSTANT)
public:
enum Roles
{
Name,
IsPublished,
IsCanonical,
IsAdvertized,
};
explicit AliasEditingModel(const std::string &room_id_, QObject *parent = nullptr);
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex &) const override { return static_cast<int>(aliases.size()); }
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool canAdvertize() const { return canSendStateEvent; }
Q_INVOKABLE bool deleteAlias(int row);
Q_INVOKABLE void addAlias(QString newAlias);
Q_INVOKABLE void makeCanonical(int row);
Q_INVOKABLE void togglePublish(int row);
Q_INVOKABLE void toggleAdvertize(int row);
Q_INVOKABLE void commit();
private slots:
void updateAlias(std::string alias, std::string target);
void updatePublishedAliases(std::vector<std::string> aliases);
private:
void fetchAliasesStatus(const std::string &alias);
void fetchPublishedAliases();
struct Entry
{
~Entry() = default;
std::string alias;
bool canonical = false;
bool advertized = false;
bool published = false;
};
std::string room_id;
QVector<Entry> aliases;
mtx::events::state::CanonicalAlias aliasEvent;
bool canSendStateEvent = false;
};

@ -10,6 +10,7 @@
#include <mtx/requests.hpp>
#include <mtx/responses/login.hpp>
#include "AliasEditModel.h"
#include "BlurhashProvider.h"
#include "Cache.h"
#include "Cache_p.h"
@ -179,6 +180,13 @@ MainWindow::registerQmlTypes()
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
qmlRegisterUncreatableType<AliasEditingModel>(
"im.nheko",
1,
0,
"AliasEditingModel",
QStringLiteral("Please use editAliases to create the models"));
qmlRegisterUncreatableType<PowerlevelEditingModels>(
"im.nheko",
1,

@ -9,6 +9,7 @@
#include <QObject>
#include <QPalette>
#include "AliasEditModel.h"
#include "PowerlevelsEditModels.h"
#include "Theme.h"
#include "UserProfile.h"
@ -59,6 +60,10 @@ public:
{
return new PowerlevelEditingModels(room_id_);
}
Q_INVOKABLE AliasEditingModel *editAliases(QString room_id_) const
{
return new AliasEditingModel(room_id_.toStdString());
}
public slots:
void updateUserProfile();

Loading…
Cancel
Save