diff --git a/eyecare/plugin.toml b/eyecare/plugin.toml index 4b9ce71..feff608 100644 --- a/eyecare/plugin.toml +++ b/eyecare/plugin.toml @@ -1,6 +1,6 @@ id = "apex077/eyecare" name = "Eye-Care Reminders" -version = "1.0.1" +version = "1.0.2" plugin_api = 3 author = "Apex077" license = "MIT" diff --git a/eyecare/service.luau b/eyecare/service.luau index 8ed5b4a..50ffeb6 100644 --- a/eyecare/service.luau +++ b/eyecare/service.luau @@ -53,26 +53,20 @@ local function isSoundAllowed() -- Check Noctalia global sound configuration options local enableSounds = noctalia.getConfig("enable_sounds") - if enableSounds == false then + if enableSounds == false or enableSounds == "false" then return false end local soundEnabled = noctalia.getConfig("sound_enabled") - if soundEnabled == false then + if soundEnabled == false or soundEnabled == "false" then return false end local audioEnableSounds = noctalia.getConfig("audio.enable_sounds") - if audioEnableSounds == false then + if audioEnableSounds == false or audioEnableSounds == "false" then return false end - if noctalia.sound and type(noctalia.sound.isEnabled) == "function" then - if not noctalia.sound.isEnabled() then - return false - end - end - if getSoundVolume() <= 0 then return false end @@ -80,27 +74,26 @@ local function isSoundAllowed() return true end --- Play a notification sound using Noctalia runtime sound API if available, falling back to system players with volume scaling +-- Play a notification sound using system players with volume scaling matching Noctalia's volume setting local function playSound(soundName) if not isSoundAllowed() then return end local vol = getSoundVolume() - - if noctalia.sound and type(noctalia.sound.play) == "function" then - noctalia.sound.play(soundName, vol) - return - elseif type(noctalia.playSound) == "function" then - noctalia.playSound(soundName, vol) + if vol <= 0 then return end local path = "/usr/share/sounds/freedesktop/stereo/" .. soundName .. ".oga" local paVol = math.floor(vol * 65536) local pwVol = string.format("%.2f", vol) - - noctalia.runAsync(string.format("canberra-gtk-play -i %s || paplay --volume=%d %s || pw-play --volume=%s %s || aplay %s || true", soundName, paVol, path, pwVol, path, path)) + + local cmd = string.format( + "pw-play --volume=%s %s || paplay --volume=%d %s || canberra-gtk-play -i %s || aplay %s || true", + pwVol, path, paVol, path, soundName, path + ) + noctalia.runAsync(cmd) end local lastLoggedIdle = nil @@ -124,6 +117,63 @@ end local wasSystemIdle = false +-- Helper functions for timer state transitions +local function triggerBreak() + inBreak = true + breakTimer = 0 + breakElapsed = 0 + activeTime = 0 + + if settings.enable_notifications then + noctalia.notify( + noctalia.tr("notifications.eyecare-break-title") or "Time for a break", + noctalia.tr("notifications.eyecare-break-body", { seconds = settings.break_duration_seconds }) or string.format("Focus on an object 20 feet away for %d seconds.", settings.break_duration_seconds) + ) + end + if settings.enable_sound then + playSound("message") + end +end + +local function finishBreak() + inBreak = false + breakTimer = 0 + breakElapsed = 0 + activeTime = 0 + + if settings.enable_notifications then + noctalia.notify( + noctalia.tr("notifications.eyecare-break-finished-title") or "Break finished", + noctalia.tr("notifications.eyecare-break-finished-body") or "Your eyes are rested. You can return to your screen." + ) + end + if settings.enable_sound then + playSound("complete") + end +end + +local function abortBreak() + inBreak = false + breakTimer = 0 + breakElapsed = 0 + activeTime = 0 +end + +local function resetTimer() + inBreak = false + breakTimer = 0 + breakElapsed = 0 + activeTime = 0 + idleTime = 0 + + if settings.enable_notifications then + noctalia.notify( + noctalia.tr("notifications.eyecare-reset-title") or "Eye-Care", + noctalia.tr("notifications.eyecare-reset-body") or "Timer has been reset." + ) + end +end + -- Tick cycle actions (every 1 second) function update() noctalia.setUpdateInterval(1000) @@ -154,20 +204,7 @@ function update() end elseif breakTimer >= settings.break_duration_seconds then -- Break completed successfully - inBreak = false - breakTimer = 0 - breakElapsed = 0 - activeTime = 0 - - if settings.enable_notifications then - noctalia.notify( - noctalia.tr("notifications.eyecare-break-finished-title"), - noctalia.tr("notifications.eyecare-break-finished-body") - ) - end - if settings.enable_sound then - playSound("complete") - end + finishBreak() end else -- Not in break @@ -189,8 +226,8 @@ function update() if settings.enable_notifications then noctalia.notify( - noctalia.tr("notifications.eyecare-break-title"), - noctalia.tr("notifications.eyecare-break-body", { seconds = settings.break_duration_seconds }) + noctalia.tr("notifications.eyecare-break-title") or "Time for a break", + noctalia.tr("notifications.eyecare-break-body", { seconds = settings.break_duration_seconds }) or string.format("Focus on an object 20 feet away for %d seconds.", settings.break_duration_seconds) ) end if settings.enable_sound then @@ -203,39 +240,6 @@ function update() updateState() end --- Helper functions for timer state transitions -local function triggerBreak() - inBreak = true - breakTimer = 0 - breakElapsed = 0 - activeTime = 0 - - if settings.enable_notifications then - noctalia.notify( - noctalia.tr("notifications.eyecare-break-title"), - noctalia.tr("notifications.eyecare-break-body", { seconds = settings.break_duration_seconds }) - ) - end - if settings.enable_sound then - playSound("message") - end -end - -local function abortBreak() - inBreak = false - breakTimer = 0 - breakElapsed = 0 - activeTime = 0 -end - -local function resetTimer() - inBreak = false - breakTimer = 0 - breakElapsed = 0 - activeTime = 0 - idleTime = 0 -end - -- Listen to compositor IPC commands function onIpc(event, payload) if event == "idled" then @@ -244,7 +248,9 @@ function onIpc(event, payload) isSystemIdle = false elseif event == "trigger-break" then triggerBreak() - elseif event == "finish-break" or event == "abort-break" then + elseif event == "finish-break" then + finishBreak() + elseif event == "abort-break" then abortBreak() elseif event == "reset" then resetTimer() diff --git a/eyecare/translations/en.json b/eyecare/translations/en.json index 73a1aee..c916c7a 100644 --- a/eyecare/translations/en.json +++ b/eyecare/translations/en.json @@ -3,7 +3,9 @@ "eyecare-break-body": "Focus on an object 20 feet away for {seconds} seconds.", "eyecare-break-finished-body": "Your eyes are rested. You can return to your screen.", "eyecare-break-finished-title": "Break finished", - "eyecare-break-title": "Time for a break" + "eyecare-break-title": "Time for a break", + "eyecare-reset-body": "Timer has been reset.", + "eyecare-reset-title": "Eye-Care" }, "settings": { "eyecare-active-duration": { diff --git a/eyecare/widget.luau b/eyecare/widget.luau index c8ab940..c45c236 100644 --- a/eyecare/widget.luau +++ b/eyecare/widget.luau @@ -94,7 +94,6 @@ end function onRightClick() noctalia.state.set("eyecare-request", "reset") - noctalia.notify("Eye-Care", "Timer has been reset.") end -- Initial render