feat: add mawaqit plugin (#53)
* feat: add mawaqit plugin * Address review feedback * Address validator errors
This commit is contained in:
@@ -0,0 +1,289 @@
|
||||
--!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()
|
||||
Reference in New Issue
Block a user