Improve asnyc updates

This commit is contained in:
Max
2026-06-01 15:36:06 +02:00
parent 4653050f45
commit 4c77395fc7
+149 -93
View File
@@ -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
getEntriesAndCountsFromCache = function()
overviewCachedCounts = getGlobalItemCounts()
overviewCachedSortedItemIds = sortOverviewItems(overviewCachedCounts)
return true, overviewCachedSortedItemIds, overviewCachedCounts
end
return false
end,
}
return overviewCachedSortedItemIds, overviewCachedCounts
end,
getId = function(entry)
return entry