Support adding Jitsi and removing widgets

This commit is contained in:
Arno Rehn
2025-10-04 20:37:55 +02:00
parent 5b07a0ff45
commit 8b0698c670
4 changed files with 78 additions and 8 deletions

View File

@@ -79,10 +79,14 @@ Kirigami.Page {
Kirigami.Action {
tooltip: i18nc("@action:button", "Open Jitsi Meet in browser")
icon.name: "camera-video-symbolic"
visible: root.widgetModel.jitsiIndex >= 0
onTriggered: {
let idx = root.widgetModel.index(root.widgetModel.jitsiIndex, 0);
let url = root.widgetModel.data(idx, WidgetModel.UrlRole);
let url
if (root.widgetModel.jitsiIndex < 0) {
url = root.widgetModel.addJitsiConference();
} else {
let idx = root.widgetModel.index(root.widgetModel.jitsiIndex, 0);
url = root.widgetModel.data(idx, WidgetModel.UrlRole);
}
Qt.openUrlExternally(url);
}
},

View File

@@ -316,3 +316,41 @@ int WidgetModel::jitsiIndex() const
return d->jitsiIndex;
}
QUrl WidgetModel::addJitsiConference()
{
// URL is not spec-compliant, but this is what Element does as well.
const auto conferenceId = QUuid::createUuid().toString(QUuid::WithoutBraces);
// clang-format off
const QJsonObject content{
{"name"_L1, "Jitsi Meet"_L1},
{"type"_L1, "jitsi"_L1},
{"url"_L1, "https://scalar.vector.im/api/widgets/jitsi.html"_L1},
{"data"_L1, QJsonObject{
{"conferenceId"_L1, conferenceId},
{"domain"_L1, "meet.element.io"_L1}, // TODO: make domain configurable
{"isAudioOnly"_L1, false},
{"roomName"_L1, room()->displayName()},
}},
};
// clang-format on
// Re-use conferenceId as state_key
room()->setState(WidgetEvent::MetaType.matrixId, conferenceId, content);
return buildWidgetUrl(JitsiMeetUrlTemplate, room(), content["data"_L1].toObject());
}
bool WidgetModel::removeWidget(int index)
{
Q_D(const WidgetModel);
if (index < 0 || index >= rowCount()) {
return false;
}
const auto stateKey = std::next(d->state.begin(), index).value()->stateKey();
room()->setState(WidgetEvent::MetaType.matrixId, stateKey, QJsonObject{});
return true;
}

View File

@@ -51,6 +51,17 @@ public:
int jitsiIndex() const;
/**
* @brief Adds a new Jitsi widget
* @return The URL of the newly added Jitsi conference
*/
Q_INVOKABLE QUrl addJitsiConference();
/**
* @brief Removes the widget at @p index
* @return `true` on success, `false` otherwise
*/
Q_INVOKABLE bool removeWidget(int index);
Q_SIGNALS:
void roomChanged();
void jitsiIndexChanged();

View File

@@ -24,6 +24,7 @@ Kirigami.ScrollablePage {
currentIndex: -1
model: WidgetModel {
id: widgetModel
room: root.room
}
@@ -33,18 +34,34 @@ Kirigami.ScrollablePage {
required text
required property url url
required property string type
required property int index
// Can we actually use the jitsi logo without being infringing any
// trademarks?
icon.name: type === "jitsi" ? "meeting-attending"
: type === "m.etherpad" ? "document-share"
: ""
icon.width: Kirigami.Units.iconSizes.smallMedium
icon.height: Kirigami.Units.iconSizes.smallMedium
contentItem: Delegates.SubtitleContentItem {
iconItem.visible: true
itemDelegate: del
subtitle: del.url
labelItem.textFormat: Text.PlainText
contentItem: RowLayout {
spacing: Kirigami.Units.smallSpacing
Delegates.SubtitleContentItem {
Layout.fillWidth: true
iconItem.visible: true
itemDelegate: del
subtitle: del.url
labelItem.textFormat: Text.PlainText
}
QQC2.ToolButton {
action: Kirigami.Action {
icon.name: "delete-symbolic"
tooltip: i18nc("@action:button", "Remove widget")
onTriggered: widgetModel.removeWidget(del.index)
}
}
}
onClicked: Qt.openUrlExternally(url)