* feat: add mawaqit plugin * Address review feedback * Address validator errors
290 lines
11 KiB
Luau
290 lines
11 KiB
Luau
--!nonstrict
|
|
-- bar_widget.luau — Mawaqit bar widget
|
|
-- Left click → toggle panel
|
|
-- Right click → cycle display mode: countdown → static time → prayer name only
|
|
|
|
-- ── Config ────────────────────────────────────────────────────────────────────
|
|
|
|
local showCountdown = noctalia.getConfig("showCountdown")
|
|
local showElapsed = noctalia.getConfig("showElapsed")
|
|
local hidePrayerName = noctalia.getConfig("hidePrayerName")
|
|
local widgetIcon = noctalia.getConfig("widgetIcon") or "building-mosque"
|
|
local dynamicIcon = noctalia.getConfig("dynamicIcon")
|
|
local textColor = noctalia.getConfig("textColor") or "on_surface"
|
|
local iconColor = noctalia.getConfig("iconColor") or "on_surface"
|
|
local activeColor = noctalia.getConfig("activeColor") or "primary"
|
|
|
|
showCountdown = (showCountdown ~= false and showCountdown ~= "false")
|
|
showElapsed = (showElapsed == true or showElapsed == "true")
|
|
hidePrayerName = (hidePrayerName == true or hidePrayerName == "true")
|
|
dynamicIcon = (dynamicIcon == true or dynamicIcon == "true")
|
|
|
|
-- ── Constants ─────────────────────────────────────────────────────────────────
|
|
|
|
local PRAYER_ICONS = {
|
|
Fajr = "moon-stars",
|
|
Sunrise = "sunrise",
|
|
Dhuhr = "sun-high",
|
|
Asr = "sun-low",
|
|
Maghrib = "sunset",
|
|
Isha = "moon",
|
|
}
|
|
|
|
local MODE_COUNTDOWN = 1
|
|
local MODE_STATIC = 2
|
|
local MODE_NAME_ONLY = 3
|
|
|
|
-- ── State ─────────────────────────────────────────────────────────────────────
|
|
|
|
local prayers = {}
|
|
local tomorrowFajr = nil
|
|
local displayMode = MODE_COUNTDOWN
|
|
local hasData = false
|
|
local errorMsg = ""
|
|
local isJumuah = false
|
|
|
|
-- ── Helpers ───────────────────────────────────────────────────────────────────
|
|
|
|
local function nowSeconds()
|
|
local t = os.date("*t")
|
|
return t.hour * 3600 + t.min * 60 + t.sec
|
|
end
|
|
|
|
local function formatCountdown(secs)
|
|
if secs < 0 then secs = 0 end
|
|
local h = math.floor(secs / 3600)
|
|
local m = math.floor((secs % 3600) / 60)
|
|
local s = secs % 60
|
|
if h > 0 then return string.format("%d:%02d:%02d", h, m, s) end
|
|
return string.format("%d:%02d", m, s)
|
|
end
|
|
|
|
local function formatCountdownShort(secs)
|
|
if secs < 0 then secs = 0 end
|
|
local h = math.floor(secs / 3600)
|
|
local m = math.floor((secs % 3600) / 60)
|
|
if h > 0 then return string.format("%dh %dm", h, m) end
|
|
if m > 0 then return string.format("%dm", m) end
|
|
return "soon"
|
|
end
|
|
|
|
local function getIcon(prayerName)
|
|
if dynamicIcon and prayerName and PRAYER_ICONS[prayerName] then
|
|
return PRAYER_ICONS[prayerName]
|
|
end
|
|
return widgetIcon ~= "" and widgetIcon or "building-mosque"
|
|
end
|
|
|
|
local function setColors(isActive)
|
|
if isActive then
|
|
barWidget.setColor(activeColor ~= "" and activeColor or "primary")
|
|
barWidget.setGlyphColor(activeColor ~= "" and activeColor or "primary")
|
|
else
|
|
barWidget.setColor(textColor ~= "" and textColor or "on_surface")
|
|
barWidget.setGlyphColor(iconColor ~= "" and iconColor or "on_surface")
|
|
end
|
|
end
|
|
|
|
local function prayerLabel(name)
|
|
if name == "Dhuhr" and isJumuah then return "Jumu'ah" end
|
|
return name
|
|
end
|
|
|
|
-- ── Prayer logic ──────────────────────────────────────────────────────────────
|
|
|
|
local function findCurrentPrayer()
|
|
if #prayers == 0 then return nil, nil, nil, nil end
|
|
local now = nowSeconds()
|
|
local currentIdx = nil
|
|
for i, p in ipairs(prayers) do
|
|
if now >= p.seconds then currentIdx = i end
|
|
end
|
|
|
|
local nextIdx, secondsToNext, secondsElapsed
|
|
|
|
if currentIdx == nil then
|
|
nextIdx = 1
|
|
secondsToNext = prayers[1].seconds - now
|
|
secondsElapsed = nil
|
|
elseif currentIdx == #prayers then
|
|
nextIdx = nil
|
|
secondsElapsed = now - prayers[currentIdx].seconds
|
|
secondsToNext = tomorrowFajr and (tomorrowFajr + 86400 - now) or nil
|
|
else
|
|
nextIdx = currentIdx + 1
|
|
secondsToNext = prayers[nextIdx].seconds - now
|
|
secondsElapsed = now - prayers[currentIdx].seconds
|
|
end
|
|
|
|
return currentIdx, nextIdx, secondsToNext, secondsElapsed
|
|
end
|
|
|
|
-- ── Display ───────────────────────────────────────────────────────────────────
|
|
|
|
local function updateDisplay()
|
|
if not hasData then
|
|
barWidget.setGlyph(widgetIcon ~= "" and widgetIcon or "building-mosque")
|
|
barWidget.setText(errorMsg ~= "" and "!" or "...")
|
|
barWidget.setColor("on_surface")
|
|
barWidget.setGlyphColor("on_surface")
|
|
barWidget.setTooltip(errorMsg ~= "" and errorMsg or noctalia.tr("panel.tooltip.no_data"))
|
|
return
|
|
end
|
|
|
|
local currentIdx, nextIdx, secondsToNext, secondsElapsed = findCurrentPrayer()
|
|
local displayPrayer, isActive, timeStr = nil, false, ""
|
|
|
|
local showingElapsed = false
|
|
if showElapsed and currentIdx ~= nil and secondsElapsed ~= nil then
|
|
local cap = math.min(3600, secondsToNext or 3600)
|
|
if secondsElapsed >= 0 and secondsElapsed <= cap then
|
|
showingElapsed = true
|
|
end
|
|
end
|
|
|
|
if nextIdx ~= nil then
|
|
displayPrayer = prayers[nextIdx].name
|
|
if showingElapsed and currentIdx ~= nil then
|
|
displayPrayer = prayers[currentIdx].name
|
|
isActive = true
|
|
if displayMode == MODE_COUNTDOWN then
|
|
timeStr = "+" .. formatCountdown(secondsElapsed)
|
|
elseif displayMode == MODE_STATIC then
|
|
timeStr = prayers[currentIdx].time
|
|
end
|
|
elseif secondsToNext ~= nil and secondsToNext <= 60 then
|
|
isActive = true
|
|
if displayMode ~= MODE_NAME_ONLY then timeStr = "now" end
|
|
else
|
|
if displayMode == MODE_COUNTDOWN and showCountdown and secondsToNext then
|
|
timeStr = formatCountdown(secondsToNext)
|
|
elseif displayMode == MODE_STATIC then
|
|
timeStr = prayers[nextIdx].time
|
|
end
|
|
end
|
|
else
|
|
displayPrayer = "Fajr"
|
|
if showingElapsed and currentIdx ~= nil then
|
|
isActive = true
|
|
displayPrayer = prayers[currentIdx].name
|
|
if displayMode == MODE_COUNTDOWN then
|
|
timeStr = "+" .. formatCountdown(secondsElapsed)
|
|
elseif displayMode == MODE_STATIC then
|
|
timeStr = prayers[currentIdx].time
|
|
end
|
|
elseif secondsToNext ~= nil then
|
|
if displayMode == MODE_COUNTDOWN and showCountdown then
|
|
timeStr = formatCountdown(secondsToNext)
|
|
elseif displayMode == MODE_STATIC then
|
|
timeStr = tomorrowFajr and prayers[1] and prayers[1].time or "?"
|
|
end
|
|
end
|
|
end
|
|
|
|
local nameLabel = prayerLabel(displayPrayer or "")
|
|
local label
|
|
if displayMode == MODE_NAME_ONLY then
|
|
label = nameLabel
|
|
elseif hidePrayerName then
|
|
label = timeStr
|
|
else
|
|
label = timeStr ~= "" and (nameLabel .. " " .. timeStr) or nameLabel
|
|
end
|
|
|
|
barWidget.setGlyph(getIcon(displayPrayer))
|
|
barWidget.setText(label)
|
|
setColors(isActive)
|
|
|
|
if nextIdx ~= nil and secondsToNext ~= nil then
|
|
barWidget.setTooltip({
|
|
{ key = noctalia.tr("panel.tooltip.next"), value = prayerLabel(prayers[nextIdx].name) },
|
|
{ key = noctalia.tr("panel.tooltip.time"), value = prayers[nextIdx].time },
|
|
{ key = noctalia.tr("panel.tooltip.in"), value = formatCountdownShort(secondsToNext) },
|
|
})
|
|
elseif tomorrowFajr ~= nil and secondsToNext ~= nil then
|
|
barWidget.setTooltip({
|
|
{ key = noctalia.tr("panel.tooltip.next"), value = noctalia.tr("panel.tooltip.tomorrow_fajr") },
|
|
{ key = noctalia.tr("panel.tooltip.in"), value = formatCountdownShort(secondsToNext) },
|
|
})
|
|
end
|
|
end
|
|
|
|
-- ── State watchers ────────────────────────────────────────────────────────────
|
|
|
|
noctalia.state.watch("prayers", function(val)
|
|
if type(val) == "table" and #val > 0 then
|
|
prayers = val
|
|
hasData = true
|
|
errorMsg = ""
|
|
end
|
|
updateDisplay()
|
|
end)
|
|
|
|
noctalia.state.watch("tomorrowFajr", function(val)
|
|
tomorrowFajr = tonumber(val)
|
|
end)
|
|
|
|
noctalia.state.watch("isJumuah", function(val)
|
|
isJumuah = (val == true)
|
|
end)
|
|
|
|
noctalia.state.watch("error", function(val)
|
|
if type(val) == "string" and val ~= "" then
|
|
errorMsg = val
|
|
if not hasData then updateDisplay() end
|
|
end
|
|
end)
|
|
|
|
-- ── Lifecycle ─────────────────────────────────────────────────────────────────
|
|
|
|
noctalia.setUpdateInterval(1000)
|
|
|
|
function update() updateDisplay() end
|
|
|
|
function onClick()
|
|
noctalia.togglePanel("ycf/mawaqit:panel")
|
|
end
|
|
|
|
function onRightClick()
|
|
if displayMode == MODE_COUNTDOWN then
|
|
displayMode = MODE_STATIC
|
|
elseif displayMode == MODE_STATIC then
|
|
displayMode = MODE_NAME_ONLY
|
|
else
|
|
displayMode = MODE_COUNTDOWN
|
|
end
|
|
updateDisplay()
|
|
end
|
|
|
|
function onIpc(event, payload)
|
|
if event == "refresh" then
|
|
noctalia.state.set("command", { action = "refresh" })
|
|
elseif event == "mode" then
|
|
if payload == "countdown" then displayMode = MODE_COUNTDOWN
|
|
elseif payload == "static" then displayMode = MODE_STATIC
|
|
elseif payload == "name" then displayMode = MODE_NAME_ONLY
|
|
end
|
|
updateDisplay()
|
|
end
|
|
end
|
|
|
|
-- ── Init ──────────────────────────────────────────────────────────────────────
|
|
|
|
barWidget.setGlyph(widgetIcon ~= "" and widgetIcon or "building-mosque")
|
|
barWidget.setText("...")
|
|
barWidget.setColor("on_surface")
|
|
barWidget.setGlyphColor("on_surface")
|
|
barWidget.setTooltip(noctalia.tr("plugin_name"))
|
|
|
|
local existing = noctalia.state.get("prayers")
|
|
if type(existing) == "table" and #existing > 0 then
|
|
prayers = existing
|
|
hasData = true
|
|
end
|
|
local existingTomorrow = noctalia.state.get("tomorrowFajr")
|
|
if existingTomorrow then tomorrowFajr = tonumber(existingTomorrow) end
|
|
local existingJumuah = noctalia.state.get("isJumuah")
|
|
if existingJumuah ~= nil then isJumuah = (existingJumuah == true) end
|
|
|
|
updateDisplay()
|