mirror of
https://github.com/IgorTimofeev/MineOS.git
synced 2025-12-24 13:02:49 +01:00
445 lines
17 KiB
Lua
Executable File
445 lines
17 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 web = require("web")
|
|
|
|
------------------------------------------------------------------------------------------------------------------
|
|
|
|
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.cfg"
|
|
local pathToNewApplications = appMarketConfigPath .. "NewApplications.cfg"
|
|
local updateImage = image.fromString([[20100000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 A40000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 730000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 430000 430000 430000 430000 430000 430000 430000 430000 430000 430000 430000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 430000 430000 430000 430000 430000 430000 430000 430000 430000 430000 430000 0000FF 0000FF 0000FF 0000FF 430000 430000 430000 430000 430000 430000 430000 430000 430000 430000 430000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 430000 430000 430000 430000 430000 430000 430000 430000 430000 430000 430000 0000FF 0000FF 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 130000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 130000 130000 130000 130000 130000 130000 130000 130000 130000 0000FF 0000FF 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0000FF 0000FF 0000FF 0000FF 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0000FF 0000FF 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0D0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0C0000 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF 0000FF ]])
|
|
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 path = appMarketConfigPath .. "TempIcon.pic"
|
|
|
|
local success, reason = web.downloadFile(url, path)
|
|
if not success then
|
|
error(reason)
|
|
end
|
|
|
|
return image.load(path)
|
|
end
|
|
|
|
local function getDescription(url)
|
|
local result, reason = web.request(url)
|
|
if not result then
|
|
error(reason)
|
|
end
|
|
|
|
return result
|
|
end
|
|
|
|
local function getApplication(i)
|
|
currentApps[i] = {}
|
|
currentApps[i].path = fs.name(newApplications[i].path)
|
|
|
|
if newApplications[i].icon then
|
|
currentApps[i].icon = getIcon(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[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].path)
|
|
buffer.text(x + 10, y + 1, colors.version, currentApps[i].version)
|
|
local appExists = checkAppExists(newApplications[i].path, 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].path)), 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].path .. "\"")
|
|
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()
|
|
web.downloadFile("https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/Applications.cfg", 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].path == newApplications[j].path 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]].path) .. "\"")
|
|
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[1] / 2), math.floor(obj.main.y + obj.main.height / 2 - updateImage[2] / 2 - 2)
|
|
buffer.image(x, y, updateImage)
|
|
return y + updateImage[2]
|
|
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]].path)
|
|
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()
|
|
web.downloadMineOSApplication(newApplications[changes[i]])
|
|
end
|
|
changes = {}
|
|
oldApplications = newApplications
|
|
saveOldApplications()
|
|
fs.remove(pathToNewApplications)
|
|
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()
|
|
web.downloadMineOSApplication(newApplications[appIndex])
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|