Merge branch 'main' into jqln/tts

custom
jacqueline 7 months ago
commit 1106012bde
  1. 3
      lua/browser.lua
  2. 3
      lua/file_browser.lua
  3. 1
      lua/images.lua
  4. BIN
      lua/img/bat/chg.png
  5. BIN
      lua/img/bat/chg_outline.png
  6. BIN
      lua/img/bt.png
  7. BIN
      lua/img/bt_conn.png
  8. BIN
      lua/img/chevron.png
  9. 2
      lua/main.lua
  10. 8
      lua/main_menu.lua
  11. 18
      lua/playing.lua
  12. 28
      lua/settings.lua
  13. 19
      lua/theme_dark.lua
  14. 27
      lua/theme_hicon.lua
  15. 19
      lua/theme_light.lua
  16. 32
      lua/widgets.lua
  17. 7
      luals-stubs/theme.lua
  18. 2
      src/drivers/storage.cpp
  19. 10
      src/tangara/lua/lua_theme.cpp
  20. 9
      src/tangara/system_fsm/running.cpp
  21. 2
      src/tangara/system_fsm/system_events.hpp
  22. 6
      src/tangara/system_fsm/system_fsm.hpp
  23. 2
      src/tangara/ui/screenshot.cpp
  24. 2
      src/tangara/ui/ui_fsm.cpp

