local Y=require("yaru.core") local gfx=require("yaru.gfx") local ui=require("yaru.ui") local computer=require("computer") local unicode=require("unicode") local M={} local TABS={{"clock","Clock"},{"stopwatch","Stopwatch"},{"timer","Timer"}} local function hms(s,tenths) s=math.max(0,s) local h,m,sec=math.floor(s//3600),math.floor(s//60%60),math.floor(s%60) local r=h>0 and string.format("%d:%02d:%02d",h,m,sec)or string.format("%02d:%02d",m,sec) if tenths then r=r..string.format(".%d",math.floor(s*10%10))end return r end function M.open() local existing=Y.windowsOf("clock")[1] if existing then Y.focusWin(existing)return existing end local st={tab="clock",sw={acc=0,laps={}},tm={len=300,left=300}} local win=Y.newWindow{app="clock",title="Clocks",w=64,h=22,fixed=true} local function swTime()return st.sw.acc+(st.sw.start and computer.uptime()-st.sw.start or 0)end local function tmLeft()return st.tm.endAt and st.tm.endAt-computer.uptime()or st.tm.left end function win.header(w,hw) local x=3 for _,tb in ipairs(TABS)do x=x+ui.button(w,x,1,tb[2],function()st.tab=tb[1]end,st.tab==tb[1]and nil or"flat")+1 end end function win.draw(w,cw,ch) local t=Y.theme local running=st.sw.start or st.tm.endAt w.tickInterval=(st.tab=="clock"or running)and 1 or nil if st.tab=="clock"then local hm=Y.date("%H:%M") ui.big((cw-ui.bigWidth(hm))//2+1,3,hm,t.fg) local d=Y.date("%A, %B %d %Y") gfx.text((cw-unicode.len(d))//2+1,12,d,t.dim) local mc=os.date("%H:%M",os.time()) local s="Minecraft time "..mc.." · uptime "..hms(computer.uptime()) gfx.text((cw-unicode.len(s))//2+1,14,s,t.dim) local z=string.format("UTC%+g",Y.cfg.tz or 0) gfx.text((cw-unicode.len(z))//2+1,16,z,t.dim) elseif st.tab=="stopwatch"then local s=hms(swTime(),not st.sw.start) ui.big((cw-ui.bigWidth((s:gsub("%.%d",""))))//2+1,2,(s:gsub("%.%d","")),t.fg) if not st.sw.start then gfx.text(cw//2+ui.bigWidth((s:gsub("%.%d","")))//2+2,9,s:match("%.%d")or"",t.dim)end local bx=(cw-30)//2 ui.button(w,bx,11,st.sw.start and"Pause"or(swTime()>0 and"Resume"or"Start"),function() if st.sw.start then st.sw.acc=swTime();st.sw.start=nil else st.sw.start=computer.uptime()end end,st.sw.start and nil or"suggested",14) ui.button(w,bx+16,11,st.sw.start and"Lap"or"Reset",function() if st.sw.start then table.insert(st.sw.laps,1,swTime())else st.sw={acc=0,laps={}}end end,nil,14) for i,l in ipairs(st.sw.laps)do if 12+i>=ch then break end local s2=string.format("Lap %d %s",#st.sw.laps-i+1,hms(l,true)) gfx.text((cw-unicode.len(s2))//2,13+i,s2,t.dim) end else local left=tmLeft() local s=hms(left) ui.big((cw-ui.bigWidth(s))//2+1,2,s,left<=0 and t.accent or t.fg) if st.tm.len>0 then ui.progress((cw-40)//2,11,40,1-math.max(0,left)/st.tm.len)end local bx=(cw-44)//2 if not st.tm.endAt then for i,d in ipairs({{"−1m",-60},{"+1m",60},{"+5m",300},{"+15m",900}})do ui.button(w,bx+(i-1)*8,13,d[1],function() st.tm.len=math.max(0,math.min(99*3600,st.tm.left+d[2]));st.tm.left=st.tm.len end,nil,7) end end ui.button(w,bx+32,13,st.tm.endAt and"Pause"or"Start",function() if st.tm.endAt then st.tm.left=tmLeft();st.tm.endAt=nil elseif st.tm.left>0 then st.tm.endAt=computer.uptime()+st.tm.left end end,st.tm.endAt and nil or"suggested",12) ui.button(w,bx+16,15,"Reset",function()st.tm.endAt=nil;st.tm.left=st.tm.len end,"flat",12) end end function win.tick(w) if st.tm.endAt and tmLeft()<=0 then st.tm.endAt,st.tm.left=nil,0 Y.notify("Timer is up",hms(st.tm.len).." timer finished",{urgent=true,timeout=10, actionLabel="Restart",action=function()st.tm.left=st.tm.len;st.tm.endAt=computer.uptime()+st.tm.len end}) for _=1,3 do computer.beep(1320,0.15)computer.beep(990,0.15)end end Y.redraw(w) end function win.key(w,char,code) if char==32 then if st.tab=="stopwatch"then if st.sw.start then st.sw.acc=swTime();st.sw.start=nil else st.sw.start=computer.uptime()end elseif st.tab=="timer"then if st.tm.endAt then st.tm.left=tmLeft();st.tm.endAt=nil elseif st.tm.left>0 then st.tm.endAt=computer.uptime()+st.tm.left end end elseif code==Y.K.tab then for i,tb in ipairs(TABS)do if tb[1]==st.tab then st.tab=TABS[i%#TABS+1][1]break end end end end return win end return M