1
1
mirror of https://github.com/NixOS/mobile-nixos.git synced 2024-12-18 05:21:47 +03:00
mobile-nixos/boot/splash/lib/ui.rb
Samuel Dionne-Riel 6cd2985bc1 boot/splash: Implement progress status display
The splash is now an application that should be started and forked from.
Once started, it will listen for messages on a ZeroMQ socket reporting
progress.

The current protocol is extremely simple, reporting (optional) label,
and reporting a progress amount.

Additionally, it responds to a string commant ("quit") to quit as
needed.
2020-11-06 16:30:22 -05:00

171 lines
4.5 KiB
Ruby

module Kernel
alias_method :_exit, :exit
# mruby-at_exit seems to not be complete :/
# Let's instead hijack exit...
def exit(*args)
# Restore the console at exit.
VTConsole.map_console(1)
_exit(*args)
end
end
class UI
attr_reader :screen
attr_reader :progress_bar
# As this is not using BaseWindow, LVGUI::init isn't handled for us.
LVGUI.init()
def initialize()
add_screen
# Biggest of horizontal or vertical; a percent.
@unit = ([@screen.get_width, @screen.get_height].max * 0.01).ceil
add_logo
add_progress_bar
add_label
add_cover # last
end
def add_label()
@label = LVGL::LVLabel.new(@screen)
@label.get_style(LVGL::LABEL_STYLE::MAIN).dup.tap do |style|
@label.set_style(LVGL::LABEL_STYLE::MAIN, style)
style.text_color = 0xFFFFFFFF
end
@label.set_long_mode(LVGL::LABEL_LONG::BREAK)
@label.set_align(LVGL::LABEL_ALIGN::CENTER)
@label.set_width(@screen.get_width * 0.9)
@label.set_pos(*center(@label, 0, 5*@unit))
@label.set_text("")
end
def add_logo()
# Try to find the logo, but don't fail if there isn't one.
file = nil
file = "/etc/logo.svg" if File.exist?("/etc/logo.svg")
file = "./logo.svg" if File.exist?("./logo.svg")
return unless file
if @screen.get_height > @screen.get_width
# 80% of the width
LVGL::Hacks::LVNanoSVG.resize_next_width((@screen.get_width * 0.8).to_i)
else
# 15% of the height
LVGL::Hacks::LVNanoSVG.resize_next_height((@screen.get_height * 0.15).to_i)
end
@logo = LVGL::LVImage.new(@screen)
@logo.set_src(file)
# Position the logo
@logo.set_pos(*center(@logo, 0, -@logo.get_height))
end
def add_progress_bar()
@progress_bar = ProgressBar.new(@screen)
@progress_bar.set_height(3 * @unit)
@progress_bar.set_width(@screen.get_width * 0.7)
@progress_bar.set_pos(*center(@progress_bar))
end
def add_screen()
@screen = LVGL::LVContainer.new()
@screen.get_style(LVGL::CONT_STYLE::MAIN).dup.tap do |style|
@screen.set_style(LVGL::CONT_STYLE::MAIN, style)
# Background for the splash, assumed black.
style.body_main_color = 0xFF000000
style.body_grad_color = 0xFF000000
end
end
# Used to handle fade-in/fade-out
# This is because opacity handles multiple overlaid objects wrong.
def add_cover()
@cover = LVGL::LVObject.new(@screen)
# Make it so we can use the opacity to fade in/out
@cover.set_opa_scale_enable(1)
@cover.set_width(@screen.get_width())
@cover.set_height(@screen.get_height())
@cover.get_style().dup.tap do |style|
@cover.set_style(style)
# Background for the splash, assumed black.
style.body_main_color = 0xFF000000
style.body_grad_color = 0xFF000000
# Some themes will add a border to LVObject.
style.body_border_width = 0
end
end
def set_progress(amount)
progress_bar.progress = amount
end
def set_label(text)
@label.set_text(text)
end
# Fade-in animation
# Note that this looks like inverted logic because it is!
# We're actually fading-out the cover!
def fade_in()
LVGL::LVAnim.new().tap do |anim|
anim.set_exec_cb(@cover, :lv_obj_set_opa_scale)
anim.set_time(FADE_LENGTH, 0)
anim.set_values(255, 0)
anim.set_path_cb(LVGL::LVAnim::Path::EASE_OUT)
# Launch the animation
anim.create()
end
end
# Fade-out animation
# Note that this looks like inverted logic because it is!
# We're actually fading-in the cover!
def fade_out()
LVGL::LVAnim.new().tap do |anim|
anim.set_exec_cb(@cover, :lv_obj_set_opa_scale)
anim.set_time(FADE_LENGTH, PROGRESS_UPDATE_LENGTH)
anim.set_values(0, 255)
anim.set_path_cb(LVGL::LVAnim::Path::EASE_IN)
# Launch the animation
anim.create()
end
end
def quit!()
fade_out()
set_progress(100)
# TODO: Callback on a timer or on the fade_out animation end.
# Though we **do** want to stop processing from the queue.
# This is not a callback yet because we don't have an ergonomic way to
# produce those callbacks for LVGL yet.
exit_timestamp = Time.now + FADE_LENGTH/1000.0 + PROGRESS_UPDATE_LENGTH/1000.0 + 0.1
LVGUI.main_loop do
if Time.now > exit_timestamp
sleep(2) if LVGL::Introspection.simulator?
exit(0)
end
end
# (end TODO)
end
private
def center(el, x = 0, y = 0)
[
@screen.get_width / 2 - el.get_width / 2 + x,
@screen.get_height / 2 - el.get_height / 2 + y,
]
end
end