local Y=require("yaru.core") local gfx=require("yaru.gfx") local ui=require("yaru.ui") local T=require("yaru.tasks") local unicode=require("unicode") local M={} local PRESETS={{"every 5","Every 5 minutes"},{"every 30","Every 30 minutes"},{"every 60","Every hour"}, {"at 09:00","Daily at 09:00"},{"login","At login"}} function M.open() local st={list=T.load()} local win=Y.newWindow{app="scheduler",title="Scheduled Tasks",w=92,h=26,minW=64,minH=12} local function save()T.save(st.list)end local function add() Y.dialog{title="New Task",text="Command to run (as in Terminal)",entry="backup",buttons={{"Cancel"},{"Next",function(cmd) if not cmd or cmd==""then return end local items={} for _,p in ipairs(PRESETS)do items[#items+1]={p[2],function() st.list[#st.list+1]={name=cmd:match("^%S+"),cmd=cmd,when=p[1],on=true,notify=true} save() end} end items[#items+1]={"Custom…",function() Y.dialog{title="Schedule",text="“every N” (minutes), “at HH:MM” or “login”",entry="every 15", buttons={{"Cancel"},{"Add",function(w2) if w2 and(w2:match("^every %d+$")or w2:match("^at %d%d?:%d%d$")or w2=="login")then st.list[#st.list+1]={name=cmd:match("^%S+"),cmd=cmd,when=w2,on=true,notify=true} save() else Y.notify("Scheduled Tasks","Unknown schedule: "..tostring(w2))end end,"suggested"}}} end} Y.menu(win.x+20,win.y+4,items) end,"suggested"}}} end function win.header(w,hw)ui.button(w,2,1,"+ Add Task",add,"suggested")end function win.draw(w,cw,ch) local t=Y.theme st.list=T.load() if#st.list==0 then Y.drawIcon((cw-8)//2,ch//2-6,"scheduler") local s="No tasks. Add one, e.g. `backup` every hour or a redstone script at 18:00." gfx.text((cw-unicode.len(s))//2,ch//2,s,t.dim) return end for i,task in ipairs(st.list)do local y=1+(i-1)*3 if y+2>ch then break end ui.round(2,y,cw-3,2,t.card) gfx.text(4,y,ui.trunc(task.name.." · "..T.describe(task),cw-40),t.fg,t.card) gfx.text(4,y+1,ui.trunc("$ "..task.cmd,cw-40),t.dim,t.card) local res=task.result or"never run" gfx.text(cw-34,y+1,ui.trunc(res,14),res:match("^failed")and t.danger or t.dim,t.card) ui.switch(w,cw-34,y,task.on,function()task.on=not task.on;save()end) ui.button(w,cw-19,y,"Run",function()T.run(Y,task);save()end,nil,7) ui.button(w,cw-11,y,"Delete",function()table.remove(st.list,i);save()end,"flat",8) end gfx.text(2,ch,"Runs while the desktop is running · output appended to /tmp/tasks.log",t.dim) end win.tickInterval=5 function win.tick(w)Y.redraw(w)end return win end return M