Support adding Jitsi and removing widgets
This commit is contained in:
@@ -79,10 +79,14 @@ Kirigami.Page {
|
|||||||
Kirigami.Action {
|
Kirigami.Action {
|
||||||
tooltip: i18nc("@action:button", "Open Jitsi Meet in browser")
|
tooltip: i18nc("@action:button", "Open Jitsi Meet in browser")
|
||||||
icon.name: "camera-video-symbolic"
|
icon.name: "camera-video-symbolic"
|
||||||
visible: root.widgetModel.jitsiIndex >= 0
|
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
let idx = root.widgetModel.index(root.widgetModel.jitsiIndex, 0);
|
let url
|
||||||
let url = root.widgetModel.data(idx, WidgetModel.UrlRole);
|
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);
|
Qt.openUrlExternally(url);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -316,3 +316,41 @@ int WidgetModel::jitsiIndex() const
|
|||||||
|
|
||||||
return d->jitsiIndex;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -51,6 +51,17 @@ public:
|
|||||||
|
|
||||||
int jitsiIndex() const;
|
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:
|
Q_SIGNALS:
|
||||||
void roomChanged();
|
void roomChanged();
|
||||||
void jitsiIndexChanged();
|
void jitsiIndexChanged();
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ Kirigami.ScrollablePage {
|
|||||||
currentIndex: -1
|
currentIndex: -1
|
||||||
|
|
||||||
model: WidgetModel {
|
model: WidgetModel {
|
||||||
|
id: widgetModel
|
||||||
room: root.room
|
room: root.room
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,18 +34,34 @@ Kirigami.ScrollablePage {
|
|||||||
required text
|
required text
|
||||||
required property url url
|
required property url url
|
||||||
required property string type
|
required property string type
|
||||||
|
required property int index
|
||||||
|
|
||||||
// Can we actually use the jitsi logo without being infringing any
|
// Can we actually use the jitsi logo without being infringing any
|
||||||
// trademarks?
|
// trademarks?
|
||||||
icon.name: type === "jitsi" ? "meeting-attending"
|
icon.name: type === "jitsi" ? "meeting-attending"
|
||||||
: type === "m.etherpad" ? "document-share"
|
: type === "m.etherpad" ? "document-share"
|
||||||
: ""
|
: ""
|
||||||
|
icon.width: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
icon.height: Kirigami.Units.iconSizes.smallMedium
|
||||||
|
|
||||||
contentItem: Delegates.SubtitleContentItem {
|
contentItem: RowLayout {
|
||||||
iconItem.visible: true
|
spacing: Kirigami.Units.smallSpacing
|
||||||
itemDelegate: del
|
Delegates.SubtitleContentItem {
|
||||||
subtitle: del.url
|
Layout.fillWidth: true
|
||||||
labelItem.textFormat: Text.PlainText
|
|
||||||
|
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)
|
onClicked: Qt.openUrlExternally(url)
|
||||||
|
|||||||
Reference in New Issue
Block a user