You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
575 lines
20 KiB
575 lines
20 KiB
/*
|
|
* Copyright 2023 jacqueline <me@jacqueline.id.au>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-only
|
|
*/
|
|
|
|
#include "screen_settings.hpp"
|
|
#include <stdint.h>
|
|
#include <string>
|
|
|
|
#include "audio_events.hpp"
|
|
#include "bluetooth.hpp"
|
|
#include "bluetooth_types.hpp"
|
|
#include "core/lv_event.h"
|
|
#include "core/lv_obj.h"
|
|
#include "core/lv_obj_tree.h"
|
|
#include "display.hpp"
|
|
#include "esp_app_desc.h"
|
|
#include "esp_log.h"
|
|
|
|
#include "core/lv_group.h"
|
|
#include "core/lv_obj_pos.h"
|
|
#include "event_queue.hpp"
|
|
#include "extra/layouts/flex/lv_flex.h"
|
|
#include "extra/widgets/list/lv_list.h"
|
|
#include "extra/widgets/menu/lv_menu.h"
|
|
#include "extra/widgets/spinbox/lv_spinbox.h"
|
|
#include "extra/widgets/spinner/lv_spinner.h"
|
|
#include "hal/lv_hal_disp.h"
|
|
#include "index.hpp"
|
|
#include "lv_api_map.h"
|
|
#include "misc/lv_anim.h"
|
|
#include "misc/lv_area.h"
|
|
#include "model_top_bar.hpp"
|
|
#include "nvs.hpp"
|
|
#include "samd.hpp"
|
|
#include "screen.hpp"
|
|
#include "themes.hpp"
|
|
#include "ui_events.hpp"
|
|
#include "ui_fsm.hpp"
|
|
#include "widget_top_bar.hpp"
|
|
#include "widgets/lv_bar.h"
|
|
#include "widgets/lv_btn.h"
|
|
#include "widgets/lv_dropdown.h"
|
|
#include "widgets/lv_label.h"
|
|
#include "widgets/lv_slider.h"
|
|
#include "widgets/lv_switch.h"
|
|
#include "wm8523.hpp"
|
|
|
|
namespace ui {
|
|
namespace screens {
|
|
|
|
using Page = internal::ShowSettingsPage::Page;
|
|
|
|
static void open_sub_menu_cb(lv_event_t* e) {
|
|
Page next_page = static_cast<Page>(reinterpret_cast<uintptr_t>(e->user_data));
|
|
events::Ui().Dispatch(internal::ShowSettingsPage{
|
|
.page = next_page,
|
|
});
|
|
}
|
|
|
|
static void sub_menu(lv_obj_t* list,
|
|
lv_group_t* group,
|
|
const std::pmr::string& text,
|
|
Page page) {
|
|
lv_obj_t* item = lv_list_add_btn(list, NULL, text.c_str());
|
|
lv_group_add_obj(group, item);
|
|
lv_obj_add_event_cb(item, open_sub_menu_cb, LV_EVENT_CLICKED,
|
|
reinterpret_cast<void*>(static_cast<uintptr_t>(page)));
|
|
}
|
|
|
|
Settings::Settings(models::TopBar& bar) : MenuScreen(bar, "Settings") {
|
|
lv_obj_t* list = lv_list_create(content_);
|
|
lv_obj_set_size(list, lv_pct(100), lv_pct(100));
|
|
|
|
themes::Theme::instance()->ApplyStyle(lv_list_add_text(list, "Audio"),
|
|
themes::Style::kMenuSubheadFirst);
|
|
sub_menu(list, group_, "Bluetooth", Page::kBluetooth);
|
|
sub_menu(list, group_, "Headphones", Page::kHeadphones);
|
|
|
|
themes::Theme::instance()->ApplyStyle(lv_list_add_text(list, "Interface"),
|
|
themes::Style::kMenuSubhead);
|
|
sub_menu(list, group_, "Appearance", Page::kAppearance);
|
|
sub_menu(list, group_, "Input Method", Page::kInput);
|
|
|
|
themes::Theme::instance()->ApplyStyle(lv_list_add_text(list, "System"),
|
|
themes::Style::kMenuSubhead);
|
|
sub_menu(list, group_, "Storage", Page::kStorage);
|
|
sub_menu(list, group_, "Firmware Update", Page::kFirmwareUpdate);
|
|
sub_menu(list, group_, "About", Page::kAbout);
|
|
}
|
|
|
|
static auto settings_container(lv_obj_t* parent) -> lv_obj_t* {
|
|
lv_obj_t* res = lv_obj_create(parent);
|
|
lv_obj_set_layout(res, LV_LAYOUT_FLEX);
|
|
lv_obj_set_size(res, lv_pct(100), LV_SIZE_CONTENT);
|
|
lv_obj_set_flex_flow(res, LV_FLEX_FLOW_ROW);
|
|
lv_obj_set_flex_align(res, LV_FLEX_ALIGN_SPACE_EVENLY, LV_FLEX_ALIGN_CENTER,
|
|
LV_FLEX_ALIGN_START);
|
|
return res;
|
|
}
|
|
|
|
static auto label_pair(lv_obj_t* parent,
|
|
const std::pmr::string& left,
|
|
const std::pmr::string& right) -> lv_obj_t* {
|
|
lv_obj_t* container = settings_container(parent);
|
|
lv_obj_t* left_label = lv_label_create(container);
|
|
lv_label_set_text(left_label, left.c_str());
|
|
lv_obj_t* right_label = lv_label_create(container);
|
|
lv_label_set_text(right_label, right.c_str());
|
|
return right_label;
|
|
}
|
|
|
|
static auto toggle_bt_cb(lv_event_t* ev) {
|
|
Bluetooth* instance = reinterpret_cast<Bluetooth*>(ev->user_data);
|
|
instance->ChangeEnabledState(lv_obj_has_state(ev->target, LV_STATE_CHECKED));
|
|
}
|
|
|
|
static auto select_device_cb(lv_event_t* ev) {
|
|
Bluetooth* instance = reinterpret_cast<Bluetooth*>(ev->user_data);
|
|
instance->OnDeviceSelected(lv_obj_get_index(ev->target));
|
|
}
|
|
|
|
static auto remove_preferred_cb(lv_event_t* ev) {
|
|
Bluetooth* instance = reinterpret_cast<Bluetooth*>(ev->user_data);
|
|
instance->OnDeviceSelected(-1);
|
|
}
|
|
|
|
Bluetooth::Bluetooth(models::TopBar& bar,
|
|
drivers::Bluetooth& bt,
|
|
drivers::NvsStorage& nvs)
|
|
: MenuScreen(bar, "Bluetooth"), bt_(bt), nvs_(nvs) {
|
|
lv_obj_t* toggle_container = settings_container(content_);
|
|
lv_obj_t* toggle_label = lv_label_create(toggle_container);
|
|
lv_label_set_text(toggle_label, "Enable");
|
|
lv_obj_set_flex_grow(toggle_label, 1);
|
|
lv_obj_t* toggle = lv_switch_create(toggle_container);
|
|
lv_group_add_obj(group_, toggle);
|
|
|
|
if (bt.IsEnabled()) {
|
|
lv_obj_add_state(toggle, LV_STATE_CHECKED);
|
|
}
|
|
|
|
lv_obj_add_event_cb(toggle, toggle_bt_cb, LV_EVENT_VALUE_CHANGED, this);
|
|
|
|
lv_obj_t* devices_label = lv_label_create(content_);
|
|
lv_label_set_text(devices_label, "Devices");
|
|
|
|
devices_list_ = lv_list_create(content_);
|
|
RefreshDevicesList();
|
|
bt_.SetDeviceDiscovery(true);
|
|
}
|
|
|
|
Bluetooth::~Bluetooth() {
|
|
bt_.SetDeviceDiscovery(false);
|
|
}
|
|
|
|
auto Bluetooth::ChangeEnabledState(bool enabled) -> void {
|
|
if (enabled) {
|
|
events::System().RunOnTask([&]() { bt_.Enable(); });
|
|
nvs_.OutputMode(drivers::NvsStorage::Output::kBluetooth);
|
|
} else {
|
|
events::System().RunOnTask([&]() { bt_.Disable(); });
|
|
nvs_.OutputMode(drivers::NvsStorage::Output::kHeadphones);
|
|
}
|
|
events::Audio().Dispatch(audio::OutputModeChanged{});
|
|
RefreshDevicesList();
|
|
}
|
|
|
|
auto Bluetooth::RefreshDevicesList() -> void {
|
|
if (!bt_.IsEnabled()) {
|
|
// Bluetooth is disabled, so we just clear the list.
|
|
RemoveAllDevices();
|
|
return;
|
|
}
|
|
|
|
auto devices = bt_.KnownDevices();
|
|
std::optional<drivers::bluetooth::mac_addr_t> preferred_device =
|
|
nvs_.PreferredBluetoothDevice();
|
|
|
|
// If the user's current selection is within the devices list, then we need
|
|
// to be careful not to rearrange the list items underneath them.
|
|
lv_obj_t* current_selection = lv_group_get_focused(group_);
|
|
bool is_in_list = current_selection != NULL &&
|
|
lv_obj_get_parent(current_selection) == devices_list_;
|
|
|
|
if (!is_in_list) {
|
|
// The user isn't in the list! We can blow everything away and recreate it
|
|
// without issues.
|
|
RemoveAllDevices();
|
|
|
|
// First look to see if the user's preferred device is in the list. If it
|
|
// is, we hoist it up to the top of the list.
|
|
if (preferred_device) {
|
|
for (size_t i = 0; i < devices.size(); i++) {
|
|
if (devices[i].address == *preferred_device) {
|
|
AddPreferredDevice(devices[i]);
|
|
devices.erase(devices.begin() + i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// The rest of the list is already sorted by signal strength.
|
|
for (const auto& device : devices) {
|
|
AddDevice(device);
|
|
}
|
|
} else {
|
|
// The user's selection is within the device list. We need to work out
|
|
// which devices are new, then add them to the end.
|
|
for (const auto& mac : macs_in_list_) {
|
|
auto pos = std::find_if(
|
|
devices.begin(), devices.end(),
|
|
[&mac](const auto& device) { return device.address == mac; });
|
|
|
|
if (pos != devices.end()) {
|
|
devices.erase(pos);
|
|
}
|
|
}
|
|
|
|
// The remaining list is now just the new devices.
|
|
for (const auto& device : devices) {
|
|
if (preferred_device && device.address == *preferred_device) {
|
|
AddPreferredDevice(device);
|
|
} else {
|
|
AddDevice(device);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto Bluetooth::RemoveAllDevices() -> void {
|
|
while (lv_obj_get_child_cnt(devices_list_) > 0) {
|
|
lv_obj_del(lv_obj_get_child(devices_list_, 0));
|
|
}
|
|
macs_in_list_.clear();
|
|
preferred_device_ = nullptr;
|
|
}
|
|
|
|
auto Bluetooth::AddPreferredDevice(const drivers::bluetooth::Device& dev)
|
|
-> void {
|
|
preferred_device_ = lv_list_add_btn(devices_list_, NULL, dev.name.c_str());
|
|
lv_obj_t* remove = lv_btn_create(preferred_device_);
|
|
lv_obj_t* remove_icon = lv_label_create(remove);
|
|
lv_label_set_text(remove_icon, "x");
|
|
lv_group_add_obj(group_, remove);
|
|
|
|
macs_in_list_.push_back(dev.address);
|
|
}
|
|
|
|
auto Bluetooth::AddDevice(const drivers::bluetooth::Device& dev) -> void {
|
|
lv_obj_t* item = lv_list_add_btn(devices_list_, NULL, dev.name.c_str());
|
|
lv_group_add_obj(group_, item);
|
|
lv_obj_add_event_cb(item, select_device_cb, LV_EVENT_CLICKED, this);
|
|
macs_in_list_.push_back(dev.address);
|
|
}
|
|
|
|
auto Bluetooth::OnDeviceSelected(ssize_t index) -> void {
|
|
if (index == -1) {
|
|
events::System().RunOnTask([=]() {
|
|
nvs_.PreferredBluetoothDevice({});
|
|
bt_.SetPreferredDevice({});
|
|
});
|
|
RefreshDevicesList();
|
|
return;
|
|
}
|
|
|
|
// Tell the bluetooth driver that our preference changed.
|
|
auto it = macs_in_list_.begin();
|
|
std::advance(it, index);
|
|
events::System().RunOnTask([=]() { bt_.SetPreferredDevice(*it); });
|
|
|
|
// Update which devices are selectable.
|
|
if (preferred_device_) {
|
|
lv_group_add_obj(group_, preferred_device_);
|
|
// Bubble the newly added object up to its visible position in the list.
|
|
size_t pos = lv_obj_get_index(preferred_device_);
|
|
while (pos > 0) {
|
|
lv_group_swap_obj(preferred_device_,
|
|
lv_obj_get_child(devices_list_, pos - 1));
|
|
pos--;
|
|
}
|
|
}
|
|
|
|
preferred_device_ = lv_obj_get_child(devices_list_, index);
|
|
lv_group_remove_obj(preferred_device_);
|
|
}
|
|
|
|
static void change_vol_limit_cb(lv_event_t* ev) {
|
|
int selected_index = lv_dropdown_get_selected(ev->target);
|
|
Headphones* instance = reinterpret_cast<Headphones*>(ev->user_data);
|
|
instance->ChangeMaxVolume(selected_index);
|
|
}
|
|
|
|
static void increase_vol_limit_cb(lv_event_t* ev) {
|
|
Headphones* instance = reinterpret_cast<Headphones*>(ev->user_data);
|
|
instance->ChangeCustomVolume(2);
|
|
}
|
|
|
|
static void decrease_vol_limit_cb(lv_event_t* ev) {
|
|
Headphones* instance = reinterpret_cast<Headphones*>(ev->user_data);
|
|
instance->ChangeCustomVolume(-2);
|
|
}
|
|
|
|
Headphones::Headphones(models::TopBar& bar, drivers::NvsStorage& nvs)
|
|
: MenuScreen(bar, "Headphones"), nvs_(nvs), custom_limit_(0) {
|
|
uint16_t reference = drivers::wm8523::kLineLevelReferenceVolume;
|
|
index_to_level_.push_back(reference - (10 * 4));
|
|
index_to_level_.push_back(reference + (6 * 4));
|
|
index_to_level_.push_back(reference + (9.5 * 4));
|
|
|
|
lv_obj_t* vol_label = lv_label_create(content_);
|
|
lv_label_set_text(vol_label, "Volume Limit");
|
|
lv_obj_t* vol_dropdown = lv_dropdown_create(content_);
|
|
lv_obj_set_width(vol_dropdown, lv_pct(100));
|
|
lv_dropdown_set_options(
|
|
vol_dropdown,
|
|
"Line Level (-10 dB)\nCD Level (+6 dB)\nMaximum (+10dB)\nCustom");
|
|
lv_group_add_obj(group_, vol_dropdown);
|
|
themes::Theme::instance()->ApplyStyle(lv_dropdown_get_list(vol_dropdown),
|
|
themes::Style::kPopup);
|
|
|
|
uint16_t level = nvs.AmpMaxVolume();
|
|
for (int i = 0; i < index_to_level_.size() + 1; i++) {
|
|
if (i == index_to_level_.size() || index_to_level_[i] == level) {
|
|
lv_dropdown_set_selected(vol_dropdown, i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
lv_obj_add_event_cb(vol_dropdown, change_vol_limit_cb, LV_EVENT_VALUE_CHANGED,
|
|
this);
|
|
|
|
custom_vol_container_ = settings_container(content_);
|
|
|
|
lv_obj_t* decrease_btn = lv_btn_create(custom_vol_container_);
|
|
lv_obj_t* btn_label = lv_label_create(decrease_btn);
|
|
lv_label_set_text(btn_label, "-");
|
|
lv_obj_add_event_cb(decrease_btn, decrease_vol_limit_cb, LV_EVENT_CLICKED,
|
|
this);
|
|
|
|
custom_vol_label_ = lv_label_create(custom_vol_container_);
|
|
UpdateCustomVol(level);
|
|
|
|
lv_obj_t* increase_btn = lv_btn_create(custom_vol_container_);
|
|
btn_label = lv_label_create(increase_btn);
|
|
lv_label_set_text(btn_label, "+");
|
|
lv_obj_add_event_cb(increase_btn, increase_vol_limit_cb, LV_EVENT_CLICKED,
|
|
this);
|
|
|
|
if (lv_dropdown_get_selected(vol_dropdown) != index_to_level_.size()) {
|
|
lv_obj_add_flag(custom_vol_container_, LV_OBJ_FLAG_HIDDEN);
|
|
}
|
|
|
|
lv_obj_t* spacer = lv_obj_create(content_);
|
|
lv_obj_set_size(spacer, 1, 4);
|
|
|
|
lv_obj_t* balance_label = lv_label_create(content_);
|
|
lv_label_set_text(balance_label, "Left/Right Balance");
|
|
|
|
spacer = lv_obj_create(content_);
|
|
lv_obj_set_size(spacer, 1, 4);
|
|
|
|
lv_obj_t* balance = lv_slider_create(content_);
|
|
lv_obj_set_size(balance, lv_pct(100), 5);
|
|
lv_slider_set_range(balance, -10, 10);
|
|
lv_slider_set_value(balance, 0, LV_ANIM_OFF);
|
|
lv_slider_set_mode(balance, LV_SLIDER_MODE_SYMMETRICAL);
|
|
lv_group_add_obj(group_, balance);
|
|
lv_obj_t* current_balance_label = lv_label_create(content_);
|
|
lv_label_set_text(current_balance_label, "0dB");
|
|
lv_obj_set_size(current_balance_label, lv_pct(100), LV_SIZE_CONTENT);
|
|
|
|
lv_obj_move_foreground(lv_dropdown_get_list(vol_dropdown));
|
|
}
|
|
|
|
auto Headphones::ChangeMaxVolume(uint8_t index) -> void {
|
|
if (index >= index_to_level_.size()) {
|
|
lv_obj_clear_flag(custom_vol_container_, LV_OBJ_FLAG_HIDDEN);
|
|
return;
|
|
}
|
|
auto vol = index_to_level_[index];
|
|
lv_obj_add_flag(custom_vol_container_, LV_OBJ_FLAG_HIDDEN);
|
|
UpdateCustomVol(vol);
|
|
events::Audio().Dispatch(audio::ChangeMaxVolume{.new_max = vol});
|
|
}
|
|
|
|
auto Headphones::ChangeCustomVolume(int8_t diff) -> void {
|
|
UpdateCustomVol(custom_limit_ + diff);
|
|
}
|
|
|
|
auto Headphones::UpdateCustomVol(uint16_t level) -> void {
|
|
custom_limit_ = level;
|
|
int16_t db = (static_cast<int32_t>(level) -
|
|
drivers::wm8523::kLineLevelReferenceVolume) /
|
|
4;
|
|
int16_t db_parts = (static_cast<int32_t>(level) -
|
|
drivers::wm8523::kLineLevelReferenceVolume) %
|
|
4;
|
|
|
|
std::ostringstream builder;
|
|
if (db >= 0) {
|
|
builder << "+";
|
|
}
|
|
builder << db << ".";
|
|
builder << (db_parts * 100 / 4);
|
|
builder << " dBV";
|
|
|
|
lv_label_set_text(custom_vol_label_, builder.str().c_str());
|
|
}
|
|
|
|
static void change_brightness_cb(lv_event_t* ev) {
|
|
Appearance* instance = reinterpret_cast<Appearance*>(ev->user_data);
|
|
instance->ChangeBrightness(lv_slider_get_value(ev->target));
|
|
}
|
|
|
|
static void release_brightness_cb(lv_event_t* ev) {
|
|
Appearance* instance = reinterpret_cast<Appearance*>(ev->user_data);
|
|
instance->CommitBrightness();
|
|
}
|
|
|
|
static auto brightness_str(uint_fast8_t percent) -> std::string {
|
|
return std::to_string(percent) + "%";
|
|
}
|
|
|
|
Appearance::Appearance(models::TopBar& bar,
|
|
drivers::NvsStorage& nvs,
|
|
drivers::Display& display)
|
|
: MenuScreen(bar, "Appearance"), nvs_(nvs), display_(display) {
|
|
lv_obj_t* toggle_container = settings_container(content_);
|
|
lv_obj_t* toggle_label = lv_label_create(toggle_container);
|
|
lv_obj_set_flex_grow(toggle_label, 1);
|
|
lv_label_set_text(toggle_label, "Dark Mode");
|
|
lv_obj_t* toggle = lv_switch_create(toggle_container);
|
|
lv_group_add_obj(group_, toggle);
|
|
|
|
uint_fast8_t initial_brightness = nvs_.ScreenBrightness();
|
|
|
|
lv_obj_t* brightness_label = lv_label_create(content_);
|
|
lv_label_set_text(brightness_label, "Brightness");
|
|
lv_obj_t* brightness = lv_slider_create(content_);
|
|
lv_obj_set_size(brightness, lv_pct(100), 5);
|
|
lv_slider_set_range(brightness, 10, 100);
|
|
lv_slider_set_value(brightness, initial_brightness, LV_ANIM_OFF);
|
|
lv_group_add_obj(group_, brightness);
|
|
current_brightness_label_ = lv_label_create(content_);
|
|
lv_label_set_text(current_brightness_label_,
|
|
brightness_str(initial_brightness).c_str());
|
|
lv_obj_set_size(current_brightness_label_, lv_pct(100), LV_SIZE_CONTENT);
|
|
|
|
lv_obj_add_event_cb(brightness, change_brightness_cb, LV_EVENT_VALUE_CHANGED,
|
|
this);
|
|
lv_obj_add_event_cb(brightness, release_brightness_cb, LV_EVENT_RELEASED,
|
|
this);
|
|
}
|
|
|
|
auto Appearance::ChangeBrightness(uint_fast8_t new_level) -> void {
|
|
current_brightness_ = new_level;
|
|
display_.SetBrightness(new_level);
|
|
lv_label_set_text(current_brightness_label_,
|
|
brightness_str(new_level).c_str());
|
|
}
|
|
|
|
auto Appearance::CommitBrightness() -> void {
|
|
nvs_.ScreenBrightness(current_brightness_);
|
|
}
|
|
|
|
InputMethod::InputMethod(models::TopBar& bar, drivers::NvsStorage& nvs)
|
|
: MenuScreen(bar, "Input Method"), nvs_(nvs) {
|
|
lv_obj_t* primary_label = lv_label_create(content_);
|
|
lv_label_set_text(primary_label, "Control scheme");
|
|
lv_obj_t* primary_dropdown = lv_dropdown_create(content_);
|
|
lv_dropdown_set_options(
|
|
primary_dropdown,
|
|
"Side buttons only\nButtons and touch\nD-Pad\nClickwheel");
|
|
lv_group_add_obj(group_, primary_dropdown);
|
|
|
|
lv_dropdown_set_selected(primary_dropdown,
|
|
static_cast<uint16_t>(nvs.PrimaryInput()));
|
|
themes::Theme::instance()->ApplyStyle(lv_dropdown_get_list(primary_dropdown),
|
|
themes::Style::kPopup);
|
|
|
|
lv_bind(primary_dropdown, LV_EVENT_VALUE_CHANGED, [this](lv_obj_t* obj) {
|
|
drivers::NvsStorage::InputModes mode;
|
|
switch (lv_dropdown_get_selected(obj)) {
|
|
case 0:
|
|
mode = drivers::NvsStorage::InputModes::kButtonsOnly;
|
|
break;
|
|
case 1:
|
|
mode = drivers::NvsStorage::InputModes::kButtonsWithWheel;
|
|
break;
|
|
case 2:
|
|
mode = drivers::NvsStorage::InputModes::kDirectionalWheel;
|
|
break;
|
|
case 3:
|
|
mode = drivers::NvsStorage::InputModes::kRotatingWheel;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
nvs_.PrimaryInput(mode);
|
|
events::Ui().Dispatch(internal::ControlSchemeChanged{});
|
|
});
|
|
}
|
|
|
|
Storage::Storage(models::TopBar& bar) : MenuScreen(bar, "Storage") {
|
|
label_pair(content_, "Storage Capacity:", "32 GiB");
|
|
label_pair(content_, "Currently Used:", "6 GiB");
|
|
label_pair(content_, "DB Size:", "1.2 MiB");
|
|
|
|
lv_obj_t* usage_bar = lv_bar_create(content_);
|
|
lv_bar_set_range(usage_bar, 0, 32);
|
|
lv_bar_set_value(usage_bar, 6, LV_ANIM_OFF);
|
|
|
|
lv_obj_t* container = lv_obj_create(content_);
|
|
lv_obj_set_size(container, lv_pct(100), 30);
|
|
lv_obj_set_layout(container, LV_LAYOUT_FLEX);
|
|
lv_obj_set_flex_flow(container, LV_FLEX_FLOW_ROW);
|
|
lv_obj_set_flex_align(container, LV_FLEX_ALIGN_SPACE_EVENLY,
|
|
LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER);
|
|
|
|
lv_obj_t* reset_btn = lv_btn_create(container);
|
|
lv_obj_t* reset_label = lv_label_create(reset_btn);
|
|
lv_label_set_text(reset_label, "Update Database");
|
|
lv_group_add_obj(group_, reset_btn);
|
|
themes::Theme::instance()->ApplyStyle(reset_btn,
|
|
themes::Style::kButtonPrimary);
|
|
|
|
lv_bind(reset_btn, LV_EVENT_CLICKED, [&](lv_obj_t*) {
|
|
events::Ui().Dispatch(internal::ReindexDatabase{});
|
|
});
|
|
}
|
|
|
|
FirmwareUpdate::FirmwareUpdate(models::TopBar& bar, drivers::Samd& samd)
|
|
: MenuScreen(bar, "Firmware Update") {
|
|
lv_obj_set_flex_align(content_, LV_FLEX_ALIGN_CENTER, LV_FLEX_ALIGN_CENTER,
|
|
LV_FLEX_ALIGN_CENTER);
|
|
|
|
auto samd_ver = samd.Version();
|
|
label_pair(content_, "SAMD21 FW:", {samd_ver.data(), samd_ver.size()});
|
|
|
|
lv_obj_t* spacer = lv_obj_create(content_);
|
|
lv_obj_set_size(spacer, 1, 4);
|
|
|
|
lv_obj_t* flash_esp_btn = lv_btn_create(content_);
|
|
lv_obj_t* flash_esp_label = lv_label_create(flash_esp_btn);
|
|
lv_label_set_text(flash_esp_label, "Update");
|
|
lv_group_add_obj(group_, flash_esp_btn);
|
|
themes::Theme::instance()->ApplyStyle(flash_esp_btn,
|
|
themes::Style::kButtonPrimary);
|
|
|
|
spacer = lv_obj_create(content_);
|
|
lv_obj_set_size(spacer, 1, 8);
|
|
|
|
auto desc = esp_app_get_description();
|
|
label_pair(content_, "ESP32 FW:", desc->version);
|
|
|
|
spacer = lv_obj_create(content_);
|
|
lv_obj_set_size(spacer, 1, 4);
|
|
|
|
lv_obj_t* flash_samd_btn = lv_btn_create(content_);
|
|
lv_obj_t* flash_samd_label = lv_label_create(flash_samd_btn);
|
|
lv_label_set_text(flash_samd_label, "Update");
|
|
lv_group_add_obj(group_, flash_samd_btn);
|
|
themes::Theme::instance()->ApplyStyle(flash_samd_btn,
|
|
themes::Style::kButtonPrimary);
|
|
}
|
|
|
|
About::About(models::TopBar& bar) : MenuScreen(bar, "About") {
|
|
lv_obj_t* label = lv_label_create(content_);
|
|
lv_label_set_text(label, "Some licenses or whatever");
|
|
}
|
|
|
|
} // namespace screens
|
|
} // namespace ui
|
|
|