init
This commit is contained in:
161
contents/ui/main.qml
Normal file
161
contents/ui/main.qml
Normal file
@@ -0,0 +1,161 @@
|
||||
// SPDX-FileCopyrightText: James Eversole <james@eversole.co>
|
||||
// SPDX-License-Identifier: ISC
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.plasma.plasmoid
|
||||
import org.kde.plasma.components as PlasmaComponents
|
||||
import org.kde.plasma.plasma5support as Plasma5Support
|
||||
|
||||
PlasmoidItem {
|
||||
id: root
|
||||
|
||||
// Panel size — small icon size for system tray / panel
|
||||
Layout.preferredWidth: Kirigami.Units.iconSizes.small
|
||||
Layout.preferredHeight: Kirigami.Units.iconSizes.small
|
||||
|
||||
// Tooltip
|
||||
Plasmoid.title: "Voxtype Toggle"
|
||||
toolTipSubText: statusText
|
||||
|
||||
// State tracking
|
||||
property string currentState: "idle"
|
||||
property string statusText: "Voxtype is idle"
|
||||
|
||||
// State file paths (same as voxtype GNOME extension)
|
||||
readonly property string runtimeDir: "/run/user/1000"
|
||||
readonly property string stateFilePath: runtimeDir + "/voxtype/state"
|
||||
readonly property string pidFilePath: runtimeDir + "/voxtype/pid"
|
||||
|
||||
// Data source for executing voxtype record toggle
|
||||
Plasma5Support.DataSource {
|
||||
id: executable
|
||||
engine: "executable"
|
||||
|
||||
function toggleRecording() {
|
||||
if (daemonRunning) {
|
||||
executable.connectSource("voxtype record toggle")
|
||||
} else {
|
||||
updateState("not-running")
|
||||
}
|
||||
}
|
||||
|
||||
function checkDaemon() {
|
||||
// Check if the voxtype daemon process is running
|
||||
var cmd = "if [ -f " + root.pidFilePath + " ]; then kill -0 $(cat " + root.pidFilePath + ") 2>/dev/null && echo running; fi"
|
||||
executable.connectSource(cmd)
|
||||
}
|
||||
|
||||
onNewData: function(sourceName, data) {
|
||||
var exitCode = data["exit code"]
|
||||
var output = data.stdout.trim()
|
||||
|
||||
// Handle the toggle command
|
||||
if (sourceName.includes("voxtype record toggle")) {
|
||||
executable.disconnectSource(sourceName)
|
||||
// Re-read state from disk after toggling
|
||||
refreshState()
|
||||
return
|
||||
}
|
||||
|
||||
// Handle daemon check
|
||||
if (sourceName.includes("kill -0")) {
|
||||
daemonRunning = output === "running"
|
||||
executable.disconnectSource(sourceName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Data source for reading the state file from disk
|
||||
Plasma5Support.DataSource {
|
||||
id: stateReader
|
||||
engine: "executable"
|
||||
connectedSources: []
|
||||
|
||||
onNewData: function(sourceName, data) {
|
||||
stateReader.disconnectSource(sourceName)
|
||||
var output = data.stdout.trim()
|
||||
// If the state file doesn't exist or is empty, default to idle
|
||||
updateState(output || "idle")
|
||||
}
|
||||
}
|
||||
|
||||
// Periodic timer to refresh state from disk
|
||||
Timer {
|
||||
id: stateRefreshTimer
|
||||
interval: 3000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
if (currentState !== "not-running") {
|
||||
refreshState()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Re-trigger polling faster when transcribing
|
||||
onCurrentStateChanged: {
|
||||
if (currentState === "transcribing") {
|
||||
stateRefreshTimer.interval = 1500
|
||||
} else {
|
||||
stateRefreshTimer.interval = 3000
|
||||
}
|
||||
}
|
||||
|
||||
// Whether the voxtype daemon is currently running
|
||||
property bool daemonRunning: false
|
||||
|
||||
function updateState(newStatus) {
|
||||
currentState = newStatus
|
||||
switch (newStatus) {
|
||||
case "idle":
|
||||
statusText = "Voxtype is idle"
|
||||
break
|
||||
case "recording":
|
||||
statusText = "Voxtype is recording"
|
||||
break
|
||||
case "transcribing":
|
||||
statusText = "Voxtype is transcribing"
|
||||
break
|
||||
case "not-running":
|
||||
statusText = "Voxtype daemon not running"
|
||||
break
|
||||
default:
|
||||
statusText = "Voxtype is " + newStatus
|
||||
}
|
||||
}
|
||||
|
||||
function refreshState() {
|
||||
stateReader.connectSource("cat " + root.stateFilePath + " 2>/dev/null || echo idle")
|
||||
}
|
||||
|
||||
// Icon source based on current state
|
||||
readonly property string iconSource: {
|
||||
switch (currentState) {
|
||||
case "recording":
|
||||
return "media-record-symbolic"
|
||||
case "transcribing":
|
||||
return "content-loading-symbolic"
|
||||
case "not-running":
|
||||
return "dialog-warning-symbolic"
|
||||
case "idle":
|
||||
default:
|
||||
return "audio-input-microphone-symbolic"
|
||||
}
|
||||
}
|
||||
|
||||
// Main clickable button
|
||||
PlasmaComponents.ToolButton {
|
||||
id: toggleButton
|
||||
anchors.centerIn: parent
|
||||
icon.name: root.iconSource
|
||||
onClicked: executable.toggleRecording()
|
||||
}
|
||||
|
||||
// Initial state check when the component is ready
|
||||
Component.onCompleted: {
|
||||
refreshState()
|
||||
executable.checkDaemon()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user