MineOS/Applications/Installer.lua
2018-05-02 16:44:06 +03:00

263 lines
8.7 KiB
Lua

local component = require("component")
local unicode = require("unicode")
local fs = require("filesystem")
local event = require("event")
local gpu = component.gpu
local internet = component.internet
---------------------------------------------------------------------------------------------------------------------------------
-- Specify required files for downloading
local files = {
{
url = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/advancedLua.lua",
path = "/lib/advancedLua.lua"
},
{
url = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/color.lua",
path = "/lib/color.lua"
},
{
url = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/FormatModules/OCIF.lua",
path = "/lib/FormatModules/OCIF.lua"
},
{
url = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/image.lua",
path = "/lib/image.lua"
},
{
url = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/doubleBuffering.lua",
path = "/lib/doubleBuffering.lua"
},
{
url = "https://raw.githubusercontent.com/IgorTimofeev/OpenComputers/master/lib/GUI.lua",
path = "/lib/GUI.lua"
},
}
local properties = {
-- Comment any coordinate to calculate it automatically (will centerize window on screen by specified axis)
-- windowX = 2,
-- windowY = 2,
-- Set window width value lower than zero (0.5 for example) to calculate it dependent on screen width
windowWidth = 54,
-- Customize offset by X axis from window corners
GUIElementsOffset = 2,
-- Customize localization as you want to
localization = {
-- Specify title of your installer
title = "GUI framework installer",
-- Use <currentProgress>, <totalProgress> and <currentFile> text insertions to automatically display their values
currentFile = "Downloading \"<currentFile>\"",
totalProgress = "Total progress: <totalProgress>%",
-- Comment this lines to automatically close installer window
finished1 = "GUI framework has been successfully installed",
finished2 = "Press any key to quit"
},
-- Customize color scheme as you want to
colors = {
window = {
background = 0xEEEEEE,
text = 0x999999,
shadow = 0x3C3C3C
},
title = {
background = 0xCCCCCC,
text = 0x555555,
},
progressBar = {
active = 0x0092FF,
passive = 0xCCCCCC
}
}
}
---------------------------------------------------------------------------------------------------------------------------------
local screenWidth, screenHeight = gpu.getResolution()
properties.windowHeight = 8
if properties.windowWidth < 1 then
properties.windowWidth = math.floor(screenWidth * properties.windowWidth)
end
progressBarWidth = properties.windowWidth - properties.GUIElementsOffset * 2
if not properties.windowX then
properties.windowX = math.floor(screenWidth / 2 - properties.windowWidth / 2)
end
if not properties.windowY then
properties.windowY = math.floor(screenHeight / 2 - properties.windowHeight / 2)
end
local currentBackground, currentForeground
---------------------------------------------------------------------------------------------------------------------------------
local function setBackground(color)
if currentBackground ~= color then
gpu.setBackground(color)
currentBackground = color
end
end
local function setForeground(color)
if currentForeground ~= color then
gpu.setForeground(color)
currentForeground = color
end
end
local function rectangle(x, y, width, height, color)
setBackground(color)
gpu.fill(x, y, width, height, " ")
end
local function centerizedText(y, color, text)
local textLength = unicode.len(text)
if textLength > progressBarWidth then
text = unicode.sub(text, 1, progressBarWidth)
textLength = progressBarWidth
end
setForeground(color)
gpu.set(properties.windowX + properties.GUIElementsOffset, y, string.rep(" ", progressBarWidth))
gpu.set(math.floor(properties.windowX + properties.GUIElementsOffset + progressBarWidth / 2 - textLength / 2), y, text)
end
local function progressBar(y, percent, text, totalProgress, currentProgress, currentFile)
setForeground(properties.colors.progressBar.passive)
gpu.set(properties.windowX + properties.GUIElementsOffset, y, string.rep("", progressBarWidth))
setForeground(properties.colors.progressBar.active)
gpu.set(properties.windowX + properties.GUIElementsOffset, y, string.rep("", math.ceil(progressBarWidth * percent)))
text = text:gsub("<totalProgress>", totalProgress)
text = text:gsub("<currentProgress>", currentProgress)
text = text:gsub("<currentFile>", currentFile)
centerizedText(y + 1, properties.colors.window.text, text)
end
local function download(url, path, totalProgress)
fs.makeDirectory(fs.path(path))
local file, fileReason = io.open(path, "w")
if file then
local pcallSuccess, requestHandle = pcall(internet.request, url)
if pcallSuccess then
if requestHandle then
-- Drawing progressbar once with zero percentage
local y = properties.windowY + 2
progressBar(y, 0, properties.localization.currentFile, totalProgress, "0", path)
-- Waiting for any response code
local responseCode, responseName, responseData
repeat
responseCode, responseName, responseData = requestHandle:response()
until responseCode
-- Downloading file by chunks
local contentLength = 12 * 1024 * 1024
local currentLength = 0
if responseData and responseData["Content-Length"] then
contentLength = tonumber(responseData["Content-Length"][1])
end
while true do
local data, reason = requestHandle.read(math.huge)
if data then
currentLength = currentLength + #data
local percent = currentLength / contentLength
progressBar(y, percent, properties.localization.currentFile, totalProgress, tostring(math.ceil(percent)), path)
file:write(data)
else
requestHandle:close()
if reason then
error(reason)
else
file:close()
return
end
end
end
else
error("Invalid URL-address: " .. tostring(url))
end
else
error("Usage: component.internet.request(string url)")
end
file:close()
else
error("Failed to open file for writing: " .. tostring(fileReason))
end
end
---------------------------------------------------------------------------------------------------------------------------------
-- Copying current screen data
local oldPixels = {}
for y = properties.windowY, properties.windowY + properties.windowHeight do
oldPixels[y] = {}
for x = properties.windowX, properties.windowX + properties.windowWidth do
oldPixels[y][x] = { gpu.get(x, y) }
end
end
local function shadowPixel(x, y, symbol)
setBackground(oldPixels[y][x][3])
gpu.set(x, y, symbol)
end
-- Vertical shadow
rectangle(properties.windowX + properties.windowWidth, properties.windowY + 1, 1, properties.windowHeight - 1, properties.colors.window.shadow)
setForeground(properties.colors.window.shadow)
shadowPixel(properties.windowX + properties.windowWidth, properties.windowY, "")
-- Horizontal shadow
for i = properties.windowX + 1, properties.windowX + properties.windowWidth do
shadowPixel(i, properties.windowY + properties.windowHeight, "")
end
-- Window background
rectangle(properties.windowX, properties.windowY + 1, properties.windowWidth, properties.windowHeight - 1, properties.colors.window.background)
-- Title
rectangle(properties.windowX, properties.windowY, properties.windowWidth, 1, properties.colors.title.background)
centerizedText(properties.windowY, properties.colors.title.text, properties.localization.title)
setBackground(properties.colors.window.background)
-- Downloading
local y = properties.windowY + 5
progressBar(y, 0, properties.localization.totalProgress, "0", "0", files[1].path)
for i = 1, #files do
local percent = i / #files
local totalProgress = tostring(math.ceil(percent * 100))
download(files[i].url, files[i].path, totalProgress)
progressBar(y, percent, properties.localization.totalProgress, totalProgress, "0", files[i].path)
end
-- On exit
if properties.localization.finished1 then
rectangle(properties.windowX, properties.windowY + 1, properties.windowWidth, properties.windowHeight - 1, properties.colors.window.background)
centerizedText(properties.windowY + 3, properties.colors.window.text, properties.localization.finished1)
centerizedText(properties.windowY + 4, properties.colors.window.text, properties.localization.finished2)
while true do
local eventType = event.pull()
if eventType == "key_down" or eventType == "touch" then
break
end
end
end
-- Redraw old pixels
for y = properties.windowY, properties.windowY + properties.windowHeight do
for x = properties.windowX, properties.windowX + properties.windowWidth do
setBackground(oldPixels[y][x][3])
setForeground(oldPixels[y][x][2])
gpu.set(x, y, oldPixels[y][x][1])
end
end