Last active
September 12, 2023 21:03
-
-
Save umnikos/3c8b2f99ae9df0a4f00744437d579cee to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- A Radon layout for 1x1 monitor shops | |
-- This is a modification of the default theme that comes with with Radon itself | |
-- https://github.com/Allymonies/Radon | |
--- Imports | |
local _ = require("util.score") | |
local sound = require("util.sound") | |
local eventHook = require("util.eventHook") | |
local renderHelpers = require("util.renderHelpers") | |
local Display = require("modules.display") | |
local Solyd = require("modules.solyd") | |
local hooks = require("modules.hooks") | |
local useCanvas = hooks.useCanvas | |
local Button = require("components.Button") | |
local BasicButton = require("components.BasicButton") | |
local SmolButton = require("components.SmolButton") | |
local BigText = require("components.BigText") | |
local bigFont = require("fonts.bigfont") | |
local SmolText = require("components.SmolText") | |
local smolFont = require("fonts.smolfont") | |
local BasicText = require("components.BasicText") | |
local Rect = require("components.Rect") | |
local RenderCanvas = require("components.RenderCanvas") | |
local Core = require("core.ShopState") | |
local Pricing = require("core.Pricing") | |
local ShopRunner = require("core.ShopRunner") | |
local ConfigValidator = require("core.ConfigValidator") | |
local loadRIF = require("modules.rif") | |
local function render(canvas, display, props, theme, version) | |
local elements = {} | |
local selectedProduct, setSelectedProduct = Solyd.useState("") | |
local categories = renderHelpers.getCategories(props.shopState.products) | |
local selectedCategory = props.shopState.selectedCategory | |
local currencyEndX = 1 | |
if #props.configState.config.currencies > 1 then | |
for i = 1, #props.configState.config.currencies do | |
local symbol = renderHelpers.getCurrencySymbol(props.configState.config.currencies[i], "large") | |
local symbolSize = math.max(3,#symbol) -- bigFont:getWidth(symbol)+6 | |
currencyEndX = currencyEndX + symbolSize | |
end | |
end | |
local categoryX = 16 --display.bgCanvas.width | |
if #categories > 1 then | |
for i = #categories, 1, -1 do | |
local category = categories[i] | |
local categoryName = category.name | |
local categoryWidth = math.max(3,#categoryName) -- smolFont:getWidth(categoryName)+6 | |
categoryX = categoryX - categoryWidth | |
end | |
end | |
local headerCx = math.floor((display.bgCanvas.width - smolFont:getWidth(props.configState.config.branding.title)) / 2) | |
local header | |
local headerHeight = 1 | |
local titleHeight = 1 | |
if props.configState.config.branding.subtitle and props.configState.config.branding.swapHeader then | |
headerHeight = 2 | |
titleHeight = 2 | |
end | |
--table.insert(elements, Rect { display=display, x=1, y=1, width=display.bgCanvas.width, height=1, color=theme.colors.headerBgColor }) | |
header = BasicText { display=display, text=props.configState.config.branding.title, x=currencyEndX, y=titleHeight, align=theme.formatting.headerAlign, bg=theme.colors.headerBgColor, color = theme.colors.headerColor, width=categoryX-currencyEndX+1 } | |
if props.configState.config.branding.subtitle then | |
local subtitleHeight = 2 | |
if props.configState.config.branding.swapHeader then | |
subtitleHeight = 1 | |
end | |
table.insert(elements, BasicText { | |
display = display, | |
text = props.configState.config.branding.subtitle, | |
x = 1, | |
y = subtitleHeight, | |
align = theme.formatting.subtitleAlign, | |
bg = theme.colors.subtitleBgColor, | |
color = theme.colors.subtitleColor, | |
width = math.floor(display.bgCanvas.width / 2) | |
}) | |
headerHeight = 2 | |
end | |
table.insert(elements, header) | |
local footerHeight = 0 | |
if props.configState.config.settings.showFooter then | |
local footerMessage | |
if props.shopState.selectedCurrency.name or not props.configState.config.lang.footerNoName then | |
footerMessage = props.configState.config.lang.footer | |
else | |
footerMessage = props.configState.config.lang.footerNoName | |
end | |
if props.shopState.selectedCurrency.name and footerMessage:find("%%name%%") then | |
footerMessage = footerMessage:gsub("%%name%%", props.shopState.selectedCurrency.name) | |
end | |
if footerMessage:find("%%addr%%") and props.shopState.selectedCurrency.host then | |
footerMessage = footerMessage:gsub("%%addr%%", props.shopState.selectedCurrency.host) | |
end | |
if footerMessage:find("%%version%%") then | |
footerMessage = footerMessage:gsub("%%version%%", version) | |
end | |
if selectedProduct and #selectedProduct > 0 and footerMessage:find("<item>") then | |
footerMessage = footerMessage:gsub("<item>", selectedProduct) | |
end | |
if props.shopState.selectedCurrency then | |
local footer | |
local footerSize = theme.formatting.footerSize | |
if footerSize == "auto" and bigFont:getWidth(footerMessage) < display.bgCanvas.width then | |
footerSize = "large" | |
elseif footerSize == "auto" and smolFont:getWidth(footerMessage) < display.bgCanvas.width then | |
footerSize = "medium" | |
elseif footerSize == "auto" then | |
footerSize = "small" | |
end | |
if footerSize == "large" then | |
footer = BigText { display=display, text=footerMessage, x=1, y=display.bgCanvas.height-bigFont.height-5, align=theme.formatting.footerAlign, bg=theme.colors.footerBgColor, color = theme.colors.footerColor, width=display.bgCanvas.width } | |
footerHeight = smolFont.height + 6 | |
elseif footerSize == "medium" then | |
footer = SmolText { display=display, text=footerMessage, x=1, y=display.bgCanvas.height-smolFont.height-2, align=theme.formatting.footerAlign, bg=theme.colors.footerBgColor, color = theme.colors.footerColor, width=display.bgCanvas.width } | |
footerHeight = smolFont.height + 4 | |
else | |
footer = BasicText { display=display, text=footerMessage, x=1, y=math.floor(display.bgCanvas.height/3), align=theme.formatting.footerAlign, bg=theme.colors.footerBgColor, color = theme.colors.footerColor, width=math.ceil(display.bgCanvas.width/2) } | |
footerHeight = smolFont.height + 4 | |
end | |
table.insert(elements, footer) | |
end | |
end | |
local maxAddrWidth = 0 | |
local maxQtyWidth = 0 | |
local maxPriceWidth = 0 | |
local maxNameWidth = 0 | |
props.shopState.numCategories = #categories | |
local catName = "*" | |
local shopProducts = {} | |
if categories[selectedCategory] then | |
catName = categories[selectedCategory].name | |
shopProducts = renderHelpers.getDisplayedProducts(categories[selectedCategory].products, props.configState.config.settings, props.shopState.selectedCurrency) | |
end | |
local productsHeight = display.bgCanvas.height - headerHeight - footerHeight - 2 | |
local heightPerProduct = math.floor(productsHeight / #shopProducts) | |
local layout | |
if theme.formatting.layout == "auto" then | |
if heightPerProduct >= 15 then | |
layout = "large" | |
elseif heightPerProduct >= 9 then | |
layout = "medium" | |
else | |
layout = "small" | |
end | |
else | |
layout = theme.formatting.layout | |
end | |
local currency = props.shopState.selectedCurrency | |
local currencySymbol = renderHelpers.getCurrencySymbol(currency, layout) | |
while #shopProducts > 0 and (maxAddrWidth == 0 or maxAddrWidth + maxQtyWidth + maxPriceWidth + maxNameWidth > display.bgCanvas.width - 3) do | |
if props.configState.config.theme.formatting.layout == "auto" and (maxAddrWidth + maxQtyWidth + maxPriceWidth + maxNameWidth > display.bgCanvas.width - 3) then | |
if layout == "large" then | |
layout = "medium" | |
maxAddrWidth = 0 | |
maxQtyWidth = 0 | |
maxPriceWidth = 0 | |
maxNameWidth = 0 | |
elseif layout == "medium" then | |
layout = "small" | |
maxAddrWidth = 0 | |
maxQtyWidth = 0 | |
maxPriceWidth = 0 | |
maxNameWidth = 0 | |
end | |
end | |
currencySymbol = renderHelpers.getCurrencySymbol(currency, layout) | |
for i = 1, #shopProducts do | |
local product = shopProducts[i] | |
local productAddr = product.address .. "@" | |
if props.shopState.selectedCurrency.name then | |
if layout == "small" then | |
if props.configState.config.settings.smallTextKristPayCompatability then | |
productAddr = product.address .. "@" .. props.shopState.selectedCurrency.name | |
else | |
productAddr = product.address .. "@ " | |
end | |
end | |
else | |
productAddr = product.address | |
end | |
product.quantity = product.quantity or 0 | |
local productPrice = Pricing.getProductPrice(product, props.shopState.selectedCurrency) | |
if layout == "large" then | |
maxAddrWidth = math.max(maxAddrWidth, renderHelpers.getWidth(productAddr, layout)+2) | |
maxQtyWidth = math.max(maxQtyWidth, renderHelpers.getWidth(tostring(product.quantity), layout)+4+2) | |
maxPriceWidth = math.max(maxPriceWidth, renderHelpers.getWidth(tostring(productPrice) .. currencySymbol, layout)+2) | |
maxNameWidth = math.max(maxNameWidth, renderHelpers.getWidth(product.name, layout)+2) | |
elseif layout == "medium" then | |
maxAddrWidth = math.max(maxAddrWidth, renderHelpers.getWidth(productAddr, layout)+2) | |
maxQtyWidth = math.max(maxQtyWidth, renderHelpers.getWidth(tostring(product.quantity), layout)+4+2) | |
maxPriceWidth = math.max(maxPriceWidth, renderHelpers.getWidth(tostring(productPrice) .. currencySymbol, layout)+2) | |
maxNameWidth = math.max(maxNameWidth, renderHelpers.getWidth(product.name, layout)+2) | |
else | |
maxAddrWidth = math.max(maxAddrWidth, renderHelpers.getWidth(productAddr, layout)+1) | |
maxQtyWidth = math.max(maxQtyWidth, renderHelpers.getWidth(tostring(product.quantity), layout)+2) | |
maxPriceWidth = math.max(maxPriceWidth, renderHelpers.getWidth(tostring(productPrice) .. currencySymbol, layout)+1) | |
maxNameWidth = math.max(maxNameWidth, renderHelpers.getWidth(product.name, layout)+1) | |
end | |
maxQtyWidth = 0 | |
maxNameWidth = 0 | |
end | |
maxQtyWidth = display.bgCanvas.width - maxAddrWidth | |
if props.configState.config.theme.formatting.layout ~= "auto" or layout == "small" then | |
break | |
end | |
end | |
local startY = headerHeight + 1 | |
local startTextY = startY -- math.ceil(headerHeight / 3) + 1 | |
for i = 1, #shopProducts do | |
local product = shopProducts[i] | |
-- Display products in format: | |
-- <quantity> <name> <price> <address> | |
product.quantity = product.quantity or 0 | |
local productPrice = Pricing.getProductPrice(product, props.shopState.selectedCurrency) | |
local qtyColor = theme.colors.normalQtyColor | |
if product.quantity == 0 then | |
qtyColor = theme.colors.outOfStockQtyColor | |
elseif product.quantity < 10 then | |
qtyColor = theme.colors.lowQtyColor | |
elseif product.quantity < 64 then | |
qtyColor = theme.colors.warningQtyColor | |
end | |
local productNameColor = theme.colors.productNameColor | |
if product.quantity == 0 then | |
productNameColor = theme.colors.outOfStockNameColor | |
end | |
local productAddr = product.address .. "@" | |
if props.shopState.selectedCurrency.name then | |
if layout == "small" then | |
if props.configState.config.settings.smallTextKristPayCompatability then | |
productAddr = product.address .. "@" .. props.shopState.selectedCurrency.name | |
else | |
productAddr = product.address .. "@ " | |
end | |
end | |
else | |
productAddr = product.address | |
end | |
local kristpayHelperText = props.shopState.selectedCurrency.host or "" | |
if props.shopState.selectedCurrency.name then | |
kristpayHelperText = product.address .. "@" .. props.shopState.selectedCurrency.name | |
end | |
local productBgColor = theme.colors.productBgColors[((i-1) % #theme.colors.productBgColors) + 1] | |
local productClickFunction = function() | |
setSelectedProduct(product.address) | |
if props.configState.eventHooks and props.configState.eventHooks.onProductSelected then | |
eventHook.execute(props.configState.eventHooks.onProductSelected, product, currency) | |
end | |
if props.configState.config.settings.playSounds then | |
sound.playSound(props.peripherals.speaker, props.configState.config.sounds.button) | |
end | |
end | |
if layout == "large" then | |
table.insert(elements, Button { | |
key="qty-"..catName..tostring(product.id), | |
display=display, | |
text=tostring(product.quantity), | |
x=1, | |
y=startY+((i-1)*15), | |
align="center", | |
bg=productBgColor, | |
color=qtyColor, | |
width=maxQtyWidth, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, Button { | |
key="name-"..catName..tostring(product.id), | |
display=display, | |
text=product.name, | |
x=maxQtyWidth+1, | |
y=startY+((i-1)*15), | |
align=theme.formatting.productNameAlign, | |
bg=productBgColor, | |
color=productNameColor, | |
width=display.bgCanvas.width-3-maxAddrWidth-maxPriceWidth-maxQtyWidth, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, Button { | |
key="price-"..catName..tostring(product.id), | |
display=display, | |
text=tostring(productPrice) .. currencySymbol, | |
x=display.bgCanvas.width-3-maxAddrWidth-maxPriceWidth, | |
y=startY+((i-1)*15), | |
align="right", | |
bg=productBgColor, | |
color=theme.colors.priceColor, | |
width=maxPriceWidth, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, Button { | |
key="addr-"..catName..tostring(product.id), | |
display=display, | |
text=productAddr, | |
x=display.bgCanvas.width-3-maxAddrWidth, | |
y=startY+((i-1)*15), | |
align="right", | |
bg=productBgColor, | |
color=theme.colors.addressColor, | |
width=maxAddrWidth+4, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, BasicText { | |
key="invis-" .. catName .. tostring(product.id), | |
display=display, | |
text=kristpayHelperText, | |
x=1, | |
y=startTextY+((i-1)*5), | |
align="center", | |
bg=productBgColor, | |
color=productBgColor, | |
width=#(kristpayHelperText) | |
}) | |
elseif layout == "medium" then | |
table.insert(elements, SmolButton { | |
key="qty-"..catName..tostring(product.id), | |
display=display, | |
text=tostring(product.quantity), | |
x=1, | |
y=startY+((i-1)*9), | |
align="center", | |
bg=productBgColor, | |
color=qtyColor, | |
width=maxQtyWidth, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, SmolButton { | |
key="name-"..catName..tostring(product.id), | |
display=display, | |
text=product.name, | |
x=maxQtyWidth+1, | |
y=startY+((i-1)*9), | |
align=theme.formatting.productNameAlign, | |
bg=productBgColor, | |
color=productNameColor, | |
width=display.bgCanvas.width-3-maxAddrWidth-maxPriceWidth-maxQtyWidth, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, SmolButton { | |
key="price-"..catName..tostring(product.id), | |
display=display, | |
text=tostring(productPrice) .. currencySymbol, | |
x=display.bgCanvas.width-3-maxAddrWidth-maxPriceWidth, | |
y=startY+((i-1)*9), | |
align="right", | |
bg=productBgColor, | |
color=theme.colors.priceColor, | |
width=maxPriceWidth, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, SmolButton { | |
ey="addr-"..catName..tostring(product.id), | |
display=display, | |
text=productAddr, | |
x=display.bgCanvas.width-3-maxAddrWidth, | |
y=startY+((i-1)*9), | |
align="right", | |
bg=productBgColor, | |
color=theme.colors.addressColor, | |
width=maxAddrWidth+4, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, BasicText { | |
key="invis-" .. catName .. tostring(product.id), | |
display=display, | |
text=kristpayHelperText, | |
x=1, | |
y=startTextY+((i-1)*3), | |
align="center", | |
bg=productBgColor, | |
color=productBgColor, | |
width=#(kristpayHelperText) | |
}) | |
else | |
--[[ | |
table.insert(elements, BasicButton { | |
key="qty-"..catName..tostring(product.id), | |
display=display, | |
text=tostring(product.quantity), | |
x=1, | |
y=startTextY+((i-1)*1), | |
align="center", | |
bg=productBgColor, | |
color=qtyColor, | |
width=maxQtyWidth, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, BasicButton { | |
key="name-"..catName..tostring(product.id), | |
display=display, | |
text=product.name, | |
x=maxQtyWidth+1, | |
y=startTextY+((i-1)*1), | |
align=theme.formatting.productNameAlign, | |
bg=productBgColor, | |
color=productNameColor, | |
width=(display.bgCanvas.width/2)-1-maxAddrWidth-maxPriceWidth-maxQtyWidth, | |
onClick=productClickFunction | |
}) | |
]] | |
table.insert(elements, BasicButton { | |
key="price-"..catName..tostring(product.id), | |
display=display, | |
text=tostring(productPrice) .. currencySymbol, | |
x=1, -- (display.bgCanvas.width/2)-1-maxAddrWidth-maxPriceWidth, | |
y=startTextY+((i-1)*1), | |
align="left", | |
bg=productBgColor, | |
color=theme.colors.priceColor, | |
width= #(tostring(productPrice) .. currencySymbol), --(display.bgCanvas.width/2)-1-maxAddrWidth -1, --maxPriceWidth + 2, | |
onClick=productClickFunction | |
}) | |
table.insert(elements, BasicButton { | |
key="addr-"..catName..tostring(product.id), | |
display=display, | |
text=productAddr, | |
x= 1 + #(tostring(productPrice) .. currencySymbol), --(display.bgCanvas.width/2)-1-maxAddrWidth, | |
y=startTextY+((i-1)*1), | |
align="right", | |
bg=productBgColor, | |
color=theme.colors.addressColor, | |
width= 15 - #(tostring(productPrice) .. currencySymbol), --maxAddrWidth+2, | |
onClick=productClickFunction | |
}) | |
end | |
end | |
local currencyX = 1 | |
if #props.configState.config.currencies > 1 then | |
for i = 1, #props.configState.config.currencies do | |
local symbol = renderHelpers.getCurrencySymbol(props.configState.config.currencies[i], "large") | |
local symbolSize = math.max(3,#symbol) --bigFont:getWidth(symbol)+6+1 | |
local bgColor = theme.colors.currencyBgColors[((i-1) % #theme.colors.currencyBgColors) + 1] | |
table.insert(elements, BasicButton { | |
display = display, | |
align = "center", | |
text = symbol, | |
x = currencyX, | |
y = titleHeight, | |
bg = bgColor, | |
color = theme.colors.currencyTextColor, | |
width = symbolSize, | |
onClick = function() | |
props.shopState.selectedCurrency = props.configState.config.currencies[i] | |
props.shopState.lastTouched = os.epoch("utc") | |
if props.configState.config.settings.playSounds then | |
sound.playSound(props.peripherals.speaker, props.configState.config.sounds.button) | |
end | |
end | |
}) | |
currencyX = currencyX + symbolSize | |
end | |
end | |
local categoryX = 16 -- display.bgCanvas.width | |
if #categories > 1 then | |
for i = #categories, 1, -1 do | |
local category = categories[i] | |
local categoryName = category.name | |
local categoryColor | |
if i == selectedCategory then | |
categoryColor = theme.colors.activeCategoryColor | |
--categoryName = "[" .. categoryName .. "]" | |
else | |
categoryColor = theme.colors.categoryBgColors[((i-1) % #theme.colors.categoryBgColors) + 1] | |
end | |
local categoryWidth = math.max(3,#categoryName) -- smolFont:getWidth(categoryName)+6 | |
categoryX = categoryX - categoryWidth | |
table.insert(elements, BasicButton { | |
display = display, | |
align = "center", | |
text = categoryName, | |
x = categoryX, | |
y = titleHeight, | |
bg = categoryColor, | |
color = theme.colors.categoryTextColor, | |
width = categoryWidth, | |
onClick = function() | |
props.shopState.selectedCategory = i | |
setSelectedProduct("") | |
props.shopState.lastTouched = os.epoch("utc") | |
if props.configState.config.settings.playSounds then | |
sound.playSound(props.peripherals.speaker, props.configState.config.sounds.button) | |
end | |
-- canvas:markRect(1, 16, canvas.width, canvas.height-16) | |
end | |
}) | |
end | |
end | |
return elements | |
end | |
return render |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment