Tasks = { _id = "tasks", } function Tasks:new(area) local me = setmetatable({ _area = area }, { __index = self }) me:layout() return me end function Tasks:layout() self._area = self._area:pad(ui.Pad(1, 1, 1, 3)) self._chunks = ui.Layout() :direction(ui.Layout.HORIZONTAL) :constraints({ ui.Constraint.Percentage(60), ui.Constraint.Percentage(40), }) :split(self._area) end function Tasks:reflow() return { self } end function Tasks:redraw() local elements = {} for i, snap in ipairs(cx.tasks.snaps) do local y = self._area.y + (i - 1) * 3 if y >= self._area.bottom then break end elements[#elements + 1] = ui.Line({ self:icon(snap), snap.title }):area(self._area { y = y, h = 1 }) if i == cx.tasks.cursor + 1 then elements[#elements] = elements[#elements]:style(th.tasks.hovered) end for _, e in ipairs(self:progress_redraw(snap, y + 1)) do elements[#elements + 1] = e end elements[#elements + 1] = ui.Bar(ui.Edge.LEFT) :area(ui.Rect { x = math.max(0, self._area.x - 2), y = y, w = self._area.w, h = 2, }) :symbol("┃") if i == cx.tasks.cursor + 1 then elements[#elements] = elements[#elements]:style(th.tasks.hovered) end end return elements end function Tasks:icon(snap) if snap.prog.kind == "FileCopy" then return " " elseif snap.prog.kind == "FileCut" then return " " elseif snap.prog.kind == "FileDelete" then return " " elseif snap.prog.kind == "FileDownload" then return " " elseif snap.prog.kind == "FileUpload" then return " " else return " " end end function Tasks:progress_redraw(snap, y) local kind = snap.prog.kind if kind == "FileCopy" or kind == "FileCut" or kind == "FileDelete" or kind == "FileDownload" or kind == "FileUpload" then local percent if snap.cooked then percent = "Cleaning…" else percent = string.format("%3d%%", math.floor(snap.percent)) end local label = string.format( "%s - %s / %s", percent, ya.readable_size(snap.prog.processed_bytes), ya.readable_size(snap.prog.total_bytes) ) local style = th.status.progress_normal if snap.failed or snap.prog.failed_files > 0 then style = th.status.progress_error end return { ui.Gauge() :area(self._chunks[1] { y = y, h = 1 }) :percent(snap.percent) :label(ui.Span(label):style(th.status.progress_label)) :gauge_style(style), ui.Line(string.format("%d/%d", snap.prog.success_files, snap.prog.total_files)) :fg("gray") :area(self._chunks[2] { y = y, h = 1 }) :align(ui.Align.RIGHT), } else local text if snap.cooked then text = "Cleaning…" elseif snap.running then text = "Running…" else text = "Failed, press Enter to view log…" end return { ui.Line(text):fg("gray"):area(self._chunks[1] { y = y, h = 1 }), } end end