import QtQml.Models import QtQuick import QtQuick.Layouts import QtQuick.Controls.Material import Quickshell import Quickshell.Io import Quickshell.Widgets import Custom as Custom Item { id: root height: parent.height width: icon.width anchors.verticalCenter: parent.verticalCenter visible: Boolean(unitsModel.values.length) WrapperMouseArea { id: widgetMouseArea anchors.fill: parent hoverEnabled: true Item { anchors.fill: parent MaterialDesignIcon { id: icon implicitSize: 14 anchors.centerIn: parent icon: "tray-arrow-down" color: "white" } } } PopupWindow { id: tooltip property bool openPopup: false property bool nextVisible: widgetMouseArea.containsMouse || tooltipMouseArea.containsMouse || openPopup anchor { item: widgetMouseArea edges: Edges.Bottom | Edges.Left } visible: false onNextVisibleChanged: hangTimer.restart() Timer { id: hangTimer interval: 100 onTriggered: tooltip.visible = tooltip.nextVisible } implicitWidth: tooltipContent.width implicitHeight: tooltipContent.height color: "transparent" Rectangle { width: tooltip.width height: tooltipLayout.childrenRect.height + 16 color: "black" } WrapperItem { id: tooltipContent WrapperMouseArea { id: tooltipMouseArea hoverEnabled: true enabled: true WrapperItem { margin: 8 child: GridLayout { id: tooltipLayout columns: 2 } Repeater { model: ScriptModel { id: unitsModel values: [...Custom.Systemd.userUnits.values].filter(unit => unit.id.match(/^yt-dlp@.+\.service$/) && unit.activeState === "active" && unit.runtimeDirectory) } Item { id: unitDelegate Component.onCompleted: { while (children.length) { children[0].parent = tooltipLayout; } } required property var modelData required property int index property var state: null Socket { id: socket path: Quickshell.env("XDG_RUNTIME_DIR") + "/" + unitDelegate.modelData.runtimeDirectory[0] + "/status.sock" connected: true onError: e => { console.warn("YtDlpWidget: Error in Socket:", socket.path, e); } parser: SplitParser { onRead: line => { try { unitDelegate.state = JSON.parse(line) } catch (e) { console.warn("YtDlpWidget: Failed to parse state:", line, e) } } } } WrapperItem { Layout.column: 0 Layout.row: unitDelegate.index implicitWidth: descText.contentWidth implicitHeight: descText.contentHeight Text { id: descText color: "white" font.pointSize: 10 font.family: "Fira Sans" text: unitDelegate.state?.title || unitDelegate.modelData.id } } /* WrapperItem { Layout.column: 1 Layout.row: unitDelegate.index implicitWidth: fragText.contentWidth implicitHeight: fragText.contentHeight visible: Boolean(unitDelegate.state) Text { id: fragText color: "white" font.pointSize: 10 font.family: "Fira Sans" text: `${unitDelegate.state?.fragment_index}/${unitDelegate.state?.fragment_count}` } } */ WrapperItem { Layout.column: 1 Layout.row: unitDelegate.index visible: Boolean(unitDelegate.state) ProgressBar { id: progress Material.background: "black" Material.accent: "white" from: 0 to: unitDelegate.state?.total_bytes || unitDelegate.state?.total_bytes_estimate || 0 value: unitDelegate.state?.downloaded_bytes || 0 indeterminate: !Boolean(unitDelegate.state?.total_bytes || unitDelegate.state?.total_bytes_estimate) || unitDelegate.state?.status !== "downloading" } } } } } } } } }