@ -42,10 +42,9 @@ return screen:new{
pad_left = 4, pad_left = 4,
pad_right = 4, pad_right = 4,
pad_bottom = 2, pad_bottom = 2,
bg_opa = lvgl.OPA(100),
scrollbar_mode = lvgl.SCROLLBAR_MODE.OFF scrollbar_mode = lvgl.SCROLLBAR_MODE.OFF
} }
theme.set_style(header, "header") theme.set_subject(header, "header")
if self.breadcrumb then if self.breadcrumb then
header:Label{ header:Label{

@ -43,10 +43,9 @@ return screen:new {
pad_left = 4, pad_left = 4,
pad_right = 4, pad_right = 4,
pad_bottom = 2, pad_bottom = 2,
bg_opa = lvgl.OPA(100),
scrollbar_mode = lvgl.SCROLLBAR_MODE.OFF scrollbar_mode = lvgl.SCROLLBAR_MODE.OFF
} }
theme.set_style(header, "header") theme.set_subject(header, "header")
if self.breadcrumb then if self.breadcrumb then
header:Label { header:Label {

@ -15,6 +15,7 @@ local img = {
queue = lvgl.ImgData("//lua/img/queue.png"), queue = lvgl.ImgData("//lua/img/queue.png"),
files = lvgl.ImgData("//lua/img/files.png"), files = lvgl.ImgData("//lua/img/files.png"),
settings = lvgl.ImgData("//lua/img/settings.png"), settings = lvgl.ImgData("//lua/img/settings.png"),
chevron = lvgl.ImgData("//lua/img/chevron.png"),
} }
return img return img

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 584 B

@ -43,7 +43,7 @@ local function init_ui()
radius = 8, radius = 8,
pad_all = 2, pad_all = 2,
}) })
theme.set_style(container, "pop_up") theme.set_subject(container, "pop_up")
container:Label { container:Label {
text = string.format("Volume %i%%", pct), text = string.format("Volume %i%%", pct),
text_font = font.fusion_10 text_font = font.fusion_10

@ -35,7 +35,7 @@ return widgets.MenuScreen:new {
pad_column = 4, pad_column = 4,
border_width = 1, border_width = 1,
}) })
theme.set_style(now_playing, "now_playing"); theme.set_subject(now_playing, "now_playing");
local play_pause = now_playing:Image { src = img.play_small } local play_pause = now_playing:Image { src = img.play_small }
local title = now_playing:Label { local title = now_playing:Label {
@ -145,7 +145,7 @@ return widgets.MenuScreen:new {
-- local queue_btn = bottom_bar:Button {} -- local queue_btn = bottom_bar:Button {}
-- queue_btn:Image { src = img.queue } -- queue_btn:Image { src = img.queue }
-- theme.set_style(queue_btn, "icon_enabled") -- theme.set_subject(queue_btn, "icon_enabled")
local files_btn = bottom_bar:Button {} local files_btn = bottom_bar:Button {}
files_btn:onClicked(function() files_btn:onClicked(function()
@ -156,7 +156,7 @@ return widgets.MenuScreen:new {
end) end)
files_btn:Image { src = img.files } files_btn:Image { src = img.files }
widgets.Description(files_btn, "File browser") widgets.Description(files_btn, "File browser")
theme.set_style(files_btn, "menu_icon") theme.set_subject(files_btn, "menu_icon")
local settings_btn = bottom_bar:Button {} local settings_btn = bottom_bar:Button {}
settings_btn:onClicked(function() settings_btn:onClicked(function()
@ -164,6 +164,6 @@ return widgets.MenuScreen:new {
end) end)
settings_btn:Image { src = img.settings } settings_btn:Image { src = img.settings }
widgets.Description(settings_btn, "Settings") widgets.Description(settings_btn, "Settings")
theme.set_style(settings_btn, "menu_icon") theme.set_subject(settings_btn, "menu_icon")
end, end,
} }

@ -119,7 +119,7 @@ return screen:new {
range = { min = 0, max = 100 }, range = { min = 0, max = 100 },
value = 0, value = 0,
} }
theme.set_style(scrubber, "scrubber"); theme.set_subject(scrubber, "scrubber");
local scrubber_desc = widgets.Description(scrubber, "Scrubber") local scrubber_desc = widgets.Description(scrubber, "Scrubber")
scrubber:onevent(lvgl.EVENT.RELEASED, function() scrubber:onevent(lvgl.EVENT.RELEASED, function()
@ -161,7 +161,7 @@ return screen:new {
queue.repeat_track:set(not queue.repeat_track:get()) queue.repeat_track:set(not queue.repeat_track:get())
end) end)
local repeat_img = repeat_btn:Image { src = img.repeat_src } local repeat_img = repeat_btn:Image { src = img.repeat_src }
theme.set_style(repeat_btn, icon_enabled_class) theme.set_subject(repeat_btn, icon_enabled_class)
local repeat_desc = widgets.Description(repeat_btn) local repeat_desc = widgets.Description(repeat_btn)
@ -174,7 +174,7 @@ return screen:new {
end end
end) end)
local prev_img = prev_btn:Image { src = img.prev } local prev_img = prev_btn:Image { src = img.prev }
theme.set_style(prev_btn, icon_enabled_class) theme.set_subject(prev_btn, icon_enabled_class)
local prev_desc = widgets.Description(prev_btn, "Previous track") local prev_desc = widgets.Description(prev_btn, "Previous track")
local play_pause_btn = controls:Button {} local play_pause_btn = controls:Button {}
@ -183,13 +183,13 @@ return screen:new {
end) end)
play_pause_btn:focus() play_pause_btn:focus()
local play_pause_img = play_pause_btn:Image { src = img.pause } local play_pause_img = play_pause_btn:Image { src = img.pause }
theme.set_style(play_pause_btn, icon_enabled_class) theme.set_subject(play_pause_btn, icon_enabled_class)
local play_pause_desc = widgets.Description(play_pause_btn, "Play") local play_pause_desc = widgets.Description(play_pause_btn, "Play")
local next_btn = controls:Button {} local next_btn = controls:Button {}
next_btn:onClicked(queue.next) next_btn:onClicked(queue.next)
local next_img = next_btn:Image { src = img.next } local next_img = next_btn:Image { src = img.next }
theme.set_style(next_btn, icon_disabled_class) theme.set_subject(next_btn, icon_disabled_class)
local next_desc = widgets.Description(next_btn, "Next track") local next_desc = widgets.Description(next_btn, "Next track")
local shuffle_btn = controls:Button {} local shuffle_btn = controls:Button {}
@ -197,7 +197,7 @@ return screen:new {
queue.random:set(not queue.random:get()) queue.random:set(not queue.random:get())
end) end)
local shuffle_img = shuffle_btn:Image { src = img.shuffle } local shuffle_img = shuffle_btn:Image { src = img.shuffle }
theme.set_style(shuffle_btn, icon_enabled_class) theme.set_subject(shuffle_btn, icon_enabled_class)
local shuffle_desc = widgets.Description(shuffle_btn) local shuffle_desc = widgets.Description(shuffle_btn)
controls:Object({ flex_grow = 1, h = 1 }) -- spacer controls:Object({ flex_grow = 1, h = 1 }) -- spacer
@ -251,12 +251,12 @@ return screen:new {
playlist_pos:set { text = tostring(pos) } playlist_pos:set { text = tostring(pos) }
local can_next = pos < queue.size:get() or queue.random:get() local can_next = pos < queue.size:get() or queue.random:get()
theme.set_style( theme.set_subject(
next_btn, can_next and icon_enabled_class or icon_disabled_class next_btn, can_next and icon_enabled_class or icon_disabled_class
) )
end), end),
queue.random:bind(function(shuffling) queue.random:bind(function(shuffling)
theme.set_style(shuffle_btn, shuffling and icon_enabled_class or icon_disabled_class) theme.set_subject(shuffle_btn, shuffling and icon_enabled_class or icon_disabled_class)
if shuffling then if shuffling then
shuffle_img:set_src(img.shuffle) shuffle_img:set_src(img.shuffle)
shuffle_desc:set { text = "Disable shuffle" } shuffle_desc:set { text = "Disable shuffle" }
@ -266,7 +266,7 @@ return screen:new {
end end
end), end),
queue.repeat_track:bind(function(en) queue.repeat_track:bind(function(en)
theme.set_style(repeat_btn, en and icon_enabled_class or icon_disabled_class) theme.set_subject(repeat_btn, en and icon_enabled_class or icon_disabled_class)
if en then if en then
repeat_img:set_src(img.repeat_src) repeat_img:set_src(img.repeat_src)
repeat_desc:set { text = "Disable track repeat" } repeat_desc:set { text = "Disable track repeat" }

@ -12,6 +12,7 @@ local database = require("database")
local usb = require("usb") local usb = require("usb")
local font = require("font") local font = require("font")
local main_menu = require("main_menu") local main_menu = require("main_menu")
local img = require("images")
local SettingsScreen = widgets.MenuScreen:new { local SettingsScreen = widgets.MenuScreen:new {
show_back = true, show_back = true,
@ -102,7 +103,7 @@ local BluetoothSettings = SettingsScreen:new {
text = "", text = "",
pad_bottom = 1, pad_bottom = 1,
} }
theme.set_style(paired_label, "settings_title") theme.set_subject(paired_label, "settings_title")
self.bindings = self.bindings + { self.bindings = self.bindings + {
bluetooth.connecting:bind(function(conn) bluetooth.connecting:bind(function(conn)
@ -152,7 +153,7 @@ local BluetoothSettings = SettingsScreen:new {
end), end),
} }
theme.set_style(self.content:Label { theme.set_subject(self.content:Label {
text = "Known Devices", text = "Known Devices",
pad_bottom = 1, pad_bottom = 1,
}, "settings_title") }, "settings_title")
@ -206,13 +207,14 @@ local HeadphonesSettings = SettingsScreen:new {
create_ui = function(self) create_ui = function(self)
SettingsScreen.create_ui(self) SettingsScreen.create_ui(self)
theme.set_style(self.content:Label { theme.set_subject(self.content:Label {
text = "Maxiumum volume limit", text = "Maxiumum volume limit",
}, "settings_title") }, "settings_title")
local volume_chooser = self.content:Dropdown { local volume_chooser = self.content:Dropdown {
options = "Line Level (-10 dB)\nCD Level (+6 dB)\nMaximum (+10dB)", options = "Line Level (-10 dB)\nCD Level (+6 dB)\nMaximum (+10dB)",
selected = 1, selected = 1,
symbol = img.chevron,
} }
local limits = { -10, 6, 10 } local limits = { -10, 6, 10 }
volume_chooser:onevent(lvgl.EVENT.VALUE_CHANGED, function() volume_chooser:onevent(lvgl.EVENT.VALUE_CHANGED, function()
@ -221,7 +223,7 @@ local HeadphonesSettings = SettingsScreen:new {
volume.limit_db:set(limits[selection]) volume.limit_db:set(limits[selection])
end) end)
theme.set_style(self.content:Label { theme.set_subject(self.content:Label {
text = "Left/Right balance", text = "Left/Right balance",
}, "settings_title") }, "settings_title")
@ -282,7 +284,7 @@ local DisplaySettings = SettingsScreen:new {
} }
brightness_title:Label { text = "Brightness", flex_grow = 1 } brightness_title:Label { text = "Brightness", flex_grow = 1 }
local brightness_pct = brightness_title:Label {} local brightness_pct = brightness_title:Label {}
theme.set_style(brightness_pct, "settings_title") theme.set_subject(brightness_pct, "settings_title")
local brightness = self.content:Slider { local brightness = self.content:Slider {
w = lvgl.PCT(100), w = lvgl.PCT(100),
@ -306,7 +308,7 @@ local ThemeSettings = SettingsScreen:new {
create_ui = function(self) create_ui = function(self)
SettingsScreen.create_ui(self) SettingsScreen.create_ui(self)
theme.set_style(self.content:Label { theme.set_subject(self.content:Label {
text = "Theme", text = "Theme",
}, "settings_title") }, "settings_title")
@ -319,7 +321,9 @@ local ThemeSettings = SettingsScreen:new {
local theme_dir_iter = filesystem.iterator("/.themes/") local theme_dir_iter = filesystem.iterator("/.themes/")
for dir in theme_dir_iter do for dir in theme_dir_iter do
local theme_name = tostring(dir):match("(.+).lua$") local theme_name = tostring(dir):match("(.+).lua$")
themeOptions[theme_name] = "/sdcard/.themes/" .. theme_name .. ".lua" if (theme_name) then
themeOptions[theme_name] = "/sd/.themes/" .. theme_name .. ".lua"
end
end end
local saved_theme = theme.theme_filename(); local saved_theme = theme.theme_filename();
@ -346,6 +350,7 @@ local ThemeSettings = SettingsScreen:new {
local theme_chooser = self.content:Dropdown { local theme_chooser = self.content:Dropdown {
options = options, options = options,
symbol = img.chevron,
} }
theme_chooser:set({selected = selected_idx}) theme_chooser:set({selected = selected_idx})
@ -365,7 +370,7 @@ local InputSettings = SettingsScreen:new {
create_ui = function(self) create_ui = function(self)
SettingsScreen.create_ui(self) SettingsScreen.create_ui(self)
theme.set_style(self.content:Label { theme.set_subject(self.content:Label {
text = "Control scheme", text = "Control scheme",
}, "settings_title") }, "settings_title")
@ -388,6 +393,7 @@ local InputSettings = SettingsScreen:new {
local controls_chooser = self.content:Dropdown { local controls_chooser = self.content:Dropdown {
options = options, options = options,
symbol = img.chevron,
} }
self.bindings = self.bindings + { self.bindings = self.bindings + {
@ -403,7 +409,7 @@ local InputSettings = SettingsScreen:new {
controls.scheme:set(scheme) controls.scheme:set(scheme)
end) end)
theme.set_style(self.content:Label { theme.set_subject(self.content:Label {
text = "Scroll Sensitivity", text = "Scroll Sensitivity",
}, "settings_title") }, "settings_title")
@ -761,7 +767,7 @@ local RegulatoryScreen = SettingsScreen:new {
pad_top = 4, pad_top = 4,
pad_column = 4, pad_column = 4,
} }
theme.set_style(logo_container, "regulatory_icons") theme.set_subject(logo_container, "regulatory_icons")
button_container:add_style(styles.list_item) button_container:add_style(styles.list_item)
logo_container:Image { src = "//lua/img/ce.png" } logo_container:Image { src = "//lua/img/ce.png" }
@ -785,7 +791,7 @@ return widgets.MenuScreen:new {
text = name, text = name,
pad_left = 4, pad_left = 4,
} }
theme.set_style(elem, "settings_title") theme.set_subject(elem, "settings_title")
end end
local function submenu(name, class) local function submenu(name, class)

@ -38,6 +38,7 @@ local theme_dark = {
}, },
button = { button = {
{lvgl.PART.MAIN, lvgl.Style { {lvgl.PART.MAIN, lvgl.Style {
bg_opa = lvgl.OPA(100),
pad_left = 2, pad_left = 2,
pad_right = 2, pad_right = 2,
pad_top = 1, pad_top = 1,
@ -217,6 +218,12 @@ local theme_dark = {
radius = 4 radius = 4
}}, }},
}, },
bluetooth_icon = {
{lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255,
image_recolor = text_color,
}},
},
battery = { battery = {
{lvgl.PART.MAIN, lvgl.Style { {lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 0, image_recolor_opa = 0,
@ -240,6 +247,18 @@ local theme_dark = {
image_recolor = "#fdd833", image_recolor = "#fdd833",
}}, }},
}, },
battery_charge_outline = {
{lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255,
image_recolor = background_color,
}},
},
regulatory_icons = {
{lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255,
image_recolor = text_color,
}},
},
} }
return theme_dark return theme_dark

@ -40,6 +40,7 @@ local theme_hicon = {
}, },
button = { button = {
{lvgl.PART.MAIN, lvgl.Style { {lvgl.PART.MAIN, lvgl.Style {
bg_opa = lvgl.OPA(100),
pad_left = 2, pad_left = 2,
pad_right = 2, pad_right = 2,
pad_top = 1, pad_top = 1,
@ -188,6 +189,14 @@ local theme_hicon = {
bg_color = text_color, bg_color = text_color,
text_color = background_color, text_color = background_color,
}}, }},
{lvgl.PART.INDICATOR, lvgl.Style {
image_recolor_opa = 255,
image_recolor = text_color,
}},
{lvgl.PART.INDICATOR | lvgl.STATE.FOCUSED, lvgl.Style {
image_recolor_opa = 255,
image_recolor = background_color,
}},
}, },
dropdownlist = { dropdownlist = {
{lvgl.PART.MAIN, lvgl.Style{ {lvgl.PART.MAIN, lvgl.Style{
@ -244,6 +253,12 @@ local theme_hicon = {
radius = 4 radius = 4
}}, }},
}, },
bluetooth_icon = {
{lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255,
image_recolor = text_color,
}},
},
battery = { battery = {
{lvgl.PART.MAIN, lvgl.Style { {lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255, image_recolor_opa = 255,
@ -268,6 +283,18 @@ local theme_hicon = {
image_recolor = text_color, image_recolor = text_color,
}}, }},
}, },
battery_charge_outline = {
{lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255,
image_recolor = background_color,
}},
},
regulatory_icons = {
{lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255,
image_recolor = text_color,
}},
},
} }
return theme_hicon return theme_hicon

@ -20,7 +20,7 @@ local theme_light = {
{lvgl.PART.MAIN, lvgl.Style { {lvgl.PART.MAIN, lvgl.Style {
bg_opa = lvgl.OPA(100), bg_opa = lvgl.OPA(100),
bg_color = background_color, -- Root background color bg_color = background_color, -- Root background color
text_color = text_color text_color = text_color,
}}, }},
}, },
header = { header = {
@ -37,6 +37,7 @@ local theme_light = {
}, },
button = { button = {
{lvgl.PART.MAIN, lvgl.Style { {lvgl.PART.MAIN, lvgl.Style {
bg_opa = lvgl.OPA(100),
pad_left = 1, pad_left = 1,
pad_right = 1, pad_right = 1,
margin_all = 1, margin_all = 1,
@ -185,6 +186,10 @@ local theme_light = {
{lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style { {lvgl.PART.MAIN | lvgl.STATE.FOCUSED, lvgl.Style {
border_color = highlight_color, border_color = highlight_color,
}}, }},
{lvgl.PART.INDICATOR, lvgl.Style {
image_recolor_opa = 255,
image_recolor = text_color,
}},
}, },
dropdownlist = { dropdownlist = {
{lvgl.PART.MAIN, lvgl.Style{ {lvgl.PART.MAIN, lvgl.Style{
@ -256,6 +261,12 @@ local theme_light = {
radius = 4 radius = 4
}}, }},
}, },
bluetooth_icon = {
{lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255,
image_recolor = text_color,
}},
},
battery = { battery = {
{lvgl.PART.MAIN, lvgl.Style { {lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 180, image_recolor_opa = 180,
@ -280,6 +291,12 @@ local theme_light = {
image_recolor = "#fdd833", image_recolor = "#fdd833",
}}, }},
}, },
battery_charge_outline = {
{lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255,
image_recolor = background_color,
}},
},
regulatory_icons = { regulatory_icons = {
{lvgl.PART.MAIN, lvgl.Style { {lvgl.PART.MAIN, lvgl.Style {
image_recolor_opa = 255, image_recolor_opa = 255,

@ -13,6 +13,7 @@ local images = require("images")
local img = { local img = {
db = lvgl.ImgData("//lua/img/db.png"), db = lvgl.ImgData("//lua/img/db.png"),
chg = lvgl.ImgData("//lua/img/bat/chg.png"), chg = lvgl.ImgData("//lua/img/bat/chg.png"),
chg_outline = lvgl.ImgData("//lua/img/bat/chg_outline.png"),
bat_100 = lvgl.ImgData("//lua/img/bat/100.png"), bat_100 = lvgl.ImgData("//lua/img/bat/100.png"),
bat_80 = lvgl.ImgData("//lua/img/bat/80.png"), bat_80 = lvgl.ImgData("//lua/img/bat/80.png"),
bat_60 = lvgl.ImgData("//lua/img/bat/60.png"), bat_60 = lvgl.ImgData("//lua/img/bat/60.png"),
@ -107,7 +108,7 @@ function widgets.StatusBar(parent, opts)
} }
if not opts.transparent_bg then if not opts.transparent_bg then
theme.set_style(root, "header"); theme.set_subject(root, "header");
end end
if opts.back_cb then if opts.back_cb then
@ -116,7 +117,7 @@ function widgets.StatusBar(parent, opts)
h = lvgl.SIZE_CONTENT, h = lvgl.SIZE_CONTENT,
} }
back:Image{src=images.back} back:Image{src=images.back}
theme.set_style(back, "back_button") theme.set_subject(back, "back_button")
widgets.Description(back, "Back") widgets.Description(back, "Back")
back:onClicked(opts.back_cb) back:onClicked(opts.back_cb)
back:onevent(lvgl.EVENT.FOCUSED, function() back:onevent(lvgl.EVENT.FOCUSED, function()
@ -145,10 +146,12 @@ function widgets.StatusBar(parent, opts)
end end
local db_updating = root:Image { src = img.db } local db_updating = root:Image { src = img.db }
theme.set_style(db_updating, "database_indicator") theme.set_subject(db_updating, "database_indicator")
local bt_icon = root:Image {} local bt_icon = root:Image {}
local battery_icon = root:Image {} local battery_icon = root:Image {}
local charge_icon = battery_icon:Image { src = img.chg } local charge_icon = battery_icon:Image { src = img.chg }
local charge_icon_outline = battery_icon:Image { src = img.chg_outline }
charge_icon_outline:center();
charge_icon:center() charge_icon:center()
local is_charging = nil local is_charging = nil
@ -157,32 +160,35 @@ function widgets.StatusBar(parent, opts)
local function update_battery_icon() local function update_battery_icon()
if is_charging == nil or percent == nil then return end if is_charging == nil or percent == nil then return end
local src local src
theme.set_style(battery_icon, "battery") theme.set_subject(battery_icon, "battery")
if percent >= 95 then if percent >= 95 then
theme.set_style(battery_icon, "battery_100") theme.set_subject(battery_icon, "battery_100")
src = img.bat_100 src = img.bat_100
elseif percent >= 75 then elseif percent >= 75 then
theme.set_style(battery_icon, "battery_80") theme.set_subject(battery_icon, "battery_80")
src = img.bat_80 src = img.bat_80
elseif percent >= 55 then elseif percent >= 55 then
theme.set_style(battery_icon, "battery_60") theme.set_subject(battery_icon, "battery_60")
src = img.bat_60 src = img.bat_60
elseif percent >= 35 then elseif percent >= 35 then
theme.set_style(battery_icon, "battery_40") theme.set_subject(battery_icon, "battery_40")
src = img.bat_40 src = img.bat_40
elseif percent >= 15 then elseif percent >= 15 then
theme.set_style(battery_icon, "battery_20") theme.set_subject(battery_icon, "battery_20")
src = img.bat_20 src = img.bat_20
else else
theme.set_style(battery_icon, "battery_0") theme.set_subject(battery_icon, "battery_0")
src = img.bat_0 src = img.bat_0
end end
if is_charging then if is_charging then
theme.set_style(battery_icon, "battery_charging") theme.set_subject(battery_icon, "battery_charging")
theme.set_style(charge_icon, "battery_charge_icon") theme.set_subject(charge_icon, "battery_charge_icon")
theme.set_subject(charge_icon_outline, "battery_charge_outline")
charge_icon:clear_flag(lvgl.FLAG.HIDDEN) charge_icon:clear_flag(lvgl.FLAG.HIDDEN)
charge_icon_outline:clear_flag(lvgl.FLAG.HIDDEN)
else else
charge_icon:add_flag(lvgl.FLAG.HIDDEN) charge_icon:add_flag(lvgl.FLAG.HIDDEN)
charge_icon_outline:add_flag(lvgl.FLAG.HIDDEN)
end end
battery_icon:set_src(src) battery_icon:set_src(src)
end end
@ -211,7 +217,7 @@ function widgets.StatusBar(parent, opts)
end end
end), end),
bluetooth.connected:bind(function(connected) bluetooth.connected:bind(function(connected)
theme.set_style(bt_icon, "bluetooth_icon") theme.set_subject(bt_icon, "bluetooth_icon")
if connected then if connected then
bt_icon:set_src(img.bt_conn) bt_icon:set_src(img.bt_conn)
else else

@ -15,11 +15,12 @@ function theme.load_theme(filename) end
--- @param theme --- @param theme
function theme.set(theme) end function theme.set(theme) end
--- Set the style name (similar in concept to a css selector) for an object --- Set the subject (similar in concept to a css class) of an object.
--- This will set any styles associated with that style name on the object --- This will set any styles within the theme associated with that subject
--- on the given object
--- @param obj Object The object to set a particular style on --- @param obj Object The object to set a particular style on
--- @param style string The name of the style to apply to this object --- @param style string The name of the style to apply to this object
function theme.set_style(obj, style) end function theme.set_subject(obj, subject_name) end
--- Returns the filename of the saved theme --- Returns the filename of the saved theme
--- @return string --- @return string

@ -31,7 +31,7 @@ static const uint8_t kMaxOpenFiles = 8;
namespace drivers { namespace drivers {
const char* kStoragePath = "/sdcard"; const char* kStoragePath = "/sd";
auto SdStorage::Create(IGpios& gpio) -> cpp::result<SdStorage*, Error> { auto SdStorage::Create(IGpios& gpio) -> cpp::result<SdStorage*, Error> {
gpio.WriteSync(IGpios::Pin::kSdPowerEnable, 1); gpio.WriteSync(IGpios::Pin::kSdPowerEnable, 1);

@ -22,12 +22,12 @@
namespace lua { namespace lua {
static auto set_style(lua_State* L) -> int { static auto set_subject(lua_State* L) -> int {
// Get the object and class name from the stack // Get the object and subject name from the stack
std::string class_name = luaL_checkstring(L, -1); std::string subject_name = luaL_checkstring(L, -1);
lv_obj_t* obj = luavgl_to_obj(L, -2); lv_obj_t* obj = luavgl_to_obj(L, -2);
if (obj != NULL) { if (obj != NULL) {
ui::themes::Theme::instance()->ApplyStyle(obj, class_name); ui::themes::Theme::instance()->ApplyStyle(obj, subject_name);
} }
return 0; return 0;
} }
@ -107,7 +107,7 @@ static auto theme_filename(lua_State* L) -> int {
} }
static const struct luaL_Reg kThemeFuncs[] = {{"set", set_theme}, static const struct luaL_Reg kThemeFuncs[] = {{"set", set_theme},
{"set_style", set_style}, {"set_subject", set_subject},
{"load_theme", load_theme}, {"load_theme", load_theme},
{"theme_filename", theme_filename}, {"theme_filename", theme_filename},
{NULL, NULL}}; {NULL, NULL}};

@ -40,7 +40,7 @@ void Running::entry() {
sUnmountTimer = xTimerCreate("unmount_timeout", kTicksBeforeUnmount, false, sUnmountTimer = xTimerCreate("unmount_timeout", kTicksBeforeUnmount, false,
NULL, timer_callback); NULL, timer_callback);
} }
mountStorage(); events::System().Dispatch(internal::Mount{});
} }
void Running::exit() { void Running::exit() {
@ -72,7 +72,8 @@ void Running::react(const SdDetectChanged& ev) {
} }
if (ev.has_sd_card && !sStorage) { if (ev.has_sd_card && !sStorage) {
mountStorage(); events::System().Dispatch(internal::Mount{});
return;
} }
// Don't automatically unmount, since this event seems to occasionally happen // Don't automatically unmount, since this event seems to occasionally happen
@ -120,7 +121,7 @@ void Running::react(const SamdUsbMscChanged& ev) {
gpios.WriteSync(drivers::IGpios::Pin::kSdPowerEnable, 0); gpios.WriteSync(drivers::IGpios::Pin::kSdPowerEnable, 0);
// Now it's ready for us. // Now it's ready for us.
mountStorage(); events::System().Dispatch(internal::Mount{});
} }
} }
@ -145,7 +146,7 @@ auto Running::updateSdState(drivers::SdState state) -> void {
events::System().Dispatch(SdStateChanged{}); events::System().Dispatch(SdStateChanged{});
} }
auto Running::mountStorage() -> void { void Running::react(const internal::Mount&) {
// Only mount our storage if we know it's not currently in use by the SAMD. // Only mount our storage if we know it's not currently in use by the SAMD.
if (sServices->samd().UsbMassStorage()) { if (sServices->samd().UsbMassStorage()) {
updateSdState(drivers::SdState::kNotMounted); updateSdState(drivers::SdState::kNotMounted);

@ -82,6 +82,8 @@ struct SamdInterrupt : tinyfsm::Event {};
struct IdleTimeout : tinyfsm::Event {}; struct IdleTimeout : tinyfsm::Event {};
struct UnmountTimeout : tinyfsm::Event {}; struct UnmountTimeout : tinyfsm::Event {};
struct Mount : tinyfsm::Event {};
} // namespace internal } // namespace internal
} // namespace system_fsm } // namespace system_fsm

@ -63,6 +63,7 @@ class SystemState : public tinyfsm::Fsm<SystemState> {
virtual void react(const audio::PlaybackUpdate&) {} virtual void react(const audio::PlaybackUpdate&) {}
virtual void react(const internal::IdleTimeout&) {} virtual void react(const internal::IdleTimeout&) {}
virtual void react(const internal::UnmountTimeout&) {} virtual void react(const internal::UnmountTimeout&) {}
virtual void react(const internal::Mount&) {}
protected: protected:
auto IdleCondition() -> bool; auto IdleCondition() -> bool;
@ -101,16 +102,17 @@ class Running : public SystemState {
void react(const audio::PlaybackUpdate&) override; void react(const audio::PlaybackUpdate&) override;
void react(const database::event::UpdateFinished&) override; void react(const database::event::UpdateFinished&) override;
void react(const SamdUsbMscChanged&) override; void react(const SamdUsbMscChanged&) override;
void react(const internal::UnmountTimeout&) override;
void react(const StorageError&) override; void react(const StorageError&) override;
void react(const internal::UnmountTimeout&) override;
void react(const internal::Mount&) override;
using SystemState::react; using SystemState::react;
private: private:
auto checkIdle() -> void; auto checkIdle() -> void;
auto updateSdState(drivers::SdState) -> void; auto updateSdState(drivers::SdState) -> void;
auto mountStorage() -> void;
auto unmountStorage() -> void; auto unmountStorage() -> void;
bool storage_mounted_; bool storage_mounted_;

@ -34,7 +34,7 @@ auto SaveScreenshot(lv_obj_t* obj, const std::string& path) -> void {
} }
// The LVGL lodepng fork uses LVGL's file API, so an extra '/' is needed. // The LVGL lodepng fork uses LVGL's file API, so an extra '/' is needed.
std::string fullpath = "//sdcard/" + path; std::string fullpath = "//sd/" + path;
auto res = lodepng_encode_file(fullpath.c_str(), buf->data, buf->header.w, auto res = lodepng_encode_file(fullpath.c_str(), buf->data, buf->header.w,
buf->header.h, LCT_RGB, 8); buf->header.h, LCT_RGB, 8);

@ -730,7 +730,7 @@ void Lua::entry() {
sPowerFastChargeEnabled.setDirect(sServices->nvs().FastCharge()); sPowerFastChargeEnabled.setDirect(sServices->nvs().FastCharge());
if (sServices->sd() == drivers::SdState::kMounted) { if (sServices->sd() == drivers::SdState::kMounted) {
sLua->RunScript("/sdcard/config.lua"); sLua->RunScript("/sd/config.lua");
} }
sLua->RunScript("/lua/main.lua"); sLua->RunScript("/lua/main.lua");
} }

Loading…
Cancel
Save