Allow editing aliases
This commit is contained in:
parent
42b53817e0
commit
931855441a
@ -420,6 +420,8 @@ set(SRC_FILES
|
|||||||
src/dock/Dock.cpp
|
src/dock/Dock.cpp
|
||||||
src/dock/Dock.h
|
src/dock/Dock.h
|
||||||
|
|
||||||
|
src/AliasEditModel.cpp
|
||||||
|
src/AliasEditModel.h
|
||||||
src/AvatarProvider.cpp
|
src/AvatarProvider.cpp
|
||||||
src/AvatarProvider.h
|
src/AvatarProvider.h
|
||||||
src/BlurhashProvider.cpp
|
src/BlurhashProvider.cpp
|
||||||
@ -579,7 +581,7 @@ if(USE_BUNDLED_MTXCLIENT)
|
|||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
MatrixClient
|
MatrixClient
|
||||||
GIT_REPOSITORY https://github.com/Nheko-Reborn/mtxclient.git
|
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_EXAMPLES OFF CACHE INTERNAL "")
|
||||||
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
set(BUILD_LIB_TESTS OFF CACHE INTERNAL "")
|
||||||
|
@ -203,7 +203,7 @@ modules:
|
|||||||
buildsystem: cmake-ninja
|
buildsystem: cmake-ninja
|
||||||
name: mtxclient
|
name: mtxclient
|
||||||
sources:
|
sources:
|
||||||
- commit: e93779692fcc00de136234dd48d0af354717b0a1
|
- commit: 842e10c4ae36aba23a20849e766f0c54b19fd4b6
|
||||||
#tag: v0.7.0
|
#tag: v0.7.0
|
||||||
type: git
|
type: git
|
||||||
url: https://github.com/Nheko-Reborn/mtxclient.git
|
url: https://github.com/Nheko-Reborn/mtxclient.git
|
||||||
|
1
resources/icons/ui/building-shop.svg
Normal file
1
resources/icons/ui/building-shop.svg
Normal file
@ -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 |
1
resources/icons/ui/room-directory.svg
Normal file
1
resources/icons/ui/room-directory.svg
Normal file
@ -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
|
hoverEnabled: true
|
||||||
width: 22
|
width: 22
|
||||||
height: 22
|
height: 22
|
||||||
image: ":/icons/icons/ui/speech-bubbles.svg"
|
image: ":/icons/icons/ui/room-directory.svg"
|
||||||
ToolTip.visible: hovered
|
ToolTip.visible: hovered
|
||||||
ToolTip.delay: Nheko.tooltipDelay
|
ToolTip.delay: Nheko.tooltipDelay
|
||||||
ToolTip.text: qsTr("Room directory")
|
ToolTip.text: qsTr("Room directory")
|
||||||
|
@ -55,13 +55,28 @@ Pane {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function showPLEditor(settings) {
|
function showAliasEditor(settings) {
|
||||||
var dialog = plEditor.createObject(timelineRoot, {
|
var dialog = aliasEditor.createObject(timelineRoot, {
|
||||||
"roomSettings": settings
|
"roomSettings": settings
|
||||||
});
|
});
|
||||||
dialog.show();
|
dialog.show();
|
||||||
destroyOnClose(dialog);
|
destroyOnClose(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: aliasEditor
|
||||||
|
|
||||||
|
AliasEditor {
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPLEditor(settings) {
|
||||||
|
var dialog = plEditor.createObject(timelineRoot, {
|
||||||
|
"roomSettings": settings
|
||||||
|
});
|
||||||
|
dialog.show();
|
||||||
|
destroyOnClose(dialog);
|
||||||
|
}
|
||||||
|
|
||||||
Component {
|
Component {
|
||||||
id: plEditor
|
id: plEditor
|
||||||
|
172
resources/qml/dialogs/AliasEditor.qml
Normal file
172
resources/qml/dialogs/AliasEditor.qml
Normal file
@ -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
|
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 {
|
Label {
|
||||||
text: qsTr("Sticker & Emote Settings")
|
text: qsTr("Sticker & Emote Settings")
|
||||||
color: Nheko.colors.text
|
color: Nheko.colors.text
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
<file>icons/ui/angle-arrow-left.svg</file>
|
<file>icons/ui/angle-arrow-left.svg</file>
|
||||||
<file>icons/ui/attach.svg</file>
|
<file>icons/ui/attach.svg</file>
|
||||||
<file>icons/ui/ban.svg</file>
|
<file>icons/ui/ban.svg</file>
|
||||||
|
<file>icons/ui/building-shop.svg</file>
|
||||||
<file>icons/ui/chat.svg</file>
|
<file>icons/ui/chat.svg</file>
|
||||||
<file>icons/ui/checkmark.svg</file>
|
<file>icons/ui/checkmark.svg</file>
|
||||||
<file>icons/ui/clock.svg</file>
|
<file>icons/ui/clock.svg</file>
|
||||||
@ -36,6 +37,7 @@
|
|||||||
<file>icons/ui/reply.svg</file>
|
<file>icons/ui/reply.svg</file>
|
||||||
<file>icons/ui/ribbon.svg</file>
|
<file>icons/ui/ribbon.svg</file>
|
||||||
<file>icons/ui/ribbon_star.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/round-remove-button.svg</file>
|
||||||
<file>icons/ui/screen-share.svg</file>
|
<file>icons/ui/screen-share.svg</file>
|
||||||
<file>icons/ui/search.svg</file>
|
<file>icons/ui/search.svg</file>
|
||||||
@ -147,6 +149,7 @@
|
|||||||
<file>qml/device-verification/NewVerificationRequest.qml</file>
|
<file>qml/device-verification/NewVerificationRequest.qml</file>
|
||||||
<file>qml/device-verification/Success.qml</file>
|
<file>qml/device-verification/Success.qml</file>
|
||||||
<file>qml/device-verification/Waiting.qml</file>
|
<file>qml/device-verification/Waiting.qml</file>
|
||||||
|
<file>qml/dialogs/AliasEditor.qml</file>
|
||||||
<file>qml/dialogs/CreateDirect.qml</file>
|
<file>qml/dialogs/CreateDirect.qml</file>
|
||||||
<file>qml/dialogs/CreateRoom.qml</file>
|
<file>qml/dialogs/CreateRoom.qml</file>
|
||||||
<file>qml/dialogs/HiddenEventsDialog.qml</file>
|
<file>qml/dialogs/HiddenEventsDialog.qml</file>
|
||||||
|
336
src/AliasEditModel.cpp
Normal file
336
src/AliasEditModel.cpp
Normal 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)));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
79
src/AliasEditModel.h
Normal file
79
src/AliasEditModel.h
Normal file
@ -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/requests.hpp>
|
||||||
#include <mtx/responses/login.hpp>
|
#include <mtx/responses/login.hpp>
|
||||||
|
|
||||||
|
#include "AliasEditModel.h"
|
||||||
#include "BlurhashProvider.h"
|
#include "BlurhashProvider.h"
|
||||||
#include "Cache.h"
|
#include "Cache.h"
|
||||||
#include "Cache_p.h"
|
#include "Cache_p.h"
|
||||||
@ -179,6 +180,13 @@ MainWindow::registerQmlTypes()
|
|||||||
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
|
qmlRegisterType<LoginPage>("im.nheko", 1, 0, "Login");
|
||||||
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
|
qmlRegisterType<RegisterPage>("im.nheko", 1, 0, "Registration");
|
||||||
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
|
qmlRegisterType<HiddenEvents>("im.nheko", 1, 0, "HiddenEvents");
|
||||||
|
qmlRegisterUncreatableType<AliasEditingModel>(
|
||||||
|
"im.nheko",
|
||||||
|
1,
|
||||||
|
0,
|
||||||
|
"AliasEditingModel",
|
||||||
|
QStringLiteral("Please use editAliases to create the models"));
|
||||||
|
|
||||||
qmlRegisterUncreatableType<PowerlevelEditingModels>(
|
qmlRegisterUncreatableType<PowerlevelEditingModels>(
|
||||||
"im.nheko",
|
"im.nheko",
|
||||||
1,
|
1,
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QPalette>
|
#include <QPalette>
|
||||||
|
|
||||||
|
#include "AliasEditModel.h"
|
||||||
#include "PowerlevelsEditModels.h"
|
#include "PowerlevelsEditModels.h"
|
||||||
#include "Theme.h"
|
#include "Theme.h"
|
||||||
#include "UserProfile.h"
|
#include "UserProfile.h"
|
||||||
@ -59,6 +60,10 @@ public:
|
|||||||
{
|
{
|
||||||
return new PowerlevelEditingModels(room_id_);
|
return new PowerlevelEditingModels(room_id_);
|
||||||
}
|
}
|
||||||
|
Q_INVOKABLE AliasEditingModel *editAliases(QString room_id_) const
|
||||||
|
{
|
||||||
|
return new AliasEditingModel(room_id_.toStdString());
|
||||||
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateUserProfile();
|
void updateUserProfile();
|
||||||
|
Loading…
Reference in New Issue
Block a user