mirror of
https://github.com/IgorTimofeev/MineOS.git
synced 2025-12-24 13:02:49 +01:00
446 lines
14 KiB
Lua
Executable File
446 lines
14 KiB
Lua
Executable File
|
|
-- package.loaded.GUI = nil
|
|
-- _G.GUI = nil
|
|
|
|
local advancedLua = require("advancedLua")
|
|
local buffer = require("doubleBuffering")
|
|
local MineOSCore = require("MineOSCore")
|
|
local image = require("image")
|
|
local GUI = require("GUI")
|
|
local fs = require("filesystem")
|
|
local component = require("component")
|
|
local unicode = require("unicode")
|
|
local event = require("event")
|
|
local ecs = require("ECSAPI")
|
|
|
|
------------------------------------------------------------------------------------------------------------------
|
|
|
|
local obj = {}
|
|
local sizes = {}
|
|
local colors = {
|
|
main = 0xFFFFFF,
|
|
topBar = 0xDDDDDD,
|
|
topBarText = 0x555555,
|
|
topBarElement = 0xCCCCCC,
|
|
topBarElementText = 0x555555,
|
|
statusBar = 0xDDDDDD,
|
|
statusBarText = 0x888888,
|
|
appName = 0x262626,
|
|
version = 0x555555,
|
|
description = 0x888888,
|
|
downloadButton = 0xAAAAAA,
|
|
downloadButtonText = 0xFFFFFF,
|
|
downloading = 0x009240,
|
|
downloadingText = 0xFFFFFF,
|
|
downloaded = 0xCCCCCC,
|
|
downloadedText = 0xFFFFFF,
|
|
}
|
|
|
|
local typeFilters = {
|
|
"Application",
|
|
"Library",
|
|
"Wallpaper",
|
|
"Script",
|
|
}
|
|
|
|
local localization = table.fromFile("MineOS/Applications/AppMarket.app/Resources/Localization/" .. _G.OSSettings.language .. ".lang")
|
|
local appMarketConfigPath = "MineOS/System/AppMarket/"
|
|
local pathToApplications = "MineOS/System/OS/Applications.txt"
|
|
local updateImage = image.load(MineOSCore.paths.icons .. "Update.pic")
|
|
local topBarElements = {localization.applications, localization.libraries, localization.wallpapers, localization.other, localization.updates}
|
|
local oldApplications, newApplications, currentApps, changes = {}, {}, {}, {}
|
|
|
|
local currentTopBarElement = 1
|
|
local from, limit, fromY = 1, 8
|
|
|
|
------------------------------------------------------------------------------------------------------------------
|
|
|
|
local function correctDouble(number)
|
|
return string.format("%.2f", number)
|
|
end
|
|
|
|
local function status(text)
|
|
text = unicode.sub(text, 1, sizes.width - 2)
|
|
local y = sizes.y + sizes.height - 1
|
|
buffer.square(sizes.x, y, sizes.width, 1, colors.statusBar, colors.statusBarText, " ")
|
|
buffer.text(sizes.x + 1, y, colors.statusBarText, text)
|
|
buffer.draw()
|
|
end
|
|
|
|
local function calculateSizes()
|
|
sizes.width, sizes.height = math.floor(buffer.screen.width * 0.6), math.floor(buffer.screen.height * 0.7)
|
|
sizes.x, sizes.y = math.floor(buffer.screen.width / 2 - sizes.width / 2), math.floor(buffer.screen.height / 2 - sizes.height / 2)
|
|
sizes.topBarHeight = 3
|
|
obj.main = GUI.object(sizes.x, sizes.y + sizes.topBarHeight, sizes.width, sizes.height - sizes.topBarHeight)
|
|
sizes.downloadButtonWidth = 17
|
|
sizes.descriptionTruncateSize = sizes.width - 6 - MineOSCore.iconWidth - sizes.downloadButtonWidth
|
|
sizes.searchFieldWidth = math.floor(sizes.width * 0.3)
|
|
obj.searchTextField = GUI.inputTextBox(math.floor(sizes.x + sizes.width / 2 - sizes.searchFieldWidth / 2), 1, sizes.searchFieldWidth, 1, 0xEEEEEE, 0x555555, 0xEEEEEE, 0x262626, "", localization.search, true)
|
|
end
|
|
|
|
local function drawTopBar()
|
|
obj.topBarButtons = GUI.tabBar(sizes.x, sizes.y, sizes.width, sizes.topBarHeight, 2, colors.topBar, colors.topBarText, colors.topBarElement, colors.topBarElementText, table.unpack(topBarElements))
|
|
obj.topBarButtons.selectedTab = currentTopBarElement
|
|
obj.topBarButtons:draw()
|
|
obj.windowActionButtons = GUI.windowActionButtons(sizes.x + 1, sizes.y):draw()
|
|
end
|
|
|
|
local function getIcon(url)
|
|
local success, response = ecs.internetRequest(url)
|
|
local path = appMarketConfigPath .. "TempIcon.pic"
|
|
if success then
|
|
local file = io.open(path, "w")
|
|
file:write(response)
|
|
file:close()
|
|
else
|
|
GUI.error(tostring(response), {title = {color = 0xFFDB40, text = localization.errorWhileLoadingIcon}})
|
|
end
|
|
return image.load(path)
|
|
end
|
|
|
|
local function getDescription(url)
|
|
local success, response = ecs.internetRequest(url)
|
|
if success then
|
|
return response
|
|
else
|
|
GUI.error(tostring(response), {title = {color = 0xFFDB40, text = localization.errorWhileLoadingDescription}})
|
|
end
|
|
end
|
|
|
|
local function getApplication(i)
|
|
currentApps[i] = {}
|
|
currentApps[i].name = fs.name(newApplications[i].name)
|
|
|
|
if newApplications[i].icon then
|
|
currentApps[i].icon = getIcon(newApplications.GitHubUserURL .. newApplications[i].icon)
|
|
else
|
|
if newApplications[i].type == "Application" then
|
|
currentApps[i].icon = failureIcon
|
|
elseif newApplications[i].type == "Wallpaper" then
|
|
currentApps[i].icon = MineOSCore.icons.image
|
|
elseif newApplications[i].type == "Library" then
|
|
currentApps[i].icon = MineOSCore.icons.lua
|
|
else
|
|
currentApps[i].icon = MineOSCore.icons.script
|
|
end
|
|
end
|
|
|
|
if newApplications[i].about then
|
|
currentApps[i].description = getDescription(newApplications.GitHubUserURL .. newApplications[i].about .. _G.OSSettings.language .. ".txt")
|
|
currentApps[i].description = string.wrap({currentApps[i].description}, sizes.descriptionTruncateSize )
|
|
else
|
|
currentApps[i].description = {localization.descriptionNotAvailable}
|
|
end
|
|
|
|
if newApplications[i].version then
|
|
currentApps[i].version = localization.version .. correctDouble(newApplications[i].version)
|
|
else
|
|
currentApps[i].version = localization.versionNotAvailable
|
|
end
|
|
end
|
|
|
|
local function checkAppExists(name, type)
|
|
if type == "Application" then
|
|
name = name .. ".app"
|
|
end
|
|
return fs.exists(name)
|
|
end
|
|
|
|
local function drawApplication(x, y, i, doNotDrawButton)
|
|
buffer.image(x, y, currentApps[i].icon)
|
|
buffer.text(x + 10, y, colors.appName, currentApps[i].name)
|
|
buffer.text(x + 10, y + 1, colors.version, currentApps[i].version)
|
|
local appExists = checkAppExists(newApplications[i].name, newApplications[i].type)
|
|
local text = appExists and localization.update or localization.download
|
|
|
|
if not doNotDrawButton then
|
|
local xButton, yButton = sizes.x + sizes.width - sizes.downloadButtonWidth - 2, y + 1
|
|
if currentApps[i].buttonObject then
|
|
currentApps[i].buttonObject.x, currentApps[i].buttonObject.y = xButton, yButton
|
|
currentApps[i].buttonObject:draw()
|
|
else
|
|
currentApps[i].buttonObject = GUI.button(xButton, yButton, sizes.downloadButtonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x555555, 0xFFFFFF, text):draw()
|
|
end
|
|
end
|
|
|
|
for j = 1, #currentApps[i].description do
|
|
buffer.text(x + 10, y + j + 1, colors.description, currentApps[i].description[j])
|
|
end
|
|
y = y + (#currentApps[i].description > 2 and #currentApps[i].description - 2 or 0)
|
|
y = y + 5
|
|
|
|
return x, y
|
|
end
|
|
|
|
local function drawPageSwitchButtons(y)
|
|
local text = localization.applicationsFrom .. from .. localization.applicationsTo .. from + limit - 1
|
|
local textLength = unicode.len(text)
|
|
local buttonWidth = 5
|
|
local width = buttonWidth * 2 + textLength + 2
|
|
local x = math.floor(sizes.x + sizes.width / 2 - width / 2)
|
|
obj.prevPageButton = GUI.button(x, y, buttonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x262626, 0xFFFFFF, "<"):draw()
|
|
x = x + obj.prevPageButton.width + 1
|
|
buffer.text(x, y, colors.version, text)
|
|
x = x + textLength + 1
|
|
obj.nextPageButton = GUI.button(x, y, buttonWidth, 1, colors.downloadButton, colors.downloadButtonText, 0x262626, 0xFFFFFF, ">"):draw()
|
|
end
|
|
|
|
local function clearMainZone()
|
|
buffer.square(sizes.x, obj.main.y, sizes.width, obj.main.height, 0xFFFFFF)
|
|
end
|
|
|
|
local function drawMain(refreshData)
|
|
clearMainZone()
|
|
local x, y = sizes.x + 2, fromY
|
|
|
|
buffer.setDrawLimit(sizes.x, obj.main.y, sizes.width, obj.main.height)
|
|
|
|
obj.searchTextField.y, obj.searchTextField.isHidden = y, false
|
|
obj.searchTextField:draw()
|
|
y = y + 2
|
|
|
|
local matchCount = 1
|
|
for i = 1, #newApplications do
|
|
if newApplications[i].type == typeFilters[currentTopBarElement] then
|
|
if obj.searchTextField.text == "" or (string.find(unicode.lower(fs.name(newApplications[i].name)), unicode.lower(obj.searchTextField.text))) then
|
|
if matchCount >= from and matchCount <= from + limit - 1 then
|
|
if refreshData and not currentApps[i] then
|
|
status(localization.downloadingInfoAboutApplication .. " \"" .. newApplications[i].name .. "\"")
|
|
getApplication(i)
|
|
end
|
|
x, y = drawApplication(x, y, i)
|
|
end
|
|
matchCount = matchCount + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
if matchCount > limit then
|
|
drawPageSwitchButtons(y)
|
|
end
|
|
|
|
buffer.resetDrawLimit()
|
|
end
|
|
|
|
local function getNewApplications()
|
|
local pathToNewApplications = appMarketConfigPath .. "NewApplications.txt"
|
|
ecs.getFileFromUrl(oldApplications.GitHubApplicationListURL, pathToNewApplications)
|
|
newApplications = table.fromFile(pathToNewApplications)
|
|
end
|
|
|
|
local function getChanges()
|
|
changes = {}
|
|
for j = 1, #newApplications do
|
|
local matchFound = false
|
|
for i = 1, #oldApplications do
|
|
if oldApplications[i].name == newApplications[j].name then
|
|
if oldApplications[i].version < newApplications[j].version then table.insert(changes, j) end
|
|
matchFound = true
|
|
break
|
|
end
|
|
end
|
|
if not matchFound then table.insert(changes, j) end
|
|
end
|
|
end
|
|
|
|
local function updates()
|
|
clearMainZone()
|
|
|
|
obj.searchTextField.isHidden = true
|
|
|
|
if #changes > 0 then
|
|
buffer.setDrawLimit(sizes.x, obj.main.y, sizes.width, obj.main.height)
|
|
local x, y = sizes.x + 2, fromY
|
|
obj.updateAllButton = GUI.button(math.floor(sizes.x + sizes.width / 2 - sizes.downloadButtonWidth / 2), y, 20, 1, colors.downloadButton, colors.downloadButtonText, 0x555555, 0xFFFFFF, "Обновить все"):draw()
|
|
y = y + 2
|
|
|
|
for i = from, (from + limit) do
|
|
if not changes[i] then break end
|
|
if not currentApps[changes[i]] then
|
|
status(localization.downloadingInfoAboutApplication .. " \"" .. fs.name(newApplications[changes[i]].name) .. "\"")
|
|
getApplication(changes[i])
|
|
end
|
|
x, y = drawApplication(x, y, changes[i], true)
|
|
end
|
|
|
|
if #changes > limit then
|
|
drawPageSwitchButtons(y)
|
|
end
|
|
buffer.resetDrawLimit()
|
|
else
|
|
local text = localization.youHaveNewestApps
|
|
buffer.text(math.floor(sizes.x + sizes.width / 2 - unicode.len(text) / 2), math.floor(obj.main.y + obj.main.height / 2 - 1), colors.description, text)
|
|
end
|
|
end
|
|
|
|
local function flush()
|
|
fromY = obj.main.y + 1
|
|
from = 1
|
|
currentApps = {}
|
|
end
|
|
|
|
local function loadOldApplications()
|
|
oldApplications = table.fromFile(pathToApplications)
|
|
end
|
|
|
|
local function saveOldApplications()
|
|
table.toFile(pathToApplications, oldApplications)
|
|
end
|
|
|
|
local function drawAll(refreshIcons, force)
|
|
drawTopBar()
|
|
if currentTopBarElement == 5 then
|
|
updates()
|
|
else
|
|
drawMain(refreshIcons)
|
|
end
|
|
buffer.draw(force)
|
|
end
|
|
|
|
local function updateImageWindow()
|
|
clearMainZone()
|
|
local x, y = math.floor(sizes.x + sizes.width / 2 - updateImage.width / 2), math.floor(obj.main.y + obj.main.height / 2 - updateImage.height / 2 - 2)
|
|
buffer.image(x, y, updateImage)
|
|
return y + updateImage.height
|
|
end
|
|
|
|
local function updateImageWindowWithText(text)
|
|
local y = updateImageWindow() + 2
|
|
local x = math.floor(sizes.x + sizes.width / 2 - unicode.len(text) / 2)
|
|
buffer.text(x, y, colors.description, text)
|
|
end
|
|
|
|
local function updateAll()
|
|
local y = updateImageWindow()
|
|
local barWidth = math.floor(sizes.width * 0.6)
|
|
local xBar = math.floor(sizes.x + sizes.width / 2 - barWidth / 2)
|
|
y = y + 2
|
|
for i = 1, #changes do
|
|
local text = localization.updating .. " " .. fs.name(newApplications[changes[i]].name)
|
|
local xText = math.floor(sizes.x + sizes.width / 2 - unicode.len(text) / 2)
|
|
buffer.square(sizes.x, y + 1, sizes.width, 1, 0xFFFFFF)
|
|
buffer.text(xText, y + 1, colors.description, text)
|
|
GUI.progressBar(xBar, y, barWidth, 0x0092FF, 0xCCCCCC, 0x0, math.ceil(i / #changes * 100), true, false):draw()
|
|
buffer.draw()
|
|
ecs.getOSApplication(newApplications[changes[i]], true)
|
|
end
|
|
changes = {}
|
|
oldApplications = newApplications
|
|
saveOldApplications()
|
|
require("computer").shutdown(true)
|
|
end
|
|
|
|
------------------------------------------------------------------------------------------------------------------
|
|
|
|
-- buffer.start()
|
|
-- buffer.clear(0xFF8888)
|
|
|
|
local args = {...}
|
|
if args[1] == "updateCheck" then
|
|
currentTopBarElement = 5
|
|
end
|
|
|
|
fs.makeDirectory(appMarketConfigPath)
|
|
calculateSizes()
|
|
flush()
|
|
loadOldApplications()
|
|
drawTopBar()
|
|
GUI.windowShadow(sizes.x, sizes.y, sizes.width, sizes.height, 50)
|
|
updateImageWindowWithText(localization.downloadingApplicationsList)
|
|
buffer.draw()
|
|
getNewApplications()
|
|
getChanges()
|
|
drawAll(true, false)
|
|
|
|
while true do
|
|
local e = {event.pull()}
|
|
if e[1] == "touch" then
|
|
|
|
if obj.main:isClicked(e[3], e[4]) then
|
|
if obj.searchTextField:isClicked(e[3], e[4]) then
|
|
obj.searchTextField:input()
|
|
flush()
|
|
drawAll(true, false)
|
|
end
|
|
|
|
if currentTopBarElement < 5 then
|
|
for appIndex, app in pairs(currentApps) do
|
|
if app.buttonObject:isClicked(e[3], e[4]) then
|
|
app.buttonObject:pressAndRelease(0.3)
|
|
if app.buttonObject.text == localization.update or app.buttonObject.text == localization.download then
|
|
app.buttonObject.text = localization.downloading
|
|
app.buttonObject.disabled = true
|
|
app.buttonObject.colors.disabled.button, app.buttonObject.colors.disabled.text = colors.downloading, colors.downloadingText
|
|
app.buttonObject:draw()
|
|
buffer.draw()
|
|
ecs.getOSApplication(newApplications[appIndex], true)
|
|
app.buttonObject.text = localization.downloaded
|
|
app.buttonObject.colors.disabled.button, app.buttonObject.colors.disabled.text = colors.downloaded, colors.downloadedText
|
|
app.buttonObject:draw()
|
|
buffer.draw()
|
|
end
|
|
break
|
|
end
|
|
end
|
|
else
|
|
if obj.updateAllButton and obj.updateAllButton:isClicked(e[3], e[4]) then
|
|
obj.updateAllButton:pressAndRelease()
|
|
updateAll()
|
|
flush()
|
|
drawAll()
|
|
end
|
|
end
|
|
|
|
if obj.nextPageButton then
|
|
if obj.nextPageButton:isClicked(e[3], e[4]) then
|
|
obj.nextPageButton:pressAndRelease()
|
|
fromY = obj.main.y + 1
|
|
from = from + limit
|
|
currentApps = {}
|
|
drawAll(true, false)
|
|
elseif obj.prevPageButton:isClicked(e[3], e[4]) then
|
|
if from > limit then
|
|
fromY = obj.main.y + 1
|
|
from = from - limit
|
|
currentApps = {}
|
|
drawAll(true, false)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
if obj.windowActionButtons.close:isClicked(e[3], e[4]) then
|
|
obj.windowActionButtons.close:pressAndRelease()
|
|
return
|
|
end
|
|
|
|
for key, button in pairs(obj.topBarButtons.tabs.children) do
|
|
if button:isClicked(e[3], e[4]) then
|
|
currentTopBarElement = key
|
|
flush()
|
|
drawAll(true, false)
|
|
break
|
|
end
|
|
end
|
|
elseif e[1] == "scroll" then
|
|
if e[5] == 1 then
|
|
if (fromY < obj.main.y) then
|
|
fromY = fromY + 2
|
|
drawAll(false, false)
|
|
end
|
|
else
|
|
fromY = fromY - 2
|
|
drawAll(false, false)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|