mirror of
https://github.com/arthur-pbty/arthur-os.git
synced 2026-08-02 04:37:49 +02:00
Split out indicators
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -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,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
@@ -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
|
||||
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
@@ -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() }
|
||||
}
|
||||
|
||||
@@ -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 || "")
|
||||
}
|
||||
|
||||
@@ -27,20 +27,17 @@
|
||||
{
|
||||
"id": "weather"
|
||||
},
|
||||
{
|
||||
"id": "indicators",
|
||||
"items": [
|
||||
"dnd",
|
||||
"stayAwake",
|
||||
"screenrecording",
|
||||
"dictation"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "update"
|
||||
},
|
||||
{
|
||||
"id": "voxtype"
|
||||
},
|
||||
{
|
||||
"id": "screenRecording"
|
||||
},
|
||||
{
|
||||
"id": "idleInhibitor"
|
||||
},
|
||||
{
|
||||
"id": "notifications"
|
||||
}
|
||||
],
|
||||
"right": [
|
||||
|
||||
Reference in New Issue
Block a user