bootpage implementation
This commit is contained in:
parent
eb55b8ffa0
commit
e8552b44a4
|
@ -0,0 +1,66 @@
|
||||||
|
require("common.class")
|
||||||
|
local Util = require("common.util")
|
||||||
|
local ServiceField = require("titlescreen.fields.service.servicefield")
|
||||||
|
|
||||||
|
---@class CheckUpdateField: ServiceField
|
||||||
|
---@field onUpdateAvailable nil|fun(url: string, version: string)
|
||||||
|
---@field _timer number
|
||||||
|
local CheckUpdateField = {
|
||||||
|
__tostring = function() return "CheckUpdateField" end,
|
||||||
|
PROGRESS_FREQ = 1 / 5, -- 5Hz
|
||||||
|
CHECK_UPDATE_MOCK_DELAY = 3, -- seconds
|
||||||
|
}
|
||||||
|
|
||||||
|
---Create a new CheckUpdateField instance
|
||||||
|
---@param o? table # initial parameters
|
||||||
|
---@return CheckUpdateField
|
||||||
|
function CheckUpdateField:new(o)
|
||||||
|
o = o or {}
|
||||||
|
|
||||||
|
o._timer = o._timer or 0
|
||||||
|
o.onUpdateAvailable = o.onUpdateAvailable or nil
|
||||||
|
|
||||||
|
local this = Inherit(self, o, ServiceField)
|
||||||
|
|
||||||
|
this._url = nil
|
||||||
|
this._version = nil
|
||||||
|
|
||||||
|
return this
|
||||||
|
end
|
||||||
|
|
||||||
|
function CheckUpdateField:drawLabel(deltaTime)
|
||||||
|
local text = self.label
|
||||||
|
local progress = math.ceil(Util.lerp(self._timer % self.PROGRESS_FREQ,
|
||||||
|
0, 0, self.PROGRESS_FREQ, 4
|
||||||
|
))
|
||||||
|
text = text .. string.rep(".", progress)
|
||||||
|
|
||||||
|
gfx.FontSize(self.FONT_SIZE)
|
||||||
|
gfx.LoadSkinFont(self.FONT_FACE)
|
||||||
|
gfx.TextAlign(gfx.TEXT_ALIGN_LEFT | gfx.TEXT_ALIGN_TOP)
|
||||||
|
gfx.FillColor(table.unpack(self.FONT_COLOR))
|
||||||
|
gfx.Text(text, 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
function CheckUpdateField:drawValue(deltaTime)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function CheckUpdateField:tick(deltaTime)
|
||||||
|
if self._timer > self.CHECK_UPDATE_MOCK_DELAY then
|
||||||
|
self._url, self._version = game.UpdateAvailable()
|
||||||
|
if self._url then
|
||||||
|
self.onUpdateAvailable(self._url, self._version)
|
||||||
|
else
|
||||||
|
self:getParentPage().viewHandler:clear() -- Exit out of bootscreen
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self._timer = self._timer + deltaTime
|
||||||
|
end
|
||||||
|
|
||||||
|
function CheckUpdateField:render(deltaTime)
|
||||||
|
self:tick(deltaTime)
|
||||||
|
ServiceField.render(self, deltaTime)
|
||||||
|
end
|
||||||
|
|
||||||
|
return CheckUpdateField
|
|
@ -11,16 +11,24 @@ SelfTestStatusEnum = {
|
||||||
ERROR = 5
|
ERROR = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local function statusToString(status)
|
||||||
|
local statusName = {"IDLE", "INPROGRESS", "OK", "PASS", "ERROR"}
|
||||||
|
return statusName[status]
|
||||||
|
end
|
||||||
|
|
||||||
---@class SelfTestField: ServiceField
|
---@class SelfTestField: ServiceField
|
||||||
|
---@field checkTask nil|fun(obj: any): SelfTestStatusEnum # a function that will run asynchronously on activating the Field
|
||||||
---@field status SelfTestStatusEnum
|
---@field status SelfTestStatusEnum
|
||||||
---@field callback nil|fun(obj: any): SelfTestStatusEnum
|
---@field onStatusChange nil|fun(status) # a callback function on finishing the checkTask
|
||||||
|
---@field _thread thread
|
||||||
---@field _timer number
|
---@field _timer number
|
||||||
local SelfTestField = {
|
local SelfTestField = {
|
||||||
SELFTEST_COLOR_INPROGRESS = {255, 255, 255, 255},
|
__tostring = function () return "SelfTestField" end,
|
||||||
SELFTEST_COLOR_OK = {0, 255, 0, 255},
|
COLOR_INPROGRESS = {255, 255, 255, 255},
|
||||||
SELFTEST_COLOR_PASS = {255, 255, 0, 255},
|
COLOR_OK = {0, 255, 0, 255},
|
||||||
SELFTEST_COLOR_ERROR = {255, 0, 0, 255},
|
COLOR_PASS = {255, 255, 0, 255},
|
||||||
SELFTEST_INPROGRESS_FREQ = 1 / 20, --20Hz
|
COLOR_ERROR = {255, 0, 0, 255},
|
||||||
|
INPROGRESS_FREQ = 1 / 20, --20Hz
|
||||||
}
|
}
|
||||||
|
|
||||||
---Create a new SelfTestField instance
|
---Create a new SelfTestField instance
|
||||||
|
@ -30,18 +38,61 @@ function SelfTestField:new(o)
|
||||||
o = o or {}
|
o = o or {}
|
||||||
|
|
||||||
o.status = o.status or SelfTestStatusEnum.IDLE
|
o.status = o.status or SelfTestStatusEnum.IDLE
|
||||||
o.callback = o.callback or nil
|
|
||||||
o._timer = 0
|
o._timer = 0
|
||||||
|
o._thread = nil
|
||||||
|
|
||||||
|
assert((not o.onStatusChange) or (o.checkTask and o.onStatusChange),
|
||||||
|
"Failed to construct SelfTestField, checkTask is mandatory when onStatusChange is defined!\n" .. debug.traceback()
|
||||||
|
)
|
||||||
|
|
||||||
return Inherit(self, o, ServiceField)
|
return Inherit(self, o, ServiceField)
|
||||||
end
|
end
|
||||||
|
|
||||||
function SelfTestField:activate(obj)
|
function SelfTestField:_closeThread()
|
||||||
if self.callback then
|
if self._thread and coroutine.status(self._thread) ~= "dead" then
|
||||||
self.status = self.callback(obj) or SelfTestStatusEnum.INPROGRESS
|
coroutine.close(self._thread)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SelfTestField:_resumeThread()
|
||||||
|
if self._thread and coroutine.status(self._thread) == "suspended" then
|
||||||
|
local success, status = coroutine.resume(self._thread)
|
||||||
|
game.Log(self.label .. ": success: " .. tostring(success) ..
|
||||||
|
", status: " .. status .. " (" .. statusToString(status) .. ")",
|
||||||
|
game.LOGGER_DEBUG
|
||||||
|
)
|
||||||
|
if success and status ~= self.status then
|
||||||
|
self.status = status
|
||||||
|
if self.onStatusChange then
|
||||||
|
game.Log("SKIN CONFIG: onStatusChange(" .. status .. ") (" ..
|
||||||
|
statusToString(status) .. ")",
|
||||||
|
game.LOGGER_DEBUG
|
||||||
|
)
|
||||||
|
self.onStatusChange(status)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SelfTestField:activate(obj)
|
||||||
|
self:_closeThread()
|
||||||
|
|
||||||
|
if self.checkTask then
|
||||||
|
self._thread = coroutine.create(self.checkTask)
|
||||||
|
self:_resumeThread()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SelfTestField:deactivate(obj)
|
||||||
|
self:_closeThread()
|
||||||
|
end
|
||||||
|
|
||||||
|
function SelfTestField:tick(deltaTime)
|
||||||
|
self:_resumeThread()
|
||||||
|
|
||||||
|
self._timer = self._timer + deltaTime
|
||||||
|
end
|
||||||
|
|
||||||
function SelfTestField:drawValue(deltaTime)
|
function SelfTestField:drawValue(deltaTime)
|
||||||
gfx.Translate(self.VALUE_OFFSETX, 0)
|
gfx.Translate(self.VALUE_OFFSETX, 0)
|
||||||
|
|
||||||
|
@ -54,18 +105,19 @@ function SelfTestField:drawValue(deltaTime)
|
||||||
color = self.FONT_COLOR
|
color = self.FONT_COLOR
|
||||||
text = ""
|
text = ""
|
||||||
elseif self.status == SelfTestStatusEnum.INPROGRESS then
|
elseif self.status == SelfTestStatusEnum.INPROGRESS then
|
||||||
self._timer = self._timer + deltaTime
|
local progress = math.ceil(Util.lerp(self._timer % self.INPROGRESS_FREQ,
|
||||||
local progress = math.ceil(Util.lerp(self._timer % 1, 0, 0, 1, 4))
|
0, 0, self.INPROGRESS_FREQ, 4
|
||||||
color = self.SELFTEST_COLOR_INPROGRESS
|
))
|
||||||
|
color = self.COLOR_INPROGRESS
|
||||||
text = string.rep(".", progress)
|
text = string.rep(".", progress)
|
||||||
elseif self.status == SelfTestStatusEnum.OK then
|
elseif self.status == SelfTestStatusEnum.OK then
|
||||||
color = self.SELFTEST_COLOR_OK
|
color = self.COLOR_OK
|
||||||
text = "OK"
|
text = "OK"
|
||||||
elseif self.status == SelfTestStatusEnum.PASS then
|
elseif self.status == SelfTestStatusEnum.PASS then
|
||||||
color = self.SELFTEST_COLOR_PASS
|
color = self.COLOR_PASS
|
||||||
text = "PASS"
|
text = "PASS"
|
||||||
elseif self.status == SelfTestStatusEnum.ERROR then
|
elseif self.status == SelfTestStatusEnum.ERROR then
|
||||||
color = self.SELFTEST_COLOR_ERROR
|
color = self.COLOR_ERROR
|
||||||
text = "ERROR"
|
text = "ERROR"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -74,4 +126,9 @@ function SelfTestField:drawValue(deltaTime)
|
||||||
gfx.Text(text, 0, 0)
|
gfx.Text(text, 0, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SelfTestField:render(deltaTime)
|
||||||
|
self:tick(deltaTime)
|
||||||
|
ServiceField.render(self, deltaTime)
|
||||||
|
end
|
||||||
|
|
||||||
return SelfTestField
|
return SelfTestField
|
|
@ -3,34 +3,11 @@ require("common.filereader")
|
||||||
local Dim = require("common.dimensions")
|
local Dim = require("common.dimensions")
|
||||||
local Version = require("common.version")
|
local Version = require("common.version")
|
||||||
local Page = require("components.pager.page")
|
local Page = require("components.pager.page")
|
||||||
|
local CheckUpdatePage = require("titlescreen.pages.boot.checkupdatepage")
|
||||||
local ServiceField = require("titlescreen.fields.service.servicefield")
|
local ServiceField = require("titlescreen.fields.service.servicefield")
|
||||||
local ListField = require("titlescreen.fields.service.listfield")
|
local ListField = require("titlescreen.fields.service.listfield")
|
||||||
local SelfTestField = require("titlescreen.fields.boot.selftestfield")
|
local SelfTestField = require("titlescreen.fields.boot.selftestfield")
|
||||||
|
|
||||||
local function checkSkinConfig(obj)
|
|
||||||
local crewpath = "textures/crew/anim/" .. game.GetSkinSetting("single_idol")
|
|
||||||
if not IsDir(crewpath) then
|
|
||||||
return SelfTestStatusEnum.ERROR
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local networkStatus = SelfTestStatusEnum.IDLE
|
|
||||||
local function irHeardbeat(res)
|
|
||||||
if res.statusCode == IRData.States.Success then
|
|
||||||
networkStatus = SelfTestStatusEnum.OK
|
|
||||||
else
|
|
||||||
networkStatus = SelfTestStatusEnum.ERROR
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function checkNetwork(obj)
|
|
||||||
if not IRData.Active then
|
|
||||||
return SelfTestStatusEnum.PASS
|
|
||||||
end
|
|
||||||
|
|
||||||
IR.Heartbeat(irHeardbeat)
|
|
||||||
end
|
|
||||||
|
|
||||||
---@class BootPage: Page
|
---@class BootPage: Page
|
||||||
local BootPage = {
|
local BootPage = {
|
||||||
__tostring = function() return "BootPage" end,
|
__tostring = function() return "BootPage" end,
|
||||||
|
@ -44,14 +21,71 @@ function BootPage:new(o)
|
||||||
|
|
||||||
local this = Inherit(self, o, Page)
|
local this = Inherit(self, o, Page)
|
||||||
|
|
||||||
|
this._networkResult = {}
|
||||||
|
|
||||||
this:addField(ServiceField:new{posX = 32, posY = 32, label = Version.getLongVersion(), value = ""})
|
this:addField(ServiceField:new{posX = 32, posY = 32, label = Version.getLongVersion(), value = ""})
|
||||||
this:addField(ServiceField:new{posX = 64, posY = 64, label = "UNNAMED SDVX CLONE STARTUP...", value = ""})
|
this:addField(ServiceField:new{posX = 64, posY = 64, label = "UNNAMED SDVX CLONE STARTUP...", value = ""})
|
||||||
|
|
||||||
local valueOffX = 220
|
local valueOffX = 220
|
||||||
|
this._mainIoTestField = SelfTestField:new{label = "MAIN I/O", VALUE_OFFSETX = valueOffX}
|
||||||
|
this._mainIoTestField.checkTask = function(obj)
|
||||||
|
return SelfTestStatusEnum.OK
|
||||||
|
end
|
||||||
|
this._mainIoTestField.onStatusChange = function(status)
|
||||||
|
if status == SelfTestStatusEnum.OK then
|
||||||
|
this._skinConfigTestField:activate()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
this._skinConfigTestField = SelfTestField:new{label = "SKIN CONFIG", VALUE_OFFSETX = valueOffX}
|
||||||
|
this._skinConfigTestField.checkTask = function(obj)
|
||||||
|
local crewpath = "skins/" .. game.GetSkin() .. "/textures/crew/anim/" .. game.GetSkinSetting("single_idol")
|
||||||
|
if not IsDir(crewpath) then
|
||||||
|
return SelfTestStatusEnum.ERROR
|
||||||
|
end
|
||||||
|
return SelfTestStatusEnum.OK
|
||||||
|
end
|
||||||
|
this._skinConfigTestField.onStatusChange = function(status)
|
||||||
|
if status == SelfTestStatusEnum.OK then
|
||||||
|
this._networkTestField:activate()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
this._networkTestField = SelfTestField:new{label = "NETWORK", VALUE_OFFSETX = valueOffX}
|
||||||
|
-- set up async network check
|
||||||
|
this._networkTestField.checkTask = function(obj)
|
||||||
|
local status = SelfTestStatusEnum.INPROGRESS
|
||||||
|
|
||||||
|
if not IRData.Active then
|
||||||
|
return SelfTestStatusEnum.PASS
|
||||||
|
end
|
||||||
|
|
||||||
|
while status == SelfTestStatusEnum.INPROGRESS do
|
||||||
|
if this._networkResult.statusCode == IRData.States.Success then
|
||||||
|
status = SelfTestStatusEnum.OK
|
||||||
|
elseif this._networkResult.statusCode then
|
||||||
|
status = SelfTestStatusEnum.ERROR -- there's a response, but it's not success
|
||||||
|
end
|
||||||
|
|
||||||
|
coroutine.yield(status)
|
||||||
|
end
|
||||||
|
|
||||||
|
return status
|
||||||
|
end
|
||||||
|
this._networkTestField.onStatusChange = function(status)
|
||||||
|
if status == SelfTestStatusEnum.INPROGRESS then
|
||||||
|
IR.Heartbeat(function(res) this._networkResult = res end) -- IR doesn't like being called in a coroutine
|
||||||
|
elseif status == SelfTestStatusEnum.PASS or status == SelfTestStatusEnum.OK then
|
||||||
|
if this.viewHandler then
|
||||||
|
this.viewHandler:navigate(CheckUpdatePage:new())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local list = ListField:new{posX = 64, posY = 96}
|
local list = ListField:new{posX = 64, posY = 96}
|
||||||
list:addField(SelfTestField:new{label = "MAIN I/O", VALUE_OFFSETX = valueOffX, status = SelfTestStatusEnum.OK})
|
list:addField(this._mainIoTestField)
|
||||||
list:addField(SelfTestField:new{label = "SKIN CONFIG", VALUE_OFFSETX = valueOffX, status = SelfTestStatusEnum.OK, callback = checkSkinConfig})
|
list:addField(this._skinConfigTestField)
|
||||||
list:addField(SelfTestField:new{label = "IR NETWORK", VALUE_OFFSETX = valueOffX, status = SelfTestStatusEnum.ERROR, callback = checkNetwork})
|
list:addField(this._networkTestField)
|
||||||
this:addField(list)
|
this:addField(list)
|
||||||
|
|
||||||
return this
|
return this
|
||||||
|
@ -65,12 +99,13 @@ function BootPage:drawBackground(deltaTime)
|
||||||
gfx.Fill()
|
gfx.Fill()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local first = true
|
||||||
function BootPage:render(deltaTime)
|
function BootPage:render(deltaTime)
|
||||||
|
if first then
|
||||||
|
self._mainIoTestField:activate()
|
||||||
|
first = false
|
||||||
|
end
|
||||||
Page.render(self, deltaTime)
|
Page.render(self, deltaTime)
|
||||||
|
|
||||||
local skinconfig = self.content[3].content[2] --this is hacktastic
|
|
||||||
|
|
||||||
local network = self.content[3].content[3] --this is also hacktastic
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return BootPage
|
return BootPage
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
require("common.class")
|
||||||
|
local Dim = require("common.dimensions")
|
||||||
|
local Page = require("components.pager.page")
|
||||||
|
local CheckUpdateField = require("titlescreen.fields.boot.checkupdatefield")
|
||||||
|
|
||||||
|
---@class CheckUpdatePage: Page
|
||||||
|
local CheckUpdatePage = {
|
||||||
|
__tostring = function() return "CheckUpdatePage" end,
|
||||||
|
}
|
||||||
|
|
||||||
|
---Create a new CheckUpdatePage instance
|
||||||
|
---@param o? table # initial parameters
|
||||||
|
---@return CheckUpdatePage
|
||||||
|
function CheckUpdatePage:new(o)
|
||||||
|
local this = Inherit(self, o, Page)
|
||||||
|
|
||||||
|
this._checkUpdateField = CheckUpdateField:new{posX = 32, posY = 64, label = "update check"}
|
||||||
|
this._checkUpdateField.onUpdateAvailable = function(url, version)
|
||||||
|
|
||||||
|
end
|
||||||
|
this:addField(this._checkUpdateField)
|
||||||
|
|
||||||
|
return this
|
||||||
|
end
|
||||||
|
|
||||||
|
---@param deltaTime number # frametime in seconds
|
||||||
|
function CheckUpdatePage:drawBackground(deltaTime)
|
||||||
|
gfx.BeginPath()
|
||||||
|
gfx.FillColor(0, 0, 0)
|
||||||
|
gfx.Rect(0, 0, Dim.design.width, Dim.design.height)
|
||||||
|
gfx.Fill()
|
||||||
|
end
|
||||||
|
|
||||||
|
return CheckUpdatePage
|
Loading…
Reference in New Issue