Split out indicators

This commit is contained in:
David Heinemeier Hansson
2026-05-20 13:05:56 +02:00
parent 8476fa7d82
commit 3b9700682c
12 changed files with 527 additions and 162 deletions
+52
View File
@@ -0,0 +1,52 @@
import QtQuick
import qs.Commons
WidgetButton {
id: root
property string moduleName: ""
property var settings: ({})
property string activeText: ""
property string inactiveText: activeText
property string activeTooltipText: ""
property string inactiveTooltipText: activeTooltipText
property string indicatorBlock: "single"
readonly property bool belongsInBlock: indicatorBlock === "active" ? active : (indicatorBlock === "inactive" ? !active : true)
readonly property bool inactiveRevealed: !active && !!bar && bar.revealInactiveIndicators
function extractData(raw) {
var text = String(raw || "").trim()
if (text === "") return {}
var lines = text.split("\n")
try {
return JSON.parse(lines[lines.length - 1])
} catch (error) {
return { text: text }
}
}
function syncIndicatorOpacity() {
root.opacity = !belongsInBlock ? 0 : (active ? 1 : (inactiveRevealed ? 0.45 : 0))
}
Component.onCompleted: syncIndicatorOpacity()
onActiveChanged: syncIndicatorOpacity()
onBarChanged: syncIndicatorOpacity()
onBelongsInBlockChanged: syncIndicatorOpacity()
onInactiveRevealedChanged: syncIndicatorOpacity()
onIndicatorBlockChanged: syncIndicatorOpacity()
visible: belongsInBlock && (text !== "" || keepSpace)
text: active ? activeText : inactiveText
tooltipText: active ? activeTooltipText : inactiveTooltipText
keepSpace: true
dimmed: !active
concealed: !active && !inactiveRevealed
interactive: belongsInBlock && (active || indicatorBlock === "inactive" || inactiveRevealed)
useActiveColor: false
maintainIndicatorReveal: indicatorBlock === "inactive"
fontSize: Style.font.caption
horizontalMargin: 5
verticalPadding: 5
}
+22 -4
View File
@@ -18,6 +18,11 @@ Item {
property real fixedHeight: -1
property real textRotation: 0
property bool keepSpace: false
property bool dimmed: false
property bool concealed: false
property bool interactive: true
property bool useActiveColor: true
property bool maintainIndicatorReveal: false
property string tooltipText: ""
property var registeredBar: null
@@ -46,7 +51,7 @@ Item {
readonly property real scaledVerticalPadding: Style.spaceReal(verticalPadding)
visible: text !== "" || keepSpace
opacity: text === "" ? 0 : 1
opacity: text === "" || concealed ? 0 : (dimmed ? 0.45 : 1)
implicitWidth: fixedWidth > 0 ? fixedWidth : (vertical ? barSize : Math.max(12, label.implicitWidth + scaledHorizontalMargin * 2 + scaledRightExtraMargin))
implicitHeight: fixedHeight > 0 ? fixedHeight : (vertical ? Math.max(12, label.implicitHeight + scaledVerticalPadding * 2) : barSize)
@@ -59,7 +64,7 @@ Item {
anchors.centerIn: parent
anchors.horizontalCenterOffset: root.vertical ? 0 : -root.scaledRightExtraMargin / 2
text: root.text
color: root.active ? root.activeColor : root.foreground
color: root.active && root.useActiveColor ? root.activeColor : root.foreground
font.family: root.fontFamily
font.pixelSize: root.fontSize
renderType: Text.NativeRendering
@@ -76,10 +81,23 @@ Item {
id: mouseArea
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
enabled: root.interactive
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onEntered: if (root.bar) root.bar.showTooltip(root, root.tooltipText)
onExited: if (root.bar) root.bar.hideTooltip(root)
onEntered: {
if (root.bar) {
root.bar.showTooltip(root, root.tooltipText)
if (root.maintainIndicatorReveal && root.bar.setIndicatorItemHovered)
root.bar.setIndicatorItemHovered(true)
}
}
onExited: {
if (root.bar) {
root.bar.hideTooltip(root)
if (root.maintainIndicatorReveal && root.bar.setIndicatorItemHovered)
root.bar.setIndicatorItemHovered(false)
}
}
onClicked: function(mouse) { root.triggerPress(mouse.button) }
onWheel: function(wheel) { root.wheelMoved(wheel.angleDelta.y) }
}
+1
View File
@@ -1,5 +1,6 @@
module qs.Ui
BarIndicator 1.0 BarIndicator.qml
BarWidget 1.0 BarWidget.qml
Button 1.0 Button.qml
ButtonGroup 1.0 ButtonGroup.qml
+236 -119
View File
@@ -56,18 +56,30 @@ Item {
Behavior on background { ColorAnimation { duration: 420; easing.type: Easing.InOutCubic } }
Behavior on urgent { ColorAnimation { duration: 420; easing.type: Easing.InOutCubic } }
property bool updateAvailable: false
property string voxtypeIcon: ""
property string voxtypeClass: ""
property string screenRecordingText: ""
property string screenRecordingTooltip: ""
property string notificationSilencingText: ""
property string notificationSilencingTooltip: ""
property bool clockAlt: false
property var tooltipTarget: null
property string tooltipText: ""
property bool tooltipShown: false
property var activePopout: null
property var clickTargets: []
property bool indicatorAreaHovered: false
property bool indicatorItemHovered: false
readonly property bool revealInactiveIndicators: indicatorAreaHovered || indicatorItemHovered
function setIndicatorAreaHovered(hovered) {
indicatorAreaHovered = hovered
if (hovered) indicatorHideTimer.stop()
else indicatorHideTimer.restart()
}
function setIndicatorItemHovered(hovered) {
if (hovered) {
indicatorItemHovered = true
indicatorHideTimer.stop()
} else {
indicatorHideTimer.restart()
}
}
function registerClickTarget(target) {
if (!target || clickTargets.indexOf(target) !== -1) return
@@ -112,6 +124,26 @@ Item {
}
}
function indicatorEntriesFromSettings(settings) {
var source = []
if (settings.items && typeof settings.items.length === "number") source = settings.items
else if (settings.indicators && typeof settings.indicators.length === "number") source = settings.indicators
var result = []
for (var i = 0; i < source.length; i++) {
var item = source[i]
if (typeof item !== "string" && item !== null && typeof item === "object") {
try {
item = JSON.parse(JSON.stringify(item))
} catch (error) {
}
}
var id = entryId(item)
if (id !== "") result.push(item)
}
return result
}
// The tray drawer reveals inward (away from the bar edge). Place it at the
// section's inner edge: start of the right section, end of the left/center
// sections. The drawer's reserved space then sits next to the bar center,
@@ -160,7 +192,10 @@ Item {
function entryId(entry) {
if (typeof entry === "string") return entry
if (Util.isPlainObject(entry) && entry.id) return String(entry.id)
if (Util.isPlainObject(entry)) {
var id = entry["id"]
if (id !== undefined && id !== null && String(id) !== "") return String(id)
}
return ""
}
@@ -193,7 +228,6 @@ Item {
function canonicalWidgetId(name) {
switch (String(name)) {
case "idle": return "idleInhibitor"
case "weatherFlyout": return "weather"
default: return String(name)
}
@@ -205,11 +239,7 @@ Item {
case "workspaces": return workspacesModuleComponent
case "clock": return clockModuleComponent
case "update": return updateModuleComponent
case "voxtype": return voxtypeModuleComponent
case "screenRecording":
case "screenrecording": return screenRecordingModuleComponent
case "notifications":
case "notificationSilencing": return notificationsModuleComponent
case "indicators": return indicatorsModuleComponent
case "tray": return trayModuleComponent
default: return null
}
@@ -362,53 +392,11 @@ Item {
tooltipShown = false
}
function parseModuleJson(raw) {
var text = String(raw || "").trim()
if (!text) return {}
var lines = text.split("\n")
try {
return JSON.parse(lines[lines.length - 1])
} catch (error) {
return { text: text }
}
}
function updateIndicator(name, raw) {
var data = parseModuleJson(raw)
var text = data.text || ""
var tooltip = data.tooltip || ""
if (name === "screenRecording") {
screenRecordingText = text
screenRecordingTooltip = tooltip
} else if (name === "notifications") {
notificationSilencingText = text
notificationSilencingTooltip = tooltip
}
}
function updateVoxtype(raw) {
var data = parseModuleJson(raw)
var state = String(data.alt || data.class || "idle")
voxtypeClass = state
if (state === "recording") voxtypeIcon = "󰍬"
else if (state === "transcribing") voxtypeIcon = "󰔟"
else voxtypeIcon = ""
}
function refreshUpdate() {
runProcess(updateProc)
}
function refreshScreenRecording() {
runProcess(screenRecordingProc)
}
function refreshIndicators() {
refreshScreenRecording()
runProcess(notificationSilencingProc)
indicatorsRefreshRequested()
}
@@ -490,6 +478,15 @@ Item {
onTriggered: root.tooltipShown = true
}
Timer {
id: indicatorHideTimer
interval: 120
onTriggered: {
if (!root.indicatorAreaHovered)
root.indicatorItemHovered = false
}
}
// Presence of the `bar-off` flag = bar hidden. Watching the parent toggles
// directory because FileView can't observe a file that doesn't exist yet,
// and the flag is created/removed by `omarchy-toggle-bar`.
@@ -523,35 +520,6 @@ Item {
onTriggered: root.refreshUpdate()
}
Process {
id: voxtypeProc
command: ["bash", "-lc", "omarchy-voxtype-status"]
running: true
stdout: SplitParser {
onRead: function(data) {
root.updateVoxtype(data)
}
}
}
Process {
id: screenRecordingProc
command: ["bash", "-lc", Util.shellQuote(root.omarchyPath + "/shell/scripts/indicators/screen-recording.sh")]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.updateIndicator("screenRecording", text)
}
}
Process {
id: notificationSilencingProc
command: ["bash", "-lc", Util.shellQuote(root.omarchyPath + "/shell/scripts/indicators/notification-silencing.sh")]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.updateIndicator("notifications", text)
}
}
Timer {
interval: 2000
running: true
@@ -568,7 +536,7 @@ Item {
}
function refreshScreenRecording(): void {
root.refreshScreenRecording()
root.refreshIndicators()
}
function refreshIndicators(): void {
@@ -725,9 +693,7 @@ Item {
Component { id: workspacesModuleComponent; WorkspacesModule {} }
Component { id: clockModuleComponent; ClockModule {} }
Component { id: updateModuleComponent; UpdateModule {} }
Component { id: voxtypeModuleComponent; VoxtypeModule {} }
Component { id: screenRecordingModuleComponent; ScreenRecordingModule {} }
Component { id: notificationsModuleComponent; NotificationsModule {} }
Component { id: indicatorsModuleComponent; IndicatorsModule {} }
Component { id: trayModuleComponent; TrayModule {} }
function findCenterAnchorEntry() {
@@ -925,6 +891,10 @@ Item {
active: !slot.qmlCustom && !slot.registered
sourceComponent: slot.builtinComponent || (slot.commandCustom ? customCommandModuleComponent : emptyModuleComponent)
anchors.fill: parent
onLoaded: {
slot.injectProps()
Qt.callLater(slot.injectProps)
}
}
Loader {
@@ -932,7 +902,10 @@ Item {
active: slot.registered
sourceComponent: slot.registered ? slot.registryComponent : null
anchors.fill: parent
onLoaded: slot.injectProps()
onLoaded: {
slot.injectProps()
Qt.callLater(slot.injectProps)
}
}
Loader {
@@ -940,13 +913,17 @@ Item {
active: slot.qmlCustom
source: slot.qmlCustom ? root.customModuleSource(slot.entry) : ""
anchors.fill: parent
onLoaded: slot.injectProps()
onLoaded: {
slot.injectProps()
Qt.callLater(slot.injectProps)
}
}
onActiveItemChanged: Qt.callLater(injectProps)
onModuleSettingsChanged: injectProps()
function injectProps() {
var target = registryLoader.item || qmlLoader.item
var target = activeItem
if (!target) return
if ("bar" in target) target.bar = root
if ("moduleName" in target) target.moduleName = moduleName
@@ -1080,10 +1057,174 @@ Item {
}
}
component IndicatorModule: ModuleButton {
fontSize: Style.font.caption
horizontalMargin: 5
verticalPadding: 5
component IndicatorsModule: Item {
id: indicatorsRoot
property var bar: root
property string moduleName: "indicators"
property var settings: ({})
readonly property var indicatorEntries: root.indicatorEntriesFromSettings(settings)
implicitWidth: root.vertical ? verticalIndicators.implicitWidth : horizontalIndicators.implicitWidth
implicitHeight: root.vertical ? verticalIndicators.implicitHeight : horizontalIndicators.implicitHeight
Row {
id: horizontalIndicators
visible: !root.vertical
spacing: 0
IndicatorBlock {
indicatorEntries: indicatorsRoot.indicatorEntries
indicatorBlock: "active"
horizontal: true
}
Item {
id: inactiveHorizontalArea
implicitWidth: inactiveHorizontalBlock.implicitWidth
implicitHeight: inactiveHorizontalBlock.implicitHeight
width: implicitWidth
height: implicitHeight
IndicatorBlock {
id: inactiveHorizontalBlock
anchors.fill: parent
indicatorEntries: indicatorsRoot.indicatorEntries
indicatorBlock: "inactive"
horizontal: true
}
HoverHandler {
onHoveredChanged: root.setIndicatorAreaHovered(hovered)
}
}
}
Column {
id: verticalIndicators
visible: root.vertical
spacing: 0
IndicatorBlock {
indicatorEntries: indicatorsRoot.indicatorEntries
indicatorBlock: "active"
horizontal: false
}
Item {
id: inactiveVerticalArea
implicitWidth: inactiveVerticalBlock.implicitWidth
implicitHeight: inactiveVerticalBlock.implicitHeight
width: implicitWidth
height: implicitHeight
IndicatorBlock {
id: inactiveVerticalBlock
anchors.fill: parent
indicatorEntries: indicatorsRoot.indicatorEntries
indicatorBlock: "inactive"
horizontal: false
}
HoverHandler {
onHoveredChanged: root.setIndicatorAreaHovered(hovered)
}
}
}
}
component IndicatorBlock: Item {
id: indicatorBlockRoot
property var indicatorEntries: []
property string indicatorBlock: "active"
property bool horizontal: true
implicitWidth: blockLoader.item ? blockLoader.item.childrenRect.width : 0
implicitHeight: blockLoader.item ? blockLoader.item.childrenRect.height : 0
width: implicitWidth
height: implicitHeight
Loader {
id: blockLoader
anchors.fill: parent
sourceComponent: indicatorBlockRoot.horizontal ? horizontalIndicatorBlock : verticalIndicatorBlock
}
Component {
id: horizontalIndicatorBlock
Row {
spacing: 0
Repeater {
model: indicatorBlockRoot.indicatorEntries
IndicatorLoader {
required property var modelData
entry: modelData
indicatorBlock: indicatorBlockRoot.indicatorBlock
}
}
}
}
Component {
id: verticalIndicatorBlock
Column {
spacing: 0
Repeater {
model: indicatorBlockRoot.indicatorEntries
IndicatorLoader {
required property var modelData
entry: modelData
indicatorBlock: indicatorBlockRoot.indicatorBlock
}
}
}
}
}
component IndicatorLoader: Item {
id: indicatorSlot
required property var entry
required property string indicatorBlock
readonly property string indicatorId: root.entryId(entry)
readonly property var indicatorSettings: root.entrySettings(entry)
implicitWidth: indicatorSource.item && indicatorSource.item.visible ? indicatorSource.item.implicitWidth : 0
implicitHeight: indicatorSource.item && indicatorSource.item.visible ? indicatorSource.item.implicitHeight : 0
width: implicitWidth
height: implicitHeight
onIndicatorBlockChanged: injectProps()
onIndicatorSettingsChanged: injectProps()
Loader {
id: indicatorSource
anchors.fill: parent
source: indicatorSlot.indicatorId ? Qt.resolvedUrl("indicators/" + indicatorSlot.indicatorId + ".qml") : ""
onLoaded: indicatorSlot.injectProps()
onStatusChanged: if (status === Loader.Error) console.warn("Indicator loader error", indicatorSlot.indicatorId, source)
}
function injectProps() {
var target = indicatorSource.item
if (!target) return
if ("bar" in target) target.bar = root
if ("moduleName" in target) target.moduleName = indicatorId
if ("settings" in target) target.settings = indicatorSettings
if ("indicatorBlock" in target) target.indicatorBlock = indicatorBlock
}
}
component OmarchyModule: ModuleButton {
@@ -1139,30 +1280,6 @@ Item {
onPressed: function() { root.run("omarchy-launch-floating-terminal-with-presentation omarchy-update") }
}
component VoxtypeModule: ModuleButton {
text: root.voxtypeIcon
active: root.voxtypeClass === "recording"
tooltipText: root.voxtypeClass
onPressed: function(button) {
if (button === Qt.RightButton) root.run("omarchy-voxtype-config")
else root.run("omarchy-voxtype-model")
}
}
component ScreenRecordingModule: IndicatorModule {
text: root.screenRecordingText
active: root.screenRecordingText !== ""
tooltipText: root.screenRecordingTooltip
onPressed: function() { root.run("omarchy-capture-screenrecording") }
}
component NotificationsModule: IndicatorModule {
text: root.notificationSilencingText
active: root.notificationSilencingText !== ""
tooltipText: root.notificationSilencingTooltip
onPressed: function() { root.run("omarchy-toggle-notification-silencing") }
}
component TrayModule: Item {
id: trayRoot
+2 -2
View File
@@ -67,9 +67,9 @@ Example `shell.json` (bar subtree only shown):
### Built-in base modules (in `Bar.qml`)
`omarchy`, `workspaces`, `clock`, `update`, `voxtype`, `screenRecording`, `notifications`, `tray`.
`omarchy`, `workspaces`, `clock`, `update`, `indicators`, `tray`.
These remain available for compact status/launcher slots. Rich panels such as `powerPanel`, `networkPanel`, and `audioPanel` live in `widgets/` above.
The `indicators` module loads individual bar indicators from `indicators/`, ordered by its `items` array in `shell.json`. Rich panels such as `powerPanel`, `networkPanel`, and `audioPanel` live in `widgets/` above.
## Orientation
@@ -0,0 +1,39 @@
import QtQuick
import Quickshell.Io
import qs.Ui
BarIndicator {
id: root
property string state: "idle"
property string icon: ""
active: state === "recording"
activeText: icon
inactiveText: "󰍬"
activeTooltipText: state
inactiveTooltipText: "Dictation"
function update(raw) {
var data = extractData(raw)
state = String(data.alt || data.class || "idle")
if (state === "recording") icon = "󰍬"
else if (state === "transcribing") icon = "󰔟"
else icon = ""
}
Process {
command: ["bash", "-lc", "omarchy-voxtype-status"]
running: true
stdout: SplitParser {
onRead: function(data) { root.update(data) }
}
}
onPressed: function(button) {
if (!root.bar) return
if (button === Qt.RightButton) root.bar.run("omarchy-voxtype-config")
else root.bar.run("omarchy-voxtype-model")
}
}
+51
View File
@@ -0,0 +1,51 @@
import QtQuick
import Quickshell.Io
import qs.Commons
import qs.Ui
BarIndicator {
id: root
property string statusText: ""
property string statusTooltip: ""
active: statusText !== ""
activeText: statusText
inactiveText: "󰂛"
activeTooltipText: statusTooltip
inactiveTooltipText: "Do Not Disturb"
function refresh() {
if (!root.bar || statusProc.running) return
statusProc.command = ["bash", "-lc", Util.shellQuote(root.bar.omarchyPath + "/shell/scripts/indicators/notification-silencing.sh")]
statusProc.running = true
}
function update(raw) {
var data = extractData(raw)
statusText = data.text || ""
statusTooltip = data.tooltip || ""
}
onBarChanged: refresh()
Component.onCompleted: refresh()
Connections {
target: root.bar
ignoreUnknownSignals: true
function onIndicatorsRefreshRequested() { root.refresh() }
}
Process {
id: statusProc
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.update(text)
}
}
onPressed: function() {
if (root.bar) root.bar.run("omarchy-toggle-notification-silencing")
}
}
@@ -0,0 +1,51 @@
import QtQuick
import Quickshell.Io
import qs.Commons
import qs.Ui
BarIndicator {
id: root
property string statusText: ""
property string statusTooltip: ""
active: statusText !== ""
activeText: statusText
inactiveText: "󰻂"
activeTooltipText: statusTooltip
inactiveTooltipText: "Screen recording"
function refresh() {
if (!root.bar || statusProc.running) return
statusProc.command = ["bash", "-lc", Util.shellQuote(root.bar.omarchyPath + "/shell/scripts/indicators/screen-recording.sh")]
statusProc.running = true
}
function update(raw) {
var data = extractData(raw)
statusText = data.text || ""
statusTooltip = data.tooltip || ""
}
onBarChanged: refresh()
Component.onCompleted: refresh()
Connections {
target: root.bar
ignoreUnknownSignals: true
function onIndicatorsRefreshRequested() { root.refresh() }
}
Process {
id: statusProc
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: root.update(text)
}
}
onPressed: function() {
if (root.bar) root.bar.run("omarchy-capture-screenrecording")
}
}
@@ -0,0 +1,56 @@
import QtQuick
import Quickshell.Io
import qs.Ui
BarIndicator {
id: root
activeText: "󰅶"
inactiveText: "󰅶"
activeTooltipText: "No lock or screensaver"
inactiveTooltipText: "Idle enabled"
function refresh() {
if (!statusProc.running) statusProc.running = true
}
function toggle() {
if (root.bar) root.bar.run("omarchy-toggle-idle")
refreshTimer.restart()
}
Component.onCompleted: refresh()
Connections {
target: root.bar
ignoreUnknownSignals: true
function onIndicatorsRefreshRequested() { root.refresh() }
}
Process {
id: statusProc
command: ["bash", "-lc", "omarchy-shell idle status 2>/dev/null"]
stdout: StdioCollector {
waitForEnd: true
onStreamFinished: {
var data = root.extractData(text)
root.active = data && data.enabled === false
}
}
}
Timer {
id: refreshTimer
interval: 1500
onTriggered: root.refresh()
}
Timer {
interval: 5000
running: true
repeat: true
onTriggered: root.refresh()
}
onPressed: function() { root.toggle() }
}
+6 -19
View File
@@ -3,15 +3,10 @@ import Quickshell
import Quickshell.Io
import qs.Ui
BarWidget {
BarIndicator {
id: root
moduleName: "idleInhibitor"
property bool active: false
readonly property string icon: active ? "󰅶" : ""
function refresh() {
if (!statusProc.running) statusProc.running = true
}
@@ -59,17 +54,9 @@ BarWidget {
onTriggered: root.refresh()
}
visible: active
implicitWidth: visible ? button.implicitWidth : 0
implicitHeight: visible ? button.implicitHeight : 0
WidgetButton {
id: button
anchors.fill: parent
bar: root.bar
text: root.icon
active: false
tooltipText: root.active ? "No lock or screensaver" : ""
onPressed: function() { root.toggle() }
}
activeText: "󰅶"
inactiveText: "󰅶"
activeTooltipText: "No lock or screensaver"
inactiveTooltipText: "Idle enabled"
onPressed: function() { root.toggle() }
}
+2 -6
View File
@@ -134,8 +134,7 @@ Item {
left: [{ id: "omarchy" }, { id: "workspaces" }],
center: [
{ id: "calendar", format: "dddd HH:mm", formatAlt: "dd MMMM 'W'ww yyyy", verticalFormat: "HH\n\u2014\nmm" },
{ id: "weather" }, { id: "update" }, { id: "voxtype" },
{ id: "screenRecording" }, { id: "idleInhibitor" }, { id: "notifications" }
{ id: "weather" }, { id: "indicators", items: [ "dnd", "stayAwake", "screenrecording", "dictation" ] }, { id: "update" }
],
right: [
{ id: "tray" }, { id: "bluetoothPanel" }, { id: "networkPanel" },
@@ -298,9 +297,7 @@ Item {
"workspaces": { name: "Workspaces", description: "Workspace number indicators", category: "Compositor" },
"clock": { name: "Clock", description: "Date / time text", category: "Time" },
"update": { name: "Updates", description: "Indicates available system updates", category: "System" },
"voxtype": { name: "Voxtype", description: "Voxtype dictation state", category: "Status" },
"screenRecording": { name: "Screen recording", description: "Active recording indicator", category: "Status" },
"notifications": { name: "DND", description: "Do-not-disturb indicator", category: "Status" },
"indicators": { name: "Indicators", description: "Manual state indicators", category: "Status" },
"tray": { name: "System tray", description: "Status notifier items", category: "Status" }
})
@@ -322,7 +319,6 @@ Item {
function canonicalWidgetId(id) {
switch (String(id || "")) {
case "idle": return "idleInhibitor"
case "weatherFlyout": return "weather"
default: return String(id || "")
}
+9 -12
View File
@@ -27,20 +27,17 @@
{
"id": "weather"
},
{
"id": "indicators",
"items": [
"dnd",
"stayAwake",
"screenrecording",
"dictation"
]
},
{
"id": "update"
},
{
"id": "voxtype"
},
{
"id": "screenRecording"
},
{
"id": "idleInhibitor"
},
{
"id": "notifications"
}
],
"right": [