-- 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