Compare commits

..

1 Commits

Author SHA1 Message Date
Nate Graham
6c8ca778b2 Increase frameworks dependency version to 6.16
de97275a38 here in NeoChat depends on
de05764b4764d5641c647bb75bdf184522f63989 in Kirigami. However, that
Kirigami commit only landed in Frameworks 6.16, while the minimum
Frameworks version specified here in NeoChat's CMake remained at 6.12.

Because the CMake dependency version wasn't set to 6.16, a potential
build-time error was converted into a potential runtime error. And
that's exactly what happened for NeoChat's 25.08 Flatpak packaging,
because the KDE Runtime doesn't yet have Frameworks 6.16 in it.

CCBUG: 508298
2025-08-17 08:39:56 -06:00
20 changed files with 150 additions and 785 deletions

View File

@@ -186,14 +186,6 @@
{
"type": "dir",
"path": "."
},
{
"type": "patch",
"path": "patches/0001-Revert-Bump-KF6-dependency-version.patch"
},
{
"type": "patch",
"path": "patches/0001-Revert-Use-new-Kirigami-builtin-column-resize-handle.patch"
}
]
}

View File

@@ -14,7 +14,7 @@ set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
set(KF_MIN_VERSION "6.17")
set(KF_MIN_VERSION "6.16")
set(QT_MIN_VERSION "6.5")
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)

View File

