update bar
This commit is contained in:
@ -11,6 +11,10 @@ Item {
|
|||||||
property string connType: "none" // "wifi", "ethernet", "none"
|
property string connType: "none" // "wifi", "ethernet", "none"
|
||||||
property string connName: ""
|
property string connName: ""
|
||||||
|
|
||||||
|
// accumulate results here, flush to displayed props on exit
|
||||||
|
property string _pendingType: "none"
|
||||||
|
property string _pendingName: ""
|
||||||
|
|
||||||
// \uf1eb = FA wifi, \uf0e8 = FA sitemap (wired proxy), \uf127 = FA chain-broken
|
// \uf1eb = FA wifi, \uf0e8 = FA sitemap (wired proxy), \uf127 = FA chain-broken
|
||||||
readonly property string netIcon:
|
readonly property string netIcon:
|
||||||
connType === "wifi" ? "\uf1eb" :
|
connType === "wifi" ? "\uf1eb" :
|
||||||
@ -25,9 +29,9 @@ Item {
|
|||||||
const state = line.substring(idx1 + 1, idx2)
|
const state = line.substring(idx1 + 1, idx2)
|
||||||
const conn = line.substring(idx2 + 1).trim()
|
const conn = line.substring(idx2 + 1).trim()
|
||||||
if (state === "connected" && (type === "wifi" || type === "ethernet")) {
|
if (state === "connected" && (type === "wifi" || type === "ethernet")) {
|
||||||
if (root.connType === "none" || type === "wifi") {
|
if (root._pendingType === "none" || type === "wifi") {
|
||||||
root.connType = type
|
root._pendingType = type
|
||||||
root.connName = conn
|
root._pendingName = conn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -38,8 +42,8 @@ Item {
|
|||||||
repeat: true
|
repeat: true
|
||||||
triggeredOnStart: true
|
triggeredOnStart: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.connType = "none"
|
root._pendingType = "none"
|
||||||
root.connName = ""
|
root._pendingName = ""
|
||||||
netProc.running = true
|
netProc.running = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,7 +55,11 @@ Item {
|
|||||||
splitMarker: "\n"
|
splitMarker: "\n"
|
||||||
onRead: data => root.parseLine(data)
|
onRead: data => root.parseLine(data)
|
||||||
}
|
}
|
||||||
onExited: running = false
|
onExited: {
|
||||||
|
root.connType = root._pendingType
|
||||||
|
root.connName = root._pendingName
|
||||||
|
running = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
|
|||||||
@ -33,30 +33,10 @@ Item {
|
|||||||
Behavior on color { ColorAnimation { duration: 80 } }
|
Behavior on color { ColorAnimation { duration: 80 } }
|
||||||
}
|
}
|
||||||
|
|
||||||
IconImage {
|
TrayIcon {
|
||||||
id: iconImg
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
implicitSize: 16
|
icon: trayDelegate.modelData.icon
|
||||||
visible: status === Image.Ready
|
size: 16
|
||||||
source: {
|
|
||||||
const icon = trayDelegate.modelData.icon
|
|
||||||
if (!icon || icon === "") return ""
|
|
||||||
if (icon.startsWith("/") || icon.startsWith("file://") || icon.startsWith("image://")) return icon
|
|
||||||
const path = Quickshell.iconPath(icon, "")
|
|
||||||
if (path !== "") return "file://" + path
|
|
||||||
return "image://icon/" + icon
|
|
||||||
}
|
|
||||||
mipmap: true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Letter fallback when icon fails to load
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
visible: iconImg.status !== Image.Ready
|
|
||||||
text: (trayDelegate.modelData.title ?? trayDelegate.modelData.id ?? "?").charAt(0).toUpperCase()
|
|
||||||
color: Theme.textDim
|
|
||||||
font.pixelSize: 11
|
|
||||||
font.bold: true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import Quickshell.Widgets
|
// import Quickshell.Widgets
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import "../components"
|
import "../components"
|
||||||
|
|
||||||
@ -27,17 +27,29 @@ Rectangle {
|
|||||||
delegate: Item {
|
delegate: Item {
|
||||||
id: iconItem
|
id: iconItem
|
||||||
required property var modelData
|
required property var modelData
|
||||||
property string appClass: modelData.lastIpcObject["class"] ?? ""
|
|
||||||
property var entry: appClass !== "" ? DesktopEntries.heuristicLookup(appClass) : null
|
|
||||||
|
|
||||||
width: 16
|
implicitWidth: 16
|
||||||
height: 16
|
implicitHeight: 16
|
||||||
|
|
||||||
IconImage {
|
property string appClass: ""
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
var cls = modelData?.lastIpcObject?.["class"] ?? ""
|
||||||
|
if (cls !== "") {
|
||||||
|
appClass = cls
|
||||||
|
} else if (modelData) {
|
||||||
|
modelData.lastIpcObjectChanged.connect(function() {
|
||||||
|
var c = iconItem.modelData?.lastIpcObject?.["class"] ?? ""
|
||||||
|
if (c !== "") iconItem.appClass = c
|
||||||
|
})
|
||||||
|
Qt.callLater(Hyprland.refreshToplevels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TrayIcon {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: iconItem.entry && iconItem.entry.icon !== ""
|
icon: iconItem.appClass
|
||||||
? "image://icon/" + iconItem.entry.icon
|
size: 16
|
||||||
: ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import Quickshell.Hyprland
|
import Quickshell.Hyprland
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
|
||||||
|
|||||||
103
roles/quickshell/files/components/TrayIcon.qml
Normal file
103
roles/quickshell/files/components/TrayIcon.qml
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
// import QtQuick
|
||||||
|
// import Quickshell.Widgets
|
||||||
|
//
|
||||||
|
// Item {
|
||||||
|
// id: root
|
||||||
|
//
|
||||||
|
// property string icon: ""
|
||||||
|
// property int size: 16
|
||||||
|
//
|
||||||
|
// implicitWidth: size
|
||||||
|
// implicitHeight: size
|
||||||
|
//
|
||||||
|
// readonly property url resolvedSource: {
|
||||||
|
// if (!icon) return ""
|
||||||
|
// if (icon.startsWith("/") || icon.startsWith("file://") || icon.startsWith("image://"))
|
||||||
|
// return icon
|
||||||
|
// if (icon.includes("?path=")) {
|
||||||
|
// const [name, path] = icon.split("?path=")
|
||||||
|
// const baseName = name.slice(name.lastIndexOf("/") + 1)
|
||||||
|
// return `file://${path}/${baseName}`
|
||||||
|
// }
|
||||||
|
// return `image://icon/${icon}`
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// readonly property bool isIconTheme: resolvedSource.toString().startsWith("image://icon/")
|
||||||
|
// readonly property bool hasSource: resolvedSource.toString() !== ""
|
||||||
|
//
|
||||||
|
// IconImage {
|
||||||
|
// anchors.fill: parent
|
||||||
|
// source: root.resolvedSource
|
||||||
|
// visible: root.hasSource && root.isIconTheme
|
||||||
|
// asynchronous: true
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Image {
|
||||||
|
// anchors.fill: parent
|
||||||
|
// source: root.hasSource && !root.isIconTheme ? root.resolvedSource : ""
|
||||||
|
// visible: root.hasSource && !root.isIconTheme
|
||||||
|
// asynchronous: true
|
||||||
|
// fillMode: Image.PreserveAspectFit
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
// import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string icon: ""
|
||||||
|
property int size: 16
|
||||||
|
|
||||||
|
implicitWidth: size
|
||||||
|
implicitHeight: size
|
||||||
|
|
||||||
|
readonly property url resolvedSource: {
|
||||||
|
if (!icon) return ""
|
||||||
|
if (icon.startsWith("/") || icon.startsWith("file://") || icon.startsWith("image://"))
|
||||||
|
return icon
|
||||||
|
if (icon.includes("?path=")) {
|
||||||
|
const [name, path] = icon.split("?path=")
|
||||||
|
const baseName = name.slice(name.lastIndexOf("/") + 1)
|
||||||
|
return `file://${path}/${baseName}`
|
||||||
|
}
|
||||||
|
// Use Quickshell's icon image provider instead of iconPath()
|
||||||
|
return `image://icon/${icon}`
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
anchors.fill: parent
|
||||||
|
// asynchronous: true
|
||||||
|
sourceComponent: root.resolvedSource && root.resolvedSource.toString() !== ""
|
||||||
|
? root.resolvedSource.toString().startsWith("image://icon/")
|
||||||
|
? iconComponent
|
||||||
|
: imageComponent
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: iconComponent
|
||||||
|
IconImage {
|
||||||
|
source: root.resolvedSource
|
||||||
|
asynchronous: true
|
||||||
|
// mipmap: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: imageComponent
|
||||||
|
Image {
|
||||||
|
source: root.resolvedSource
|
||||||
|
asynchronous: true
|
||||||
|
// mipmap: true
|
||||||
|
fillMode: Image.PreserveAspectFit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ -1,2 +1,3 @@
|
|||||||
singleton Theme 1.0 Theme.qml
|
singleton Theme 1.0 Theme.qml
|
||||||
Enclosure 1.0 Enclosure.qml
|
Enclosure 1.0 Enclosure.qml
|
||||||
|
TrayIcon 1.0 TrayIcon.qml
|
||||||
|
|||||||
Reference in New Issue
Block a user