Merge develop into main (#338)

### Cardputer:
- Fix keyboard issue with up/down button conflict when selecting switch
- Fix backlight flickering

### UI improvements
- Removed a 3 pixel border that went around the entire desktop environment
- Improved system layout (GuiService)
- Statusbar: improved layout (mainly margin/padding)
- Toolbar: fixed margin/padding of all buttons, fixed alignment of all content
- Improved layout/UI of many apps

### Other
- Update LVGL to 9.3.0 official release (was dev version)
This commit is contained in:
Ken Van Hoeylandt
2025-09-16 23:12:07 +02:00
committed by GitHub
parent 53b711584f
commit a2af95b92d
30 changed files with 362 additions and 495 deletions
+6 -3
View File
@@ -145,16 +145,19 @@ public:
}
void onShow(TT_UNUSED AppContext& app, lv_obj_t* parent) override {
lvgl::obj_set_style_bg_blacken(parent);
lv_obj_set_style_border_width(parent, 0, LV_STATE_DEFAULT);
lv_obj_set_style_radius(parent, 0, LV_STATE_DEFAULT);
auto* image = lv_image_create(parent);
lv_obj_set_size(image, LV_PCT(100), LV_PCT(100));
lv_obj_set_size(image, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_align(image, LV_ALIGN_CENTER, 0, 0);
const auto paths = app.getPaths();
const char* logo = hal::usb::isUsbBootMode() ? "logo_usb.png" : "logo.png";
const auto logo_path = paths->getSystemPathLvgl(logo);
TT_LOG_I(TAG, "%s", logo_path.c_str());
lv_image_set_src(image, logo_path.c_str());
lvgl::obj_set_style_bg_blacken(parent);
}
};
@@ -1,21 +1,21 @@
#ifdef ESP_PLATFORM
#include "Tactility/app/crashdiagnostics/QrHelpers.h"
#include "Tactility/app/crashdiagnostics/QrUrl.h"
#include "Tactility/app/launcher/Launcher.h"
#include "Tactility/lvgl/Statusbar.h"
#include "Tactility/service/loader/Loader.h"
#include <Tactility/app/crashdiagnostics/QrHelpers.h>
#include <Tactility/app/crashdiagnostics/QrUrl.h>
#include <Tactility/app/launcher/Launcher.h>
#include <Tactility/lvgl/Statusbar.h>
#include <Tactility/service/loader/Loader.h>
#include <lvgl.h>
#include <qrcode.h>
#define TAG "crash_diagnostics"
#define TAG "CrashDiagnostics"
namespace tt::app::crashdiagnostics {
void onContinuePressed(TT_UNUSED lv_event_t* event) {
tt::service::loader::stopApp();
tt::app::launcher::start();
service::loader::stopApp();
launcher::start();
}
class CrashDiagnosticsApp : public App {
@@ -24,7 +24,7 @@ public:
void onShow(AppContext& app, lv_obj_t* parent) override {
auto* display = lv_obj_get_display(parent);
int32_t parent_height = lv_display_get_vertical_resolution(display) - STATUSBAR_HEIGHT;
int32_t parent_height = lv_display_get_vertical_resolution(display) - lvgl::STATUSBAR_HEIGHT;
lv_obj_add_event_cb(parent, onContinuePressed, LV_EVENT_SHORT_CLICKED, nullptr);
auto* top_label = lv_label_create(parent);
@@ -108,45 +108,45 @@ public:
// Wrappers
lv_obj_t* secondary_flex = lv_obj_create(parent);
lv_obj_set_width(secondary_flex, LV_PCT(100));
lv_obj_set_flex_grow(secondary_flex, 1);
lv_obj_set_flex_flow(secondary_flex, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_border_width(secondary_flex, 0, 0);
lv_obj_set_style_pad_all(secondary_flex, 0, 0);
lv_obj_set_style_pad_gap(secondary_flex, 0, 0);
lvgl::obj_set_style_bg_invisible(secondary_flex);
// align() methods don't work on flex, so we need this extra wrapper
lv_obj_t* wrapper = lv_obj_create(secondary_flex);
lv_obj_set_size(wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lvgl::obj_set_style_bg_invisible(wrapper);
lv_obj_set_style_border_width(wrapper, 0, 0);
lv_obj_t* content_wrapper = lv_obj_create(parent);
lv_obj_set_width(content_wrapper, LV_PCT(100));
lv_obj_set_flex_grow(content_wrapper, 1);
lv_obj_set_flex_flow(content_wrapper, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_border_width(content_wrapper, 0, LV_STATE_DEFAULT);
lvgl::obj_set_style_bg_invisible(content_wrapper);
// Enable on boot
lv_obj_t* enable_label = lv_label_create(wrapper);
lv_label_set_text(enable_label, "Enable on boot");
lv_obj_align(enable_label, LV_ALIGN_TOP_LEFT, 0, 6);
lv_obj_t* enable_wrapper = lv_obj_create(content_wrapper);
lv_obj_set_size(enable_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lvgl::obj_set_style_bg_invisible(enable_wrapper);
lv_obj_set_style_border_width(enable_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_all(enable_wrapper, 0, LV_STATE_DEFAULT);
enableOnBootSwitch = lv_switch_create(wrapper);
lv_obj_t* enable_label = lv_label_create(enable_wrapper);
lv_label_set_text(enable_label, "Enable on boot");
lv_obj_align(enable_label, LV_ALIGN_LEFT_MID, 0, 0);
enableOnBootSwitch = lv_switch_create(enable_wrapper);
lv_obj_add_event_cb(enableOnBootSwitch, onEnableOnBootSwitchChanged, LV_EVENT_VALUE_CHANGED, this);
lv_obj_align(enableOnBootSwitch, LV_ALIGN_TOP_RIGHT, 0, 0);
lv_obj_align(enableOnBootSwitch, LV_ALIGN_RIGHT_MID, 0, 0);
if (service::development::shouldEnableOnBoot()) {
lv_obj_add_state(enableOnBootSwitch, LV_STATE_CHECKED);
} else {
lv_obj_remove_state(enableOnBootSwitch, LV_STATE_CHECKED);
}
statusLabel = lv_label_create(wrapper);
lv_obj_align(statusLabel, LV_ALIGN_TOP_LEFT, 0, 50);
// Status
auto warning_label = lv_label_create(wrapper);
statusLabel = lv_label_create(content_wrapper);
// Warning
auto warning_label = lv_label_create(content_wrapper);
lv_label_set_text(warning_label, "This feature is experimental and uses an unsecured http connection.");
lv_obj_set_width(warning_label, LV_PCT(100));
lv_label_set_long_mode(warning_label, LV_LABEL_LONG_WRAP);
lv_obj_set_style_text_color(warning_label, lv_color_make(0xff, 0xff, 00), LV_STATE_DEFAULT);
lv_obj_align(warning_label, LV_ALIGN_TOP_LEFT, 0, 80);
updateViewState();
+25 -12
View File
@@ -65,6 +65,7 @@ public:
void onShow(AppContext& app, lv_obj_t* parent) override {
displaySettings = settings::display::loadOrGetDefault();
auto ui_scale = hal::getConfiguration()->uiScale;
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
@@ -79,39 +80,49 @@ public:
lv_obj_set_width(main_wrapper, LV_PCT(100));
lv_obj_set_flex_grow(main_wrapper, 1);
// Backlight slider
if (hal_display->supportsBacklightDuty()) {
auto* brightness_wrapper = lv_obj_create(main_wrapper);
lv_obj_set_size(brightness_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_pad_hor(brightness_wrapper, 0, 0);
lv_obj_set_style_pad_ver(brightness_wrapper, 6, 0);
lv_obj_set_style_border_width(brightness_wrapper, 0, 0);
lv_obj_set_style_pad_hor(brightness_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(brightness_wrapper, 0, LV_STATE_DEFAULT);
if (ui_scale != hal::UiScale::Smallest) {
lv_obj_set_style_pad_ver(brightness_wrapper, 4, LV_STATE_DEFAULT);
}
auto* brightness_label = lv_label_create(brightness_wrapper);
lv_label_set_text(brightness_label, "Brightness");
lv_obj_align(brightness_label, LV_ALIGN_LEFT_MID, 0, 0);
auto* brightness_slider = lv_slider_create(brightness_wrapper);
lv_obj_set_width(brightness_slider, LV_PCT(50));
lv_obj_align(brightness_slider, LV_ALIGN_TOP_RIGHT, -8, 0);
lv_obj_align(brightness_slider, LV_ALIGN_RIGHT_MID, 0, 0);
lv_slider_set_range(brightness_slider, 0, 255);
lv_obj_add_event_cb(brightness_slider, onBacklightSliderEvent, LV_EVENT_VALUE_CHANGED, this);
lv_slider_set_value(brightness_slider, displaySettings.backlightDuty, LV_ANIM_OFF);
}
// Gamma slider
if (hal_display->getGammaCurveCount() > 0) {
auto* gamma_wrapper = lv_obj_create(main_wrapper);
lv_obj_set_size(gamma_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_pad_hor(gamma_wrapper, 0, 0);
lv_obj_set_style_pad_ver(gamma_wrapper, 6, 0);
lv_obj_set_style_border_width(gamma_wrapper, 0, 0);
lv_obj_set_style_pad_hor(gamma_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(gamma_wrapper, 0, LV_STATE_DEFAULT);
if (ui_scale != hal::UiScale::Smallest) {
lv_obj_set_style_pad_ver(gamma_wrapper, 4, LV_STATE_DEFAULT);
}
auto* gamma_label = lv_label_create(gamma_wrapper);
lv_label_set_text(gamma_label, "Gamma");
lv_obj_align(gamma_label, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_set_y(gamma_label, 0);
auto* gamma_slider = lv_slider_create(gamma_wrapper);
lv_obj_set_width(gamma_slider, LV_PCT(50));
lv_obj_align(gamma_slider, LV_ALIGN_TOP_RIGHT, -8, 0);
lv_obj_align(gamma_slider, LV_ALIGN_RIGHT_MID, 0, 0);
lv_slider_set_range(gamma_slider, 0, hal_display->getGammaCurveCount());
lv_obj_add_event_cb(gamma_slider, onGammaSliderEvent, LV_EVENT_VALUE_CHANGED, this);
@@ -119,19 +130,21 @@ public:
lv_slider_set_value(gamma_slider, curve_index, LV_ANIM_OFF);
}
// Orientation
auto* orientation_wrapper = lv_obj_create(main_wrapper);
lv_obj_set_size(orientation_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(orientation_wrapper, 0, 0);
lv_obj_set_style_border_width(orientation_wrapper, 0, 0);
lv_obj_set_style_pad_all(orientation_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(orientation_wrapper, 0, LV_STATE_DEFAULT);
auto* orientation_label = lv_label_create(orientation_wrapper);
lv_label_set_text(orientation_label, "Orientation");
lv_obj_align(orientation_label, LV_ALIGN_TOP_LEFT, 0, 8);
lv_obj_align(orientation_label, LV_ALIGN_LEFT_MID, 0, 0);
auto* orientation_dropdown = lv_dropdown_create(orientation_wrapper);
// Note: order correlates with settings::display::Orientation item order
lv_dropdown_set_options(orientation_dropdown, "Landscape\nPortrait Right\nLandscape Flipped\nPortrait Left");
lv_obj_align(orientation_dropdown, LV_ALIGN_TOP_RIGHT, 0, 0);
lv_obj_align(orientation_dropdown, LV_ALIGN_RIGHT_MID, 0, 0);
lv_obj_set_style_border_color(orientation_dropdown, lv_color_hex(0xFAFAFA), LV_PART_MAIN);
lv_obj_set_style_border_width(orientation_dropdown, 1, LV_PART_MAIN);
lv_obj_add_event_cb(orientation_dropdown, onOrientationSet, LV_EVENT_VALUE_CHANGED, this);
@@ -24,7 +24,7 @@ public:
}
void onShow(AppContext& appContext, lv_obj_t* parent) override {
view->init(parent);
view->init(appContext, parent);
}
void onResult(AppContext& appContext, TT_UNUSED LaunchId launchId, Result result, std::unique_ptr<Bundle> bundle) override {
+2 -2
View File
@@ -255,11 +255,11 @@ void View::update() {
}
}
void View::init(lv_obj_t* parent) {
void View::init(const AppContext& appContext, lv_obj_t* parent) {
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
auto* toolbar = lvgl::toolbar_create(parent, "Files");
auto* toolbar = lvgl::toolbar_create(parent, appContext);
navigate_up_button = lvgl::toolbar_add_button_action(toolbar, LV_SYMBOL_UP, &onNavigateUpPressedCallback, this);
auto* wrapper = lv_obj_create(parent);
+15 -9
View File
@@ -1,4 +1,4 @@
#include "Tactility/service/loader/Loader.h"
#include <Tactility/service/loader/Loader.h>
#include <Tactility/Assets.h>
#include <Tactility/app/gpio/GpioHal.h>
#include "Tactility/lvgl/Toolbar.h"
@@ -119,11 +119,17 @@ void GpioApp::onShow(AppContext& app, lv_obj_t* parent) {
lv_obj_align(toolbar, LV_ALIGN_TOP_MID, 0, 0);
// Main content wrapper, enables scrolling content without scrolling the toolbar
auto* wrapper = lv_obj_create(parent);
lv_obj_set_width(wrapper, LV_PCT(100));
lv_obj_set_flex_grow(wrapper, 1);
lv_obj_set_style_border_width(wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_all(wrapper, 0, LV_STATE_DEFAULT);
auto* expansion_wrapper = lv_obj_create(parent);
lv_obj_set_width(expansion_wrapper, LV_PCT(100));
lv_obj_set_flex_grow(expansion_wrapper, 1);
lv_obj_set_style_border_width(expansion_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_all(expansion_wrapper, 0, LV_STATE_DEFAULT);
auto* centering_wrapper = lv_obj_create(expansion_wrapper);
lv_obj_set_size(centering_wrapper, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_align(centering_wrapper, LV_ALIGN_CENTER);
lv_obj_set_style_border_width(centering_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_all(centering_wrapper, 0, LV_STATE_DEFAULT);
auto* display = lv_obj_get_display(parent);
auto horizontal_px = lv_display_get_horizontal_resolution(display);
@@ -134,14 +140,14 @@ void GpioApp::onShow(AppContext& app, lv_obj_t* parent) {
const auto square_spacing = getSquareSpacing(ui_scale);
int32_t x_spacing = block_width + square_spacing;
uint8_t column = 0;
const uint8_t offset_from_left_label = 4;
const uint8_t column_limit = is_landscape_display ? 10 : 5;
auto* row_wrapper = createGpioRowWrapper(wrapper);
auto* row_wrapper = createGpioRowWrapper(centering_wrapper);
lv_obj_align(row_wrapper, LV_ALIGN_TOP_MID, 0, 0);
mutex.lock();
for (int i = GPIO_NUM_MIN; i < GPIO_NUM_MAX; ++i) {
constexpr uint8_t offset_from_left_label = 4;
// Add the GPIO number before the first item on a row
if (column == 0) {
@@ -165,7 +171,7 @@ void GpioApp::onShow(AppContext& app, lv_obj_t* parent) {
lv_obj_set_pos(postfix, (column + 1) * x_spacing + offset_from_left_label, 0);
// Add a new row wrapper underneath the last one
auto* new_row_wrapper = createGpioRowWrapper(wrapper);
auto* new_row_wrapper = createGpioRowWrapper(centering_wrapper);
lv_obj_align_to(new_row_wrapper, row_wrapper, LV_ALIGN_BOTTOM_LEFT, 0, square_spacing);
row_wrapper = new_row_wrapper;
@@ -91,6 +91,13 @@ public:
lv_obj_set_style_border_width(buttons_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_flex_grow(buttons_wrapper, 1);
// Fix for button selection (problem with UiScale::Small on Cardputer)
if (!hal::hasDevice(hal::Device::Type::Touch)) {
lv_obj_set_style_pad_all(buttons_wrapper, 6, LV_STATE_DEFAULT);
} else {
lv_obj_set_style_pad_all(buttons_wrapper, 0, LV_STATE_DEFAULT);
}
const auto* display = lv_obj_get_display(parent);
const auto horizontal_px = lv_display_get_horizontal_resolution(display);
const auto vertical_px = lv_display_get_vertical_resolution(display);
@@ -82,6 +82,8 @@ class LocaleSettingsApp : public App {
public:
void onShow(AppContext& app, lv_obj_t* parent) override {
auto ui_scale = hal::getConfiguration()->uiScale;
textResources.load();
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
@@ -94,6 +96,8 @@ public:
lv_obj_set_width(main_wrapper, LV_PCT(100));
lv_obj_set_flex_grow(main_wrapper, 1);
// Region
auto* region_wrapper = lv_obj_create(main_wrapper);
lv_obj_set_width(region_wrapper, LV_PCT(100));
lv_obj_set_height(region_wrapper, LV_SIZE_CONTENT);
@@ -104,20 +108,23 @@ public:
lv_label_set_text(regionLabel , textResources[i18n::Text::REGION].c_str());
lv_obj_align(regionLabel , LV_ALIGN_LEFT_MID, 0, 0);
auto* region_button = lv_button_create(region_wrapper);
lv_obj_align(region_button, LV_ALIGN_RIGHT_MID, 0, 0);
auto* region_button_image = lv_image_create(region_button);
lv_obj_add_event_cb(region_button, onConfigureTimeZonePressed, LV_EVENT_SHORT_CLICKED, nullptr);
lv_image_set_src(region_button_image, LV_SYMBOL_SETTINGS);
timeZoneLabel = lv_label_create(region_wrapper);
std::string timeZoneName = settings::getTimeZoneName();
if (timeZoneName.empty()) {
timeZoneName = "not set";
}
lv_label_set_text(timeZoneLabel, timeZoneName.c_str());
// TODO: Find out why Y offset is needed
lv_obj_align_to(timeZoneLabel, regionLabel, LV_ALIGN_OUT_RIGHT_MID, 10, 8);
auto* region_button = lv_button_create(region_wrapper);
lv_obj_align(region_button, LV_ALIGN_TOP_RIGHT, 0, 0);
auto* region_button_image = lv_image_create(region_button);
lv_obj_add_event_cb(region_button, onConfigureTimeZonePressed, LV_EVENT_SHORT_CLICKED, nullptr);
lv_image_set_src(region_button_image, LV_SYMBOL_SETTINGS);
lv_label_set_text(timeZoneLabel, timeZoneName.c_str());
const int offset = ui_scale == hal::UiScale::Smallest ? -2 : -10;
lv_obj_align_to(timeZoneLabel, region_button, LV_ALIGN_OUT_LEFT_MID, offset, 0);
// Language
auto* language_wrapper = lv_obj_create(main_wrapper);
lv_obj_set_width(language_wrapper, LV_PCT(100));
+9 -10
View File
@@ -1,8 +1,8 @@
#include "Tactility/app/selectiondialog/SelectionDialog.h"
#include "Tactility/lvgl/Style.h"
#include "Tactility/lvgl/Toolbar.h"
#include "Tactility/lvgl/LvglSync.h"
#include "Tactility/service/loader/Loader.h"
#include <Tactility/app/selectiondialog/SelectionDialog.h>
#include <Tactility/lvgl/Style.h>
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/lvgl/LvglSync.h>
#include <Tactility/service/loader/Loader.h>
#include <sstream>
#include <vector>
@@ -10,18 +10,16 @@
#include <lvgl.h>
#define TAG "text_viewer"
namespace tt::app::log {
class LogApp : public App {
private:
static constexpr auto* TAG = "LogApp";
LogLevel filterLevel = LogLevel::Info;
lv_obj_t* labelWidget = nullptr;
static inline bool shouldShowLog(LogLevel filterLevel, LogLevel logLevel) {
static bool shouldShowLog(LogLevel filterLevel, LogLevel logLevel) {
return filterLevel >= logLevel;
}
@@ -67,7 +65,8 @@ private:
"Warning",
"Error",
};
app::selectiondialog::start("Log Level", items);
selectiondialog::start("Log Level", items);
}
public:
+19 -20
View File
@@ -1,5 +1,5 @@
#include "Tactility/TactilityConfig.h"
#include "Tactility/lvgl/Toolbar.h"
#include <Tactility/TactilityConfig.h>
#include <Tactility/lvgl/Toolbar.h>
#include <Tactility/Assets.h>
#include <Tactility/hal/Device.h>
@@ -106,8 +106,8 @@ static void addMemoryBar(lv_obj_t* parent, const char* label, uint64_t free, uin
uint64_t used = total - free;
auto* container = lv_obj_create(parent);
lv_obj_set_size(container, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(container, 0, 0);
lv_obj_set_style_border_width(container, 0, 0);
lv_obj_set_style_pad_all(container, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(container, 0, LV_STATE_DEFAULT);
lv_obj_set_flex_flow(container, LV_FLEX_FLOW_ROW);
lv_obj_set_style_bg_opa(container, 0, LV_STATE_DEFAULT);
@@ -203,7 +203,15 @@ static void addDevices(lv_obj_t* parent) {
}
}
class SystemInfoApp : public App {
static lv_obj_t* createTab(lv_obj_t* tabview, const char* name) {
auto* tab = lv_tabview_add_tab(tabview, name);
lv_obj_set_flex_flow(tab, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(tab, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(tab, 0, LV_STATE_DEFAULT);
return tab;
}
class SystemInfoApp final : public App {
void onShow(AppContext& app, lv_obj_t* parent) override {
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
@@ -212,7 +220,7 @@ class SystemInfoApp : public App {
// This wrapper automatically has its children added vertically underneath eachother
auto* wrapper = lv_obj_create(parent);
lv_obj_set_style_border_width(wrapper, 0, 0);
lv_obj_set_style_border_width(wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_flex_flow(wrapper, LV_FLEX_FLOW_COLUMN);
lv_obj_set_width(wrapper, LV_PCT(100));
lv_obj_set_flex_grow(wrapper, 1);
@@ -224,20 +232,11 @@ class SystemInfoApp : public App {
// Tabs
auto* memory_tab = lv_tabview_add_tab(tabview, "Memory");
lv_obj_set_flex_flow(memory_tab, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(memory_tab, 0, LV_STATE_DEFAULT);
auto* storage_tab = lv_tabview_add_tab(tabview, "Storage");
lv_obj_set_flex_flow(storage_tab, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(storage_tab, 0, LV_STATE_DEFAULT);
auto* tasks_tab = lv_tabview_add_tab(tabview, "Tasks");
lv_obj_set_flex_flow(tasks_tab, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(tasks_tab, 4, LV_STATE_DEFAULT);
auto* devices_tab = lv_tabview_add_tab(tabview, "Devices");
lv_obj_set_flex_flow(devices_tab, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(devices_tab, 4, LV_STATE_DEFAULT);
auto* about_tab = lv_tabview_add_tab(tabview, "About");
lv_obj_set_flex_flow(about_tab, LV_FLEX_FLOW_COLUMN);
auto* memory_tab = createTab(tabview, "Memory");
auto* storage_tab = createTab(tabview, "Storage");
auto* tasks_tab = createTab(tabview, "Tasks");
auto* devices_tab = createTab(tabview, "Devices");
auto* about_tab = createTab(tabview, "About");
// Memory tab content
@@ -80,16 +80,16 @@ class WifiApSettings : public App {
auto* auto_connect_wrapper = lv_obj_create(wrapper);
lv_obj_set_size(auto_connect_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(auto_connect_wrapper, 0, 0);
lv_obj_set_style_pad_gap(auto_connect_wrapper, 0, 0);
lv_obj_set_style_border_width(auto_connect_wrapper, 0, 0);
lv_obj_set_style_pad_all(auto_connect_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_gap(auto_connect_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(auto_connect_wrapper, 0, LV_STATE_DEFAULT);
auto* auto_connect_label = lv_label_create(auto_connect_wrapper);
lv_label_set_text(auto_connect_label, "Auto-connect");
lv_obj_align(auto_connect_label, LV_ALIGN_TOP_LEFT, 0, 6);
auto* auto_connect_switch = lv_switch_create(auto_connect_wrapper);
lv_obj_add_event_cb(auto_connect_switch, onToggleAutoConnect, LV_EVENT_VALUE_CHANGED, (void*)&paremeters);
lv_obj_add_event_cb(auto_connect_switch, onToggleAutoConnect, LV_EVENT_VALUE_CHANGED, &paremeters);
lv_obj_align(auto_connect_switch, LV_ALIGN_TOP_RIGHT, 0, 0);
auto* forget_button = lv_button_create(wrapper);
+19 -19
View File
@@ -83,9 +83,9 @@ void View::createBottomButtons(lv_obj_t* parent) {
auto* button_container = lv_obj_create(parent);
lv_obj_set_width(button_container, LV_PCT(100));
lv_obj_set_height(button_container, LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(button_container, 0, 0);
lv_obj_set_style_pad_gap(button_container, 0, 0);
lv_obj_set_style_border_width(button_container, 0, 0);
lv_obj_set_style_pad_all(button_container, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_gap(button_container, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(button_container, 0, LV_STATE_DEFAULT);
remember_switch = lv_switch_create(button_container);
lv_obj_add_state(remember_switch, LV_STATE_CHECKED);
@@ -124,17 +124,17 @@ void View::init(AppContext& app, lv_obj_t* parent) {
auto* ssid_wrapper = lv_obj_create(wrapper);
lv_obj_set_width(ssid_wrapper, LV_PCT(100));
lv_obj_set_height(ssid_wrapper, LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(ssid_wrapper, 0, 0);
lv_obj_set_style_pad_gap(ssid_wrapper, 0, 0);
lv_obj_set_style_border_width(ssid_wrapper, 0, 0);
lv_obj_set_style_pad_all(ssid_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_gap(ssid_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(ssid_wrapper, 0, LV_STATE_DEFAULT);
auto* ssid_label_wrapper = lv_obj_create(ssid_wrapper);
lv_obj_set_width(ssid_label_wrapper, LV_PCT(50));
lv_obj_set_height(ssid_label_wrapper, LV_SIZE_CONTENT);
lv_obj_align(ssid_label_wrapper, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_set_style_border_width(ssid_label_wrapper, 0, 0);
lv_obj_set_style_pad_left(ssid_label_wrapper, 0, 0);
lv_obj_set_style_pad_right(ssid_label_wrapper, 0, 0);
lv_obj_align(ssid_label_wrapper, LV_ALIGN_LEFT_MID, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(ssid_label_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_left(ssid_label_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(ssid_label_wrapper, 0, LV_STATE_DEFAULT);
auto* ssid_label = lv_label_create(ssid_label_wrapper);
lv_label_set_text(ssid_label, "Network:");
@@ -145,7 +145,7 @@ void View::init(AppContext& app, lv_obj_t* parent) {
lv_obj_set_width(ssid_textarea, LV_PCT(50));
ssid_error = lv_label_create(wrapper);
lv_obj_set_style_text_color(ssid_error, lv_color_make(255, 50, 50), 0);
lv_obj_set_style_text_color(ssid_error, lv_color_make(255, 50, 50), LV_STATE_DEFAULT);
lv_obj_add_flag(ssid_error, LV_OBJ_FLAG_HIDDEN);
// Password
@@ -153,17 +153,17 @@ void View::init(AppContext& app, lv_obj_t* parent) {
auto* password_wrapper = lv_obj_create(wrapper);
lv_obj_set_width(password_wrapper, LV_PCT(100));
lv_obj_set_height(password_wrapper, LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(password_wrapper, 0, 0);
lv_obj_set_style_pad_gap(password_wrapper, 0, 0);
lv_obj_set_style_border_width(password_wrapper, 0, 0);
lv_obj_set_style_pad_all(password_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_gap(password_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(password_wrapper, 0, LV_STATE_DEFAULT);
auto* password_label_wrapper = lv_obj_create(password_wrapper);
lv_obj_set_width(password_label_wrapper, LV_PCT(50));
lv_obj_set_height(password_label_wrapper, LV_SIZE_CONTENT);
lv_obj_align_to(password_label_wrapper, password_wrapper, LV_ALIGN_LEFT_MID, 0, 0);
lv_obj_set_style_border_width(password_label_wrapper, 0, 0);
lv_obj_set_style_pad_left(password_label_wrapper, 0, 0);
lv_obj_set_style_pad_right(password_label_wrapper, 0, 0);
lv_obj_set_style_border_width(password_label_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_left(password_label_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_right(password_label_wrapper, 0, LV_STATE_DEFAULT);
auto* password_label = lv_label_create(password_label_wrapper);
lv_label_set_text(password_label, "Password:");
@@ -175,12 +175,12 @@ void View::init(AppContext& app, lv_obj_t* parent) {
lv_obj_set_width(password_textarea, LV_PCT(50));
password_error = lv_label_create(wrapper);
lv_obj_set_style_text_color(password_error, lv_color_make(255, 50, 50), 0);
lv_obj_set_style_text_color(password_error, lv_color_make(255, 50, 50), LV_STATE_DEFAULT);
lv_obj_add_flag(password_error, LV_OBJ_FLAG_HIDDEN);
// Connection error
connection_error = lv_label_create(wrapper);
lv_obj_set_style_text_color(connection_error, lv_color_make(255, 50, 50), 0);
lv_obj_set_style_text_color(connection_error, lv_color_make(255, 50, 50), LV_STATE_DEFAULT);
lv_obj_add_flag(connection_error, LV_OBJ_FLAG_HIDDEN);
// Bottom buttons
+63 -42
View File
@@ -95,14 +95,16 @@ static void showDetails(lv_event_t* event) {
}
void View::createSsidListItem(const service::wifi::ApRecord& record, bool isConnecting) {
auto ui_scale = hal::getConfiguration()->uiScale;
auto* wrapper = lv_obj_create(networks_list);
lv_obj_add_event_cb(wrapper, &connect, LV_EVENT_SHORT_CLICKED, bindings);
lv_obj_set_user_data(wrapper, bindings);
lv_obj_set_size(wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(wrapper, 0, 0);
lv_obj_set_style_pad_gap(wrapper, 0, 0);
lv_obj_set_style_margin_all(wrapper, 0, 0);
lv_obj_set_style_border_width(wrapper, 0, 0);
lv_obj_set_style_pad_all(wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_gap(wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_margin_all(wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(wrapper, 0, LV_STATE_DEFAULT);
auto* label = lv_label_create(wrapper);
lv_obj_align(label, LV_ALIGN_LEFT_MID, 0, 0);
@@ -111,9 +113,17 @@ void View::createSsidListItem(const service::wifi::ApRecord& record, bool isConn
lv_obj_set_width(label, LV_PCT(70));
auto* info_wrapper = lv_obj_create(wrapper);
lv_obj_set_style_pad_all(info_wrapper, 0, 0);
lv_obj_set_style_margin_all(info_wrapper, 0, 0);
lv_obj_set_size(info_wrapper, 36, 36);
lv_obj_set_style_margin_all(info_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_align(info_wrapper, LV_ALIGN_RIGHT_MID);
if (ui_scale == hal::UiScale::Smallest) {
lv_obj_set_size(info_wrapper, LV_SIZE_CONTENT, LV_SIZE_CONTENT);
lv_obj_set_style_pad_hor(info_wrapper, 4, LV_STATE_DEFAULT);
} else {
lv_obj_set_size(info_wrapper, 36, 36);
lv_obj_set_style_pad_all(info_wrapper, 0, LV_STATE_DEFAULT);
}
lv_obj_set_style_border_color(info_wrapper, lv_theme_get_color_primary(info_wrapper), 0);
lv_obj_add_event_cb(info_wrapper, &showDetails, LV_EVENT_SHORT_CLICKED, bindings);
lv_obj_align(info_wrapper, LV_ALIGN_RIGHT_MID, 0, 0);
@@ -124,26 +134,28 @@ void View::createSsidListItem(const service::wifi::ApRecord& record, bool isConn
auto* ssid_label = lv_label_create(info_wrapper);
lv_label_set_text(ssid_label, record.ssid.c_str());
lv_obj_add_flag(ssid_label, LV_OBJ_FLAG_HIDDEN);
lv_obj_set_style_text_color(info_label, lv_theme_get_color_primary(info_wrapper), 0);
lv_obj_set_style_text_color(info_label, lv_theme_get_color_primary(info_wrapper), LV_STATE_DEFAULT);
lv_obj_align(info_label, LV_ALIGN_CENTER, 0, 0);
if (isConnecting) {
auto* connecting_spinner = tt::lvgl::spinner_create(wrapper);
lv_obj_align_to(connecting_spinner, info_wrapper, LV_ALIGN_OUT_LEFT_MID, -8, 0);
auto* connecting_spinner = lvgl::spinner_create(wrapper);
auto spinner_offset_x = (ui_scale == hal::UiScale::Smallest) ? -2 : -8;
lv_obj_align_to(connecting_spinner, info_wrapper, LV_ALIGN_OUT_LEFT_MID, spinner_offset_x, 0);
} else {
auto percentage = mapRssiToPercentage(record.rssi);
std::string auth_info;
if (record.auth_mode == WIFI_AUTH_OPEN) {
auth_info = "(open) ";
auth_info = "(open)";
} else {
auth_info = "";
}
auto info = std::format("{}{}%", auth_info, percentage);
auto* open_label = lv_label_create(wrapper);
lv_label_set_text(open_label, info.c_str());
lv_obj_align(open_label, LV_ALIGN_RIGHT_MID, -42, 0);
auto signal = std::format("{}{}%", auth_info, percentage);
auto* signal_label = lv_label_create(wrapper);
lv_label_set_text(signal_label, signal.c_str());
auto info_label_offset = (ui_scale == hal::UiScale::Smallest) ? -4 : -16;
lv_obj_align_to(signal_label, info_wrapper, LV_ALIGN_OUT_LEFT_MID, info_label_offset, 0);
}
}
@@ -178,7 +190,7 @@ void View::updateNetworkList() {
state->withApRecords([this, &connection_target](const std::vector<service::wifi::ApRecord>& apRecords){
bool is_connected = !connection_target.empty() &&
state->getRadioState() == service::wifi::RadioState::ConnectionActive;
state->getRadioState() == ConnectionActive;
bool added_connected = false;
if (is_connected && !apRecords.empty()) {
for (auto &record : apRecords) {
@@ -198,7 +210,7 @@ void View::updateNetworkList() {
if (used_ssids.find(record.ssid) == used_ssids.end()) {
bool connection_target_match = (record.ssid == connection_target);
bool is_connecting = connection_target_match
&& state->getRadioState() == service::wifi::RadioState::ConnectionPending &&
&& state->getRadioState() == ConnectionPending &&
!connection_target.empty();
bool skip = connection_target_match && added_connected;
if (!skip) {
@@ -272,6 +284,8 @@ void View::updateEnableOnBootToggle() {
// region Main
void View::init(const AppContext& app, lv_obj_t* parent) {
auto ui_scale = hal::getConfiguration()->uiScale;
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
@@ -290,45 +304,52 @@ void View::init(const AppContext& app, lv_obj_t* parent) {
// Wrappers
lv_obj_t* secondary_flex = lv_obj_create(parent);
lv_obj_set_width(secondary_flex, LV_PCT(100));
lv_obj_set_flex_grow(secondary_flex, 1);
lv_obj_set_flex_flow(secondary_flex, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_border_width(secondary_flex, 0, 0);
lv_obj_set_style_pad_all(secondary_flex, 0, 0);
lv_obj_set_style_pad_gap(secondary_flex, 0, 0);
lvgl::obj_set_style_bg_invisible(secondary_flex);
auto* flex_wrapper = lv_obj_create(parent);
lv_obj_set_width(flex_wrapper, LV_PCT(100));
lv_obj_set_flex_grow(flex_wrapper, 1);
lv_obj_set_flex_flow(flex_wrapper, LV_FLEX_FLOW_COLUMN);
lv_obj_set_style_border_width(flex_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_all(flex_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_gap(flex_wrapper, 0, LV_STATE_DEFAULT);
lvgl::obj_set_style_bg_invisible(flex_wrapper);
// align() methods don't work on flex, so we need this extra wrapper
lv_obj_t* wrapper = lv_obj_create(secondary_flex);
lv_obj_set_size(wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lvgl::obj_set_style_bg_invisible(wrapper);
lv_obj_set_style_border_width(wrapper, 0, 0);
// Fixed size content wrapper: align() methods don't work on flex, so we need this extra wrapper
auto* content_wrapper = lv_obj_create(flex_wrapper);
lv_obj_set_size(content_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lvgl::obj_set_style_bg_invisible(content_wrapper);
lv_obj_set_style_border_width(content_wrapper, 0, LV_STATE_DEFAULT);
// Enable on boot
lv_obj_t* enable_label = lv_label_create(wrapper);
lv_label_set_text(enable_label, "Enable on boot");
lv_obj_align(enable_label, LV_ALIGN_TOP_LEFT, 0, 6);
auto* enable_on_boot_wrapper = lv_obj_create(content_wrapper);
lv_obj_set_size(enable_on_boot_wrapper, LV_PCT(100), LV_SIZE_CONTENT);
lv_obj_set_style_pad_all(enable_on_boot_wrapper, 0, LV_STATE_DEFAULT);
lv_obj_set_style_border_width(enable_on_boot_wrapper, 0, LV_STATE_DEFAULT);
enable_on_boot_switch = lv_switch_create(wrapper);
auto* enable_label = lv_label_create(enable_on_boot_wrapper);
lv_label_set_text(enable_label, "Enable on boot");
lv_obj_align(enable_label, LV_ALIGN_LEFT_MID, 0, 0);
enable_on_boot_switch = lv_switch_create(enable_on_boot_wrapper);
lv_obj_add_event_cb(enable_on_boot_switch, on_enable_on_boot_switch_changed, LV_EVENT_VALUE_CHANGED, bindings);
lv_obj_align(enable_on_boot_switch, LV_ALIGN_TOP_RIGHT, 0, 0);
lv_obj_align(enable_on_boot_switch, LV_ALIGN_RIGHT_MID, 0, 0);
// Networks
networks_list = lv_obj_create(wrapper);
networks_list = lv_obj_create(content_wrapper);
lv_obj_set_flex_flow(networks_list, LV_FLEX_FLOW_COLUMN);
lv_obj_set_width(networks_list, LV_PCT(100));
lv_obj_set_height(networks_list, LV_SIZE_CONTENT);
lv_obj_set_style_pad_top(networks_list, 0, 0);
lv_obj_set_style_pad_bottom(networks_list, 0, 0);
lv_obj_align(networks_list, LV_ALIGN_TOP_LEFT, 0, 44);
lv_obj_set_style_pad_top(networks_list, 0, LV_STATE_DEFAULT);
lv_obj_set_style_pad_bottom(networks_list, 0, LV_STATE_DEFAULT);
const int network_list_y_offset = ui_scale == hal::UiScale::Smallest ? 22 : 44;
lv_obj_align(networks_list, LV_ALIGN_TOP_LEFT, 0, network_list_y_offset);
connect_to_hidden = lv_button_create(secondary_flex);
connect_to_hidden = lv_button_create(flex_wrapper);
lv_obj_set_width(connect_to_hidden, LV_PCT(100));
lv_obj_set_style_margin_bottom(connect_to_hidden, 8, 0);
lv_obj_set_style_margin_hor(connect_to_hidden, 12, 0);
lv_obj_set_style_margin_bottom(connect_to_hidden, 8, LV_STATE_DEFAULT);
lv_obj_set_style_margin_hor(connect_to_hidden, 12, LV_STATE_DEFAULT);
lv_obj_add_event_cb(connect_to_hidden, onConnectToHiddenClicked, LV_EVENT_SHORT_CLICKED, bindings);
auto* connect_to_hidden_label = lv_label_create(connect_to_hidden);
lv_label_set_text(connect_to_hidden_label, "Connect to hidden SSID");