From 4c77395fc786d8b304514cca7b5be72e066e4246 Mon Sep 17 00:00:00 2001 From: Max <33982882+maxboeer@users.noreply.github.com> Date: Mon, 1 Jun 2026 15:36:06 +0200 Subject: [PATCH] Improve asnyc updates --- compcount.lua | 244 +++++++++++++++++++++++++++++++------------------- 1 file changed, 150 insertions(+), 94 deletions(-) diff --git a/compcount.lua b/compcount.lua index a6aaeeb..dd5deb0 100644 --- a/compcount.lua +++ b/compcount.lua @@ -46,6 +46,7 @@ end local chainItemsByBaseId local baseItemIds +local allChainItemIds local itemById local defaultBaseId local whitelistLookup @@ -57,6 +58,11 @@ local overviewCachedCounts = {} local overviewCachedSortedItemIds = nil local overviewScrollCurrentRow = 0 local overviewScrollTargetRow = 0 +local globalItemCounts = {} +local globalCountRefreshInterval = 5 +local globalCountRefreshJob +local globalCountRefreshTimer +local globalCountLastRefreshAt = 0 local drawOverview local function ensureWhitelistLoaded() @@ -107,6 +113,7 @@ local function ensureChainsLoaded() chainItemsByBaseId = {} baseItemIds = {} + allChainItemIds = {} itemById = {} for _, chain in ipairs(chains) do @@ -129,6 +136,7 @@ local function ensureChainsLoaded() id = item.item_id, icon_nfp = item.icon_nfp_16x16, } + allChainItemIds[#allChainItemIds + 1] = item.item_id else itemCount = itemCount + 1 items[itemCount] = { @@ -136,6 +144,7 @@ local function ensureChainsLoaded() icon_nfp = item.icon_nfp_16x16, } itemById[item.item_id] = items[itemCount] + allChainItemIds[#allChainItemIds + 1] = item.item_id end end else @@ -143,6 +152,7 @@ local function ensureChainsLoaded() id = baseId, icon_nfp = chain[2], } + allChainItemIds[#allChainItemIds + 1] = baseId for i = 1, #(chain[3] or {}) do local compactItem = chain[3][i] @@ -152,6 +162,7 @@ local function ensureChainsLoaded() icon_nfp = compactItem[2], } itemById[compactItem[1]] = items[itemCount] + allChainItemIds[#allChainItemIds + 1] = compactItem[1] end end @@ -282,12 +293,24 @@ local function listBridgeItems(bridge) local ok, items = pcall(listItems, {}) if ok and type(items) == "table" then - return items + local normalized = {} + + for _, item in pairs(items) do + normalized[#normalized + 1] = item + end + + return normalized end ok, items = pcall(listItems) if ok and type(items) == "table" then - return items + local normalized = {} + + for _, item in pairs(items) do + normalized[#normalized + 1] = item + end + + return normalized end return nil @@ -339,30 +362,28 @@ local function makeZeroCounts(itemIds) return counts end -local function createAsyncMeItemCountsJob(itemIds, batchSize) - local counts = makeZeroCounts(itemIds) +local function createAsyncCountsFromSnapshotJob(itemIds, snapshot, batchSize, baseCounts) + local counts = {} local index = 1 - local snapshot local wanted = {} batchSize = math.max(1, math.floor(tonumber(batchSize) or 1)) for i = 1, #itemIds do wanted[itemIds[i]] = true + counts[itemIds[i]] = 0 + end + + if type(baseCounts) == "table" then + for itemId, count in pairs(baseCounts) do + if wanted[itemId] then + counts[itemId] = tonumber(count) or 0 + end + end end return { step = function() - local bridge = ensureStorageBridge() - - if not bridge then - return true, counts - end - - if not snapshot then - snapshot = listBridgeItems(bridge) or {} - end - local lastIndex = math.min(#snapshot, index + batchSize - 1) for i = index, lastIndex do @@ -380,6 +401,91 @@ local function createAsyncMeItemCountsJob(itemIds, batchSize) } end +local function getGlobalItemCounts() + ensureChainsLoaded() + return globalItemCounts +end + +local function hasGlobalItemCounts() + return next(globalItemCounts) ~= nil +end + +local function createGlobalCountRefreshJob() + ensureChainsLoaded() + + local bridge = ensureStorageBridge() + if not bridge then + return nil + end + + local snapshot = listBridgeItems(bridge) + if not snapshot then + return nil + end + + local job = createAsyncCountsFromSnapshotJob(allChainItemIds or {}, snapshot, 25, globalItemCounts) + + return { + step = function() + local isDone, counts = job.step() + + if isDone then + globalItemCounts = counts + globalCountLastRefreshAt = os.epoch("utc") + end + + return isDone, counts + end, + } +end + +local function shouldStartGlobalCountRefresh() + if globalCountRefreshJob then + return false + end + + if not hasGlobalItemCounts() then + return true + end + + return os.epoch("utc") - globalCountLastRefreshAt >= globalCountRefreshInterval * 1000 +end + +local function startGlobalCountRefreshIfNeeded(force) + if globalCountRefreshJob then + return false + end + + if not force and not shouldStartGlobalCountRefresh() then + return false + end + + globalCountRefreshJob = createGlobalCountRefreshJob() + if not globalCountRefreshJob then + return false + end + + globalCountRefreshTimer = os.startTimer(0.01) + return true +end + +local function stepGlobalCountRefresh(timerId) + if not globalCountRefreshJob or timerId ~= globalCountRefreshTimer then + return false, false + end + + local isDone = globalCountRefreshJob.step() + + if isDone then + globalCountRefreshJob = nil + globalCountRefreshTimer = nil + return true, true + end + + globalCountRefreshTimer = os.startTimer(0.01) + return true, false +end + local function getFallbackIcon() if fallbackIcon == false then fallbackIcon = parseNfpImage(table.concat({ @@ -625,9 +731,6 @@ local function runScrollableGrid(options) local targetScrollRow = 0 local refreshTimer local animationTimer - local refreshJob - local refreshJobTimer - local queuedRefresh = false local columns = 3 local rowsPerView = 3 @@ -698,19 +801,8 @@ local function runScrollableGrid(options) end end - local function startRefreshJob() - if refreshJob then - return false - end - - refreshJob = options.createRefreshJob(entries, counts) - - if not refreshJob then - return false - end - - refreshJobTimer = os.startTimer(options.refreshStepSeconds or 0.05) - return true + local function syncFromCache() + entries, counts = options.getEntriesAndCountsFromCache(entries, counts) end local function renderGrid() @@ -768,45 +860,22 @@ local function runScrollableGrid(options) frame:drawBuffer() end + syncFromCache() renderGrid() if options.shouldStartRefreshImmediately == nil or options.shouldStartRefreshImmediately(entries, counts) then - startRefreshJob() + startGlobalCountRefreshIfNeeded(false) end - refreshTimer = os.startTimer(options.refreshSeconds or 30) + refreshTimer = os.startTimer(options.refreshSeconds or globalCountRefreshInterval) while true do local event, p1, x, y = os.pullEvent() if event == "timer" and p1 == refreshTimer then - if refreshJob then - queuedRefresh = true - else - startRefreshJob() - end - refreshTimer = os.startTimer(options.refreshSeconds or 30) + startGlobalCountRefreshIfNeeded(false) + refreshTimer = os.startTimer(options.refreshSeconds or globalCountRefreshInterval) scheduleAnimation() - elseif event == "timer" and p1 == refreshJobTimer then - local isDone, newEntries, newCounts = refreshJob.step() - - if isDone then - refreshJob = nil - refreshJobTimer = nil - - if newEntries and newCounts then - entries = newEntries - counts = newCounts - renderGrid() - end - - if queuedRefresh then - queuedRefresh = false - startRefreshJob() - end - else - refreshJobTimer = os.startTimer(options.refreshStepSeconds or 0.05) - end elseif event == "timer" and p1 == animationTimer then local delta = targetScrollRow - currentScrollRow @@ -833,6 +902,13 @@ local function runScrollableGrid(options) persistScrollState() renderGrid() + elseif event == "timer" then + local handled, isDone = stepGlobalCountRefresh(p1) + + if handled and isDone then + syncFromCache() + renderGrid() + end elseif event == "monitor_touch" and p1 == monName then if options.handleChromeTouch and options.handleChromeTouch(x, y) then return @@ -889,28 +965,15 @@ local function drawPage(base_id) end runScrollableGrid({ - refreshSeconds = 5, - refreshStepSeconds = 0.02, + refreshSeconds = globalCountRefreshInterval, getInitialEntries = function() return pageItems end, getInitialCounts = function() - return makeZeroCounts(pageItemIds) + return getGlobalItemCounts() end, - createRefreshJob = function(currentEntries) - local job = createAsyncMeItemCountsJob(pageItemIds, 1) - - return { - step = function() - local isDone, itemCounts = job.step() - - if isDone then - return true, currentEntries, itemCounts - end - - return false - end, - } + getEntriesAndCountsFromCache = function(currentEntries) + return currentEntries, getGlobalItemCounts() end, getId = function(entry) return entry.id @@ -961,8 +1024,7 @@ drawOverview = function() end runScrollableGrid({ - refreshSeconds = 30, - refreshStepSeconds = 0.02, + refreshSeconds = globalCountRefreshInterval, getInitialEntries = function() if overviewCachedSortedItemIds and #overviewCachedSortedItemIds > 0 then return overviewCachedSortedItemIds @@ -971,6 +1033,12 @@ drawOverview = function() return sortOverviewItems(overviewCachedCounts) end, getInitialCounts = function() + local counts = getGlobalItemCounts() + + if next(counts) ~= nil then + overviewCachedCounts = counts + end + return overviewCachedCounts end, getInitialScrollState = function() @@ -980,22 +1048,10 @@ drawOverview = function() overviewScrollCurrentRow = currentRow overviewScrollTargetRow = targetRow end, - createRefreshJob = function() - local job = createAsyncMeItemCountsJob(items, 1) - - return { - step = function() - local isDone, itemCounts = job.step() - - if isDone then - overviewCachedCounts = itemCounts - overviewCachedSortedItemIds = sortOverviewItems(overviewCachedCounts) - return true, overviewCachedSortedItemIds, overviewCachedCounts - end - - return false - end, - } + getEntriesAndCountsFromCache = function() + overviewCachedCounts = getGlobalItemCounts() + overviewCachedSortedItemIds = sortOverviewItems(overviewCachedCounts) + return overviewCachedSortedItemIds, overviewCachedCounts end, getId = function(entry) return entry