Improve asnyc updates
This commit is contained in:
+149
-93
@@ -46,6 +46,7 @@ end
|
|||||||
|
|
||||||
local chainItemsByBaseId
|
local chainItemsByBaseId
|
||||||
local baseItemIds
|
local baseItemIds
|
||||||
|
local allChainItemIds
|
||||||
local itemById
|
local itemById
|
||||||
local defaultBaseId
|
local defaultBaseId
|
||||||
local whitelistLookup
|
local whitelistLookup
|
||||||
@@ -57,6 +58,11 @@ local overviewCachedCounts = {}
|
|||||||
local overviewCachedSortedItemIds = nil
|
local overviewCachedSortedItemIds = nil
|
||||||
local overviewScrollCurrentRow = 0
|
local overviewScrollCurrentRow = 0
|
||||||
local overviewScrollTargetRow = 0
|
local overviewScrollTargetRow = 0
|
||||||
|
local globalItemCounts = {}
|
||||||
|
local globalCountRefreshInterval = 5
|
||||||
|
local globalCountRefreshJob
|
||||||
|
local globalCountRefreshTimer
|
||||||
|
local globalCountLastRefreshAt = 0
|
||||||
local drawOverview
|
local drawOverview
|
||||||
|
|
||||||
local function ensureWhitelistLoaded()
|
local function ensureWhitelistLoaded()
|
||||||
@@ -107,6 +113,7 @@ local function ensureChainsLoaded()
|
|||||||
|
|
||||||
chainItemsByBaseId = {}
|
chainItemsByBaseId = {}
|
||||||
baseItemIds = {}
|
baseItemIds = {}
|
||||||
|
allChainItemIds = {}
|
||||||
itemById = {}
|
itemById = {}
|
||||||
|
|
||||||
for _, chain in ipairs(chains) do
|
for _, chain in ipairs(chains) do
|
||||||
@@ -129,6 +136,7 @@ local function ensureChainsLoaded()
|
|||||||
id = item.item_id,
|
id = item.item_id,
|
||||||
icon_nfp = item.icon_nfp_16x16,
|
icon_nfp = item.icon_nfp_16x16,
|
||||||
}
|
}
|
||||||
|
allChainItemIds[#allChainItemIds + 1] = item.item_id
|
||||||
else
|
else
|
||||||
itemCount = itemCount + 1
|
itemCount = itemCount + 1
|
||||||
items[itemCount] = {
|
items[itemCount] = {
|
||||||
@@ -136,6 +144,7 @@ local function ensureChainsLoaded()
|
|||||||
icon_nfp = item.icon_nfp_16x16,
|
icon_nfp = item.icon_nfp_16x16,
|
||||||
}
|
}
|
||||||
itemById[item.item_id] = items[itemCount]
|
itemById[item.item_id] = items[itemCount]
|
||||||
|
allChainItemIds[#allChainItemIds + 1] = item.item_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@@ -143,6 +152,7 @@ local function ensureChainsLoaded()
|
|||||||
id = baseId,
|
id = baseId,
|
||||||
icon_nfp = chain[2],
|
icon_nfp = chain[2],
|
||||||
}
|
}
|
||||||
|
allChainItemIds[#allChainItemIds + 1] = baseId
|
||||||
|
|
||||||
for i = 1, #(chain[3] or {}) do
|
for i = 1, #(chain[3] or {}) do
|
||||||
local compactItem = chain[3][i]
|
local compactItem = chain[3][i]
|
||||||
@@ -152,6 +162,7 @@ local function ensureChainsLoaded()
|
|||||||
icon_nfp = compactItem[2],
|
icon_nfp = compactItem[2],
|
||||||
}
|
}
|
||||||
itemById[compactItem[1]] = items[itemCount]
|
itemById[compactItem[1]] = items[itemCount]
|
||||||
|
allChainItemIds[#allChainItemIds + 1] = compactItem[1]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -282,12 +293,24 @@ local function listBridgeItems(bridge)
|
|||||||
|
|
||||||
local ok, items = pcall(listItems, {})
|
local ok, items = pcall(listItems, {})
|
||||||
if ok and type(items) == "table" then
|
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
|
end
|
||||||
|
|
||||||
ok, items = pcall(listItems)
|
ok, items = pcall(listItems)
|
||||||
if ok and type(items) == "table" then
|
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
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -339,30 +362,28 @@ local function makeZeroCounts(itemIds)
|
|||||||
return counts
|
return counts
|
||||||
end
|
end
|
||||||
|
|
||||||
local function createAsyncMeItemCountsJob(itemIds, batchSize)
|
local function createAsyncCountsFromSnapshotJob(itemIds, snapshot, batchSize, baseCounts)
|
||||||
local counts = makeZeroCounts(itemIds)
|
local counts = {}
|
||||||
local index = 1
|
local index = 1
|
||||||
local snapshot
|
|
||||||
local wanted = {}
|
local wanted = {}
|
||||||
|
|
||||||
batchSize = math.max(1, math.floor(tonumber(batchSize) or 1))
|
batchSize = math.max(1, math.floor(tonumber(batchSize) or 1))
|
||||||
|
|
||||||
for i = 1, #itemIds do
|
for i = 1, #itemIds do
|
||||||
wanted[itemIds[i]] = true
|
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
|
end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
step = function()
|
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)
|
local lastIndex = math.min(#snapshot, index + batchSize - 1)
|
||||||
|
|
||||||
for i = index, lastIndex do
|
for i = index, lastIndex do
|
||||||
@@ -380,6 +401,91 @@ local function createAsyncMeItemCountsJob(itemIds, batchSize)
|
|||||||
}
|
}
|
||||||
end
|
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()
|
local function getFallbackIcon()
|
||||||
if fallbackIcon == false then
|
if fallbackIcon == false then
|
||||||
fallbackIcon = parseNfpImage(table.concat({
|
fallbackIcon = parseNfpImage(table.concat({
|
||||||
@@ -625,9 +731,6 @@ local function runScrollableGrid(options)
|
|||||||
local targetScrollRow = 0
|
local targetScrollRow = 0
|
||||||
local refreshTimer
|
local refreshTimer
|
||||||
local animationTimer
|
local animationTimer
|
||||||
local refreshJob
|
|
||||||
local refreshJobTimer
|
|
||||||
local queuedRefresh = false
|
|
||||||
|
|
||||||
local columns = 3
|
local columns = 3
|
||||||
local rowsPerView = 3
|
local rowsPerView = 3
|
||||||
@@ -698,19 +801,8 @@ local function runScrollableGrid(options)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function startRefreshJob()
|
local function syncFromCache()
|
||||||
if refreshJob then
|
entries, counts = options.getEntriesAndCountsFromCache(entries, counts)
|
||||||
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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function renderGrid()
|
local function renderGrid()
|
||||||
@@ -768,45 +860,22 @@ local function runScrollableGrid(options)
|
|||||||
frame:drawBuffer()
|
frame:drawBuffer()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
syncFromCache()
|
||||||
renderGrid()
|
renderGrid()
|
||||||
|
|
||||||
if options.shouldStartRefreshImmediately == nil or options.shouldStartRefreshImmediately(entries, counts) then
|
if options.shouldStartRefreshImmediately == nil or options.shouldStartRefreshImmediately(entries, counts) then
|
||||||
startRefreshJob()
|
startGlobalCountRefreshIfNeeded(false)
|
||||||
end
|
end
|
||||||
|
|
||||||
refreshTimer = os.startTimer(options.refreshSeconds or 30)
|
refreshTimer = os.startTimer(options.refreshSeconds or globalCountRefreshInterval)
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local event, p1, x, y = os.pullEvent()
|
local event, p1, x, y = os.pullEvent()
|
||||||
|
|
||||||
if event == "timer" and p1 == refreshTimer then
|
if event == "timer" and p1 == refreshTimer then
|
||||||
if refreshJob then
|
startGlobalCountRefreshIfNeeded(false)
|
||||||
queuedRefresh = true
|
refreshTimer = os.startTimer(options.refreshSeconds or globalCountRefreshInterval)
|
||||||
else
|
|
||||||
startRefreshJob()
|
|
||||||
end
|
|
||||||
refreshTimer = os.startTimer(options.refreshSeconds or 30)
|
|
||||||
scheduleAnimation()
|
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
|
elseif event == "timer" and p1 == animationTimer then
|
||||||
local delta = targetScrollRow - currentScrollRow
|
local delta = targetScrollRow - currentScrollRow
|
||||||
|
|
||||||
@@ -833,6 +902,13 @@ local function runScrollableGrid(options)
|
|||||||
|
|
||||||
persistScrollState()
|
persistScrollState()
|
||||||
renderGrid()
|
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
|
elseif event == "monitor_touch" and p1 == monName then
|
||||||
if options.handleChromeTouch and options.handleChromeTouch(x, y) then
|
if options.handleChromeTouch and options.handleChromeTouch(x, y) then
|
||||||
return
|
return
|
||||||
@@ -889,28 +965,15 @@ local function drawPage(base_id)
|
|||||||
end
|
end
|
||||||
|
|
||||||
runScrollableGrid({
|
runScrollableGrid({
|
||||||
refreshSeconds = 5,
|
refreshSeconds = globalCountRefreshInterval,
|
||||||
refreshStepSeconds = 0.02,
|
|
||||||
getInitialEntries = function()
|
getInitialEntries = function()
|
||||||
return pageItems
|
return pageItems
|
||||||
end,
|
end,
|
||||||
getInitialCounts = function()
|
getInitialCounts = function()
|
||||||
return makeZeroCounts(pageItemIds)
|
return getGlobalItemCounts()
|
||||||
end,
|
end,
|
||||||
createRefreshJob = function(currentEntries)
|
getEntriesAndCountsFromCache = function(currentEntries)
|
||||||
local job = createAsyncMeItemCountsJob(pageItemIds, 1)
|
return currentEntries, getGlobalItemCounts()
|
||||||
|
|
||||||
return {
|
|
||||||
step = function()
|
|
||||||
local isDone, itemCounts = job.step()
|
|
||||||
|
|
||||||
if isDone then
|
|
||||||
return true, currentEntries, itemCounts
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
end,
|
end,
|
||||||
getId = function(entry)
|
getId = function(entry)
|
||||||
return entry.id
|
return entry.id
|
||||||
@@ -961,8 +1024,7 @@ drawOverview = function()
|
|||||||
end
|
end
|
||||||
|
|
||||||
runScrollableGrid({
|
runScrollableGrid({
|
||||||
refreshSeconds = 30,
|
refreshSeconds = globalCountRefreshInterval,
|
||||||
refreshStepSeconds = 0.02,
|
|
||||||
getInitialEntries = function()
|
getInitialEntries = function()
|
||||||
if overviewCachedSortedItemIds and #overviewCachedSortedItemIds > 0 then
|
if overviewCachedSortedItemIds and #overviewCachedSortedItemIds > 0 then
|
||||||
return overviewCachedSortedItemIds
|
return overviewCachedSortedItemIds
|
||||||
@@ -971,6 +1033,12 @@ drawOverview = function()
|
|||||||
return sortOverviewItems(overviewCachedCounts)
|
return sortOverviewItems(overviewCachedCounts)
|
||||||
end,
|
end,
|
||||||
getInitialCounts = function()
|
getInitialCounts = function()
|
||||||
|
local counts = getGlobalItemCounts()
|
||||||
|
|
||||||
|
if next(counts) ~= nil then
|
||||||
|
overviewCachedCounts = counts
|
||||||
|
end
|
||||||
|
|
||||||
return overviewCachedCounts
|
return overviewCachedCounts
|
||||||
end,
|
end,
|
||||||
getInitialScrollState = function()
|
getInitialScrollState = function()
|
||||||
@@ -980,22 +1048,10 @@ drawOverview = function()
|
|||||||
overviewScrollCurrentRow = currentRow
|
overviewScrollCurrentRow = currentRow
|
||||||
overviewScrollTargetRow = targetRow
|
overviewScrollTargetRow = targetRow
|
||||||
end,
|
end,
|
||||||
createRefreshJob = function()
|
getEntriesAndCountsFromCache = function()
|
||||||
local job = createAsyncMeItemCountsJob(items, 1)
|
overviewCachedCounts = getGlobalItemCounts()
|
||||||
|
|
||||||
return {
|
|
||||||
step = function()
|
|
||||||
local isDone, itemCounts = job.step()
|
|
||||||
|
|
||||||
if isDone then
|
|
||||||
overviewCachedCounts = itemCounts
|
|
||||||
overviewCachedSortedItemIds = sortOverviewItems(overviewCachedCounts)
|
overviewCachedSortedItemIds = sortOverviewItems(overviewCachedCounts)
|
||||||
return true, overviewCachedSortedItemIds, overviewCachedCounts
|
return overviewCachedSortedItemIds, overviewCachedCounts
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
end,
|
end,
|
||||||
getId = function(entry)
|
getId = function(entry)
|
||||||
return entry
|
return entry
|
||||||
|
|||||||
Reference in New Issue
Block a user