@@ -1,28 +0,0 @@
SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
SPDX-License-Identifier: BSD-2-Clause
From dbd1cefd0f07a6942aef450f8f3e082aa3b1cc25 Mon Sep 17 00:00:00 2001
From: Tobias Fella <tobias.fella@kde.org>
Date: Sun, 17 Aug 2025 20:04:04 +0200
Subject: [PATCH] Revert "Bump KF6 dependency version"
This reverts commit 18a6ea98232b3a734905fb18eebba9cf39bf5325.
---
CMakeLists.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 10fe66daa..cd063113d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,7 +14,7 @@ set(RELEASE_SERVICE_VERSION "${RELEASE_SERVICE_VERSION_MAJOR}.${RELEASE_SERVICE_
project(NeoChat VERSION ${RELEASE_SERVICE_VERSION})
-set(KF_MIN_VERSION "6.17")
+set(KF_MIN_VERSION "6.12")
set(QT_MIN_VERSION "6.5")
find_package(ECM ${KF_MIN_VERSION} REQUIRED NO_MODULE)
--
2.50.1

View File

@@ -1,123 +0,0 @@
SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
SPDX-License-Identifier: BSD-2-Clause
From ca72345b8ee550be2172d8ac5e5dc9e4c2b508c9 Mon Sep 17 00:00:00 2001
From: Tobias Fella <tobias.fella@kde.org>
Date: Sun, 17 Aug 2025 20:00:08 +0200
Subject: [PATCH] Revert "Use new Kirigami builtin column resize handle"
This reverts commit de97275a387abcbca6fcb185bcbd1b69c30f5c66.
---
src/app/qml/Main.qml | 1 -
src/rooms/RoomListPage.qml | 70 +++++++++++++++++++++++++++++---------
2 files changed, 54 insertions(+), 17 deletions(-)
diff --git a/src/app/qml/Main.qml b/src/app/qml/Main.qml
index ea8955674..6eed271c1 100644
--- a/src/app/qml/Main.qml
+++ b/src/app/qml/Main.qml
@@ -45,7 +45,6 @@ Kirigami.ApplicationWindow {
showExisting: true
onConnectionChosen: root.load()
}
- columnView.columnResizeMode: pageStack.wideMode ? Kirigami.ColumnView.DynamicColumns : Kirigami.ColumnView.SingleColumn
globalToolBar.canContainHandles: true
globalToolBar {
style: Kirigami.ApplicationHeaderStyle.ToolBar
diff --git a/src/rooms/RoomListPage.qml b/src/rooms/RoomListPage.qml
index 2ac211fd5..f5586d789 100644
--- a/src/rooms/RoomListPage.qml
+++ b/src/rooms/RoomListPage.qml
@@ -17,22 +17,13 @@ import org.kde.neochat
Kirigami.Page {
id: root
- Kirigami.ColumnView.interactiveResizeEnabled: true
- Kirigami.ColumnView.minimumWidth: _private.collapsedSize + spaceDrawer.width + 1
- Kirigami.ColumnView.maximumWidth: _private.defaultWidth + spaceDrawer.width + 1
- Kirigami.ColumnView.onInteractiveResizingChanged: {
- if (!Kirigami.ColumnView.interactiveResizing && collapsed) {
- Kirigami.ColumnView.preferredWidth = root.Kirigami.ColumnView.minimumWidth;
- }
- }
- Kirigami.ColumnView.preferredWidth: _private.currentWidth + spaceDrawer.width + 1
- Kirigami.ColumnView.onPreferredWidthChanged: {
- if (width > _private.collapseWidth) {
- NeoChatConfig.collapsed = false;
- } else if (Kirigami.ColumnView.interactiveResizing) {
- NeoChatConfig.collapsed = true;
- }
- }
+ /**
+ * @brief The current width of the room list.
+ *
+ * @note Other objects can access the value but the private function makes sure
+ * that only the internal members can modify it.
+ */
+ readonly property int currentWidth: _private.currentWidth + spaceDrawer.width + 1
required property NeoChatConnection connection
@@ -40,6 +31,10 @@ Kirigami.Page {
signal search
+ onCurrentWidthChanged: pageStack.defaultColumnWidth = root.currentWidth
+ Component.onCompleted: pageStack.defaultColumnWidth = root.currentWidth
+
+
onCollapsedChanged: {
if (collapsed) {
RoomManager.sortFilterRoomTreeModel.filterText = "";
@@ -252,6 +247,49 @@ Kirigami.Page {
sourceComponent: Kirigami.Settings.isMobile ? exploreComponentMobile : userInfoDesktop
}
+ MouseArea {
+ anchors.top: parent.top
+ anchors.bottom: parent.bottom
+ parent: applicationWindow().overlay.parent
+
+ x: root.currentWidth - width / 2
+ width: Kirigami.Units.smallSpacing * 2
+ z: root.z + 1
+ enabled: RoomManager.hasOpenRoom && applicationWindow().width >= Kirigami.Units.gridUnit * 35
+ visible: enabled
+ cursorShape: Qt.SplitHCursor
+
+ property int _lastX
+
+ onPressed: mouse => {
+ _lastX = mouse.x;
+ }
+ onPositionChanged: mouse => {
+ if (_lastX == -1) {
+ return;
+ }
+ if (mouse.x > _lastX) {
+ // we moved to the right
+ if (_private.currentWidth < _private.collapseWidth && _private.currentWidth + (mouse.x - _lastX) >= _private.collapseWidth) {
+ // Here we get back directly to a more wide mode.
+ _private.currentWidth = _private.defaultWidth;
+ NeoChatConfig.collapsed = false;
+ } else if (_private.currentWidth >= _private.collapseWidth) {
+ // Increase page width
+ _private.currentWidth = Math.min(_private.defaultWidth, _private.currentWidth + (mouse.x - _lastX));
+ }
+ } else if (mouse.x < _lastX) {
+ const tmpWidth = _private.currentWidth - (_lastX - mouse.x);
+ if (tmpWidth < _private.collapseWidth) {
+ _private.currentWidth = Qt.binding(() => _private.collapsedSize);
+ NeoChatConfig.collapsed = true;
+ } else {
+ _private.currentWidth = tmpWidth;
+ }
+ }
+ }
+ }
+
Component {
id: userInfo
UserInfo {
--
2.50.1

View File

@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2025-08-16 00:43+0000\n"
"PO-Revision-Date: 2025-08-17 22:16+0400\n"
"PO-Revision-Date: 2025-08-14 11:59+0400\n"
"Last-Translator: Zayed Al-Saidi <zayed.alsaidi@gmail.com>\n"
"Language-Team: ar\n"
"Language: ar\n"
@@ -306,7 +306,8 @@ msgid "Add Account"
msgstr "أضف حسابًا"
#: src/app/qml/AccountSwitchDialog.qml:58
#, kde-format
#, fuzzy, kde-format
#| msgid "Log in or create a new account"
msgctxt "@info"
msgid "Log in or create a new account"
msgstr "لج إلى حساب موجود أو أنشئ حسابا جديدا"
@@ -324,7 +325,8 @@ msgid "Start a chat"
msgstr "ابدأ دردشة"
#: src/app/qml/AskDirectChatConfirmation.qml:21
#, kde-format
#, fuzzy, kde-format
#| msgid "Do you want to start a chat with %1?"
msgctxt "@info"
msgid "Do you want to start a chat with %1?"
msgstr "هل ترغب في بَدء دردشة مع %1؟"
@@ -347,7 +349,8 @@ msgid "Edit"
msgstr "حرّر"
#: src/app/qml/AttachmentPane.qml:61
#, kde-format
#, fuzzy, kde-format
#| msgid "Cancel sending attachment"
msgctxt "@action:button"
msgid "Cancel sending attachment"
msgstr "ألغ إرسال المرفق"
@@ -826,37 +829,43 @@ msgid "Create Poll"
msgstr "أنشئ استفتاء"
#: src/app/qml/NewPollDialog.qml:45
#, kde-format
#, fuzzy, kde-format
#| msgid "Poll type:"
msgctxt "@label"
msgid "Poll type:"
msgstr "نوع الاستفتاء:"
#: src/app/qml/NewPollDialog.qml:50
#, kde-format
#, fuzzy, kde-format
#| msgid "Open poll"
msgctxt "@item:inlistbox"
msgid "Open poll"
msgstr "افتح استفتاء"
#: src/app/qml/NewPollDialog.qml:51
#, kde-format
#, fuzzy, kde-format
#| msgid "Closed poll"
msgctxt "@item:inlistbox"
msgid "Closed poll"
msgstr "استفتاء مغلق"
#: src/app/qml/NewPollDialog.qml:56
#, kde-format
#, fuzzy, kde-format
#| msgid "Voters can see the result as soon as they have voted"
msgctxt "@info"
msgid "Voters can see the result as soon as they have voted"
msgstr "يمكن للمصوتين رؤية النتيجة بمجرد التصويت"
#: src/app/qml/NewPollDialog.qml:56
#, kde-format
#, fuzzy, kde-format
#| msgid "Results are revealed only after the poll has closed"
msgctxt "@info"
msgid "Results are revealed only after the poll has closed"
msgstr "لا تظهر النتائج إلا بعد إغلاق الاستفتاء"
#: src/app/qml/NewPollDialog.qml:60
#, kde-format
#, fuzzy, kde-format
#| msgid "Question:"
msgctxt "@label"
msgid "Question:"
msgstr "السؤال:"
@@ -904,7 +913,8 @@ msgid "No Notifications"
msgstr "لا يوجد إشعارات"
#: src/app/qml/OpenFileDialog.qml:12
#, kde-format
#, fuzzy, kde-format
#| msgid "Select a File"
msgctxt "@title:dialog"
msgid "Select a File"
msgstr "اختر ملف"
@@ -916,43 +926,50 @@ msgid "Scan a QR Code"
msgstr "امسح رمز الاستجابة السريعة"
#: src/app/qml/QuickFormatBar.qml:22
#, kde-format
#, fuzzy, kde-format
#| msgid "Bold"
msgctxt "@action:button"
msgid "Bold"
msgstr "ثخين"
#: src/app/qml/QuickFormatBar.qml:41
#, kde-format
#, fuzzy, kde-format
#| msgid "Italic"
msgctxt "@action:button"
msgid "Italic"
msgstr "مائل"
#: src/app/qml/QuickFormatBar.qml:60
#, kde-format
#, fuzzy, kde-format
#| msgid "Strikethrough"
msgctxt "@action:button"
msgid "Strikethrough"
msgstr "شطب"
#: src/app/qml/QuickFormatBar.qml:79
#, kde-format
#, fuzzy, kde-format
#| msgid "Spoiler"
msgctxt "@action:button"
msgid "Spoiler"
msgstr "مخفي"
#: src/app/qml/QuickFormatBar.qml:98
#, kde-format
#, fuzzy, kde-format
#| msgid "Code block"
msgctxt "@action:button"
msgid "Code block"
msgstr "كتلة شفرة"
#: src/app/qml/QuickFormatBar.qml:117
#, kde-format
#, fuzzy, kde-format
#| msgid "Quote"
msgctxt "@action:button"
msgid "Quote"
msgstr "اقتباس"
#: src/app/qml/QuickFormatBar.qml:136
#, kde-format
#, fuzzy, kde-format
#| msgid "Insert link"
msgctxt "@action:button"
msgid "Insert link"
msgstr "أدرج رابط"
@@ -1073,19 +1090,22 @@ msgid "Share"
msgstr "شارك"
#: src/app/qml/ShareAction.qml:25
#, kde-format
#, fuzzy, kde-format
#| msgid "Share the selected media"
msgctxt "@info:tooltip"
msgid "Share the selected media"
msgstr "شارك الوسيط المحدد"
#: src/app/qml/ShareDialog.qml:36
#, kde-format
#, fuzzy, kde-format
#| msgid "Sharing failed"
msgctxt "@info:status"
msgid "Sharing failed"
msgstr "فشلت المشاركة"
#: src/app/qml/ShareDialog.qml:58
#, kde-format
#, fuzzy, kde-format
#| msgid "Shared url for image is <a href='%1'>%1</a>"
msgctxt "@info"
msgid "Shared url for image is <a href='%1'>%1</a>"
msgstr "عنوان الصورة المشارك بها هو <a href='%1'>%1</a>"
@@ -1209,7 +1229,8 @@ msgid "Ignore this user"
msgstr "تجاهل هذا المستخدم"
#: src/app/qml/UserDetailDialog.qml:156
#, kde-format
#, fuzzy, kde-format
#| msgid "Kick this user"
msgctxt "@action:button"
msgid "Kick this user"
msgstr "اطرد هذا المستخدم"
@@ -1233,13 +1254,15 @@ msgid "Kick"
msgstr "اطرد"
#: src/app/qml/UserDetailDialog.qml:179
#, kde-format
#, fuzzy, kde-format
#| msgid "Invite this user"
msgctxt "@action:button"
msgid "Invite this user"
msgstr "أدعو هذا المستخدم"
#: src/app/qml/UserDetailDialog.qml:190
#, kde-format
#, fuzzy, kde-format
#| msgid "Ban this user"
msgctxt "@action:button"
msgid "Ban this user"
msgstr "احظر هذا المستخدم"
@@ -1263,13 +1286,15 @@ msgid "Ban"
msgstr "احظر"
#: src/app/qml/UserDetailDialog.qml:213
#, kde-format
#, fuzzy, kde-format
#| msgid "Unban this user"
msgctxt "@action:button"
msgid "Unban this user"
msgstr "ألغ حظر هذا المستخدم"
#: src/app/qml/UserDetailDialog.qml:224
#, kde-format
#, fuzzy, kde-format
#| msgid "Set user power level"
msgctxt "@action:button"
msgid "Set user power level"
msgstr "عيّن مستوى قدرة المستخدم"
@@ -1542,13 +1567,15 @@ msgid "Quit"
msgstr "أنهِ"
#: src/chatbar/AttachDialog.qml:29
#, kde-format
#, fuzzy, kde-format
#| msgid "Choose local file"
msgctxt "@action:button"
msgid "Choose local file"
msgstr "اختر ملف محلي"
#: src/chatbar/AttachDialog.qml:45
#, kde-format
#, fuzzy, kde-format
#| msgid "Clipboard image"
msgctxt "@action:button"
msgid "Clipboard image"
msgstr "صورة الحافظة"
@@ -1560,13 +1587,15 @@ msgid "Attach an image or file"
msgstr "أرفق صورة أو ملف"
#: src/chatbar/ChatBar.qml:104
#, kde-format
#, fuzzy, kde-format
#| msgid "Emojis & Stickers"
msgctxt "@action:button"
msgid "Emojis & Stickers"
msgstr "الصور التعبيرية والملصقات"
#: src/chatbar/ChatBar.qml:121
#, kde-format
#, fuzzy, kde-format
#| msgid "Send a Location"
msgctxt "@action:button"
msgid "Send a Location"
msgstr "أرسل موقعاً جغرافياً"
@@ -1578,7 +1607,8 @@ msgid "Create a Poll"
msgstr "أنشئ استفتاء"
#: src/chatbar/ChatBar.qml:151
#, kde-format
#, fuzzy, kde-format
#| msgid "Send message"
msgctxt "@action:button"
msgid "Send message"
msgstr "أرسل رسالة"
@@ -1590,19 +1620,22 @@ msgid "The user you're replying to has left the room, and can't be notified."
msgstr "المستخدم الذي ترد عليه غادر الغرفة، ولا يمكن إشعاره."
#: src/chatbar/ChatBar.qml:253
#, kde-format
#, fuzzy, kde-format
#| msgid "Send an encrypted message…"
msgctxt "@placeholder"
msgid "Send an encrypted message…"
msgstr "أرسل رسالة معماة…"
#: src/chatbar/ChatBar.qml:253
#, kde-format
#, fuzzy, kde-format
#| msgid "Set an attachment caption…"
msgctxt "@placeholder"
msgid "Set an attachment caption…"
msgstr "ضع اسم للمرفق…"
#: src/chatbar/ChatBar.qml:253
#, kde-format
#, fuzzy, kde-format
#| msgid "Send a message…"
msgctxt "@placeholder"
msgid "Send a message…"
msgstr "أرسل رسالة…"
@@ -3992,13 +4025,15 @@ msgid "Create New"
msgstr "أنشئ جديدًا"
#: src/rooms/ExploreComponentMobile.qml:143
#, kde-format
#, fuzzy, kde-format
#| msgid "Create a Room"
msgctxt "@action:button"
msgid "Create a Room"
msgstr "أنشئ غرفة"
#: src/rooms/ExploreComponentMobile.qml:161
#, kde-format
#, fuzzy, kde-format
#| msgid "Create a Space"
msgctxt "@action:button"
msgid "Create a Space"
msgstr "أنشئ فضاء"
@@ -4536,13 +4571,15 @@ msgid "Confirm new display name"
msgstr "أكّد اسم العرض الجديد"
#: src/settings/DeviceDelegate.qml:89
#, kde-format
#, fuzzy, kde-format
#| msgid "Edit device name"
msgctxt "@action:button"
msgid "Edit device name"
msgstr "حرر اسم الجهاز"
#: src/settings/DeviceDelegate.qml:99
#, kde-format
#, fuzzy, kde-format
#| msgid "Verify device"
msgctxt "@action:button"
msgid "Verify device"
msgstr "تَثَبّت من الجهاز"
@@ -4554,7 +4591,8 @@ msgid "Verified"
msgstr "متحقّق منه"
#: src/settings/DeviceDelegate.qml:124
#, kde-format
#, fuzzy, kde-format
#| msgid "Logout device"
msgctxt "@action:button"
msgid "Logout device"
msgstr "اخرج الجهاز"
@@ -5819,7 +5857,8 @@ msgid "Canonical"
msgstr "عالمي"
#: src/settings/RoomGeneralPage.qml:274
#, kde-format
#, fuzzy, kde-format
#| msgid "Make canonical parent"
msgctxt "@action:button"
msgid "Make canonical parent"
msgstr "اجعله فضاء رئيس عالمي"
@@ -6684,25 +6723,29 @@ msgid ""
msgstr "هذه هي بداية الدردشة. ولا توجد رسائل قديمة قبل هذه النقطة."
#: src/timeline/TimelineView.qml:219
#, kde-format
#, fuzzy, kde-format
#| msgid "Jump to first unread message"
msgctxt "@action:button"
msgid "Jump to first unread message"
msgstr "اقفز إلى أول رسالة غير المقروءة"
#: src/timeline/TimelineView.qml:219
#, kde-format
#, fuzzy, kde-format
#| msgid "Jump to oldest loaded message"
msgctxt "@action:button"
msgid "Jump to oldest loaded message"
msgstr "اقفز إلى أقدم رسالة محملة"
#: src/timeline/TimelineView.qml:250
#, kde-format
#, fuzzy, kde-format
#| msgid "Jump to latest message"
msgctxt "@action:button"
msgid "Jump to latest message"
msgstr "اقفز إلى أحدث رسالة"
#: src/timeline/TimelineView.qml:285
#, kde-format
#, fuzzy, kde-format
#| msgid "Drag items here to share them"
msgctxt "@info:placeholder"
msgid "Drag items here to share them"
msgstr "اسحب عناصر هنا لتشاركهم"

View File

@@ -7,7 +7,7 @@ msgstr ""
"Project-Id-Version: neochat\n"
"Report-Msgid-Bugs-To: https://bugs.kde.org\n"
"POT-Creation-Date: 2025-08-16 00:43+0000\n"
"PO-Revision-Date: 2025-08-16 20:08+0200\n"
"PO-Revision-Date: 2025-08-14 21:22+0200\n"
"Last-Translator: Vincenzo Reale <smart2128vr@gmail.com>\n"
"Language-Team: Italian <kde-i18n-it@kde.org>\n"
"Language: it\n"
@@ -347,7 +347,8 @@ msgid "Edit"
msgstr "Modifica"
#: src/app/qml/AttachmentPane.qml:61
#, kde-format
#, fuzzy, kde-format
#| msgid "Cancel sending attachment"
msgctxt "@action:button"
msgid "Cancel sending attachment"
msgstr "Annulla l'invio dell'allegato"
@@ -828,37 +829,43 @@ msgid "Create Poll"
msgstr "Crea sondaggio"
#: src/app/qml/NewPollDialog.qml:45
#, kde-format
#, fuzzy, kde-format
#| msgid "Poll type:"
msgctxt "@label"
msgid "Poll type:"
msgstr "Tipo di sondaggio:"
#: src/app/qml/NewPollDialog.qml:50
#, kde-format
#, fuzzy, kde-format
#| msgid "Open poll"
msgctxt "@item:inlistbox"
msgid "Open poll"
msgstr "Sondaggio aperto"
#: src/app/qml/NewPollDialog.qml:51
#, kde-format
#, fuzzy, kde-format
#| msgid "Closed poll"
msgctxt "@item:inlistbox"
msgid "Closed poll"
msgstr "Sondaggio chiuso"
#: src/app/qml/NewPollDialog.qml:56
#, kde-format
#, fuzzy, kde-format
#| msgid "Voters can see the result as soon as they have voted"
msgctxt "@info"
msgid "Voters can see the result as soon as they have voted"
msgstr "I votanti possono vedere il risultato non appena hanno votato"
#: src/app/qml/NewPollDialog.qml:56
#, kde-format
#, fuzzy, kde-format
#| msgid "Results are revealed only after the poll has closed"
msgctxt "@info"
msgid "Results are revealed only after the poll has closed"
msgstr "I risultati saranno rivelati solo dopo la chiusura del sondaggio"
#: src/app/qml/NewPollDialog.qml:60
#, kde-format
#, fuzzy, kde-format
#| msgid "Question:"
msgctxt "@label"
msgid "Question:"
msgstr "Domanda:"
@@ -918,43 +925,50 @@ msgid "Scan a QR Code"
msgstr "Scansione di un codice QR"
#: src/app/qml/QuickFormatBar.qml:22
#, kde-format
#, fuzzy, kde-format
#| msgid "Bold"
msgctxt "@action:button"
msgid "Bold"
msgstr "Grassetto"
#: src/app/qml/QuickFormatBar.qml:41
#, kde-format
#, fuzzy, kde-format
#| msgid "Italic"
msgctxt "@action:button"
msgid "Italic"
msgstr "Corsivo"
#: src/app/qml/QuickFormatBar.qml:60
#, kde-format
#, fuzzy, kde-format
#| msgid "Strikethrough"
msgctxt "@action:button"
msgid "Strikethrough"
msgstr "Barrato"
#: src/app/qml/QuickFormatBar.qml:79
#, kde-format
#, fuzzy, kde-format
#| msgid "Spoiler"
msgctxt "@action:button"
msgid "Spoiler"
msgstr "Visualizza nascosto"
#: src/app/qml/QuickFormatBar.qml:98
#, kde-format
#, fuzzy, kde-format
#| msgid "Code block"
msgctxt "@action:button"
msgid "Code block"
msgstr "Blocco di codice"
#: src/app/qml/QuickFormatBar.qml:117
#, kde-format
#, fuzzy, kde-format
#| msgid "Quote"
msgctxt "@action:button"
msgid "Quote"
msgstr "Citazione"
#: src/app/qml/QuickFormatBar.qml:136
#, kde-format
#, fuzzy, kde-format
#| msgid "Insert link"
msgctxt "@action:button"
msgid "Insert link"
msgstr "Inserisci collegamento"
@@ -1211,7 +1225,8 @@ msgid "Ignore this user"
msgstr "Ignora questo utente"
#: src/app/qml/UserDetailDialog.qml:156
#, kde-format
#, fuzzy, kde-format
#| msgid "Kick this user"
msgctxt "@action:button"
msgid "Kick this user"
msgstr "Espelli questo utente"
@@ -1235,13 +1250,15 @@ msgid "Kick"
msgstr "Espelli"
#: src/app/qml/UserDetailDialog.qml:179
#, kde-format
#, fuzzy, kde-format
#| msgid "Invite this user"
msgctxt "@action:button"
msgid "Invite this user"
msgstr "Invita questo utente"
#: src/app/qml/UserDetailDialog.qml:190
#, kde-format
#, fuzzy, kde-format
#| msgid "Ban this user"
msgctxt "@action:button"
msgid "Ban this user"
msgstr "Bandisci questo utente"
@@ -1265,13 +1282,15 @@ msgid "Ban"
msgstr "Bando"
#: src/app/qml/UserDetailDialog.qml:213
#, kde-format
#, fuzzy, kde-format
#| msgid "Unban this user"
msgctxt "@action:button"
msgid "Unban this user"
msgstr "Rimuovi il bando questo utente"
#: src/app/qml/UserDetailDialog.qml:224
#, kde-format
#, fuzzy, kde-format
#| msgid "Set user power level"
msgctxt "@action:button"
msgid "Set user power level"
msgstr "Imposta il livello di potere dell'utente"
@@ -4023,13 +4042,15 @@ msgid "Create New"
msgstr "Crea nuovo"
#: src/rooms/ExploreComponentMobile.qml:143
#, kde-format
#, fuzzy, kde-format
#| msgid "Create a Room"
msgctxt "@action:button"
msgid "Create a Room"
msgstr "Crea una stanza"
#: src/rooms/ExploreComponentMobile.qml:161
#, kde-format
#, fuzzy, kde-format
#| msgid "Create a Space"
msgctxt "@action:button"
msgid "Create a Space"
msgstr "Crea uno spazio"
@@ -4566,13 +4587,15 @@ msgid "Confirm new display name"
msgstr "Conferma il nuovo nome visualizzato"
#: src/settings/DeviceDelegate.qml:89
#, kde-format
#, fuzzy, kde-format
#| msgid "Edit device name"
msgctxt "@action:button"
msgid "Edit device name"
msgstr "Modifica il nome del dispositivo"
#: src/settings/DeviceDelegate.qml:99
#, kde-format
#, fuzzy, kde-format
#| msgid "Verify device"
msgctxt "@action:button"
msgid "Verify device"
msgstr "Verifica il dispositivo"
@@ -4584,7 +4607,8 @@ msgid "Verified"
msgstr "Verificato"
#: src/settings/DeviceDelegate.qml:124
#, kde-format
#, fuzzy, kde-format
#| msgid "Logout device"
msgctxt "@action:button"
msgid "Logout device"
msgstr "Disconnetti il dispositivo"
@@ -5875,7 +5899,8 @@ msgid "Canonical"
msgstr "Canonico"
#: src/settings/RoomGeneralPage.qml:274
#, kde-format
#, fuzzy, kde-format
#| msgid "Make canonical parent"
msgctxt "@action:button"
msgid "Make canonical parent"
msgstr "Crea genitore canonico"
@@ -6748,19 +6773,22 @@ msgstr ""
"punto."
#: src/timeline/TimelineView.qml:219
#, kde-format
#, fuzzy, kde-format
#| msgid "Jump to first unread message"
msgctxt "@action:button"
msgid "Jump to first unread message"
msgstr "Passa al primo messaggio non letto"
#: src/timeline/TimelineView.qml:219
#, kde-format
#, fuzzy, kde-format
#| msgid "Jump to oldest loaded message"
msgctxt "@action:button"
msgid "Jump to oldest loaded message"
msgstr "Salta al messaggio caricato più vecchio"
#: src/timeline/TimelineView.qml:250
#, kde-format
#, fuzzy, kde-format
#| msgid "Jump to latest message"
msgctxt "@action:button"
msgid "Jump to latest message"
msgstr "Salta all'ultimo messaggio"

View File

@@ -24,6 +24,8 @@ add_library(neochat STATIC
models/notificationsmodel.h
proxycontroller.cpp
proxycontroller.h
mediamanager.cpp
mediamanager.h
sharehandler.cpp
sharehandler.h
foreigntypes.h
@@ -99,11 +101,10 @@ ecm_add_qml_module(neochat URI org.kde.neochat GENERATE_PLUGIN_SOURCE
qml/ReasonDialog.qml
qml/NewPollDialog.qml
qml/UserMenu.qml
qml/IncomingCallDialog.qml
DEPENDENCIES
QtCore
QtQuick
io.github.quotient_im.libquotient
com.github.quotient_im.libquotient
IMPORTS
org.kde.neochat.libneochat
org.kde.neochat.rooms

View File

@@ -18,7 +18,6 @@
#include <Quotient/settings.h>
#include "accountmanager.h"
#include "callmanager.h"
#include "enums/roomsortparameter.h"
#include "mediasizehelper.h"
#include "models/actionsmodel.h"
@@ -73,11 +72,6 @@ Controller::Controller(QObject *parent)
{
Connection::setRoomType<NeoChatRoom>();
CallManager::instance().setCallsEnabled(NeoChatConfig::calls());
connect(NeoChatConfig::self(), &NeoChatConfig::CallsChanged, this, []() {
CallManager::instance().setCallsEnabled(NeoChatConfig::calls());
});
Connection::setDirectChatEncryptionDefault(NeoChatConfig::preferUsingEncryption());
connect(NeoChatConfig::self(), &NeoChatConfig::PreferUsingEncryptionChanged, this, [] {
Connection::setDirectChatEncryptionDefault(NeoChatConfig::preferUsingEncryption());

View File

@@ -1,18 +1,11 @@
// SPDX-FileCopyrightText: 2023-2025 Tobias Fella <tobias.fella@kde.org>
// SPDX-FileCopyrightText: 2023 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "mediamanager.h"
#include <Quotient/qt_connection_util.h>
void MediaManager::startPlayback()
{
Q_EMIT playbackStarted();
}
MediaManager::MediaManager()
: QObject(nullptr)
{
}
#include "moc_mediamanager.cpp"

View File

@@ -39,7 +39,4 @@ Q_SIGNALS:
* @brief Emitted when any media player starts playing. Other objects should stop / pause playback.
*/
void playbackStarted();
private:
MediaManager();
};

View File

@@ -1,39 +0,0 @@
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: GPL-2.0-or-later
import QtQuick
import QtQuick.Controls as QQC2
import org.kde.kirigami as Kirigami
import org.kde.kirigamiaddons.formcard as FormCard
import org.kde.kirigamiaddons.components as Components
import org.kde.neochat.libneochat
FormCard.FormCardPage {
id: root
title: i18nc("@title:dialog", "Incoming Call")
FormCard.FormCard {
topPadding: Kirigami.Units.largeSpacing
FormCard.AbstractFormDelegate {
contentItem: Components.Avatar {
name: CallManager.room.displayName
source: CallManager.room.avatarMediaUrl
}
}
FormCard.FormTextDelegate {
text: i18nc("@info", "%1 is calling you.", CallManager.callingMember.htmlSafeDisplayName)
}
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Accept Call")
onClicked: console.warn("unimplemented")
}
FormCard.FormButtonDelegate {
text: i18nc("@action:button", "Decline Call")
onClicked: CallManager.declineCall()
}
}
}

View File

@@ -83,16 +83,6 @@ Kirigami.ApplicationWindow {
}
}
Connections {
target: CallManager
property IncomingCallDialog dialog
function onIsRingingChanged(): void {
if (CallManager.isRinging) {
root.pageStack.pushDialogLayer(Qt.createComponent("org.kde.neochat", "IncomingCallDialog"));
}
}
}
Loader {
active: Kirigami.Settings.hasPlatformMenuBar && !Kirigami.Settings.isMobile
sourceComponent: GlobalMenu {

View File

@@ -8,7 +8,6 @@ target_sources(LibNeoChat PRIVATE
neochatroom.cpp
neochatroommember.cpp
accountmanager.cpp
callmanager.cpp
chatbarcache.cpp
chatdocumenthandler.cpp
clipboard.cpp
@@ -24,8 +23,6 @@ target_sources(LibNeoChat PRIVATE
urlhelper.cpp
utils.cpp
enums/chatbartype.h
mediamanager.cpp
mediamanager.h
enums/messagecomponenttype.h
enums/messagetype.h
enums/powerlevel.cpp
@@ -35,7 +32,6 @@ target_sources(LibNeoChat PRIVATE
enums/timelinemarkreadcondition.h
events/imagepackevent.cpp
events/pollevent.cpp
events/callmemberevent.cpp
jobs/neochatgetcommonroomsjob.cpp
models/actionsmodel.cpp
models/completionmodel.cpp
@@ -55,9 +51,6 @@ if (TARGET KF6::KIOWidgets)
target_compile_definitions(LibNeoChat PUBLIC -DHAVE_KIO)
endif()
qt_add_dbus_interface(MediaPlayer_SRCS org.mpris.MediaPlayer2.Player.xml mediaplayer2player)
target_sources(LibNeoChat PRIVATE ${MediaPlayer_SRCS})
ecm_add_qml_module(LibNeoChat GENERATE_PLUGIN_SOURCE
URI org.kde.neochat.libneochat
OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/src/org/kde/neochat/libneochat
@@ -70,7 +63,7 @@ ecm_add_qml_module(LibNeoChat GENERATE_PLUGIN_SOURCE
qml/CreateRoomDialog.qml
qml/CreateSpaceDialog.qml
DEPENDENCIES
io.github.quotient_im.libquotient
com.github.quotient_im.libquotient
)
ecm_qt_declare_logging_category(LibNeoChat

View File

@@ -1,166 +0,0 @@
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org
// SPDX-License-Identifier: GPL-2.0-or-later
#include "callmanager.h"
#include "events/callmemberevent.h"
#include "mediamanager.h"
#include "mediaplayer2player.h"
#include "neochatroom.h"
#include <QAudioOutput>
#include <QDBusConnection>
#include <QMediaPlayer>
#include <QMimeDatabase>
#include <QTimer>
#include <Quotient/qt_connection_util.h>
using namespace Quotient;
using namespace Qt::Literals::StringLiterals;
void CallManager::ring(const QJsonObject &json, NeoChatRoom *room)
{
if (!m_callsEnabled) {
return;
}
// TODO: check sender != us
// Consider multiple accounts being logged in
if (json["content"_L1]["application"_L1].toString() != "m.call"_L1) {
return;
}
if (!json["content"_L1]["m.mentions"_L1]["room"_L1].toBool() || json["sender"_L1].toString() == room->connection()->userId()) {
if (std::ranges::none_of(json["content"_L1]["m.mentions"_L1]["user_ids"_L1].toArray(), [room](const auto &user) {
return user.toString() == room->connection()->userId();
})) {
return;
}
}
if (json["content"_L1]["notify_type"_L1].toString() != "ring"_L1) {
return;
}
if (room->pushNotificationState() == PushNotificationState::Mute) {
return;
}
if (isRinging()) {
return;
}
if (const auto &event = room->currentState().get<CallMemberEvent>(room->connection()->userId())) {
if (event) {
auto memberships = event->contentJson()["memberships"_L1].toArray();
for (const auto &m : memberships) {
const auto &membership = m.toObject();
if (membership["application"_L1] == "m.call"_L1 && membership["call_id"_L1].toString().isEmpty()) {
qWarning() << "already in a call";
return;
}
}
}
}
connectUntil(room, &NeoChatRoom::changed, this, [this, room]() {
if (const auto &event = room->currentState().get<CallMemberEvent>(room->connection()->userId())) {
auto memberships = event->contentJson()["memberships"_L1].toArray();
for (const auto &m : memberships) {
const auto &membership = m.toObject();
if (membership["application"_L1] == "m.call"_L1 && membership["call_id"_L1].toString().isEmpty()) {
stopRinging();
return true;
}
}
}
return false;
});
if (json["unsigned"_L1]["age"_L1].toInt() > 10000) {
return;
}
m_room = room;
m_callingMember = json["sender"_L1].toString();
Q_EMIT roomChanged();
QTimer::singleShot(60000, this, &CallManager::stopRinging);
ringUnchecked();
}
void CallManager::ringUnchecked()
{
MediaManager::instance().startPlayback();
// Pause all media players registered with the system
for (const auto &iface : QDBusConnection::sessionBus().interface()->registeredServiceNames().value()) {
if (iface.startsWith("org.mpris.MediaPlayer2"_L1)) {
OrgMprisMediaPlayer2PlayerInterface mprisInterface(iface, "/org/mpris/MediaPlayer2"_L1, QDBusConnection::sessionBus());
QString status = mprisInterface.playbackStatus();
if (status == "Playing"_L1) {
if (mprisInterface.canPause()) {
mprisInterface.Pause();
} else {
mprisInterface.Stop();
}
}
}
}
static QString path;
if (path.isEmpty()) {
for (const auto &dir : QString::fromUtf8(qgetenv("XDG_DATA_DIRS")).split(u':')) {
if (QFileInfo(dir + QStringLiteral("/sounds/freedesktop/stereo/phone-incoming-call.oga")).exists()) {
path = dir + QStringLiteral("/sounds/freedesktop/stereo/phone-incoming-call.oga");
break;
}
}
}
if (path.isEmpty()) {
return;
}
m_player->setSource(QUrl::fromLocalFile(path));
m_player->play();
m_ringing = true;
Q_EMIT isRingingChanged();
}
bool CallManager::isRinging() const
{
return m_ringing;
}
void CallManager::stopRinging()
{
m_ringing = false;
m_player->pause();
m_timer.stop();
Q_EMIT isRingingChanged();
}
void CallManager::setCallsEnabled(bool enabled)
{
m_callsEnabled = enabled;
}
CallManager::CallManager()
: QObject(nullptr)
, m_player(new QMediaPlayer())
, m_output(new QAudioOutput())
{
m_player->setAudioOutput(m_output);
m_timer.setInterval(1000);
m_timer.setSingleShot(true);
connect(&m_timer, &QTimer::timeout, this, [this]() {
m_player->play();
});
connect(m_player, &QMediaPlayer::playbackStateChanged, this, [this]() {
if (m_player->playbackState() == QMediaPlayer::StoppedState) {
m_timer.start();
}
});
}
NeoChatRoom *CallManager::room() const
{
return m_room.get();
}
NeochatRoomMember *CallManager::callingMember() const
{
return m_room->qmlSafeMember(m_callingMember);
}

View File

@@ -1,68 +0,0 @@
// SPDX-FileCopyrightText: 2025 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#pragma once
#include <QObject>
#include <QQmlEngine>
#include <QTimer>
#include "neochatroom.h"
#include "neochatroommember.h"
class QAudioOutput;
class QMediaPlayer;
/**
* @class CallManager
*
* Manages calls.
*/
class CallManager : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_SINGLETON
Q_PROPERTY(bool isRinging READ isRinging NOTIFY isRingingChanged)
Q_PROPERTY(NeoChatRoom *room READ room NOTIFY roomChanged)
Q_PROPERTY(NeochatRoomMember *callingMember READ callingMember NOTIFY roomChanged)
public:
static CallManager &instance()
{
static CallManager _instance;
return _instance;
}
static CallManager *create(QQmlEngine *, QJSEngine *)
{
QQmlEngine::setObjectOwnership(&instance(), QQmlEngine::CppOwnership);
return &instance();
}
void ring(const QJsonObject &json, NeoChatRoom *room);
void stopRinging();
bool isRinging() const;
void setCallsEnabled(bool enabled);
NeoChatRoom *room() const;
NeochatRoomMember *callingMember() const;
Q_SIGNALS:
void isRingingChanged();
void roomChanged();
private:
CallManager();
void ringUnchecked();
bool m_ringing = false;
QMediaPlayer *m_player;
QAudioOutput *m_output;
QTimer m_timer;
bool m_callsEnabled = false;
QPointer<NeoChatRoom> m_room;
QString m_callingMember;
};

View File

@@ -1,38 +0,0 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.0-or-later
#include "callmemberevent.h"
#include <QString>
using namespace Quotient;
using namespace Qt::Literals::StringLiterals;
CallMemberEventContent::CallMemberEventContent(const QJsonObject &json)
{
for (const auto &membership : json["memberships"_L1].toArray()) {
QList<Focus> foci;
for (const auto &focus : membership["foci_active"_L1].toArray()) {
foci.append(Focus{
.livekitAlias = focus["livekit_alias"_L1].toString(),
.livekitServiceUrl = focus["livekit_service_url"_L1].toString(),
.type = focus["livekit"_L1].toString(),
});
}
memberships.append(CallMembership{
.application = membership["application"_L1].toString(),
.callId = membership["call_id"_L1].toString(),
.deviceId = membership["device_id"_L1].toString(),
.expires = membership["expires"_L1].toInt(),
.expiresTs = membership["expires"_L1].toVariant().value<uint64_t>(),
.fociActive = foci,
.membershipId = membership["membershipID"_L1].toString(),
.scope = membership["scope"_L1].toString(),
});
}
}
QJsonObject CallMemberEventContent::toJson() const
{
return {};
}

View File

@@ -1,59 +0,0 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.1-or-later
#pragma once
#include <Quotient/events/stateevent.h>
namespace Quotient
{
struct Focus {
QString livekitAlias;
QString livekitServiceUrl;
QString type;
};
struct CallMembership {
QString application;
QString callId;
QString deviceId;
int expires;
uint64_t expiresTs;
QList<Focus> fociActive;
QString membershipId;
QString scope;
};
class CallMemberEventContent
{
public:
explicit CallMemberEventContent(const QJsonObject &json);
QJsonObject toJson() const;
QList<CallMembership> memberships;
};
/**
* @class CallMemberEvent
*
* Class to define a call member event.
*
* @sa Quotient::StateEvent
*/
class CallMemberEvent : public KeyedStateEventBase<CallMemberEvent, CallMemberEventContent>
{
public:
QUO_EVENT(CallMemberEvent, "org.matrix.msc3401.call.member")
explicit CallMemberEvent(const QJsonObject &obj)
: KeyedStateEventBase(obj)
{
}
QJsonArray memberships() const
{
return contentJson()["memberships"_L1].toArray();
}
};
}

View File

@@ -1,21 +0,0 @@
// SPDX-FileCopyrightText: 2024 Tobias Fella <tobias.fella@kde.org>
// SPDX-License-Identifier: LGPL-2.1-or-later
#pragma once
#include <Quotient/events/roomevent.h>
namespace Quotient
{
class CallNotifyEvent : public RoomEvent
{
public:
QUO_EVENT(CallNotifyEvent, "org.matrix.msc4075.call.notify");
explicit CallNotifyEvent(const QJsonObject &obj)
: RoomEvent(obj)
{
}
};
}

View File

@@ -44,10 +44,8 @@
#include <Quotient/thread.h>
#endif
#include "callmanager.h"
#include "chatbarcache.h"
#include "clipboard.h"
#include "events/callnotifyevent.h"
#include "events/pollevent.h"
#include "filetransferpseudojob.h"
#include "neochatconnection.h"
@@ -119,14 +117,6 @@ NeoChatRoom::NeoChatRoom(Connection *connection, QString roomId, JoinState joinS
}
connect(this, &Room::addedMessages, this, &NeoChatRoom::cacheLastEvent);
connect(this, &NeoChatRoom::aboutToAddNewMessages, this, [this](const auto &events) {
for (const auto &event : events) {
if (event->template is<CallNotifyEvent>()) {
CallManager::instance().ring(event->fullJson(), this);
}
}
});
connect(this, &Quotient::Room::eventsHistoryJobChanged, this, &NeoChatRoom::lastActiveTimeChanged);
connect(this, &Room::joinStateChanged, this, [this](JoinState oldState, JoinState newState) {

View File

@@ -1,114 +0,0 @@
<?xml version="1.0" ?>
<!--
SPDX-FileCopyrightText: 2006-2012 the VideoLAN team (Mirsal Ennaime, Rafaël Carré, Jean-Paul Saman)
SPDX-FileCopyrightText: 2005-2008 Milosz Derezynski
SPDX-FileCopyrightText: 2008 Nick Welch
SPDX-FileCopyrightText: 2010-2012 Alex Merry
SPDX-License-Identifier: LGPL-2.1-or-later
-->
<node xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
<interface name="org.mpris.MediaPlayer2.Player">
<method name="Next" tp:name-for-bindings="Next">
</method>
<method name="Previous" tp:name-for-bindings="Previous">
</method>
<method name="Pause" tp:name-for-bindings="Pause">
</method>
<method name="PlayPause" tp:name-for-bindings="PlayPause">
</method>
<method name="Stop" tp:name-for-bindings="Stop">
</method>
<method name="Play" tp:name-for-bindings="Play">
</method>
<method name="Seek" tp:name-for-bindings="Seek">
<arg direction="in" type="x" name="Offset" tp:type="Time_In_Us">
</arg>
</method>
<method name="SetPosition" tp:name-for-bindings="Set_Position">
<arg direction="in" type="o" tp:type="Track_Id" name="TrackId">
</arg>
<arg direction="in" type="x" tp:type="Time_In_Us" name="Position">
</arg>
</method>
<method name="OpenUri" tp:name-for-bindings="Open_Uri">
<arg direction="in" type="s" tp:type="Uri" name="Uri">
</arg>
</method>
<property name="PlaybackStatus" tp:name-for-bindings="Playback_Status" type="s" tp:type="Playback_Status" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="LoopStatus" type="s" access="readwrite"
tp:name-for-bindings="Loop_Status" tp:type="Loop_Status">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="Rate" tp:name-for-bindings="Rate" type="d" tp:type="Playback_Rate" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="Shuffle" tp:name-for-bindings="Shuffle" type="b" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="Metadata" tp:name-for-bindings="Metadata" type="a{sv}" tp:type="Metadata_Map" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
<annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/>
</property>
<property name="Volume" type="d" tp:type="Volume" tp:name-for-bindings="Volume" access="readwrite">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true" />
</property>
<property name="Position" type="x" tp:type="Time_In_Us" tp:name-for-bindings="Position" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
<property name="MinimumRate" tp:name-for-bindings="Minimum_Rate" type="d" tp:type="Playback_Rate" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="MaximumRate" tp:name-for-bindings="Maximum_Rate" type="d" tp:type="Playback_Rate" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="CanGoNext" tp:name-for-bindings="Can_Go_Next" type="b" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="CanGoPrevious" tp:name-for-bindings="Can_Go_Previous" type="b" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="CanPlay" tp:name-for-bindings="Can_Play" type="b" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="CanPause" tp:name-for-bindings="Can_Pause" type="b" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="CanSeek" tp:name-for-bindings="Can_Seek" type="b" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="true"/>
</property>
<property name="CanControl" tp:name-for-bindings="Can_Control" type="b" access="read">
<annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
</property>
<signal name="Seeked" tp:name-for-bindings="Seeked">
<arg name="Position" type="x" tp:type="Time_In_Us">
</arg>
</signal>
</interface>
</node>